diff --git a/.gitignore b/.gitignore index 201326e9..ebf36527 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ libbitcoind **/*.files **/*.config **/*.creator +libbitcoind.includes +*.log diff --git a/PATCH_VERSION b/PATCH_VERSION index 3123ff93..fd2726c9 100644 --- a/PATCH_VERSION +++ b/PATCH_VERSION @@ -1 +1 @@ -v0.10.2 +v0.11.0 diff --git a/etc/bitcoin.patch b/etc/bitcoin.patch index ff740d9d..5606ee64 100644 --- a/etc/bitcoin.patch +++ b/etc/bitcoin.patch @@ -1,33 +1,33 @@ -From d354526706953a6f77800f9c77f854e062fda635 Mon Sep 17 00:00:00 2001 +From 05084f2a640b862132588b322461ec8e13058fc3 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte -Date: Tue, 7 Jul 2015 11:20:20 -0400 -Subject: [PATCH] added support for libbitcoind.so/dylib +Date: Mon, 13 Jul 2015 12:49:30 -0400 +Subject: [PATCH] libbitcoind --- config_me.sh | 1 + - configure.ac | 31 +++++++++++++++++++++++++++++-- + configure.ac | 37 ++++++++++++++++++++++++++++++++----- src/Makefile.am | 42 ++++++++++++++++++++++++++++++++++-------- - src/bitcoind.cpp | 5 +++++ + src/bitcoind.cpp | 6 ++++++ src/init.h | 5 +++++ src/leveldb/Makefile | 6 +++++- src/leveldbwrapper.h | 12 ++++++++++++ - 7 files changed, 91 insertions(+), 11 deletions(-) + 7 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 config_me.sh diff --git a/config_me.sh b/config_me.sh new file mode 100644 -index 0000000..9623c59 +index 0000000..19e9a1b --- /dev/null +++ b/config_me.sh @@ -0,0 +1 @@ +./configure --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --without-bdb --enable-debug --disable-wallet --without-utils diff --git a/configure.ac b/configure.ac -index 579035f..cd20489 100644 +index 37fe47e..27a9b9a 100644 --- a/configure.ac +++ b/configure.ac -@@ -126,6 +126,12 @@ AC_ARG_ENABLE([reduce-exports], +@@ -119,6 +119,12 @@ AC_ARG_ENABLE([reduce-exports], [use_reduce_exports=$enableval], - [use_reduce_exports=auto]) + [use_reduce_exports=no]) +AC_ARG_ENABLE([daemonlib], + [AS_HELP_STRING([--enable-daemonlib], @@ -38,7 +38,7 @@ index 579035f..cd20489 100644 AC_ARG_ENABLE([ccache], [AS_HELP_STRING([--enable-ccache], [use ccache for building (default is yes if ccache is found)])], -@@ -409,6 +415,9 @@ fi +@@ -402,6 +408,9 @@ fi if test x$use_hardening != xno; then AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) @@ -48,7 +48,7 @@ index 579035f..cd20489 100644 AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=2],[ AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[ -@@ -422,7 +431,7 @@ if test x$use_hardening != xno; then +@@ -415,7 +424,7 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"]) AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) @@ -57,7 +57,7 @@ index 579035f..cd20489 100644 # All windows code is PIC, forcing it on just adds useless compile warnings AX_CHECK_COMPILE_FLAG([-fPIE],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIE"]) AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"]) -@@ -440,6 +449,17 @@ if test x$use_hardening != xno; then +@@ -433,6 +442,17 @@ if test x$use_hardening != xno; then OBJCXXFLAGS="$CXXFLAGS" fi @@ -75,17 +75,14 @@ index 579035f..cd20489 100644 dnl this flag screws up non-darwin gcc even when the check fails. special-case it. if test x$TARGET_OS = xdarwin; then AX_CHECK_LINK_FLAG([[-Wl,-dead_strip]], [LDFLAGS="$LDFLAGS -Wl,-dead_strip"]) -@@ -485,7 +505,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ +@@ -483,11 +503,18 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ ] ) --if test x$use_reduce_exports != xno; then -+if test x$use_reduce_exports != xno -a x$use_daemonlib = xno; then +-if test x$use_reduce_exports = xyes; then ++if test x$use_reduce_exports = xyes -a x$use_daemonlib = xno; then AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], - [ - if test x$use_reduce_exports = xyes; then -@@ -496,6 +516,13 @@ if test x$use_reduce_exports != xno; then - ]) + [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) fi +AC_MSG_CHECKING([whether to compile as daemonlib]) @@ -99,7 +96,7 @@ index 579035f..cd20489 100644 LIBLEVELDB= LIBMEMENV= diff --git a/src/Makefile.am b/src/Makefile.am -index 81b16d1..d05c91a 100644 +index 1c2f770..632f608 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,7 @@ @@ -113,7 +110,7 @@ index 81b16d1..d05c91a 100644 @@ -15,6 +16,10 @@ $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS)" + OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" + +LIBLEVELDB_SHARED: + @echo "Building the LevelDB shared library..." && $(MAKE) -C ./leveldb @@ -155,7 +152,7 @@ index 81b16d1..d05c91a 100644 .PHONY: FORCE # bitcoin core # -@@ -156,8 +164,9 @@ obj/build.h: FORCE +@@ -169,8 +177,9 @@ obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ $(abs_top_srcdir) @@ -166,16 +163,10 @@ index 81b16d1..d05c91a 100644 # server: shared between bitcoind and bitcoin-qt libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) libbitcoin_server_a_SOURCES = \ -@@ -304,16 +313,33 @@ bitcoind_LDADD = \ - if ENABLE_WALLET - bitcoind_LDADD += libbitcoin_wallet.a - endif -+MEMOBJ = helpers/memenv/memenv.lo -+$(MEMOBJ): -+ @echo "Building the Memenv shared library..." && $(MAKE) -C ./leveldb $@ -+ +@@ -309,9 +318,18 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h bitcoind_SOURCES = bitcoind.cpp - # + bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) + bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +libbitcoind_la_SOURCES = bitcoind.cpp +libbitcoind_la_SOURCES += $(libbitcoin_util_a_SOURCES) +libbitcoind_la_SOURCES += $(libbitcoin_univalue_a_SOURCES) @@ -190,31 +181,39 @@ index 81b16d1..d05c91a 100644 +libbitcoind_la_SOURCES += bitcoind-res.rc endif + bitcoind_LDADD = \ +@@ -328,7 +346,15 @@ if ENABLE_WALLET + bitcoind_LDADD += libbitcoin_wallet.a + endif + ++MEMOBJ = helpers/memenv/memenv.lo ++$(MEMOBJ): ++ @echo "Building the Memenv shared library..." && $(MAKE) -C ./leveldb $@ ++ bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) - bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) - bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +libbitcoind_la_LIBADD = $(BOOST_LIBS) $(SSL_LIBS) $(LIBSECP256K1) $(CRYPTO_LIBS) leveldb/$(MEMOBJ) +libbitcoind_la_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoind_la_LDFLAGS = -lleveldb -L./leveldb $(RELDFLAGS) -no-undefined +libbitcoind_la_DEPENDENCIES = $(LIBSECP256K1) LIBLEVELDB_SHARED $(MEMOBJ) + # # bitcoin-cli binary # - bitcoin_cli_LDADD = \ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp -index be7757b..0eb62d8 100644 +index cce687a..0f162ff 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp -@@ -15,6 +15,9 @@ - #include - #include +@@ -33,6 +33,10 @@ + + static bool fDaemon; +#if ENABLE_DAEMONLIB -+extern void DetectShutdownThread(boost::thread_group* threadGroup); ++extern void WaitForShutdown(boost::thread_group* threadGroup); +#endif - /* Introduction text for doxygen: */ - - /*! \mainpage Developer documentation -@@ -175,6 +178,7 @@ bool AppInit(int argc, char* argv[]) ++ + void WaitForShutdown(boost::thread_group* threadGroup) + { + bool fShutdown = ShutdownRequested(); +@@ -166,6 +170,7 @@ bool AppInit(int argc, char* argv[]) return fRet; } @@ -222,16 +221,16 @@ index be7757b..0eb62d8 100644 int main(int argc, char* argv[]) { SetupEnvironment(); -@@ -184,3 +188,4 @@ int main(int argc, char* argv[]) +@@ -175,3 +180,4 @@ int main(int argc, char* argv[]) return (AppInit(argc, argv) ? 0 : 1); } +#endif diff --git a/src/init.h b/src/init.h -index f2f7ac6..9106580 100644 +index dcb2b29..5ce68ba 100644 --- a/src/init.h +++ b/src/init.h -@@ -17,6 +17,11 @@ class thread_group; +@@ -18,6 +18,11 @@ class thread_group; extern CWallet* pwalletMain; @@ -268,7 +267,7 @@ index 2bd2cad..490ba66 100644 $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h -index 4247920..c75c63c 100644 +index c65e842..0e44bb5 100644 --- a/src/leveldbwrapper.h +++ b/src/leveldbwrapper.h @@ -29,10 +29,16 @@ class CLevelDBBatch diff --git a/platform/os.sh b/platform/os.sh index 3edba5e8..14406da7 100755 --- a/platform/os.sh +++ b/platform/os.sh @@ -75,8 +75,12 @@ if test -z "$1" -o x"$1" = x'thread'; then fi if test -z "$1" -o x"$1" = x'lib'; then - if test -e "${os_dir}/libbitcoind.${ext}"; then - echo -n "$(pwd)/platform/${os}/libbitcoind.${ext}" + if test -e "${os_dir}/libbitcoind.${ext}" -o -e "${os_dir}/lib/libbitcoind.${ext}"; then + if test -e "${os_dir}/lib/libbitcoind.${ext}"; then + echo -n "$(pwd)/platform/${os}/lib/libbitcoind.${ext}" + else + echo -n "$(pwd)/platform/${os}/libbitcoind.${ext}" + fi else echo -n "${BITCOIN_DIR}/src/.libs/libbitcoind.${ext}" fi diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 28599bad..e7acf634 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -20,19 +20,9 @@ using namespace v8; // These global functions and variables are // required to be defined/exposed here. -extern void DetectShutdownThread(boost::thread_group*); -extern int nScriptCheckThreads; -extern std::map mapArgs; -extern CFeeRate payTxFee; -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); -extern std::string DecodeDumpString(const std::string &str); -extern bool fTxIndex; +extern void WaitForShutdown(boost::thread_group* threadGroup); static termios orig_termios; - /** * Node.js Internal Function Templates */ @@ -67,72 +57,12 @@ async_get_block(uv_work_t *req); static void async_get_block_after(uv_work_t *req); -static void -async_get_progress(uv_work_t *req); - -static void -async_get_progress_after(uv_work_t *req); - static void async_get_tx(uv_work_t *req); static void async_get_tx_after(uv_work_t *req); -static void -async_get_addrtx(uv_work_t *req); - -static void -async_get_addrtx_after(uv_work_t *req); - -static void -async_broadcast_tx(uv_work_t *req); - -static void -async_broadcast_tx_after(uv_work_t *req); - -static void -async_block_tx(uv_work_t *req); - -static void -async_block_tx_after(uv_work_t *req); - -static void -async_block_time(uv_work_t *req); - -static void -async_block_time_after(uv_work_t *req); - -static void -async_from_tx(uv_work_t *req); - -static void -async_from_tx_after(uv_work_t *req); - -static inline void -cblock_to_jsblock(const CBlock& cblock, CBlockIndex* cblock_index, Local jsblock, bool is_new); - -static inline void -ctx_to_jstx(const CTransaction& ctx, uint256 blockhash, Local jstx); - -static inline void -jsblock_to_cblock(const Local jsblock, CBlock& cblock); - -static inline void -jstx_to_ctx(const Local jstx, CTransaction& ctx); - -static void -hook_packets(void); - -static void -unhook_packets(void); - -static bool -process_packets(CNode* pfrom); - -static bool -process_packet(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived); - static int get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx); @@ -187,7 +117,7 @@ struct async_node_data { struct async_block_data { std::string err_msg; - std::string hash; + const char* hash; int64_t height; char* buffer; uint32_t size; @@ -202,8 +132,8 @@ struct async_block_data { struct async_tx_data { std::string err_msg; - std::string txid; - std::string blockhash; + const char* txid; + const char* blockhash; CTransaction ctx; Eternal callback; }; @@ -286,20 +216,6 @@ struct async_from_tx_data { Eternal callback; }; -/** - * Read Raw DB - */ - -#if USE_LDB_ADDR -static ctx_list * -read_addr(const std::string addr, const int64_t blockheight, const int64_t blocktime); -#endif - -#if USE_LDB_TX -static bool -get_block_by_tx(const std::string itxid, CBlock& rcblock, CBlockIndex **rcblock_index, CTransaction& rctx); -#endif - /** * Helpers */ @@ -545,16 +461,13 @@ start_node(void) { signal(SIGHUP, SIG_DFL); signal(SIGQUIT, SIG_DFL); - // Hook into packet handling - new boost::thread(boost::bind(&hook_packets)); - return 0; } static void start_node_thread(void) { boost::thread_group threadGroup; - boost::thread* detectShutdownThread = NULL; + CScheduler scheduler; // Workaround for AppInit2() arg parsing. Not ideal, but it works. int argc = 0; @@ -634,38 +547,27 @@ start_node_thread(void) { CreatePidFile(GetPidFile(), getpid()); - detectShutdownThread = new boost::thread( - boost::bind(&DetectShutdownThread, &threadGroup)); - - fRet = AppInit2(threadGroup); + fRet = AppInit2(threadGroup, scheduler); } catch (std::exception& e) { if (set_cooked()) { - fprintf(stderr, "bitcoind.js: AppInit(): std::exception\n"); + fprintf(stderr, "bitcoind.js: AppInit2(): std::exception\n"); } } catch (...) { if (set_cooked()) { - fprintf(stderr, "bitcoind.js: AppInit(): other exception\n"); + fprintf(stderr, "bitcoind.js: AppInit2(): other exception\n"); } } - if (!fRet) { - if (detectShutdownThread) { - detectShutdownThread->interrupt(); - } - threadGroup.interrupt_all(); - } - - if (detectShutdownThread) { - detectShutdownThread->join(); - delete detectShutdownThread; - detectShutdownThread = NULL; + if (!fRet) + { + threadGroup.interrupt_all(); + } else { + WaitForShutdown(&threadGroup); } Shutdown(); - - // bitcoind is shutdown. Notify the main thread - // which is polling this variable: shutdown_complete = true; + } /** @@ -716,7 +618,6 @@ NAN_METHOD(StopBitcoind) { static void async_stop_node(uv_work_t *req) { async_node_data *data = static_cast(req->data); - unhook_packets(); StartShutdown(); while(!shutdown_complete) { usleep(1E6); @@ -807,13 +708,12 @@ NAN_METHOD(GetBlock) { if (args[0]->IsNumber()) { int64_t height = args[0]->IntegerValue(); data->err_msg = std::string(""); - data->hash = std::string(""); + data->hash = NULL; 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->hash = *hash_; data->height = -1; } @@ -838,8 +738,7 @@ async_get_block(uv_work_t *req) { async_block_data* data = static_cast(req->data); CBlockIndex* pblockindex; - std::string strHash = data->hash; - uint256 hash(strHash); + uint256 hash = uint256S(data->hash); if (data->height != -1) { pblockindex = chainActive[data->height]; @@ -902,7 +801,6 @@ async_get_block_after(uv_work_t *req) { node::FatalException(try_catch); } } else { - CBlockIndex* cblock_index = data->cblock_index; Local rawNodeBuffer = node::Buffer::New(isolate, data->buffer, data->size); @@ -946,20 +844,20 @@ NAN_METHOD(GetTransaction) { String::Utf8Value blockhash_(args[1]->ToString()); Local callback = Local::Cast(args[2]); - std::string txid = std::string(*txid_); - std::string blockhash = std::string(*blockhash_); - - if (blockhash == "") { - blockhash = uint256(0).GetHex(); - } - async_tx_data *data = new async_tx_data(); + data->err_msg = std::string(""); - data->txid = txid; - data->blockhash = blockhash; + data->txid = *txid_; Eternal eternal(isolate, callback); data->callback = eternal; + if (blockhash_.length() == 0) { + data->blockhash = uint256().GetHex().c_str(); + } + else { + data->blockhash = *blockhash_; + } + uv_work_t *req = new uv_work_t(); req->data = data; @@ -976,13 +874,13 @@ static void async_get_tx(uv_work_t *req) { async_tx_data* data = static_cast(req->data); - uint256 hash(data->txid); - uint256 blockhash(data->blockhash); + uint256 hash = uint256S(data->txid); + uint256 blockhash = uint256S(data->blockhash); CTransaction ctx; if (get_tx(hash, blockhash, ctx)) { data->ctx = ctx; - data->blockhash = blockhash.GetHex(); + data->blockhash = blockhash.GetHex().c_str(); } else { data->err_msg = std::string("Transaction not found."); } @@ -995,7 +893,6 @@ async_get_tx_after(uv_work_t *req) { async_tx_data* data = static_cast(req->data); CTransaction ctx = data->ctx; - uint256 blockhash(data->blockhash); Local cb = data->callback.Get(isolate); if (data->err_msg != "") { @@ -1009,7 +906,6 @@ async_get_tx_after(uv_work_t *req) { } } else { Local jstx = NanNew(); - ctx_to_jstx(ctx, blockhash, jstx); const unsigned argc = 2; Local argv[argc] = { @@ -1026,194 +922,6 @@ async_get_tx_after(uv_work_t *req) { delete req; } -/** - * BroadcastTx() - * bitcoind.broadcastTx(tx, override_fees, own_only, callback) - * Broadcast a raw transaction. This can be used to relay transaction received - * or to broadcast one's own transaction. - */ - -NAN_METHOD(BroadcastTx) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 4 - || !args[0]->IsObject() - || !args[1]->IsBoolean() - || !args[2]->IsBoolean() - || !args[3]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.broadcastTx(tx, override_fees, own_only, callback)"); - } - - Local jstx = Local::Cast(args[0]); - Local callback = Local::Cast(args[3]); - - async_broadcast_tx_data *data = new async_broadcast_tx_data(); - data->override_fees = args[1]->ToBoolean()->IsTrue(); - data->own_only = args[2]->ToBoolean()->IsTrue(); - data->err_msg = std::string(""); - Eternal eternal(isolate, callback); - data->callback = eternal; - - Eternal eternalObject(isolate, jstx); - data->jstx = eternalObject; - - CTransaction ctx; - jstx_to_ctx(jstx, ctx); - data->ctx = ctx; - - 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)); -} - -static void -async_broadcast_tx(uv_work_t *req) { - async_broadcast_tx_data* data = static_cast(req->data); - - bool fOverrideFees = false; - bool fOwnOnly = false; - - if (data->override_fees) { - fOverrideFees = true; - } - - if (data->own_only) { - fOwnOnly = true; - } - - CTransaction ctx = data->ctx; - - uint256 hashTx = ctx.GetHash(); - - bool fHave = false; - CCoinsViewCache &view = *pcoinsTip; - CCoins existingCoins; - if (fOwnOnly) { - fHave = view.GetCoins(hashTx, existingCoins); - if (!fHave) { - CValidationState state; - if (!AcceptToMemoryPool(mempool, state, ctx, 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; - } - } - - RelayTransaction(ctx); - - data->txid = hashTx.GetHex(); -} - -static void -async_broadcast_tx_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - async_broadcast_tx_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - Local obj = data->jstx.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local 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 = 3; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, NanNew(data->txid)), - Local::New(isolate, obj) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * VerifyBlock() - * bitcoindjs.verifyBlock(block) - * This will verify the authenticity of a block (merkleRoot, etc) - * using the internal bitcoind functions. - */ - -NAN_METHOD(VerifyBlock) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.verifyBlock(block)"); - } - - Local jsblock = Local::Cast(args[0]); - - String::Utf8Value block_hex_(jsblock->Get(NanNew("hex"))->ToString()); - std::string block_hex = std::string(*block_hex_); - - CBlock cblock; - jsblock_to_cblock(jsblock, cblock); - - CValidationState state; - bool valid = CheckBlock(cblock, state); - - NanReturnValue(NanNew(valid)); -} - -/** - * VerifyTransaction() - * bitcoindjs.verifyTransaction(tx) - * This will verify a transaction, ensuring it is signed properly using the - * internal bitcoind functions. - */ - -NAN_METHOD(VerifyTransaction) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsObject()) { - return NanThrowError( - "Usage: bitcoindjs.verifyTransaction(tx)"); - } - - Local jstx = Local::Cast(args[0]); - - String::Utf8Value tx_hex_(jstx->Get(NanNew("hex"))->ToString()); - std::string tx_hex = std::string(*tx_hex_); - - CTransaction ctx; - jstx_to_ctx(jstx, ctx); - - CValidationState state; - bool valid = CheckTransaction(ctx, state); - - std::string reason; - bool standard = IsStandardTx(ctx, reason); - - NanReturnValue(NanNew(valid && standard)); -} - /** * GetInfo() * bitcoindjs.getInfo() @@ -1238,7 +946,6 @@ NAN_METHOD(GetInfo) { obj->Set(NanNew("blocks"), NanNew((int)chainActive.Height())->ToInt32()); obj->Set(NanNew("timeoffset"), NanNew(GetTimeOffset())); obj->Set(NanNew("connections"), NanNew((int)vNodes.size())->ToInt32()); - obj->Set(NanNew("proxy"), NanNew(proxy.IsValid() ? proxy.ToStringIPPort() : std::string(""))); obj->Set(NanNew("difficulty"), NanNew((double)GetDifficulty())); obj->Set(NanNew("testnet"), NanNew(Params().NetworkIDString() == "test")); obj->Set(NanNew("relayfee"), NanNew(::minRelayTxFee.GetFeePerK())); // double @@ -1247,1685 +954,11 @@ NAN_METHOD(GetInfo) { NanReturnValue(obj); } -/** - * GetPeerInfo() - * bitcoindjs.getPeerInfo() - * Get peer information - */ - -NAN_METHOD(GetPeerInfo) { - NanScope(); - - if (args.Length() > 0) { - return NanThrowError( - "Usage: bitcoindjs.getPeerInfo()"); - } - - Local array = NanNew(); - int i = 0; - - vector vstats; - vstats.clear(); - LOCK(cs_vNodes); - vstats.reserve(vNodes.size()); - BOOST_FOREACH(CNode* pnode, vNodes) { - CNodeStats stats; - pnode->copyStats(stats); - vstats.push_back(stats); - } - - BOOST_FOREACH(const CNodeStats& stats, vstats) { - Local obj = NanNew(); - - CNodeStateStats statestats; - bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); - obj->Set(NanNew("id"), NanNew(stats.nodeid)); - obj->Set(NanNew("addr"), NanNew(stats.addrName)); - if (!(stats.addrLocal.empty())) { - obj->Set(NanNew("addrlocal"), NanNew(stats.addrLocal)); - } - obj->Set(NanNew("services"), NanNew(strprintf("%016x", stats.nServices))); - obj->Set(NanNew("lastsend"), NanNew(stats.nLastSend)); - obj->Set(NanNew("lastrecv"), NanNew(stats.nLastRecv)); - obj->Set(NanNew("bytessent"), NanNew(stats.nSendBytes)); - obj->Set(NanNew("bytesrecv"), NanNew(stats.nRecvBytes)); - obj->Set(NanNew("conntime"), NanNew(stats.nTimeConnected)); - obj->Set(NanNew("pingtime"), NanNew(stats.dPingTime)); // double - if (stats.dPingWait > 0.0) { - obj->Set(NanNew("pingwait"), NanNew(stats.dPingWait)); // double - } - obj->Set(NanNew("version"), NanNew(stats.nVersion)); - obj->Set(NanNew("subver"), NanNew(stats.cleanSubVer)); - obj->Set(NanNew("inbound"), NanNew(stats.fInbound)); - obj->Set(NanNew("startingheight"), NanNew(stats.nStartingHeight)); - if (fStateStats) { - obj->Set(NanNew("banscore"), NanNew(statestats.nMisbehavior)); - obj->Set(NanNew("syncheight"), NanNew(statestats.nSyncHeight)->ToInt32()); - obj->Set(NanNew("synced_headers"), NanNew(statestats.nSyncHeight)->ToInt32()); - obj->Set(NanNew("synced_blocks"), NanNew(statestats.nCommonHeight)->ToInt32()); - Local heights = NanNew(); - int hi = 0; - BOOST_FOREACH(int height, statestats.vHeightInFlight) { - heights->Set(hi, NanNew(height)); - hi++; - } - obj->Set(NanNew("inflight"), heights); - } - - obj->Set(NanNew("whitelisted"), NanNew(stats.fWhitelisted)); - // obj->Set(NanNew("relaytxes"), NanNew(stats.fRelayTxes)); - - array->Set(i, obj); - i++; - } - - NanReturnValue(array); -} - -/** - * GetAddresses() - * bitcoindjs.getAddresses() - * Get all addresses - */ - -NAN_METHOD(GetAddresses) { - NanScope(); - - if (args.Length() > 0) { - return NanThrowError( - "Usage: bitcoindjs.getAddresses()"); - } - - Local array = NanNew(); - int i = 0; - - std::vector vAddr = addrman.GetAddr(); - - BOOST_FOREACH(const CAddress& addr, vAddr) { - Local obj = NanNew(); - - char nServices[21] = {0}; - int written = snprintf(nServices, sizeof(nServices), "%020llu", (uint64_t)addr.nServices); - assert(written == 20); - - obj->Set(NanNew("services"), NanNew((char *)nServices)); - obj->Set(NanNew("time"), NanNew((unsigned int)addr.nTime)->ToUint32()); - obj->Set(NanNew("last"), NanNew((int64_t)addr.nLastTry)); - obj->Set(NanNew("ip"), NanNew((std::string)addr.ToStringIP())); - obj->Set(NanNew("port"), NanNew((unsigned short)addr.GetPort())->ToUint32()); - obj->Set(NanNew("address"), NanNew((std::string)addr.ToStringIPPort())); - - array->Set(i, obj); - i++; - } - - NanReturnValue(array); -} - -/** - * GetProgress() - * bitcoindjs.getProgress(callback) - * Get progress of blockchain download - */ - -NAN_METHOD(GetProgress) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 1 || !args[0]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.getProgress(callback)"); - } - - Local callback = Local::Cast(args[0]); - - async_block_data *data = new async_block_data(); - data->err_msg = std::string(""); - CBlockIndex *pindex = chainActive.Tip(); - data->hash = pindex->GetBlockHash().GetHex(); - data->height = -1; - - Eternal 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_get_progress, - (uv_after_work_cb)async_get_progress_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_get_progress(uv_work_t *req) { - async_get_block(req); -} - -static void -async_get_progress_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - async_block_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const CBlock& cblock = data->cblock; - CBlockIndex* cblock_index = data->cblock_index; - - Local jsblock = NanNew(); - cblock_to_jsblock(cblock, cblock_index, jsblock, false); - - const CBlock& cgenesis = Params().GenesisBlock(); - - Local genesis = NanNew(); - cblock_to_jsblock(cgenesis, NULL, genesis, false); - - // Get progress: - double progress = Checkpoints::GuessVerificationProgress(cblock_index, false); - - // 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); - - // Calculate tangible progress: - unsigned int hours_behind = left / 60 / 60; - unsigned int days_behind = left / 60 / 60 / 24; - unsigned int percent = (unsigned int)(progress * 100.0); - - if (percent == 100 || left < 0) { - hours_behind = 0; - days_behind = 0; - } - - Local result = NanNew(); - - result->Set(NanNew("blocks"), - NanNew(cblock_index->nHeight)); - result->Set(NanNew("connections"), - NanNew((int)vNodes.size())->ToInt32()); - result->Set(NanNew("genesisBlock"), genesis); - result->Set(NanNew("currentBlock"), jsblock); - result->Set(NanNew("hoursBehind"), NanNew(hours_behind)); - result->Set(NanNew("daysBehind"), NanNew(days_behind)); - result->Set(NanNew("percent"), NanNew(percent)); - - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate,result) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * GetMiningInfo() - * bitcoindjs.getMiningInfo() - * Get coin generation / mining information - */ - -NAN_METHOD(GetMiningInfo) { - NanScope(); - - Local obj = NanNew(); - - json_spirit::Array empty_params; - - obj->Set(NanNew("blocks"), NanNew((int)chainActive.Height())); - obj->Set(NanNew("currentblocksize"), NanNew((uint64_t)nLastBlockSize)); - obj->Set(NanNew("currentblocktx"), NanNew((uint64_t)nLastBlockTx)); - obj->Set(NanNew("difficulty"), NanNew((double)GetDifficulty())); - obj->Set(NanNew("errors"), NanNew(GetWarnings("statusbar"))); - obj->Set(NanNew("genproclimit"), NanNew((int)GetArg("-genproclimit", -1))); - obj->Set(NanNew("networkhashps"), NanNew( - (int64_t)getnetworkhashps(empty_params, false).get_int64())); - obj->Set(NanNew("pooledtx"), NanNew((uint64_t)mempool.size())); - obj->Set(NanNew("testnet"), NanNew(Params().NetworkIDString() == "test")); - obj->Set(NanNew("chain"), NanNew(Params().NetworkIDString())); - - NanReturnValue(obj); -} - -/** - * GetAddrTransactions() - * bitcoind.getAddrTransactions(addr, callback) - * Read any transaction from disk asynchronously. - */ - -NAN_METHOD(GetAddrTransactions) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 - || (!args[0]->IsString() && !args[0]->IsObject()) - || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.getAddrTransactions(addr, callback)"); - } - - std::string addr = ""; - int64_t blockheight = -1; - int64_t blocktime = -1; - - if (args[0]->IsString()) { - String::Utf8Value addr_(args[0]->ToString()); - addr = std::string(*addr_); - } else if (args[0]->IsObject()) { - Local options = Local::Cast(args[0]); - if (options->Get(NanNew("address"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("address"))->ToString()); - addr = std::string(*s_); - } - if (options->Get(NanNew("addr"))->IsString()) { - String::Utf8Value s_(options->Get(NanNew("addr"))->ToString()); - addr = std::string(*s_); - } - if (options->Get(NanNew("height"))->IsNumber()) { - blockheight = options->Get(NanNew("height"))->IntegerValue(); - } - if (options->Get(NanNew("blockheight"))->IsNumber()) { - blockheight = options->Get(NanNew("blockheight"))->IntegerValue(); - } - if (options->Get(NanNew("time"))->IsNumber()) { - blocktime = options->Get(NanNew("time"))->IntegerValue(); - } - if (options->Get(NanNew("blocktime"))->IsNumber()) { - blocktime = options->Get(NanNew("blocktime"))->IntegerValue(); - } - } - - Local callback = Local::Cast(args[1]); - - async_addrtx_data *data = new async_addrtx_data(); - data->err_msg = std::string(""); - data->addr = addr; - data->ctxs = NULL; - data->blockheight = blockheight; - data->blocktime = blocktime; - Eternal 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_get_addrtx, - (uv_after_work_cb)async_get_addrtx_after); - - assert(status == 0); - - NanReturnValue(Undefined(isolate)); -} - -static void -async_get_addrtx(uv_work_t *req) { - async_addrtx_data* data = static_cast(req->data); - - if (data->addr.empty()) { - data->err_msg = std::string("Invalid address."); - return; - } - - CBitcoinAddress address = CBitcoinAddress(data->addr); - if (!address.IsValid()) { - data->err_msg = std::string("Invalid address."); - return; - } - -#if !USE_LDB_ADDR - CScript expected = GetScriptForDestination(address.Get()); - - int64_t i = 0; - - if (data->blockheight != -1) { - i = data->blockheight; - } - - 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) { - if (txin.scriptSig.ToString() == expected.ToString()) { - 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; - } - 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 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(); - if (data->ctxs == NULL) { - data->ctxs = item; - } else { - data->ctxs->next = item; - data->ctxs = item; - } - goto done; - } - } - } - } - } - -done: - continue; - } else { - data->err_msg = std::string("Address not found."); - break; - } - } - return; -#else - ctx_list *ctxs = read_addr(data->addr, data->blockheight, data->blocktime); - if (!ctxs->err_msg.empty()) { - data->err_msg = ctxs->err_msg; - return; - } - data->ctxs = ctxs; - if (data->ctxs == NULL) { - data->err_msg = std::string("Could not read database."); - } -#endif -} - -static void -async_get_addrtx_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_addrtx_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local 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 result = NanNew(); - Local tx = NanNew(); - int i = 0; - ctx_list *next; - for (ctx_list *item = data->ctxs; item; item = next) { - Local jstx = NanNew(); - ctx_to_jstx(item->ctx, item->blockhash, jstx); - tx->Set(i, jstx); - i++; - next = item->next; - delete item; - } - result->Set(NanNew("address"), NanNew(data->addr)); - result->Set(NanNew("tx"), tx); - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, result) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * GetBestBlock() - * bitcoindjs.getBestBlock() - * Get the best block - */ - -NAN_METHOD(GetBestBlock) { - NanScope(); - - if (args.Length() < 0) { - return NanThrowError( - "Usage: bitcoindjs.getBestBlock()"); - } - - uint256 hash = pcoinsTip->GetBestBlock(); - - NanReturnValue(NanNew(hash.GetHex())); -} - -/** - * GetChainHeight() - * bitcoindjs.getChainHeight() - * Get miscellaneous information - */ - -NAN_METHOD(GetChainHeight) { - NanScope(); - - if (args.Length() > 0) { - return NanThrowError( - "Usage: bitcoindjs.getChainHeight()"); - } - - NanReturnValue(NanNew((int)chainActive.Height())->ToInt32()); -} - -/** - * GetBlockByTx() - * bitcoindjs.getBlockByTx() - * Get block by tx hash (requires -txindex or it's very slow) - */ - -NAN_METHOD(GetBlockByTx) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - 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; - - String::Utf8Value txid_(args[0]->ToString()); - std::string txid = std::string(*txid_); - data->err_msg = std::string(""); - data->txid = txid; - - Local callback = Local::Cast(args[1]); - Eternal eternal(isolate, callback); - data->callback = eternal; - - 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)); -} - -static void -async_block_tx(uv_work_t *req) { - async_block_tx_data* data = static_cast(req->data); -#if USE_LDB_TX - if (!g_txindex) { -parse: -#endif - 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& tx, cblock.vtx) { - if (tx.GetHash().GetHex() == data->txid) { - data->cblock = cblock; - data->cblock_index = pblockindex; - data->ctx = tx; - return; - } - } - } - } - data->err_msg = std::string("Block not found."); - return; -#if USE_LDB_TX - } - if (!get_block_by_tx(data->txid, data->cblock, &data->cblock_index, data->ctx)) { - goto parse; - } -#endif -} - -static void -async_block_tx_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - async_block_tx_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const CBlock& cblock = data->cblock; - CBlockIndex* cblock_index = data->cblock_index; - const CTransaction& ctx = data->ctx; - - Local jsblock = NanNew(); - cblock_to_jsblock(cblock, cblock_index, jsblock, false); - - Local jstx = NanNew(); - ctx_to_jstx(ctx, cblock.GetHash(), jstx); - - const unsigned argc = 3; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, jsblock), - Local::New(isolate, jstx) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * GetBlocksByTime() - * bitcoindjs.getBlocksByTime() - * Get block by tx hash (requires -txindex or it's very slow) - */ - -NAN_METHOD(GetBlocksByTime) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - if (args.Length() < 2 - || !args[0]->IsString() - || !args[1]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.getBlocksByTime(options, callback)"); - } - - async_block_time_data *data = new async_block_time_data(); - - data->gte = 0; - data->lte = 0; - - uv_work_t *req = new uv_work_t(); - req->data = data; - - Local options = Local::Cast(args[0]); - if (options->Get(NanNew("gte"))->IsNumber()) { - data->gte = options->Get(NanNew("gte"))->IntegerValue(); - } - if (options->Get(NanNew("lte"))->IsNumber()) { - data->lte = options->Get(NanNew("lte"))->IntegerValue(); - } - if (options->Get(NanNew("limit"))->IsNumber()) { - data->limit = options->Get(NanNew("limit"))->IntegerValue(); - } - data->err_msg = std::string(""); - data->cblocks = NULL; - - Local callback = Local::Cast(args[1]); - Eternal eternal(isolate, callback); - data->callback = eternal; - - 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)); -} - -static void -async_block_time(uv_work_t *req) { - async_block_time_data* data = static_cast(req->data); - if (!data->gte && !data->lte) { - data->err_msg = std::string("gte and lte not found."); - return; - } - int64_t i = 0; - // XXX Slow: figure out how to ballpark the height based on gte and lte. - int64_t height = chainActive.Height(); - bool found_range = false; - int64_t found = 0; - 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) { - 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; - } - } - } - data->err_msg = std::string("Block not found."); -} - -static void -async_block_time_after(uv_work_t *req) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - - async_block_time_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - Local jsblocks = NanNew(); - int i = 0; - cblocks_list *next; - for (cblocks_list *item = data->cblocks; item; item = next) { - Local jsblock = NanNew(); - cblock_to_jsblock(item->cblock, item->cblock_index, jsblock, false); - jsblocks->Set(i, jsblock); - i++; - next = item->next; - delete item; - } - const unsigned argc = 2; - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, jsblocks) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - delete data; - delete req; -} - -/** - * GetFromTx() - * bitcoindjs.getFromTx() - * Get all TXes beyond a txid - */ - -NAN_METHOD(GetFromTx) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - 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 callback = Local::Cast(args[1]); - Eternal eternal(isolate, callback); - data->callback = eternal; - - 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)); -} - -static void -async_from_tx(uv_work_t *req) { - async_from_tx_data* data = static_cast(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(); - HandleScope scope(isolate); - - async_from_tx_data* data = static_cast(req->data); - Local cb = data->callback.Get(isolate); - - if (data->err_msg != "") { - Local err = Exception::Error(NanNew(data->err_msg)); - const unsigned argc = 1; - Local 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 tx = NanNew(); - int i = 0; - ctx_list *next; - for (ctx_list *item = data->ctxs; item; item = next) { - Local jstx = NanNew(); - ctx_to_jstx(item->ctx, item->blockhash, jstx); - tx->Set(i, jstx); - i++; - next = item->next; - delete item; - } - Local argv[argc] = { - Local::New(isolate, NanNull()), - Local::New(isolate, tx) - }; - TryCatch try_catch; - cb->Call(isolate->GetCurrentContext()->Global(), argc, argv); - 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(blockPos.nFile)); -} - -/** - * 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 jsblock = Local::Cast(args[0]); - - CBlock cblock; - jsblock_to_cblock(jsblock, cblock); - - Local data = NanNew(); - - data->Set(NanNew("hash"), NanNew(cblock.GetHash().GetHex())); - - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - ssBlock << cblock; - std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); - data->Set(NanNew("hex"), NanNew(strHex)); - - NanReturnValue(data); -} - -/** - * 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 jstx = Local::Cast(args[0]); - - CTransaction ctx; - jstx_to_ctx(jstx, ctx); - - Local data = NanNew(); - - data->Set(NanNew("hash"), NanNew(ctx.GetHash().GetHex())); - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << ctx; - std::string strHex = HexStr(ssTx.begin(), ssTx.end()); - data->Set(NanNew("hex"), NanNew(strHex)); - - NanReturnValue(data); -} - - -/** - * BlockFromHex() - * bitcoindjs.blockFromHex(hex) - * Create a javascript block from a hex string. - */ - -NAN_METHOD(BlockFromHex) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsString()) { - return NanThrowError( - "Usage: bitcoindjs.blockFromHex(hex)"); - } - String::Utf8Value hex_string_(args[0]->ToString()); - std::string hex_string = *hex_string_; - - CBlock cblock; - CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> cblock; - } catch (std::exception &e) { - return NanThrowError("Bad Block decode"); - } - - Local jsblock = NanNew(); - cblock_to_jsblock(cblock, NULL, jsblock, false); - - NanReturnValue(jsblock); -} - -/** - * TxFromHex() - * bitcoindjs.txFromHex(hex) - * Create a javascript tx from a hex string. - */ - -NAN_METHOD(TxFromHex) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsString()) { - return NanThrowError( - "Usage: bitcoindjs.txFromHex(hex)"); - } - - String::Utf8Value hex_string_(args[0]->ToString()); - std::string hex_string = *hex_string_; - - CTransaction ctx; - CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> ctx; - } catch (std::exception &e) { - return NanThrowError("Bad Block decode"); - } - - Local jstx = NanNew(); - ctx_to_jstx(ctx, 0, jstx); - - NanReturnValue(jstx); -} - -/** - * Linked List for queued packets - */ - -typedef struct _poll_packets_list { - CNode *pfrom; - char *strCommand; - CDataStream *vRecv; - int64_t nTimeReceived; - struct _poll_packets_list *next; -} poll_packets_list; - -poll_packets_list *packets_queue_head = NULL; -poll_packets_list *packets_queue_tail = NULL; -boost::mutex poll_packets_mutex; - -/** - * HookPackets() - * bitcoind.hookPackets(callback) - */ - -NAN_METHOD(HookPackets) { - Isolate* isolate = Isolate::GetCurrent(); - HandleScope scope(isolate); - Local obj = NanNew(); - poll_packets_list *cur = NULL; - poll_packets_list *next = NULL; - int i = 0; - - poll_packets_mutex.lock(); - - 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; - - Local o = NanNew(); - - o->Set(NanNew("name"), NanNew(strCommand)); - o->Set(NanNew("received"), NanNew((int64_t)nTimeReceived)); - o->Set(NanNew("peerId"), NanNew(pfrom->id)); - o->Set(NanNew("userAgent"), - NanNew(pfrom->cleanSubVer)); - - if (strCommand == "version") { - - bool fRelayTxes = false; - int nStartingHeight = 0; - int cleanSubVer = 0; - std::string strSubVer = pfrom->strSubVer; - int nVersion = pfrom->nVersion; - uint64_t nServices = pfrom->nServices; - - 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)); - } - - 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; - } - - // Disconnect if we connected to ourself - if (nNonce == nLocalHostNonce && nNonce > 1) { - NanReturnValue(obj); - } - - o->Set(NanNew("receiveVersion"), NanNew(cleanSubVer)); - o->Set(NanNew("version"), NanNew(nVersion)); - o->Set(NanNew("height"), NanNew(nStartingHeight)); - o->Set(NanNew("us"), NanNew(addrMe.ToString())); - o->Set(NanNew("address"), NanNew(pfrom->addr.ToString())); - o->Set(NanNew("relay"), NanNew(fRelayTxes)); - } else if (pfrom->nVersion == 0) { - // Must have a version message before anything else - NanReturnValue(Undefined(isolate)); - } else if (strCommand == "verack") { - o->Set(NanNew("receiveVersion"), NanNew(min(pfrom->nVersion, PROTOCOL_VERSION))); - } else if (strCommand == "addr") { - vector vAddr; - vRecv >> vAddr; - - // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) { - NanReturnValue(obj); - } - - // Bad address size - if (vAddr.size() > 1000) { - NanReturnValue(Undefined(isolate)); - } - - Local array = NanNew(); - int i = 0; - - // Get the new addresses - int64_t nNow = GetAdjustedTime(); - BOOST_FOREACH(CAddress& addr, vAddr) { - boost::this_thread::interruption_point(); - - unsigned int nTime = addr.nTime; - if (nTime <= 100000000 || nTime > nNow + 10 * 60) { - nTime = nNow - 5 * 24 * 60 * 60; - } - - bool fReachable = IsReachable(addr); - - Local obj = NanNew(); - - char nServices[21] = {0}; - int written = snprintf(nServices, sizeof(nServices), "%020llu", (uint64_t)addr.nServices); - assert(written == 20); - - obj->Set(NanNew("services"), NanNew((char *)nServices)); - obj->Set(NanNew("time"), NanNew((unsigned int)nTime)->ToUint32()); - obj->Set(NanNew("last"), NanNew((int64_t)addr.nLastTry)); - obj->Set(NanNew("ip"), NanNew((std::string)addr.ToStringIP())); - obj->Set(NanNew("port"), NanNew((unsigned short)addr.GetPort())->ToUint32()); - obj->Set(NanNew("address"), NanNew((std::string)addr.ToStringIPPort())); - obj->Set(NanNew("reachable"), NanNew((bool)fReachable)); - - array->Set(i, obj); - i++; - } - - o->Set(NanNew("addresses"), array); - } else if (strCommand == "inv") { - vector vInv; - vRecv >> vInv; - - // Bad size - if (vInv.size() > MAX_INV_SZ) { - NanReturnValue(Undefined(isolate)); - } - - LOCK(cs_main); - - Local array = NanNew(); - int i = 0; - - for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { - const CInv &inv = vInv[nInv]; - - boost::this_thread::interruption_point(); - - // Bad size - if (pfrom->nSendSize > (SendBufferSize() * 2)) { - NanReturnValue(Undefined(isolate)); - } - - Local item = NanNew(); - item->Set(NanNew("hash"), NanNew(inv.hash.GetHex())); - item->Set(NanNew("type"), NanNew( - inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK - ? "block" : "tx")); - if (inv.type == MSG_FILTERED_BLOCK) { - item->Set(NanNew("filtered"), NanNew(true)); - } else if (inv.type == MSG_BLOCK) { - item->Set(NanNew("filtered"), NanNew(false)); - } - - array->Set(i, item); - i++; - } - - o->Set(NanNew("items"), array); - } else if (strCommand == "getdata") { - vector vInv; - vRecv >> vInv; - - // Bad size - if (vInv.size() > MAX_INV_SZ) { - NanReturnValue(Undefined(isolate)); - } - - o->Set(NanNew("size"), NanNew(vInv.size())); - if (vInv.size() > 0) { - o->Set(NanNew("first"), NanNew(vInv[0].ToString())); - } - } else if (strCommand == "getblocks") { - CBlockLocator locator; - uint256 hashStop; - vRecv >> locator >> hashStop; - - LOCK(cs_main); - - // Find the last block the caller has in the main chain - CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); - - // Send the rest of the chain - if (pindex) { - pindex = chainActive.Next(pindex); - } - - o->Set(NanNew("fromHeight"), NanNew(pindex ? pindex->nHeight : -1)); - o->Set(NanNew("toHash"), NanNew( - hashStop == uint256(0) ? "end" : hashStop.GetHex())); - o->Set(NanNew("limit"), NanNew(500)); - } else if (strCommand == "getheaders") { - CBlockLocator locator; - uint256 hashStop; - vRecv >> locator >> hashStop; - - LOCK(cs_main); - - 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); - } - } - - o->Set(NanNew("fromHeight"), NanNew(pindex ? pindex->nHeight : -1)); - o->Set(NanNew("toHash"), NanNew(hashStop.GetHex())); - } else if (strCommand == "tx") { - // XXX May be able to do prev_list asynchronously - // XXX Potentially check for "reject" in original code - CTransaction tx; - vRecv >> tx; - Local jstx = NanNew(); - ctx_to_jstx(tx, 0, jstx); - o->Set(NanNew("tx"), jstx); - CNodeStats stats; - pfrom->copyStats(stats); - jstx->Set(NanNew("from"), NanNew(stats.addrName)); - if (!stats.addrLocal.empty()) { - jstx->Set(NanNew("fromlocal"), NanNew(stats.addrLocal)); - } - } else if (strCommand == "block" && !fImporting && !fReindex) { - // XXX May be able to do prev_list asynchronously - CBlock block; - vRecv >> block; - Local jsblock = NanNew(); - cblock_to_jsblock(block, NULL, jsblock, true); - o->Set(NanNew("block"), jsblock); - CNodeStats stats; - pfrom->copyStats(stats); - jsblock->Set(NanNew("from"), NanNew(stats.addrName)); - if (!stats.addrLocal.empty()) { - jsblock->Set(NanNew("fromlocal"), NanNew(stats.addrLocal)); - } - } 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}; - int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)nonce); - assert(written == 20); - o->Set(NanNew("nonce"), NanNew(sNonce)); - } else { - char sNonce[21] = {0}; - int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)0); - assert(written == 20); - o->Set(NanNew("nonce"), NanNew(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; - - if (nAvail >= sizeof(nonce)) { - vRecv >> nonce; - - // 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"; - } - - char sNonce[21] = {0}; - int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)nonce); - assert(written == 20); - - char sPingNonceSent[21] = {0}; - written = snprintf(sPingNonceSent, sizeof(sPingNonceSent), "%020llu", (uint64_t)pfrom->nPingNonceSent); - assert(written == 20); - - o->Set(NanNew("expected"), NanNew(sPingNonceSent)); - o->Set(NanNew("received"), NanNew(sNonce)); - o->Set(NanNew("bytes"), NanNew((unsigned int)nAvail)); - - if (!(sProblem.empty())) { - o->Set(NanNew("problem"), NanNew(sProblem)); - } - - if (bPingFinished) { - o->Set(NanNew("finished"), NanNew(true)); - } else { - o->Set(NanNew("finished"), NanNew(false)); - } - } else if (strCommand == "alert") { - CAlert alert; - vRecv >> alert; - - uint256 alertHash = alert.GetHash(); - - o->Set(NanNew("hash"), NanNew(alertHash.GetHex())); - - 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()); - o->Set(NanNew("message"), NanNew(vchMsg)); - o->Set(NanNew("signature"), NanNew(vchSig)); - o->Set(NanNew("misbehaving"), NanNew(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("misbehaving"), NanNew(true)); - } - } - } else if (strCommand == "filterload") { - CBloomFilter filter; - vRecv >> filter; - - if (!filter.IsWithinSizeConstraints()) { - // There is no excuse for sending a too-large filter - o->Set(NanNew("misbehaving"), NanNew(true)); - } else { - LOCK(pfrom->cs_filter); - filter.UpdateEmptyFull(); - - o->Set(NanNew("misbehaving"), NanNew(false)); - } - } else if (strCommand == "filteradd") { - vector vData; - vRecv >> vData; - - // 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("misbehaving"), NanNew(true)); - } else { - LOCK(pfrom->cs_filter); - if (pfrom->pfilter) { - o->Set(NanNew("misbehaving"), NanNew(false)); - } else { - o->Set(NanNew("misbehaving"), NanNew(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("unknown"), NanNew(true)); - } - - // 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("connected"), NanNew(true)); - } - } - - obj->Set(i, o); - i++; - - if (cur == packets_queue_head) { - packets_queue_head = NULL; - } - - if (cur == packets_queue_tail) { - packets_queue_tail = NULL; - } - - next = cur->next; - free(cur->strCommand); - delete cur->vRecv; - free(cur); - } - - poll_packets_mutex.unlock(); - - NanReturnValue(obj); -} - -static void -hook_packets(void) { - CNodeSignals& nodeSignals = GetNodeSignals(); - nodeSignals.ProcessMessages.connect(&process_packets); -} - -static void -unhook_packets(void) { - CNodeSignals& nodeSignals = GetNodeSignals(); - nodeSignals.ProcessMessages.disconnect(&process_packets); -} - -static bool -process_packets(CNode* pfrom) { - bool fOk = true; - - std::deque::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; - } - - // get next message - CNetMessage& msg = *it; - - // end, if an incomplete message is found - if (!msg.complete()) { - break; - } - - // at this point, any failure means we can delete the current message - it++; - - // Scan for message start - if (memcmp(msg.hdr.pchMessageStart, - Params().MessageStart(), MESSAGE_START_SIZE) != 0) { - fOk = false; - break; - } - - // Read header - CMessageHeader& hdr = msg.hdr; - if (!hdr.IsValid()) { - continue; - } - string strCommand = hdr.GetCommand(); - - // Message size - unsigned int nMessageSize = hdr.nMessageSize; - - // 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); - boost::this_thread::interruption_point(); - - break; - } - - 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; -} - -/** - * 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. - */ - -// 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; - } - - // 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; - } - - *is_allocated = true; - - return pindexNew; -} - -static inline void -cblock_to_jsblock(const CBlock& cblock, CBlockIndex* cblock_index, Local 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(); - - jsblock->Set(NanNew("hash"), NanNew(blockhash.GetHex())); - jsblock->Set(NanNew("size"), - NanNew((int)::GetSerializeSize(cblock, SER_NETWORK, PROTOCOL_VERSION))->ToInt32()); - - if (cblock_index) { - jsblock->Set(NanNew("height"), NanNew(cblock_index->nHeight)); - } - - // - // Headers - // - jsblock->Set(NanNew("version"), NanNew((int32_t)cblock.nVersion)); - jsblock->Set(NanNew("previousblockhash"), NanNew((std::string)cblock.hashPrevBlock.ToString())); - jsblock->Set(NanNew("merkleroot"), NanNew((std::string)cblock.hashMerkleRoot.GetHex())); - jsblock->Set(NanNew("time"), NanNew((uint32_t)cblock.GetBlockTime())->ToUint32()); - jsblock->Set(NanNew("bits"), NanNew((uint32_t)cblock.nBits)->ToUint32()); - jsblock->Set(NanNew("nonce"), NanNew((uint32_t)cblock.nNonce)->ToUint32()); - - if (cblock_index) { - jsblock->Set(NanNew("difficulty"), NanNew(GetDifficulty(cblock_index))); - jsblock->Set(NanNew("chainwork"), NanNew(cblock_index->nChainWork.GetHex())); - } - - if (cblock_index) { - CBlockIndex *pnext = chainActive.Next(cblock_index); - if (pnext) { - jsblock->Set(NanNew("nextblockhash"), NanNew(pnext->GetBlockHash().GetHex())); - } - } - - // Build merkle tree - if (cblock.vMerkleTree.empty()) { - cblock.BuildMerkleTree(); - } - Local merkle = NanNew(); - int mi = 0; - BOOST_FOREACH(uint256& hash, cblock.vMerkleTree) { - merkle->Set(mi, NanNew(hash.ToString())); - mi++; - } - jsblock->Set(NanNew("merkletree"), merkle); - - Local txs = NanNew(); - int ti = 0; - BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) { - Local jstx = NanNew(); - ctx_to_jstx(ctx, blockhash, jstx); - txs->Set(ti, jstx); - ti++; - } - jsblock->Set(NanNew("tx"), txs); - - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - ssBlock << cblock; - std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); - jsblock->Set(NanNew("hex"), NanNew(strHex)); - - // Was it allocated in find_new_block_index(), or did it already exist? - // (race condition here) - if (is_allocated) { - delete cblock_index; - } -} - static int get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx) { if (GetTransaction(txid, ctx, blockhash, true)) { return 1; - } else if (blockhash != 0) { + } else if (blockhash.IsNull()) { CBlock block; CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if (ReadBlockFromDisk(block, pblockindex)) { @@ -2941,658 +974,6 @@ get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx) { return 0; } -static inline void -ctx_to_jstx(const CTransaction& ctx, uint256 blockhash, Local jstx) { - // Find block hash if it's in our wallet - - jstx->Set(NanNew("current_version"), - NanNew((int)ctx.CURRENT_VERSION)->ToInt32()); - - jstx->Set(NanNew("txid"), NanNew(ctx.GetHash().GetHex())); - jstx->Set(NanNew("version"), - NanNew((int)ctx.nVersion)->ToInt32()); - jstx->Set(NanNew("locktime"), - NanNew((unsigned int)ctx.nLockTime)->ToUint32()); - - jstx->Set(NanNew("size"), - NanNew((int)::GetSerializeSize(ctx, SER_NETWORK, PROTOCOL_VERSION))->ToInt32()); - - Local vin = NanNew(); - int vi = 0; - BOOST_FOREACH(const CTxIn& txin, ctx.vin) { - Local in = NanNew(); - - if (ctx.IsCoinBase()) { - in->Set(NanNew("coinbase"), - NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - } - - in->Set(NanNew("txid"), NanNew(txin.prevout.hash.GetHex())); - in->Set(NanNew("vout"), - NanNew((unsigned int)txin.prevout.n)->ToUint32()); - - Local o = NanNew(); - o->Set(NanNew("asm"), - NanNew(txin.scriptSig.ToString())); - o->Set(NanNew("hex"), - NanNew(HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); - - Local jsprev = NanNew(); - CTransaction prev_tx; - if (get_tx(txin.prevout.hash, blockhash, prev_tx)) { - CTxDestination from; - CTxOut prev_out = prev_tx.vout[txin.prevout.n]; - ExtractDestination(prev_out.scriptPubKey, from); - CBitcoinAddress addrFrom(from); - jsprev->Set(NanNew("address"), - NanNew(addrFrom.ToString())); - jsprev->Set(NanNew("value"), - NanNew((int64_t)prev_out.nValue)->ToInteger()); - } else { - const CTxOut& txout = ctx.vout[0]; - const CScript& scriptPubKey = txout.scriptPubKey; - txnouttype type; - vector 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]; - jsprev->Set(NanNew("address"), - NanNew(CBitcoinAddress(addr).ToString() + std::string("?"))); - jsprev->Set(NanNew("value"), - NanNew((int64_t)txout.nValue)->ToInteger()); - } else { - jsprev->Set(NanNew("address"), - NanNew(std::string("Unknown"))); - jsprev->Set(NanNew("value"), NanNew(0)); - } - } - in->Set(NanNew("prev"), jsprev); - - in->Set(NanNew("scriptSig"), o); - - in->Set(NanNew("sequence"), NanNew((unsigned int)txin.nSequence)->ToUint32()); - - vin->Set(vi, in); - vi++; - } - jstx->Set(NanNew("vin"), vin); - - Local vout = NanNew(); - for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) { - const CTxOut& txout = ctx.vout[vo]; - Local out = NanNew(); - - out->Set(NanNew("value"), NanNew((int64_t)txout.nValue)->ToInteger()); - out->Set(NanNew("n"), NanNew((unsigned int)vo)->ToUint32()); - - Local o = NanNew(); - { - const CScript& scriptPubKey = txout.scriptPubKey; - Local out = o; - - txnouttype type; - vector addresses; - int nRequired; - out->Set(NanNew("asm"), NanNew(scriptPubKey.ToString())); - out->Set(NanNew("hex"), - NanNew(HexStr(scriptPubKey.begin(), scriptPubKey.end()))); - if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { - out->Set(NanNew("type"), - NanNew(GetTxnOutputType(type))); - } else { - out->Set(NanNew("reqSigs"), - NanNew((int)nRequired)->ToInt32()); - out->Set(NanNew("type"), - NanNew(GetTxnOutputType(type))); - Local a = NanNew(); - int ai = 0; - BOOST_FOREACH(const CTxDestination& addr, addresses) { - a->Set(ai, NanNew(CBitcoinAddress(addr).ToString())); - ai++; - } - out->Set(NanNew("addresses"), a); - } - } - out->Set(NanNew("scriptPubKey"), o); - - vout->Set(vo, out); - } - jstx->Set(NanNew("vout"), vout); - - if (blockhash != 0) { - jstx->Set(NanNew("blockhash"), NanNew(blockhash.GetHex())); - if (ctx.IsCoinBase()) { - jstx->Set(NanNew("generated"), NanNew(true)); - } - if (mapBlockIndex.count(blockhash) > 0) { - CBlockIndex* pindex = mapBlockIndex[blockhash]; - jstx->Set(NanNew("confirmations"), - NanNew(pindex->nHeight)); - // XXX Not really index: - jstx->Set(NanNew("blockindex"), - NanNew(pindex->nHeight)); - jstx->Set(NanNew("blockheight"), - NanNew(pindex->nHeight)); - jstx->Set(NanNew("blocktime"), - NanNew((int64_t)pindex->GetBlockTime())->ToInteger()); - jstx->Set(NanNew("time"), - NanNew((int64_t)pindex->GetBlockTime())->ToInteger()); - jstx->Set(NanNew("timereceived"), - NanNew((int64_t)pindex->GetBlockTime())->ToInteger()); - } else { - jstx->Set(NanNew("confirmations"), NanNew(0)); - // XXX Not really index: - jstx->Set(NanNew("blockindex"), NanNew(-1)); - jstx->Set(NanNew("blockheight"), NanNew(-1)); - jstx->Set(NanNew("blocktime"), NanNew(0)); - jstx->Set(NanNew("time"), NanNew(0)); - jstx->Set(NanNew("timereceived"), NanNew(0)); - } - jstx->Set(NanNew("walletconflicts"), NanNew()); - } else { - jstx->Set(NanNew("blockhash"), NanNew(uint256(0).GetHex())); - jstx->Set(NanNew("generated"), NanNew(false)); - jstx->Set(NanNew("confirmations"), NanNew(-1)); - // XXX Not really index: - jstx->Set(NanNew("blockindex"), NanNew(-1)); - jstx->Set(NanNew("blockheight"), NanNew(-1)); - jstx->Set(NanNew("blocktime"), NanNew(0)); - jstx->Set(NanNew("walletconflicts"), NanNew()); - jstx->Set(NanNew("time"), NanNew(0)); - jstx->Set(NanNew("timereceived"), NanNew(0)); - } - - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << ctx; - std::string strHex = HexStr(ssTx.begin(), ssTx.end()); - jstx->Set(NanNew("hex"), NanNew(strHex)); -} - -static inline void -jsblock_to_cblock(const Local jsblock, CBlock& cblock) { - cblock.nVersion = (int32_t)jsblock->Get(NanNew("version"))->Int32Value(); - - if (jsblock->Get(NanNew("previousblockhash"))->IsString()) { - String::Utf8Value hash__(jsblock->Get(NanNew("previousblockhash"))->ToString()); - std::string hash_ = *hash__; - uint256 hash(hash_); - cblock.hashPrevBlock = (uint256)hash; - } else { - // genesis block - cblock.hashPrevBlock = (uint256)uint256(0); - } - - String::Utf8Value mhash__(jsblock->Get(NanNew("merkleroot"))->ToString()); - std::string mhash_ = *mhash__; - uint256 mhash(mhash_); - cblock.hashMerkleRoot = (uint256)mhash; - - cblock.nTime = (uint32_t)jsblock->Get(NanNew("time"))->Uint32Value(); - cblock.nBits = (uint32_t)jsblock->Get(NanNew("bits"))->Uint32Value(); - cblock.nNonce = (uint32_t)jsblock->Get(NanNew("nonce"))->Uint32Value(); - - Local txs = Local::Cast(jsblock->Get(NanNew("tx"))); - for (unsigned int ti = 0; ti < txs->Length(); ti++) { - Local jstx = Local::Cast(txs->Get(ti)); - CTransaction ctx; - jstx_to_ctx(jstx, ctx); - cblock.vtx.push_back(ctx); - } - - if (cblock.vMerkleTree.empty()) { - cblock.BuildMerkleTree(); - } -} - -// 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 jstx, CTransaction& ctx_) { - String::Utf8Value hex_string_(jstx->Get(NanNew("hex"))->ToString()); - std::string hex_string = *hex_string_; - - CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> ctx_; - } catch (std::exception &e) { - NanThrowError("Bad TX decode"); - return; - } - - return; - - CMutableTransaction& ctx = (CMutableTransaction&)ctx_; - - // With v0.9.0 - // ctx.nMinTxFee = (int64_t)jstx->Get(NanNew("mintxfee"))->IntegerValue(); - // ctx.nMinRelayTxFee = (int64_t)jstx->Get(NanNew("minrelaytxfee"))->IntegerValue(); - - // ctx.CURRENT_VERSION = (unsigned int)jstx->Get(NanNew("current_version"))->Int32Value(); - - ctx.nVersion = (int)jstx->Get(NanNew("version"))->Int32Value(); - - Local vin = Local::Cast(jstx->Get(NanNew("vin"))); - for (unsigned int vi = 0; vi < vin->Length(); vi++) { - CTxIn txin; - - Local in = Local::Cast(vin->Get(vi)); - - String::Utf8Value phash__(in->Get(NanNew("txid"))->ToString()); - std::string phash_ = *phash__; - uint256 phash(phash_); - - txin.prevout.hash = phash; - txin.prevout.n = (unsigned int)in->Get(NanNew("vout"))->Uint32Value(); - - std::string shash_; - Local script_obj = Local::Cast(in->Get(NanNew("scriptSig"))); - String::Utf8Value shash__(script_obj->Get(NanNew("hex"))->ToString()); - shash_ = *shash__; - - std::vector shash(shash_.begin(), shash_.end()); - CScript scriptSig(shash.begin(), shash.end()); - - txin.scriptSig = scriptSig; - txin.nSequence = (unsigned int)in->Get(NanNew("sequence"))->Uint32Value(); - - ctx.vin.push_back(txin); - } - - Local vout = Local::Cast(jstx->Get(NanNew("vout"))); - for (unsigned int vo = 0; vo < vout->Length(); vo++) { - CTxOut txout; - - Local out = Local::Cast(vout->Get(vo)); - - int64_t nValue = (int64_t)out->Get(NanNew("value"))->IntegerValue(); - txout.nValue = nValue; - - Local script_obj = Local::Cast(out->Get(NanNew("scriptPubKey"))); - String::Utf8Value phash__(script_obj->Get(NanNew("hex"))); - std::string phash_ = *phash__; - - std::vector phash(phash_.begin(), phash_.end()); - CScript scriptPubKey(phash.begin(), phash.end()); - - txout.scriptPubKey = scriptPubKey; - - ctx.vout.push_back(txout); - } - - ctx.nLockTime = (unsigned int)jstx->Get(NanNew("locktime"))->Uint32Value(); -} - -#if USE_LDB_ADDR - -/** - LevelDB Parser - DB: blocks/blk/revXXXXX.dat - */ - -static ctx_list * -read_addr(const std::string addr, const int64_t blockheight, const int64_t blocktime) { - ctx_list *head = new ctx_list(); - ctx_list *cur = NULL; - - head->err_msg = std::string(""); - - 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(); - - CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); - - char type; - ssKey >> type; - - // Blockchain Index Structure: - // http://bitcoin.stackexchange.com/questions/28168 - - // File info record structure - // 'f' + 4-byte file number - // 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') { - goto next; - } - - // Last block file number used structure - // 'l' - // 4-byte file number - if (type == 'l') { - goto next; - } - - // Reindexing structure - // 'R' - // 1-byte Boolean (1 if reindexing) - if (type == 'R') { - goto next; - } - - // Flags structure - // 'F' + 1-byte flag name + flag name string - // 1-byte Boolean (key may be `txindex` if transaction index is enabled) - if (type == 'F') { - goto next; - } - - // 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 - if (type == 'b') { - leveldb::Slice slValue = pcursor->value(); - - CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - - uint256 blockhash; - ssKey >> blockhash; - - // 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; - // }; - - CDiskBlockIndex index; - ssValue >> index; - - if (blocktime != -1 && index.GetBlockTime() < blocktime) { - goto next; - } - - // struct CDiskBlockPos { - // int nFile; - // unsigned int nPos; - // }; - - CDiskBlockPos blockPos; - blockPos.nFile = index.nFile; - blockPos.nPos = index.nDataPos; - - CBlock cblock; - - if (!ReadBlockFromDisk(cblock, blockPos)) { - goto next; - } - - 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; - } - goto next; - } - - 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 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; - } - goto next; - } - } - } - } - - // 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 - if (type == 't') { - leveldb::Slice slValue = pcursor->value(); - - CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - - uint256 txid; - ssKey >> txid; - - // struct CDiskBlockPos { - // int nFile; - // unsigned int nPos; - // }; - // struct CDiskTxPos : public CDiskBlockPos { - // unsigned int nTxOffset; - // }; - - CDiskTxPos txPos; - ssValue >> txPos; - - CTransaction ctx; - uint256 blockhash; - - if (!pblocktree->ReadTxIndex(txid, txPos)) { - goto next; - } - - 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(); - - 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; - } - goto next; - } - - 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 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; - } - goto next; - } - } - } - -next: - pcursor->Next(); - } catch (std::exception &e) { - head->err_msg = std::string(e.what() - + std::string(" : Deserialize error. Key: ") - + pcursor->key().ToString()); - delete pcursor; - return head; - } - } - - delete pcursor; - return head; - -error: - head->err_msg = std::string("Deserialize Error."); - - delete pcursor; - return head; -} -#endif - -/** - LevelDB Parser - DB: blocks/blk/revXXXXX.dat - */ - -#if USE_LDB_TX -static bool -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; - - pblocktree->pdb->Get(leveldb::ReadOptions(), txkey, &slValue); - - CDataStream ssValue(slValue.begin(), slValue.end(), SER_DISK, CLIENT_VERSION); - //CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - - // Blockchain Index Structure: - // http://bitcoin.stackexchange.com/questions/28168 - - // 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 - - // struct CDiskBlockPos { - // int nFile; - // unsigned int nPos; - // }; - // struct CDiskTxPos : public CDiskBlockPos { - // unsigned int nTxOffset; - // }; - - CDiskTxPos txPos; - ssValue >> txPos; - - CTransaction ctx; - uint256 blockhash; - - if (!pblocktree->ReadTxIndex(txid, txPos)) { - goto error; - } - - 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(); - - CBlockIndex* pblockindex = mapBlockIndex[blockhash]; - - if (ReadBlockFromDisk(rcblock, pblockindex)) { - *rcblock_index = pblockindex; - rctx = ctx; - return true; - } - - return false; -} -#endif /** * Helpers @@ -3628,26 +1009,7 @@ init(Handle target) { NODE_SET_METHOD(target, "stopped", IsStopped); NODE_SET_METHOD(target, "getBlock", GetBlock); NODE_SET_METHOD(target, "getTransaction", GetTransaction); - NODE_SET_METHOD(target, "broadcastTx", BroadcastTx); - NODE_SET_METHOD(target, "verifyBlock", VerifyBlock); - NODE_SET_METHOD(target, "verifyTransaction", VerifyTransaction); NODE_SET_METHOD(target, "getInfo", GetInfo); - NODE_SET_METHOD(target, "getPeerInfo", GetPeerInfo); - NODE_SET_METHOD(target, "getAddresses", GetAddresses); - NODE_SET_METHOD(target, "getProgress", GetProgress); - NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo); - NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions); - NODE_SET_METHOD(target, "getBestBlock", GetBestBlock); - NODE_SET_METHOD(target, "getChainHeight", GetChainHeight); - NODE_SET_METHOD(target, "getBlockByTx", GetBlockByTx); - NODE_SET_METHOD(target, "getBlocksByTime", GetBlocksByTime); - NODE_SET_METHOD(target, "getFromTx", GetFromTx); - NODE_SET_METHOD(target, "getLastFileIndex", GetLastFileIndex); - NODE_SET_METHOD(target, "getBlockHex", GetBlockHex); - NODE_SET_METHOD(target, "getTxHex", GetTxHex); - NODE_SET_METHOD(target, "blockFromHex", BlockFromHex); - NODE_SET_METHOD(target, "txFromHex", TxFromHex); - NODE_SET_METHOD(target, "hookPackets", HookPackets); } diff --git a/src/bitcoindjs.h b/src/bitcoindjs.h index 73fc6c7c..787c9b23 100644 --- a/src/bitcoindjs.h +++ b/src/bitcoindjs.h @@ -7,6 +7,8 @@ */ #include "nan.h" +#include "scheduler.h" +#include "main.h" #include "addrman.h" #include "alert.h" #include "base58.h" @@ -24,25 +26,4 @@ NAN_METHOD(IsStopped); NAN_METHOD(StopBitcoind); NAN_METHOD(GetBlock); NAN_METHOD(GetTransaction); -NAN_METHOD(BroadcastTx); -NAN_METHOD(VerifyBlock); -NAN_METHOD(VerifyTransaction); NAN_METHOD(GetInfo); -NAN_METHOD(GetPeerInfo); -NAN_METHOD(GetAddresses); -NAN_METHOD(GetProgress); -NAN_METHOD(GetMiningInfo); -NAN_METHOD(GetAddrTransactions); -NAN_METHOD(GetBestBlock); -NAN_METHOD(GetChainHeight); -NAN_METHOD(GetBlockByTx); -NAN_METHOD(GetBlocksByTime); -NAN_METHOD(GetFromTx); -NAN_METHOD(GetLastFileIndex); -NAN_METHOD(GetBlockHex); -NAN_METHOD(GetTxHex); -NAN_METHOD(BlockFromHex); -NAN_METHOD(TxFromHex); -NAN_METHOD(HookPackets); - -