diff --git a/.gitignore b/.gitignore index 0be5158e..201326e9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,10 @@ Makefile.gyp *.user *.project test.js +**/*.dylib +**/*.so +**/*.old +libbitcoind +**/*.files +**/*.config +**/*.creator diff --git a/LICENSE b/LICENSE index 9e8cd324..d3e4d2e1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ bitcoind,js -------------------------------------------------------------------------------- -Copyright (c) 2014, BitPay +Copyright (c) 2014-2015, BitPay Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/PATCH_VERSION b/PATCH_VERSION new file mode 100644 index 00000000..3123ff93 --- /dev/null +++ b/PATCH_VERSION @@ -0,0 +1 @@ +v0.10.2 diff --git a/README.md b/README.md index 2012d017..31e2bbbb 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # bitcoind.js __bitcoind.js__ as a node.js module which dynamically loads a node.js C++ -modules which links to libbitcoind.so (bitcoind compiled as a shared library), -making all useful bitcoind functions asynchronous. +modules which links to libbitcoind.{so|dylib}. Unix/Linux use the file extension "so" whereas Mac OSX uses "dylib" (bitcoind compiled as a shared library), +making all useful bitcoind functions asynchronous (with the exception of the wallet functionality). ## Building -### libbitcoind.so +### libbitcoind.{so|dylib} #### Compiling bitcoind as a library @@ -16,44 +16,34 @@ making all useful bitcoind functions asynchronous. - Bost Header Files (`/usr/include/boost`) - NOTE: These are now included in the repo if they're not present. -- Berkeley DB - -- LevelDB Header Files (included in bitcoin source repo, leveldb itself - unnecessary, libbitcoind.so is already linked to them) - - NOTE: These also are now included in the repo if they're not present. - -- Protobuf - - secp256k1 +- OpenSSL headers and libraries (-lcrypto and -lssl) + +- If target platform is Mac OS X, then OS X >= 10.9, Clang and associated linker. + ##### Building ``` bash $ cd ~/node_modules/bitcoind.js -$ ./bin/build-libbitcoind remote +$ ./bin/build-libbitcoind ``` NOTE: This script will run automatically on an `npm install`, along with the compilation below. -`remote` will clone the latest bitcoin upstream, apply a patch to it, compile -libbitcoind.so, and place it in the appropriate directory. The first argument -can also be a bitcoin repo directory you already have on your disk, otherwise -it will check for ~/bitcoin by default. +The first argument can also be a bitcoin repo directory you already have on your disk, otherwise +it will check for ~/bitcoin by default. The `PATCH_VERSION` file dictates what version/tag the patch goes clean against. -NOTE: libbitcoind.so is currently unsupported on OSX due to OSX's mess of -header files and libraries. Special magic is required to make this work that -has not been implemented yet. This will only compile on a real unix (linux is -recommended). ###### In the build-libbitcoind.sh script: `--enable-daemonlib` will compile all object files with `-fPIC` (Position Independent Code - needed to create a shared object). -`make` will then compile `./src/libbitcoind.so` (with `-shared -fPIC`), linking +`make` will then compile `./src/libbitcoind.{so|dylib}` (with `-shared -fPIC`), linking to all the freshly compiled PIC object files. This will completely ignore -compiling tests and the QT object files. +compiling tests, QT object files and the wallet features in bitcoind/libbitcoind.{so|dylib}. Without `--enable-daemonlib`, the Makefile with compile bitcoind with -fPIE (Position Independent for Executable), this allows compiling of bitcoind. @@ -106,8 +96,7 @@ bitcoind.on('addr', function(addr) { }); bitcoind.on('open', function() { - console.log('Your Wallet:'); - console.log(bitcoind.wallet.getAccounts()); + console.log('Whatever you want from the open signal'); }); bitcoind.start(); @@ -116,15 +105,6 @@ bitcoind.start(); ``` bash $ node ./my-example.js bitcoind.js: status="start_node(): bitcoind opened." -Your Wallet: -{ '': - { balance: 0, - addresses: - [ { address: '16PvEk4NggaCyfR2keZaP9nPufJvDb2ATZ', - privkeycompressed: true, - privkey: 'L47MC7gtB5UdWYsmxT6czzGophFm6Zj99PYVQWDNkJG6Mf12GGyi', - pubkeycompressed: true, - pubkey: '02bf636e7a3ad48ea2cf0c8dbdf992792e617a4f92f2e161f20f3c038883647f0d' } ] } } ^C bitcoind.js: stop_node(): bitcoind shutdown. bitcoind.js: shutting down... @@ -134,7 +114,7 @@ bitcoind.js: shut down. ## Documentation -**bitcoind.js** is a node.js module which links to libbitcoind.so (bitcoind +**bitcoind.js** is a node.js module which links to libbitcoind.{so|dylib} (bitcoind complied as a shared library). ### Javascript API @@ -300,102 +280,6 @@ be your own transaction or a transaction relayed to you. Static method to broadcast a transaction. - -#### Wallet Object/Class (Singleton) - -##### `Wallet::createAddress(options)` - -Create a new address for the global wallet. - -##### `Wallet::getAccountAddress(options)` - -Get the main address associated with the provided account. - -##### `Wallet::setAccount(options)` - -Associate account name with address. - -##### `Wallet::getAccount(options)` - -Get account name by address. - -##### `Wallet::sendTo(options)` - -Automatically create a transaction and fill/sign it with any available unspent -outputs/inputs and broadcast it. - -##### `Wallet::signMessage(options)` - -Sign any piece of text using the private key associated with the provided -address. - -##### `Wallet::verifyMessage(options)` - -Verify any signed piece of text using the public key associated with signing -private key. - -##### `Wallet::createMultiSigAddress(options)` - -Create a multi-signature for the global wallet. - -##### `Wallet::getBalance(options)` - -Get the total balance of the global wallet in satoshis. - -##### `Wallet::getUnconfirmedBalance(options)` - -Get the total unconfirmed balance of the global wallet in satoshis - -##### `Wallet::sendFrom(options)` - -Automatically create a transaction and fill/sign it with any available unspent -outputs/inputs and broadcast it. This method will also select unspent outputs -from the provided account name to fill the transaction. - -##### `Wallet::listTransactions(options)` - -List transactions associated with the global wallet - NOT YET IMPLEMENTED. - -##### `Wallet::listAccounts(options)` - -Return a javascript object containing account names, addresses, public keys, -private keys, balances, and whether the keys are in compressed format. - -##### `Wallet::getTransaction(options)` - -Return any transaction associated with the global wallet - NOT YET IMPLEMENTED. - -##### `Wallet::backup(options)` - -Backup wallet.dat to provided path. - -##### `Wallet::decrypt(options), Wallet::passphrase(options)` - -Temporarily decrypt the wallet using the provided passphrase. - -##### `Wallet::passphraseChange(options)` - -Change passphrase for the global encrypted wallet. - -##### `Wallet::forgetPassphrase(options), Wallet::lock(options)` - -Forget the current passphrase so the wallet is once again encrypted and -unusuable for any meaningful purpose. - -##### `Wallet::encrypt(options)` - -Encrypt the global wallet with the provided passphrase. - -##### `Wallet::setTxFee(options)` - -The the default transaction fee for the global wallet in satoshis. - -##### `Wallet::importKey(options)` - -Import a private key to global wallet in the standard bitcoind compressed -format. - - #### Utils Object (Singleton) ##### `utils.forEach(obj, iter, done)` @@ -435,6 +319,20 @@ The bitcoind.js Wallet singleton. The bitcoind.js utils object. +## Discussion about the patch to Bitcoin to allow the shared library creation + +To provide native bindings to JavaScript (or any other language for that matter), Bitcoin code, itself, must be linkable. Currently, Bitcoind achieves this by providing an JSON RPC interface to bitcoind. The major drawbacks to this interface are: + +1. JSON RPC interfaces are much slower than linking natively to the C++ code. +2. There can be errors in the interface that prevent clients from using bitcoind's functionality. +3. Functionality can be limited or otherwise unavailable to clients through this interface. + +Linking C++ binding code directly to bitcoind can mitigate all of the above disadvantage, but has its own disadavantages: + +1. The original authors are not explicitly (or implicitly) providing ANY API support to the C++ bindings written here. This means that in subsequent releases of bitcoind, the bindings could fail and this project's authors will need to update the bindings retroactively. +2. As such, there is likely a lag in support for newer versions of bitcoind. + +Due to the pros and cons listed above. The patch to Bitcoin will not be merged by the core devs due to the attitude that the cons outweigh the pros. Every effort will be made to ensure that this project stays up-to-date with the latest release of Bitcoin. At the very least, this project began supporting Bitcoin v0.10.2. ## Contribution and License Agreement @@ -445,6 +343,6 @@ all code is your original work. `` ## License -- bitcoind.js: Copyright (c) 2014, BitPay (MIT License). -- bitcoin: Copyright (c) 2009-2013 Bitcoin Core Developers (MIT License) +- bitcoind.js: Copyright (c) 2015, BitPay (MIT License). +- bitcoin: Copyright (c) 2009-2015 Bitcoin Core Developers (MIT License) - bcoin (some code borrowed temporarily): Copyright Fedor Indutny, 2014. diff --git a/etc/bitcoin.patch b/etc/bitcoin.patch index dbf90e75..e10e655e 100644 --- a/etc/bitcoin.patch +++ b/etc/bitcoin.patch @@ -1,15 +1,17 @@ -From 5aeac9628b35cee9dc61cba7fc4636f96b522dd7 Mon Sep 17 00:00:00 2001 +From de8aca2d16e14cdbfc098f8dfc654355e6b0e549 Mon Sep 17 00:00:00 2001 From: Chris Kleeschulte Date: Mon, 15 Jun 2015 18:34:03 -0400 -Subject: [PATCH] New patch using AC_DEFINE's and without the wallet stuff. +Subject: [PATCH 1/1] Added lib_LTLIBRARIES for the shared library. Added + conditional LDFLAGS for the different ways that Mac and Linux force + load/whole archive an archived library into a shared library. --- configure.ac | 31 +++++++++++++++++++++++++++++-- - src/Makefile.am | 31 +++++++++++++++++++------------ + src/Makefile.am | 50 ++++++++++++++++++++++++++++++++++---------------- src/bitcoind.cpp | 8 ++++++-- src/init.h | 6 ++++++ src/leveldbwrapper.h | 13 ++++++++++++- - 5 files changed, 72 insertions(+), 17 deletions(-) + 5 files changed, 87 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index 579035f..cd20489 100644 @@ -89,10 +91,16 @@ index 579035f..cd20489 100644 LIBLEVELDB= LIBMEMENV= diff --git a/src/Makefile.am b/src/Makefile.am -index 81b16d1..b64eb24 100644 +index 81b16d1..456cfbe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am -@@ -7,7 +7,6 @@ LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include +@@ -1,20 +1,19 @@ + DIST_SUBDIRS = secp256k1 + AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) + +- + if EMBEDDED_LEVELDB + LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv LIBLEVELDB += $(builddir)/leveldb/libleveldb.a LIBMEMENV += $(builddir)/leveldb/libmemenv.a @@ -100,6 +108,16 @@ index 81b16d1..b64eb24 100644 # NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race $(LIBLEVELDB): $(LIBMEMENV) + $(LIBLEVELDB) $(LIBMEMENV): + @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ +- CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ +- OPT="$(CXXFLAGS) $(CPPFLAGS)" ++ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ ++ OPT="$(CXXFLAGS) $(CPPFLAGS)" ++ + endif + + BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config @@ -49,22 +48,26 @@ BITCOIN_INCLUDES += $(BDB_CPPFLAGS) EXTRA_LIBRARIES += libbitcoin_wallet.a endif @@ -144,28 +162,40 @@ index 81b16d1..b64eb24 100644 libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt -@@ -305,15 +309,19 @@ if ENABLE_WALLET +@@ -305,15 +309,30 @@ if ENABLE_WALLET bitcoind_LDADD += libbitcoin_wallet.a endif bitcoind_SOURCES = bitcoind.cpp -# +libbitcoind_la_SOURCES = bitcoind.cpp ++libbitcoind_la_SOURCES += $(libbitcoin_util_a_SOURCES) ++libbitcoind_la_SOURCES += $(libbitcoin_univalue_a_SOURCES) ++libbitcoind_la_SOURCES += $(libbitcoin_crypto_a_SOURCES) ++libbitcoind_la_SOURCES += $(libbitcoin_common_a_SOURCES) ++libbitcoind_la_SOURCES += $(libbitcoin_server_a_SOURCES) ++libbitcoind_la_SOURCES += $(crypto_libbitcoin_crypto_a_SOURCES) ++libbitcoind_la_SOURCES += $(univalue_libbitcoin_univalue_a_SOURCES) if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc +libbitcoind_la_SOURCES += bitcoind-res.rc ++endif ++if TARGET_DARWIN ++libbitcoind_la_LDFLAGS = $(RELDFLAGS) -no-undefined -Wl,-force_load,$(LIBLEVELDB),$(LIBMEMENV) ++else ++libbitcoind_la_LDFLAGS = $(RELDFLAGS) -no-undefined -Wl,-whole-archive $(LIBLEVELDB) $(LIBMEMENV) -Wl,-no-whole-archive endif - +- bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) -+libbitcoind_la_LIBADD = $(bitcoind_LDADD) ++libbitcoind_la_LIBADD = $(BOOST_LIBS) $(SSL_LIBS) $(LIBSECP256K1) $(CRYPTO_LIBS) bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoind_la_CPPFLAGS = $(BITCOIN_INCLUDES) bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -+libbitcoind_la_LDFLAGS = $(RELDFLAGS) -no-undefined ++libbitcoind_la_DEPENDENCIES = $(LIBSECP256K1) $(LIBLEVELDB) $(LIBMEMENV) # bitcoin-cli binary # bitcoin_cli_LDADD = \ -@@ -386,7 +394,6 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno +@@ -386,7 +405,6 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno DISTCLEANFILES = obj/build.h EXTRA_DIST = leveldb diff --git a/example/index.js b/example/index.js index 7c3c36ae..54e297ff 100755 --- a/example/index.js +++ b/example/index.js @@ -233,8 +233,6 @@ bitcoind.on('open', function(status) { bitcoind.log(bitcoind.getInfo()); bitcoind.log(bitcoind.getPeerInfo()); - bitcoind.log(bitcoind.wallet.listAccounts()); - bitcoind.log(bitcoind.wallet.getRecipients()); bitcoind.once('version', function(version) { bitcoind.log('VERSION packet:'); @@ -249,7 +247,7 @@ bitcoind.on('open', function(status) { }); }, 2000); - return bitcoind.log(""); + return; }); /** diff --git a/platform/os.sh b/platform/os.sh index 6bb1cc20..d4f1d904 100755 --- a/platform/os.sh +++ b/platform/os.sh @@ -14,6 +14,7 @@ if test x"$1" = x'btcdir'; then fi os= +ext=so if test -f /etc/centos-release \ || grep -q 'CentOS' /etc/redhat-release \ @@ -26,6 +27,7 @@ elif test -f /etc/redhat_release \ os=rhel elif uname -a | grep -q '^Darwin'; then os=osx + ext=dylib elif test -f /etc/SuSE-release; then os=suse elif test -f /etc/mandrake-release \ @@ -64,12 +66,12 @@ if test x"$1" = x'osdir'; then echo -n "$(pwd)/platform/${os}" exit 0 fi - +echo $ext if test -z "$1" -o x"$1" = x'lib'; then - if test -n "$BITCOIN_DIR" -a -e "${BITCOIN_DIR}/src/libbitcoind.so"; then - echo -n "${BITCOIN_DIR}/src/libbitcoind.so" + if test -n "$BITCOIN_DIR" -a -e "${BITCOIN_DIR}/src/.libs/libbitcoind.${ext}"; then + echo -n "$(pwd)/libbitcoind/src/.libs/libbitcoind.${ext}" else - echo -n "$(pwd)/platform/${os}/libbitcoind.dylib" + echo -n "$(pwd)/platform/${os}/libbitcoind.${ext}" fi exit 0 fi diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index fd9b8335..2a682aaa 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -2185,15 +2185,10 @@ NAN_METHOD(HookPackets) { NanNew(pfrom->cleanSubVer)); if (strCommand == "version") { - // Each connection can only send one version message - if (pfrom->nVersion != 0) { - NanReturnValue(Undefined(isolate)); - } bool fRelayTxes = false; int nStartingHeight = 0; int cleanSubVer = 0; - //std::string strSubVer(strdup(pfrom->strSubVer.c_str())); std::string strSubVer = pfrom->strSubVer; int nVersion = pfrom->nVersion; uint64_t nServices = pfrom->nServices; @@ -2733,9 +2728,6 @@ cblock_to_jsblock(const CBlock& cblock, CBlockIndex* cblock_index, Local uint256 blockhash = cblock.GetHash(); jsblock->Set(NanNew("hash"), NanNew(blockhash.GetHex())); - CMerkleTx txGen(cblock.vtx[0]); - txGen.SetMerkleBranch(cblock); - jsblock->Set(NanNew("confirmations"), NanNew((int)txGen.GetDepthInMainChain())->ToInt32()); jsblock->Set(NanNew("size"), NanNew((int)::GetSerializeSize(cblock, SER_NETWORK, PROTOCOL_VERSION))->ToInt32());