From 5d9338d22a40a654924deb427ec58ab76e48c845 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Mon, 13 Jul 2015 16:34:29 -0400 Subject: [PATCH] 1. Updated patch for v0.11.0 2. Updated bindings to cover the changes to bitcoin 3. Added some file matchers to gitignore for Qt Creator 4. Fixed platform lib path for Mac OS X 5. Removed unneeded methods in bindings (they will be re-added later --- .gitignore | 2 + PATCH_VERSION | 2 +- etc/bitcoin.patch | 95 +- platform/os.sh | 8 +- src/bitcoindjs.cc | 2698 +-------------------------------------------- src/bitcoindjs.h | 23 +- 6 files changed, 88 insertions(+), 2740 deletions(-) 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); - -