diff --git a/src/Makefile.am b/src/Makefile.am index 8b12c38deb..d0fe3d0d88 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,638 +1,639 @@ # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(SANITIZER_LDFLAGS) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) $(SANITIZER_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) EXTRA_LIBRARIES = if EMBEDDED_UNIVALUE LIBUNIVALUE = univalue/libunivalue.la $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) else LIBUNIVALUE = $(UNIVALUE_LIBS) endif BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) BITCOIN_SEEDER_INCLUDES = -I$(srcdir)/seeder BITCOIN_SEEDER_INCLUDES += $(BITCOIN_INCLUDES) LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a endif if BUILD_BITCOIN_LIBS LIBBITCOINCONSENSUS=libbitcoinconsensus.la endif if BUILD_BITCOIN_SEEDER LIBBITCOIN_SEEDER=libbitcoin_seeder.a endif if ENABLE_WALLET LIBBITCOIN_WALLET=libbitcoin_wallet.a endif LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE) if ENABLE_SSE41 LIBBITCOIN_CRYPTO_SSE41 = crypto/libbitcoin_crypto_sse41.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SSE41) endif if ENABLE_AVX2 LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2) endif if ENABLE_SHANI LIBBITCOIN_CRYPTO_SHANI = crypto/libbitcoin_crypto_shani.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SHANI) endif $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: EXTRA_LIBRARIES += \ $(LIBBITCOIN_CRYPTO) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_CLI) \ $(LIBBITCOIN_SEEDER) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_ZMQ) lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) bin_PROGRAMS = noinst_PROGRAMS = TESTS = BENCHMARKS = if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif if BUILD_BITCOIN_SEEDER bin_PROGRAMS += bitcoin-seeder endif if BUILD_BITCOIN_UTILS bin_PROGRAMS += bitcoin-cli bitcoin-tx endif .PHONY: FORCE check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ addrdb.h \ addrman.h \ base58.h \ bloom.h \ blockencodings.h \ blockfileinfo.h \ blockindexworkcomparator.h \ blockstatus.h \ blockvalidity.h \ cashaddr.h \ cashaddrenc.h \ chain.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ checkpoints.h \ checkqueue.h \ clientversion.h \ coins.h \ compat.h \ compat/byteswap.h \ compat/endian.h \ compat/sanity.h \ compressor.h \ config.h \ consensus/activation.h \ consensus/consensus.h \ consensus/tx_verify.h \ core_io.h \ core_memusage.h \ cuckoocache.h \ diskblockpos.h \ dstencode.h \ fs.h \ globals.h \ httprpc.h \ httpserver.h \ indirectmap.h \ init.h \ key.h \ keystore.h \ dbwrapper.h \ limitedmap.h \ logging.h \ memusage.h \ merkleblock.h \ miner.h \ net.h \ net_processing.h \ netaddress.h \ netbase.h \ netmessagemaker.h \ noui.h \ policy/fees.h \ policy/policy.h \ pow.h \ protocol.h \ random.h \ reverselock.h \ rpc/blockchain.h \ rpc/client.h \ rpc/jsonrpcrequest.h \ rpc/mining.h \ rpc/misc.h \ rpc/protocol.h \ rpc/safemode.h \ rpc/server.h \ rpc/tojson.h \ rpc/register.h \ + rwcollection.h \ scheduler.h \ script/scriptcache.h \ script/sigcache.h \ script/sign.h \ script/standard.h \ script/ismine.h \ streams.h \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ support/cleanse.h \ support/events.h \ support/lockedpool.h \ sync.h \ threadsafety.h \ threadinterrupt.h \ timedata.h \ torcontrol.h \ txdb.h \ txmempool.h \ ui_interface.h \ undo.h \ util.h \ utilmoneystr.h \ utiltime.h \ validation.h \ validationinterface.h \ versionbits.h \ wallet/coincontrol.h \ wallet/crypter.h \ wallet/db.h \ wallet/finaltx.h \ wallet/rpcdump.h \ wallet/fees.h \ wallet/init.h \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/walletdb.h \ warnings.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ zmq/zmqnotificationinterface.h \ zmq/zmqpublishnotifier.h obj/build.h: FORCE @$(MKDIR_P) "$(builddir)/obj" @$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \ "$(abs_top_srcdir)" libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ addrdb.cpp \ bloom.cpp \ blockencodings.cpp \ chain.cpp \ checkpoints.cpp \ config.cpp \ consensus/activation.cpp \ consensus/tx_verify.cpp \ globals.cpp \ httprpc.cpp \ httpserver.cpp \ init.cpp \ dbwrapper.cpp \ merkleblock.cpp \ miner.cpp \ net.cpp \ net_processing.cpp \ noui.cpp \ policy/fees.cpp \ policy/policy.cpp \ pow.cpp \ rest.cpp \ rpc/abc.cpp \ rpc/blockchain.cpp \ rpc/jsonrpcrequest.cpp \ rpc/mining.cpp \ rpc/misc.cpp \ rpc/net.cpp \ rpc/rawtransaction.cpp \ rpc/safemode.cpp \ rpc/server.cpp \ script/scriptcache.cpp \ script/sigcache.cpp \ script/ismine.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ txmempool.cpp \ ui_interface.cpp \ validation.cpp \ validationinterface.cpp \ versionbits.cpp \ $(BITCOIN_CORE_H) if ENABLE_ZMQ libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ zmq/zmqabstractnotifier.cpp \ zmq/zmqnotificationinterface.cpp \ zmq/zmqpublishnotifier.cpp endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ wallet/crypter.cpp \ wallet/db.cpp \ wallet/finaltx.cpp \ wallet/fees.cpp \ wallet/init.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ $(BITCOIN_CORE_H) # crypto primitives library crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_base_a_SOURCES = \ crypto/aes.cpp \ crypto/aes.h \ crypto/chacha20.h \ crypto/chacha20.cpp \ crypto/common.h \ crypto/hmac_sha256.cpp \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ crypto/hmac_sha512.h \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ crypto/sha1.cpp \ crypto/sha1.h \ crypto/sha256.cpp \ crypto/sha256.h \ crypto/sha512.cpp \ crypto/sha512.h if USE_ASM crypto_libbitcoin_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp endif crypto_libbitcoin_crypto_sse41_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_sse41_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_sse41_a_CXXFLAGS += $(SSE41_CXXFLAGS) crypto_libbitcoin_crypto_sse41_a_CPPFLAGS += -DENABLE_SSE41 crypto_libbitcoin_crypto_sse41_a_SOURCES = crypto/sha256_sse41.cpp crypto_libbitcoin_crypto_avx2_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_avx2_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS) crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2 crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp crypto_libbitcoin_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS) crypto_libbitcoin_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS) crypto_libbitcoin_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI crypto_libbitcoin_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp # consensus: shared between all executables that validate any consensus rules. libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_consensus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_consensus_a_SOURCES = \ amount.h \ arith_uint256.cpp \ arith_uint256.h \ consensus/merkle.cpp \ consensus/merkle.h \ consensus/params.h \ consensus/validation.h \ feerate.h \ hash.cpp \ hash.h \ prevector.h \ primitives/block.cpp \ primitives/block.h \ primitives/transaction.cpp \ primitives/transaction.h \ primitives/txid.h \ pubkey.cpp \ pubkey.h \ script/bitcoinconsensus.cpp \ script/sighashtype.h \ script/interpreter.cpp \ script/interpreter.h \ script/script.cpp \ script/script.h \ script/script_error.cpp \ script/script_error.h \ script/script_flags.h \ script/sigencoding.cpp \ script/sigencoding.h \ serialize.h \ tinyformat.h \ uint256.cpp \ uint256.h \ utilstrencodings.cpp \ utilstrencodings.h \ version.h # common: shared between bitcoind, and bitcoin-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ base58.cpp \ cashaddr.cpp \ cashaddrenc.cpp \ chainparams.cpp \ config.cpp \ coins.cpp \ compressor.cpp \ dstencode.cpp \ feerate.cpp \ globals.cpp \ core_read.cpp \ core_write.cpp \ key.cpp \ keystore.cpp \ netaddress.cpp \ netbase.cpp \ protocol.cpp \ scheduler.cpp \ script/sign.cpp \ script/standard.cpp \ warnings.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/lockedpool.cpp \ chainparamsbase.cpp \ clientversion.cpp \ compat/glibc_sanity.cpp \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ fs.cpp \ logging.cpp \ random.cpp \ rpc/protocol.cpp \ support/cleanse.cpp \ sync.cpp \ threadinterrupt.cpp \ uint256.cpp \ uint256.h \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ utiltime.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between bitcoin-cli and bitcoin-qt libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ rpc/client.cpp \ $(BITCOIN_CORE_H) # seeder library libbitcoin_seeder_a_CPPFLAGS = $(AM_CPPFLAGS) $(PIE_FLAGS) $(BITCOIN_SEEDER_INCLUDES) libbitcoin_seeder_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_seeder_a_SOURCES = \ seeder/bitcoin.cpp \ seeder/bitcoin.h \ seeder/compat.h \ seeder/db.cpp \ seeder/db.h \ seeder/dns.cpp \ seeder/dns.h \ seeder/strlcpy.h \ seeder/util.h nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # # bitcoind binary # bitcoind_SOURCES = bitcoind.cpp bitcoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) bitcoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoind_SOURCES += bitcoind-res.rc endif bitcoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ $(LIBSECP256K1) bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) # bitcoin-cli binary # bitcoin_cli_SOURCES = bitcoin-cli.cpp bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoin_cli_SOURCES += bitcoin-cli-res.rc endif bitcoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # # bitcoin-seeder binary # bitcoin_seeder_SOURCES = seeder/main.cpp bitcoin_seeder_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_SEEDER_INCLUDES) bitcoin_seeder_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_seeder_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) bitcoin_seeder_LDADD = \ $(LIBBITCOIN_SEEDER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) bitcoin_seeder_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # # bitcoin-tx binary # bitcoin_tx_SOURCES = bitcoin-tx.cpp bitcoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) bitcoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS bitcoin_tx_SOURCES += bitcoin-tx-res.rc endif bitcoin_tx_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # # bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) if GLIBC_BACK_COMPAT libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif # CTAES_DIST = crypto/ctaes/bench.c CTAES_DIST += crypto/ctaes/ctaes.c CTAES_DIST += crypto/ctaes/ctaes.h CTAES_DIST += crypto/ctaes/README.md CTAES_DIST += crypto/ctaes/test.c CLEANFILES = $(EXTRA_LIBRARIES) CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += consensus/*.gcda consensus/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno CLEANFILES += policy/*.gcda policy/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno CLEANFILES += script/*.gcda script/*.gcno CLEANFILES += support/*.gcda support/*.gcno CLEANFILES += univalue/*.gcda univalue/*.gcno CLEANFILES += wallet/*.gcda wallet/*.gcno CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno CLEANFILES += zmq/*.gcda zmq/*.gcno DISTCLEANFILES = obj/build.h EXTRA_DIST = $(CTAES_DIST) clean-local: -$(MAKE) -C secp256k1 clean -$(MAKE) -C univalue clean -rm -f leveldb/*/*.gcda leveldb/*/*.gcno leveldb/helpers/memenv/*.gcda leveldb/helpers/memenv/*.gcno -rm -rf test/__pycache__ .rc.o: @test -f $(WINDRES) ## FIXME: How to get the appropriate modulename_CPPFLAGS in here? $(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@ .mm.o: $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $< check-symbols: $(bin_PROGRAMS) if GLIBC_BACK_COMPAT @echo "Checking glibc back compat..." $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) endif check-security: $(bin_PROGRAMS) if HARDEN @echo "Checking binary security..." $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/rwcollection.h b/src/rwcollection.h new file mode 100644 index 0000000000..093362ba19 --- /dev/null +++ b/src/rwcollection.h @@ -0,0 +1,75 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RWCOLLECTION_H +#define BITCOIN_RWCOLLECTION_H + +#include +#include +#include + +#include +#include +#include + +template class RWCollectionView : boost::noncopyable { +private: + L lock; + T *collection; + + template struct BracketType { + typedef decltype(std::declval()[std::declval()]) type; + }; + +public: + RWCollectionView(L l, T &c) : lock(std::move(l)), collection(&c) {} + RWCollectionView(RWCollectionView &&other) + : lock(std::move(other.lock)), collection(other.collection) {} + + T *operator->() { return collection; } + const T *operator->() const { return collection; } + + /** + * Iterator mechanics. + */ + typedef typename boost::range_iterator::type iterator; + iterator begin() { return std::begin(*collection); } + iterator end() { return std::end(*collection); } + + typedef typename boost::range_iterator::type const_iterator; + const_iterator begin() const { return std::begin(*collection); } + const_iterator end() const { return std::end(*collection); } + + /** + * Forward bracket operator. + */ + template typename BracketType::type operator[](I &&index) { + return (*collection)[std::forward(index)]; + } +}; + +template class RWCollection { +private: + mutable boost::shared_mutex rwlock; + T collection; + +public: + RWCollection() : collection() {} + + typedef RWCollectionView> + ReadView; + ReadView getReadView() const { + return ReadView(boost::shared_lock(rwlock), + collection); + } + + typedef RWCollectionView> + WriteView; + WriteView getWriteView() { + return WriteView(boost::unique_lock(rwlock), + collection); + } +}; + +#endif // BITCOIN_RWCOLLECTION_H diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index cc62a8e6ec..dad56df444 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,100 +1,100 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "sigcache.h" #include "cuckoocache.h" #include "memusage.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" -#include +#include namespace { /** * Valid signature cache, to avoid doing expensive ECDSA signature checking * twice for every transaction (once when accepted into memory pool, and * again when accepted into the block chain) */ class CSignatureCache { private: //! Entries are SHA256(nonce || signature hash || public key || signature): uint256 nonce; typedef CuckooCache::cache map_type; map_type setValid; boost::shared_mutex cs_sigcache; public: CSignatureCache() { GetRandBytes(nonce.begin(), 32); } void ComputeEntry(uint256 &entry, const uint256 &hash, const std::vector &vchSig, const CPubKey &pubkey) { CSHA256() .Write(nonce.begin(), 32) .Write(hash.begin(), 32) .Write(&pubkey[0], pubkey.size()) .Write(&vchSig[0], vchSig.size()) .Finalize(entry.begin()); } bool Get(const uint256 &entry, const bool erase) { boost::shared_lock lock(cs_sigcache); return setValid.contains(entry, erase); } void Set(uint256 &entry) { boost::unique_lock lock(cs_sigcache); setValid.insert(entry); } uint32_t setup_bytes(size_t n) { return setValid.setup_bytes(n); } }; /** * In previous versions of this code, signatureCache was a local static variable * in CachingTransactionSignatureChecker::VerifySignature. We initialize * signatureCache outside of VerifySignature to avoid the atomic operation per * call overhead associated with local static variables even though * signatureCache could be made local to VerifySignature. */ static CSignatureCache signatureCache; } // namespace // To be called once in AppInit2/TestingSetup to initialize the signatureCache void InitSignatureCache() { // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero, // setup_bytes creates the minimum possible cache (2 elements). size_t nMaxCacheSize = std::min(std::max(int64_t(0), gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE)), MAX_MAX_SIG_CACHE_SIZE) * (size_t(1) << 20); size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to " "store %zu elements\n", (nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); } bool CachingTransactionSignatureChecker::VerifySignature( const std::vector &vchSig, const CPubKey &pubkey, const uint256 &sighash) const { uint256 entry; signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); if (signatureCache.Get(entry, !store)) { return true; } if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) { return false; } if (store) { signatureCache.Set(entry); } return true; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d0a74411c7..c00c17ceba 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,167 +1,168 @@ # Copyright (c) 2018 The Bitcoin developers project(bitcoin-test) # Process json files. file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data") find_program(PYTHON python) function(gen_json_header NAME) set(HEADERS "") foreach(f ${ARGN}) set(h "${CMAKE_CURRENT_BINARY_DIR}/${f}.h") # Get the proper name for the test variable. get_filename_component(TEST_NAME ${f} NAME_WE) add_custom_command(OUTPUT ${h} COMMAND ${PYTHON} ARGS "${CMAKE_CURRENT_SOURCE_DIR}/data/generate_header.py" "${TEST_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/${f}" > ${h} MAIN_DEPENDENCY ${f} DEPENDS "data/generate_header.py" VERBATIM ) list(APPEND HEADERS ${h}) endforeach(f) set(${NAME} "${HEADERS}" PARENT_SCOPE) endfunction() gen_json_header(JSON_HEADERS data/script_tests.json data/base58_keys_valid.json data/base58_encode_decode.json data/base58_keys_invalid.json data/tx_invalid.json data/tx_valid.json data/sighash.json ) include(TestSuite) create_test_suite(bitcoin) add_dependencies(check check-bitcoin) add_test_to_suite(bitcoin test_bitcoin arith_uint256_tests.cpp addrman_tests.cpp amount_tests.cpp allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp bip32_tests.cpp blockcheck_tests.cpp blockencodings_tests.cpp blockindex_tests.cpp blockstatus_tests.cpp bloom_tests.cpp bswap_tests.cpp cashaddr_tests.cpp cashaddrenc_tests.cpp checkdatasig_tests.cpp checkpoints_tests.cpp checkqueue_tests.cpp coins_tests.cpp compress_tests.cpp config_tests.cpp core_io_tests.cpp crypto_tests.cpp cuckoocache_tests.cpp dbwrapper_tests.cpp DoS_tests.cpp dstencode_tests.cpp excessiveblock_tests.cpp feerate_tests.cpp getarg_tests.cpp hash_tests.cpp inv_tests.cpp jsonutil.cpp key_tests.cpp limitedmap_tests.cpp main_tests.cpp mempool_tests.cpp merkle_tests.cpp miner_tests.cpp monolith_opcodes.cpp multisig_tests.cpp net_tests.cpp netbase_tests.cpp pmt_tests.cpp policyestimator_tests.cpp pow_tests.cpp prevector_tests.cpp raii_event_tests.cpp random_tests.cpp reverselock_tests.cpp rpc_tests.cpp + rwcollection_tests.cpp sanity_tests.cpp scheduler_tests.cpp script_commitment_tests.cpp script_P2SH_tests.cpp script_tests.cpp scriptflags.cpp scriptnum_tests.cpp serialize_tests.cpp sigencoding_tests.cpp sighash_tests.cpp sighashtype_tests.cpp sigopcount_tests.cpp sigutil.cpp skiplist_tests.cpp streams_tests.cpp sync_tests.cpp test_bitcoin.cpp test_bitcoin_main.cpp testutil.cpp timedata_tests.cpp transaction_tests.cpp txvalidationcache_tests.cpp versionbits_tests.cpp uint256_tests.cpp undo_tests.cpp univalue_tests.cpp util_tests.cpp validation_tests.cpp work_comparator_tests.cpp # RPC Tests ../rpc/test/server_tests.cpp # Tests generated from JSON ${JSON_HEADERS} ) target_include_directories(test_bitcoin PUBLIC # To access the generated json headers. ${CMAKE_CURRENT_BINARY_DIR} ) find_package(Boost 1.58 REQUIRED unit_test_framework) target_link_libraries(test_bitcoin Boost::unit_test_framework rpcclient server) # We need to detect if the BOOST_TEST_DYN_LINK flag is required. set(CMAKE_REQUIRED_LIBRARIES Boost::unit_test_framework) check_cxx_source_compiles(" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MAIN #include " BOOST_TEST_DYN_LINK) if(BOOST_TEST_DYN_LINK) target_compile_definitions(test_bitcoin PRIVATE BOOST_TEST_DYN_LINK) endif(BOOST_TEST_DYN_LINK) if(BUILD_BITCOIN_WALLET) target_sources(test_bitcoin PRIVATE ../wallet/test/wallet_test_fixture.cpp ../wallet/test/accounting_tests.cpp ../wallet/test/wallet_tests.cpp ../wallet/test/walletdb_tests.cpp ../wallet/test/crypto_tests.cpp ) endif() diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index 84ddacb08e..8ef075ee8d 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -1,397 +1,397 @@ // Copyright (c) 2012-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "cuckoocache.h" #include "random.h" #include "script/sigcache.h" #include "test/test_bitcoin.h" -#include +#include #include /** Test Suite for CuckooCache * * 1) All tests should have a deterministic result (using insecure rand * with deterministic seeds) * 2) Some test methods are templated to allow for easier testing * against new versions / comparing * 3) Results should be treated as a regression test, i.e., did the behavior * change significantly from what was expected. This can be OK, depending on * the nature of the change, but requires updating the tests to reflect the new * expected behavior. For example improving the hit rate may cause some tests * using BOOST_CHECK_CLOSE to fail. */ FastRandomContext local_rand_ctx(true); BOOST_AUTO_TEST_SUITE(cuckoocache_tests); /** * insecure_GetRandHash fills in a uint256 from local_rand_ctx */ void insecure_GetRandHash(uint256 &t) { uint32_t *ptr = (uint32_t *)t.begin(); for (uint8_t j = 0; j < 8; ++j) { *(ptr++) = local_rand_ctx.rand32(); } } /** * Test that no values not inserted into the cache are read out of it. * * There are no repeats in the first 200000 insecure_GetRandHash calls */ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) { local_rand_ctx = FastRandomContext(true); CuckooCache::cache cc{}; cc.setup_bytes(32 << 20); uint256 v; for (int x = 0; x < 100000; ++x) { insecure_GetRandHash(v); cc.insert(v); } for (int x = 0; x < 100000; ++x) { insecure_GetRandHash(v); BOOST_CHECK(!cc.contains(v, false)); } }; /** * This helper returns the hit rate when megabytes*load worth of entries are * inserted into a megabytes sized cache */ template double test_cache(size_t megabytes, double load) { local_rand_ctx = FastRandomContext(true); std::vector hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); for (uint32_t i = 0; i < n_insert; ++i) { uint32_t *ptr = (uint32_t *)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) { *(ptr++) = local_rand_ctx.rand32(); } } /** * We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is "future * proofed". */ std::vector hashes_insert_copy = hashes; /** Do the insert */ for (uint256 &h : hashes_insert_copy) { set.insert(h); } /** Count the hits */ uint32_t count = 0; for (uint256 &h : hashes) { count += set.contains(h, false); } double hit_rate = double(count) / double(n_insert); return hit_rate; } /** The normalized hit rate for a given load. * * The semantics are a little confusing, so please see the below * explanation. * * Examples: * * 1) at load 0.5, we expect a perfect hit rate, so we multiply by * 1.0 * 2) at load 2.0, we expect to see half the entries, so a perfect hit rate * would be 0.5. Therefore, if we see a hit rate of 0.4, 0.4*2.0 = 0.8 is the * normalized hit rate. * * This is basically the right semantics, but has a bit of a glitch depending on * how you measure around load 1.0 as after load 1.0 your normalized hit rate * becomes effectively perfect, ignoring freshness. */ double normalize_hit_rate(double hits, double load) { return hits * std::max(load, 1.0); } /** Check the hit rate on loads ranging from 0.1 to 2.0 */ BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) { /** * Arbitrarily selected Hit Rate threshold that happens to work for this * test as a lower bound on performance. */ double HitRateThresh = 0.98; size_t megabytes = 32; for (double load = 0.1; load < 2; load *= 2) { double hits = test_cache>( megabytes, load); BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh); } } /** This helper checks that erased elements are preferentially inserted onto and * that the hit rate of "fresher" keys is reasonable*/ template void test_cache_erase(size_t megabytes) { double load = 1; local_rand_ctx = FastRandomContext(true); std::vector hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); for (uint32_t i = 0; i < n_insert; ++i) { uint32_t *ptr = (uint32_t *)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) { *(ptr++) = local_rand_ctx.rand32(); } } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is * "future proofed". */ std::vector hashes_insert_copy = hashes; /** Insert the first half */ for (uint32_t i = 0; i < (n_insert / 2); ++i) { set.insert(hashes_insert_copy[i]); } /** Erase the first quarter */ for (uint32_t i = 0; i < (n_insert / 4); ++i) { set.contains(hashes[i], true); } /** Insert the second half */ for (uint32_t i = (n_insert / 2); i < n_insert; ++i) { set.insert(hashes_insert_copy[i]); } /** elements that we marked erased but that are still there */ size_t count_erased_but_contained = 0; /** elements that we did not erase but are older */ size_t count_stale = 0; /** elements that were most recently inserted */ size_t count_fresh = 0; for (uint32_t i = 0; i < (n_insert / 4); ++i) { count_erased_but_contained += set.contains(hashes[i], false); } for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i) { count_stale += set.contains(hashes[i], false); } for (uint32_t i = (n_insert / 2); i < n_insert; ++i) { count_fresh += set.contains(hashes[i], false); } double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0); double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0); double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0); // Check that our hit_rate_fresh is perfect BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0); // Check that we have a more than 2x better hit rate on stale elements than // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok) { size_t megabytes = 32; test_cache_erase>( megabytes); } template void test_cache_erase_parallel(size_t megabytes) { double load = 1; local_rand_ctx = FastRandomContext(true); std::vector hashes; Cache set{}; size_t bytes = megabytes * (1 << 20); set.setup_bytes(bytes); uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); hashes.resize(n_insert); for (uint32_t i = 0; i < n_insert; ++i) { uint32_t *ptr = (uint32_t *)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) { *(ptr++) = local_rand_ctx.rand32(); } } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is * "future proofed". */ std::vector hashes_insert_copy = hashes; boost::shared_mutex mtx; { /** Grab lock to make sure we release inserts */ boost::unique_lock l(mtx); /** Insert the first half */ for (uint32_t i = 0; i < (n_insert / 2); ++i) { set.insert(hashes_insert_copy[i]); } } /** Spin up 3 threads to run contains with erase. */ std::vector threads; /** Erase the first quarter */ for (uint32_t x = 0; x < 3; ++x) /** Each thread is emplaced with x copy-by-value */ threads.emplace_back([&, x] { boost::shared_lock l(mtx); size_t ntodo = (n_insert / 4) / 3; size_t start = ntodo * x; size_t end = ntodo * (x + 1); for (uint32_t i = start; i < end; ++i) { set.contains(hashes[i], true); } }); /** Wait for all threads to finish */ for (std::thread &t : threads) { t.join(); } /** Grab lock to make sure we observe erases */ boost::unique_lock l(mtx); /** Insert the second half */ for (uint32_t i = (n_insert / 2); i < n_insert; ++i) { set.insert(hashes_insert_copy[i]); } /** elements that we marked erased but that are still there */ size_t count_erased_but_contained = 0; /** elements that we did not erase but are older */ size_t count_stale = 0; /** elements that were most recently inserted */ size_t count_fresh = 0; for (uint32_t i = 0; i < (n_insert / 4); ++i) { count_erased_but_contained += set.contains(hashes[i], false); } for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i) { count_stale += set.contains(hashes[i], false); } for (uint32_t i = (n_insert / 2); i < n_insert; ++i) { count_fresh += set.contains(hashes[i], false); } double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0); double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0); double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0); // Check that our hit_rate_fresh is perfect BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0); // Check that we have a more than 2x better hit rate on stale elements than // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok) { size_t megabytes = 32; test_cache_erase_parallel< CuckooCache::cache>(megabytes); } template void test_cache_generations() { // This test checks that for a simulation of network activity, the fresh hit // rate is never below 99%, and the number of times that it is worse than // 99.9% are less than 1% of the time. double min_hit_rate = 0.99; double tight_hit_rate = 0.999; double max_rate_less_than_tight_hit_rate = 0.01; // A cache that meets this specification is therefore shown to have a hit // rate of at least tight_hit_rate * (1 - max_rate_less_than_tight_hit_rate) // + // min_hit_rate*max_rate_less_than_tight_hit_rate = 0.999*99%+0.99*1% == // 99.89% // hit rate with low variance. // We use deterministic values, but this test has also passed on many // iterations with non-deterministic values, so it isn't "overfit" to the // specific entropy in FastRandomContext(true) and implementation of the // cache. local_rand_ctx = FastRandomContext(true); // block_activity models a chunk of network activity. n_insert elements are // adde to the cache. The first and last n/4 are stored for removal later // and the middle n/2 are not stored. This models a network which uses half // the signatures of recently (since the last block) added transactions // immediately and never uses the other half. struct block_activity { std::vector reads; block_activity(uint32_t n_insert, Cache &c) : reads() { std::vector inserts; inserts.resize(n_insert); reads.reserve(n_insert / 2); for (uint32_t i = 0; i < n_insert; ++i) { uint32_t *ptr = (uint32_t *)inserts[i].begin(); for (uint8_t j = 0; j < 8; ++j) { *(ptr++) = local_rand_ctx.rand32(); } } for (uint32_t i = 0; i < n_insert / 4; ++i) { reads.push_back(inserts[i]); } for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i) { reads.push_back(inserts[i]); } for (auto h : inserts) { c.insert(h); } } }; const uint32_t BLOCK_SIZE = 10000; // We expect window size 60 to perform reasonably given that each epoch // stores 45% of the cache size (~472k). const uint32_t WINDOW_SIZE = 60; const uint32_t POP_AMOUNT = (BLOCK_SIZE / WINDOW_SIZE) / 2; const double load = 10; const size_t megabytes = 32; const size_t bytes = megabytes * (1 << 20); const uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); std::vector hashes; Cache set{}; set.setup_bytes(bytes); hashes.reserve(n_insert / BLOCK_SIZE); std::deque last_few; uint32_t out_of_tight_tolerance = 0; uint32_t total = n_insert / BLOCK_SIZE; // we use the deque last_few to model a sliding window of blocks. at each // step, each of the last WINDOW_SIZE block_activities checks the cache for // POP_AMOUNT of the hashes that they inserted, and marks these erased. for (uint32_t i = 0; i < total; ++i) { if (last_few.size() == WINDOW_SIZE) last_few.pop_front(); last_few.emplace_back(BLOCK_SIZE, set); uint32_t count = 0; for (auto &act : last_few) { for (uint32_t k = 0; k < POP_AMOUNT; ++k) { count += set.contains(act.reads.back(), true); act.reads.pop_back(); } } // We use last_few.size() rather than WINDOW_SIZE for the correct // behavior on the first WINDOW_SIZE iterations where the deque is not // full yet. double hit = double(count) / (last_few.size() * POP_AMOUNT); // Loose Check that hit rate is above min_hit_rate BOOST_CHECK(hit > min_hit_rate); // Tighter check, count number of times we are less than tight_hit_rate // (and implicityly, greater than min_hit_rate) out_of_tight_tolerance += hit < tight_hit_rate; } // Check that being out of tolerance happens less than // max_rate_less_than_tight_hit_rate of the time BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate); } BOOST_AUTO_TEST_CASE(cuckoocache_generations) { test_cache_generations>(); } BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/test/rwcollection_tests.cpp b/src/test/rwcollection_tests.cpp new file mode 100644 index 0000000000..36e9a2e6e6 --- /dev/null +++ b/src/test/rwcollection_tests.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "rwcollection.h" + +#include "test/test_bitcoin.h" + +#include +#include + +#include +#include + +BOOST_AUTO_TEST_SUITE(rwcollection_tests); + +BOOST_AUTO_TEST_CASE(vector) { + RWCollection> rwvector; + + { + auto w = rwvector.getWriteView(); + for (int i = 0; i < 100; i++) { + w->push_back(i + 10); + BOOST_CHECK_EQUAL(w[i], i + 10); + BOOST_CHECK_EQUAL(w->back(), i + 10); + BOOST_CHECK_EQUAL(w->size(), i + 1); + + w[i] = i; + BOOST_CHECK_EQUAL(w[i], i); + } + + int e = 0; + for (int &i : w) { + BOOST_CHECK_EQUAL(i, e++); + i *= 2; + } + + e = 0; + for (int &i : boost::adaptors::reverse(w)) { + BOOST_CHECK_EQUAL(i, 198 - 2 * e); + i = e++; + } + } + + { + auto r = rwvector.getReadView(); + for (int i = 0; i < 100; i++) { + BOOST_CHECK_EQUAL(r[i], 99 - i); + } + + int e = 0; + for (const int &i : r) { + BOOST_CHECK_EQUAL(i, 99 - (e++)); + } + + e = 0; + for (const int &i : boost::adaptors::reverse(r)) { + BOOST_CHECK_EQUAL(i, e++); + } + } +} + +BOOST_AUTO_TEST_CASE(set) { + RWCollection> rwset; + + { + auto w = rwset.getWriteView(); + for (int i = 0; i < 100; i++) { + w->insert(i); + BOOST_CHECK_EQUAL(w->count(i), 1); + BOOST_CHECK_EQUAL(*(w->find(i)), i); + BOOST_CHECK_EQUAL(w->size(), i + 1); + } + + for (int i = 0; i < 100; i += 2) { + BOOST_CHECK_EQUAL(w->erase(i), 1); + BOOST_CHECK_EQUAL(w->count(i), 0); + BOOST_CHECK(w->find(i) == std::end(w)); + } + + int e = 0; + for (const int &i : w) { + BOOST_CHECK_EQUAL(i / 2, e++); + } + } + + { + auto r = rwset.getReadView(); + for (int i = 0; i < 100; i += 2) { + BOOST_CHECK_EQUAL(r->count(i), 0); + BOOST_CHECK(r->find(i) == std::end(r)); + } + + for (int i = 1; i < 100; i += 2) { + BOOST_CHECK_EQUAL(r->count(i), 1); + BOOST_CHECK_EQUAL(*(r->find(i)), i); + } + + int e = 0; + for (const int &i : r) { + BOOST_CHECK_EQUAL(i / 2, e++); + } + } +} + +BOOST_AUTO_TEST_CASE(map) { + RWCollection> rwmap; + + { + auto w = rwmap.getWriteView(); + w["1"] = "one"; + w["2"] = "two"; + w["3"] = "three"; + BOOST_CHECK_EQUAL(w["1"], "one"); + BOOST_CHECK_EQUAL(w["2"], "two"); + BOOST_CHECK_EQUAL(w["3"], "three"); + + for (const std::pair &p : w) { + BOOST_CHECK_EQUAL(w[p.first], p.second); + } + } + + { + auto r = rwmap.getReadView(); + BOOST_CHECK_EQUAL(r->count("1"), 1); + BOOST_CHECK_EQUAL(r->find("1")->first, "1"); + BOOST_CHECK_EQUAL(r->find("1")->second, "one"); + + for (const std::pair &p : r) { + BOOST_CHECK_EQUAL(r->at(p.first), p.second); + } + } +} + +BOOST_AUTO_TEST_SUITE_END();