diff --git a/src/Makefile.am b/src/Makefile.am index a02da9e6a..f617ac444 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,564 +1,564 @@ # 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) AM_CXXFLAGS = $(HARDENED_CXXFLAGS) $(ERROR_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_CONFIG_INCLUDES=-I$(builddir)/config 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=crypto/libbitcoin_crypto.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 $(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 \ 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/consensus.h \ core_io.h \ core_memusage.h \ cuckoocache.h \ globals.h \ httprpc.h \ httpserver.h \ indirectmap.h \ init.h \ key.h \ keystore.h \ dbwrapper.h \ limitedmap.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/misc.h \ rpc/protocol.h \ rpc/server.h \ rpc/register.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/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 \ 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/mining.cpp \ rpc/misc.cpp \ rpc/net.cpp \ rpc/rawtransaction.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/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ $(BITCOIN_CORE_H) # crypto primitives library crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_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 # 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 \ hash.cpp \ hash.h \ prevector.h \ primitives/block.cpp \ primitives/block.h \ primitives/transaction.cpp \ primitives/transaction.h \ pubkey.cpp \ pubkey.h \ script/bitcoinconsensus.cpp \ script/interpreter.cpp \ script/interpreter.h \ script/script.cpp \ script/script.h \ script/script_error.cpp \ script/script_error.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 \ chainparams.cpp \ coins.cpp \ compressor.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 \ random.cpp \ rpc/protocol.cpp \ support/cleanse.cpp \ sync.cpp \ threadinterrupt.cpp \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ utiltime.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp 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) $(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.c \ seeder/dns.h \ seeder/netbase.cpp \ seeder/netbase.h \ seeder/protocol.cpp \ seeder/protocol.h \ - seeder/serialize.h \ seeder/strlcpy.h \ - seeder/uint256.h \ seeder/util.cpp \ 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) \ $(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) +bitcoin_seeder_LDADD = \ + $(LIBBITCOIN_SEEDER) \ + $(LIBBITCOIN_UTIL) bitcoin_seeder_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_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_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=$( #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL class CNode { SOCKET sock; CDataStream vSend; CDataStream vRecv; unsigned int nHeaderStart; unsigned int nMessageStart; int nVersion; std::string strSubVer; int nStartingHeight; std::vector *vAddr; int ban; int64_t doneAfter; CAddress you; int GetTimeout() { return you.IsTor() ? 120 : 30; } void BeginMessage(const char *pszCommand) { if (nHeaderStart != -1) AbortMessage(); nHeaderStart = vSend.size(); vSend << CMessageHeader(pszCommand, 0); nMessageStart = vSend.size(); // printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand); } void AbortMessage() { if (nHeaderStart == -1) return; vSend.resize(nHeaderStart); nHeaderStart = -1; nMessageStart = -1; } void EndMessage() { if (nHeaderStart == -1) return; unsigned int nSize = vSend.size() - nMessageStart; memcpy((char *)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); if (vSend.GetVersion() >= 209) { uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); memcpy((char *)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); } nHeaderStart = -1; nMessageStart = -1; } void Send() { if (sock == INVALID_SOCKET) return; if (vSend.empty()) return; int nBytes = send(sock, &vSend[0], vSend.size(), 0); if (nBytes > 0) { vSend.erase(vSend.begin(), vSend.begin() + nBytes); } else { close(sock); sock = INVALID_SOCKET; } } void PushVersion() { int64_t nTime = time(nullptr); uint64_t nLocalNonce = BITCOIN_SEED_NONCE; int64_t nLocalServices = 0; CAddress me(CService("0.0.0.0")); BeginMessage("version"); int nBestHeight = GetRequireHeight(); std::string ver = "/bitcoin-cash-seeder:0.15/"; vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight; EndMessage(); } void GotVersion() { // printf("\n%s: version %i\n", ToString(you).c_str(), nVersion); if (vAddr) { BeginMessage("getaddr"); EndMessage(); doneAfter = time(nullptr) + GetTimeout(); } else { doneAfter = time(nullptr) + 1; } } bool ProcessMessage(std::string strCommand, CDataStream &vRecv) { // printf("%s: RECV %s\n", ToString(you).c_str(), // strCommand.c_str()); if (strCommand == "version") { int64_t nTime; CAddress addrMe; CAddress addrFrom; uint64_t nNonce = 1; vRecv >> nVersion >> you.nServices >> nTime >> addrMe; if (nVersion == 10300) nVersion = 300; if (nVersion >= 106 && !vRecv.empty()) vRecv >> addrFrom >> nNonce; if (nVersion >= 106 && !vRecv.empty()) vRecv >> strSubVer; if (nVersion >= 209 && !vRecv.empty()) vRecv >> nStartingHeight; if (nVersion >= 209) { BeginMessage("verack"); EndMessage(); } vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); if (nVersion < 209) { this->vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); GotVersion(); } return false; } if (strCommand == "verack") { this->vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); GotVersion(); return false; } if (strCommand == "addr" && vAddr) { std::vector vAddrNew; vRecv >> vAddrNew; // printf("%s: got %i addresses\n", ToString(you).c_str(), // (int)vAddrNew.size()); int64_t now = time(nullptr); std::vector::iterator it = vAddrNew.begin(); if (vAddrNew.size() > 1) { if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; } while (it != vAddrNew.end()) { CAddress &addr = *it; // printf("%s: got address %s\n", ToString(you).c_str(), // addr.ToString().c_str(), (int)(vAddr->size())); it++; if (addr.nTime <= 100000000 || addr.nTime > now + 600) addr.nTime = now - 5 * 86400; if (addr.nTime > now - 604800) vAddr->push_back(addr); // printf("%s: added address %s (#%i)\n", // ToString(you).c_str(), addr.ToString().c_str(), // (int)(vAddr->size())); if (vAddr->size() > 1000) { doneAfter = 1; return true; } } return false; } return false; } bool ProcessMessages() { if (vRecv.empty()) return false; do { CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); - int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); + int nHeaderSize = GetSerializeSize( + CMessageHeader(), vRecv.GetType(), vRecv.GetVersion()); if (vRecv.end() - pstart < nHeaderSize) { if (vRecv.size() > nHeaderSize) { vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); } break; } vRecv.erase(vRecv.begin(), pstart); std::vector vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); CMessageHeader hdr; vRecv >> hdr; if (!hdr.IsValid()) { // printf("%s: BAD (invalid header)\n", ToString(you).c_str()); ban = 100000; return true; } std::string strCommand = hdr.GetCommand(); unsigned int nMessageSize = hdr.nMessageSize; if (nMessageSize > MAX_SIZE) { // printf("%s: BAD (message too large)\n", // ToString(you).c_str()); ban = 100000; return true; } if (nMessageSize > vRecv.size()) { vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); break; } if (vRecv.GetVersion() >= 209) { uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); if (nChecksum != hdr.nChecksum) continue; } CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, - vRecv.nType, vRecv.nVersion); + vRecv.GetType(), vRecv.GetVersion()); vRecv.ignore(nMessageSize); if (ProcessMessage(strCommand, vMsg)) return true; // printf("%s: done processing %s\n", ToString(you).c_str(), // strCommand.c_str()); } while (1); return false; } public: CNode(const CService &ip, std::vector *vAddrIn) - : you(ip), nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), + : vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), you(ip), + nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), doneAfter(0), nVersion(0) { - vSend.SetType(SER_NETWORK); - vSend.SetVersion(0); - vRecv.SetType(SER_NETWORK); - vRecv.SetVersion(0); if (time(nullptr) > 1329696000) { vSend.SetVersion(209); vRecv.SetVersion(209); } } + bool Run() { bool res = true; if (!ConnectSocket(you, sock)) return false; PushVersion(); Send(); int64_t now; while (now = time(nullptr), ban == 0 && (doneAfter == 0 || doneAfter > now) && sock != INVALID_SOCKET) { char pchBuf[0x10000]; fd_set set; FD_ZERO(&set); FD_SET(sock, &set); struct timeval wa; if (doneAfter) { wa.tv_sec = doneAfter - now; wa.tv_usec = 0; } else { wa.tv_sec = GetTimeout(); wa.tv_usec = 0; } int ret = select(sock + 1, &set, nullptr, &set, &wa); if (ret != 1) { if (!doneAfter) res = false; break; } int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); int nPos = vRecv.size(); if (nBytes > 0) { vRecv.resize(nPos + nBytes); memcpy(&vRecv[nPos], pchBuf, nBytes); } else if (nBytes == 0) { // printf("%s: BAD (connection closed prematurely)\n", // ToString(you).c_str()); res = false; break; } else { // printf("%s: BAD (connection error)\n", // ToString(you).c_str()); res = false; break; } ProcessMessages(); Send(); } if (sock == INVALID_SOCKET) res = false; close(sock); sock = INVALID_SOCKET; return (ban == 0) && res; } int GetBan() { return ban; } int GetClientVersion() { return nVersion; } std::string GetClientSubVersion() { return strSubVer; } int GetStartingHeight() { return nStartingHeight; } }; bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, std::vector *vAddr) { try { CNode node(cip, vAddr); bool ret = node.Run(); if (!ret) { ban = node.GetBan(); } else { ban = 0; } clientV = node.GetClientVersion(); clientSV = node.GetClientSubVersion(); blocks = node.GetStartingHeight(); // printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD"); return ret; } catch (std::ios_base::failure &e) { ban = 0; return false; } } /* int main(void) { CService ip("bitcoin.sipa.be", 8333, true); std::vector vAddr; vAddr.clear(); int ban = 0; bool ret = TestNode(ip, ban, vAddr); printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size()); } */ diff --git a/src/seeder/db.h b/src/seeder/db.h index 25a4fd0d7..8a7d2ec04 100644 --- a/src/seeder/db.h +++ b/src/seeder/db.h @@ -1,404 +1,425 @@ #ifndef BITCOIN_SEEDER_DB_H #define BITCOIN_SEEDER_DB_H #include "netbase.h" #include "protocol.h" #include "sync.h" #include "util.h" +#include "version.h" #include #include #include #include #include #include #define MIN_RETRY 1000 #define REQUIRE_VERSION 70001 static inline int GetRequireHeight(const bool testnet = fTestNet) { return testnet ? 500000 : 350000; } static inline std::string ToString(const CService &ip) { std::string str = ip.ToString(); while (str.size() < 22) str += ' '; return str; } class CAddrStat { private: float weight; float count; float reliability; public: CAddrStat() : weight(0), count(0), reliability(0) {} void Update(bool good, int64_t age, double tau) { double f = exp(-age / tau); reliability = reliability * f + (good ? (1.0 - f) : 0); count = count * f + 1; weight = weight * f + (1.0 - f); } - IMPLEMENT_SERIALIZE(READWRITE(weight); READWRITE(count); - READWRITE(reliability);) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(weight); + READWRITE(count); + READWRITE(reliability); + } friend class CAddrInfo; }; class CAddrReport { public: CService ip; int clientVersion; int blocks; double uptime[5]; std::string clientSubVersion; int64_t lastSuccess; bool fGood; uint64_t services; }; class CAddrInfo { private: CService ip; uint64_t services; int64_t lastTry; int64_t ourLastTry; int64_t ourLastSuccess; int64_t ignoreTill; CAddrStat stat2H; CAddrStat stat8H; CAddrStat stat1D; CAddrStat stat1W; CAddrStat stat1M; int clientVersion; int blocks; int total; int success; std::string clientSubVersion; public: CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {} CAddrReport GetReport() const { CAddrReport ret; ret.ip = ip; ret.clientVersion = clientVersion; ret.clientSubVersion = clientSubVersion; ret.blocks = blocks; ret.uptime[0] = stat2H.reliability; ret.uptime[1] = stat8H.reliability; ret.uptime[2] = stat1D.reliability; ret.uptime[3] = stat1W.reliability; ret.uptime[4] = stat1M.reliability; ret.lastSuccess = ourLastSuccess; ret.fGood = IsGood(); ret.services = services; return ret; } bool IsGood() const { if (ip.GetPort() != GetDefaultPort()) return false; if (!(services & NODE_NETWORK)) return false; if (!(services & NODE_BITCOIN_CASH)) return false; if (!ip.IsRoutable()) return false; if (clientVersion && clientVersion < REQUIRE_VERSION) return false; if (blocks && blocks < GetRequireHeight()) return false; if (total <= 3 && success * 2 >= total) return true; if (stat2H.reliability > 0.85 && stat2H.count > 2) return true; if (stat8H.reliability > 0.70 && stat8H.count > 4) return true; if (stat1D.reliability > 0.55 && stat1D.count > 8) return true; if (stat1W.reliability > 0.45 && stat1W.count > 16) return true; if (stat1M.reliability > 0.35 && stat1M.count > 32) return true; return false; } int GetBanTime() const { if (IsGood()) return 0; if (clientVersion && clientVersion < 31900) { return 604800; } if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 && stat1M.count > 32) { return 30 * 86400; } if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 && stat1W.count > 16) { return 7 * 86400; } if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 && stat1D.count > 8) { return 1 * 86400; } return 0; } int GetIgnoreTime() const { if (IsGood()) return 0; if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 && stat1M.count > 2) { return 10 * 86400; } if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 && stat1W.count > 2) { return 3 * 86400; } if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 && stat1D.count > 2) { return 8 * 3600; } if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 && stat8H.count > 2) { return 2 * 3600; } return 0; } void Update(bool good); friend class CAddrDb; - IMPLEMENT_SERIALIZE(uint8_t version = 4; READWRITE(version); READWRITE(ip); - READWRITE(services); READWRITE(lastTry); - uint8_t tried = ourLastTry != 0; READWRITE(tried); - if (tried) { - READWRITE(ourLastTry); - READWRITE(ignoreTill); - READWRITE(stat2H); - READWRITE(stat8H); - READWRITE(stat1D); - READWRITE(stat1W); - if (version >= 1) - READWRITE(stat1M); - else if (!fWrite) - *((CAddrStat *)(&stat1M)) = stat1W; - READWRITE(total); - READWRITE(success); - READWRITE(clientVersion); - if (version >= 2) READWRITE(clientSubVersion); - if (version >= 3) READWRITE(blocks); - if (version >= 4) READWRITE(ourLastSuccess); - }) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + uint8_t version = 4; + READWRITE(version); + READWRITE(ip); + READWRITE(services); + READWRITE(lastTry); + uint8_t tried = ourLastTry != 0; + READWRITE(tried); + if (tried) { + READWRITE(ourLastTry); + READWRITE(ignoreTill); + READWRITE(stat2H); + READWRITE(stat8H); + READWRITE(stat1D); + READWRITE(stat1W); + if (version >= 1) { + READWRITE(stat1M); + } else if (!ser_action.ForRead()) { + *((CAddrStat *)(&stat1M)) = stat1W; + } + READWRITE(total); + READWRITE(success); + READWRITE(clientVersion); + if (version >= 2) READWRITE(clientSubVersion); + if (version >= 3) READWRITE(blocks); + if (version >= 4) READWRITE(ourLastSuccess); + } + } }; class CAddrDbStats { public: int nBanned; int nAvail; int nTracked; int nNew; int nGood; int nAge; }; struct CServiceResult { CService service; bool fGood; int nBanTime; int nHeight; int nClientV; std::string strClientV; int64_t ourLastSuccess; }; // seen nodes // / \ // (a) banned nodes available nodes-------------- // / | \ // tracked nodes (b) unknown nodes (e) active nodes // / \ // (d) good nodes (c) non-good nodes class CAddrDb { private: mutable CCriticalSection cs; // number of address id's int nId; // map address id to address info (b,c,d,e) std::map idToInfo; // map ip to id (b,c,d,e) std::map ipToId; // sequence of tried nodes, in order we have tried connecting to them (c,d) std::deque ourId; // set of nodes not yet tried (b) std::set unkId; // set of good nodes (d, good e) std::set goodId; int nDirty; protected: // internal routines that assume proper locks are acquired // add an address void Add_(const CAddress &addr, bool force); // get an IP to test (must call Good_, Bad_, or Skipped_ on result // afterwards) bool Get_(CServiceResult &ip, int &wait); bool GetMany_(std::vector &ips, int max, int &wait); // mark an IP as good (must have been returned by Get_) void Good_(const CService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as bad (and optionally ban it) (must have been returned by // Get_) void Bad_(const CService &ip, int ban); // mark an IP as skipped (must have been returned by Get_) void Skipped_(const CService &ip); // look up id of an IP int Lookup_(const CService &ip); // get a random set of IPs (shared lock only) void GetIPs_(std::set &ips, uint64_t requestedFlags, int max, const bool *nets); public: // nodes that are banned, with their unban time (a) std::map banned; void GetStats(CAddrDbStats &stats) { LOCK(cs); stats.nBanned = banned.size(); stats.nAvail = idToInfo.size(); stats.nTracked = ourId.size(); stats.nGood = goodId.size(); stats.nNew = unkId.size(); stats.nAge = time(nullptr) - idToInfo[ourId[0]].ourLastTry; } void ResetIgnores() { for (std::map::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) { (*it).second.ignoreTill = 0; } } std::vector GetAll() { std::vector ret; LOCK(cs); for (std::deque::const_iterator it = ourId.begin(); it != ourId.end(); it++) { const CAddrInfo &info = idToInfo[*it]; if (info.success > 0) { ret.push_back(info.GetReport()); } } return ret; } // serialization code // format: // nVersion (0 for now) // n (number of ips in (b,c,d)) // CAddrInfo[n] // banned // acquires a shared lock (this does not suffice for read mode, but we // assume that only happens at startup, single-threaded) // this way, dumping does not interfere with GetIPs_, which is called from // the DNS thread - IMPLEMENT_SERIALIZE(({ - int nVersion = 0; - READWRITE(nVersion); - LOCK(cs); - if (fWrite) { - CAddrDb *db = const_cast(this); - int n = ourId.size() + unkId.size(); - READWRITE(n); - for (std::deque::const_iterator it = - ourId.begin(); - it != ourId.end(); it++) { - std::map::iterator ci = - db->idToInfo.find(*it); - READWRITE((*ci).second); - } - for (std::set::const_iterator it = - unkId.begin(); - it != unkId.end(); it++) { - std::map::iterator ci = - db->idToInfo.find(*it); - READWRITE((*ci).second); - } - } else { - CAddrDb *db = const_cast(this); - db->nId = 0; - int n; - READWRITE(n); - for (int i = 0; i < n; i++) { - CAddrInfo info; - READWRITE(info); - if (!info.GetBanTime()) { - int id = db->nId++; - db->idToInfo[id] = info; - db->ipToId[info.ip] = id; - if (info.ourLastTry) { - db->ourId.push_back(id); - if (info.IsGood()) - db->goodId.insert(id); - } else { - db->unkId.insert(id); - } - } - } - db->nDirty++; - } - READWRITE(banned); - });) + template void Serialize(Stream &s) const { + LOCK(cs); + + int nVersion = 0; + s << nVersion; + + CAddrDb *db = const_cast(this); + int n = ourId.size() + unkId.size(); + s << n; + for (std::deque::const_iterator it = ourId.begin(); + it != ourId.end(); it++) { + std::map::iterator ci = db->idToInfo.find(*it); + s << (*ci).second; + } + for (std::set::const_iterator it = unkId.begin(); + it != unkId.end(); it++) { + std::map::iterator ci = db->idToInfo.find(*it); + s << (*ci).second; + } + s << banned; + } + + template void Unserialize(Stream &s) { + LOCK(cs); + + int nVersion; + s >> nVersion; + + CAddrDb *db = const_cast(this); + db->nId = 0; + int n; + s >> n; + for (int i = 0; i < n; i++) { + CAddrInfo info; + s >> info; + if (!info.GetBanTime()) { + int id = db->nId++; + db->idToInfo[id] = info; + db->ipToId[info.ip] = id; + if (info.ourLastTry) { + db->ourId.push_back(id); + if (info.IsGood()) db->goodId.insert(id); + } else { + db->unkId.insert(id); + } + } + } + db->nDirty++; + + s >> banned; + } void Add(const CAddress &addr, bool fForce = false) { LOCK(cs); Add_(addr, fForce); } void Add(const std::vector &vAddr, bool fForce = false) { LOCK(cs); for (size_t i = 0; i < vAddr.size(); i++) { Add_(vAddr[i], fForce); } } void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) { LOCK(cs); Good_(addr, clientVersion, clientSubVersion, blocks); } void Skipped(const CService &addr) { LOCK(cs); Skipped_(addr); } void Bad(const CService &addr, int ban = 0) { LOCK(cs); Bad_(addr, ban); } bool Get(CServiceResult &ip, int &wait) { LOCK(cs); return Get_(ip, wait); } void GetMany(std::vector &ips, int max, int &wait) { LOCK(cs); while (max > 0) { CServiceResult ip = {}; if (!Get_(ip, wait)) return; ips.push_back(ip); max--; } } void ResultMany(const std::vector &ips) { LOCK(cs); for (int i = 0; i < ips.size(); i++) { if (ips[i].fGood) { Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV, ips[i].nHeight); } else { Bad_(ips[i].service, ips[i].nBanTime); } } } void GetIPs(std::set &ips, uint64_t requestedFlags, int max, const bool *nets) { LOCK(cs); GetIPs_(ips, requestedFlags, max, nets); } }; #endif diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp index 7d20758da..3a36b2e4f 100644 --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -1,561 +1,560 @@ #include "bitcoin.h" +#include "clientversion.h" #include "db.h" +#include "streams.h" #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include bool fTestNet = false; class CDnsSeedOpts { public: int nThreads; int nPort; int nDnsThreads; int fUseTestNet; int fWipeBan; int fWipeIgnore; const char *mbox; const char *ns; const char *host; const char *tor; const char *ipv4_proxy; const char *ipv6_proxy; std::set filter_whitelist; CDnsSeedOpts() : nThreads(96), nDnsThreads(4), nPort(53), mbox(nullptr), ns(nullptr), host(nullptr), tor(nullptr), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false), ipv4_proxy(nullptr), ipv6_proxy(nullptr) {} void ParseCommandLine(int argc, char **argv) { static const char *help = "Bitcoin-cash-seeder\n" "Usage: %s -h -n [-m ] [-t ] [-p " "]\n" "\n" "Options:\n" "-h Hostname of the DNS seed\n" "-n Hostname of the nameserver\n" "-m E-Mail address reported in SOA records\n" "-t Number of crawlers to run in parallel (default " "96)\n" "-d Number of DNS server threads (default 4)\n" "-p UDP port to listen on (default 53)\n" "-o Tor proxy IP/Port\n" "-i IPV4 SOCKS5 proxy IP/Port\n" "-k IPV6 SOCKS5 proxy IP/Port\n" "-w f1,f2,... Allow these flag combinations as filters\n" "--testnet Use testnet\n" "--wipeban Wipe list of banned nodes\n" "--wipeignore Wipe list of ignored nodes\n" "-?, --help Show this text\n" "\n"; bool showHelp = false; while (1) { static struct option long_options[] = { {"host", required_argument, 0, 'h'}, {"ns", required_argument, 0, 'n'}, {"mbox", required_argument, 0, 'm'}, {"threads", required_argument, 0, 't'}, {"dnsthreads", required_argument, 0, 'd'}, {"port", required_argument, 0, 'p'}, {"onion", required_argument, 0, 'o'}, {"proxyipv4", required_argument, 0, 'i'}, {"proxyipv6", required_argument, 0, 'k'}, {"filter", required_argument, 0, 'w'}, {"testnet", no_argument, &fUseTestNet, 1}, {"wipeban", no_argument, &fWipeBan, 1}, {"wipeignore", no_argument, &fWipeBan, 1}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; int option_index = 0; int c = getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': { host = optarg; break; } case 'm': { mbox = optarg; break; } case 'n': { ns = optarg; break; } case 't': { int n = strtol(optarg, nullptr, 10); if (n > 0 && n < 1000) nThreads = n; break; } case 'd': { int n = strtol(optarg, nullptr, 10); if (n > 0 && n < 1000) nDnsThreads = n; break; } case 'p': { int p = strtol(optarg, nullptr, 10); if (p > 0 && p < 65536) nPort = p; break; } case 'o': { tor = optarg; break; } case 'i': { ipv4_proxy = optarg; break; } case 'k': { ipv6_proxy = optarg; break; } case 'w': { char *ptr = optarg; while (*ptr != 0) { unsigned long l = strtoul(ptr, &ptr, 0); if (*ptr == ',') { ptr++; } else if (*ptr != 0) { break; } filter_whitelist.insert(l); } break; } case '?': { showHelp = true; break; } } } if (filter_whitelist.empty()) { filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_BLOOM); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_XTHIN); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_BLOOM | NODE_XTHIN); } if (host != nullptr && ns == nullptr) showHelp = true; if (showHelp) fprintf(stderr, help, argv[0]); } }; extern "C" { #include "dns.h" } CAddrDb db; extern "C" void *ThreadCrawler(void *data) { int *nThreads = (int *)data; do { std::vector ips; int wait = 5; db.GetMany(ips, 16, wait); int64_t now = time(nullptr); if (ips.empty()) { wait *= 1000; wait += rand() % (500 * *nThreads); Sleep(wait); continue; } std::vector addr; for (int i = 0; i < ips.size(); i++) { CServiceResult &res = ips[i]; res.nBanTime = 0; res.nClientV = 0; res.nHeight = 0; res.strClientV = ""; bool getaddr = res.ourLastSuccess + 86400 < now; res.fGood = TestNode(res.service, res.nBanTime, res.nClientV, res.strClientV, res.nHeight, getaddr ? &addr : nullptr); } db.ResultMany(ips); db.Add(addr); } while (1); return nullptr; } extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6); class CDnsThread { public: struct FlagSpecificData { int nIPv4, nIPv6; std::vector cache; time_t cacheTime; unsigned int cacheHits; FlagSpecificData() : nIPv4(0), nIPv6(0), cacheTime(0), cacheHits(0) {} }; dns_opt_t dns_opt; // must be first const int id; std::map perflag; std::atomic dbQueries; std::set filterWhitelist; void cacheHit(uint64_t requestedFlags, bool force = false) { static bool nets[NET_MAX] = {}; if (!nets[NET_IPV4]) { nets[NET_IPV4] = true; nets[NET_IPV6] = true; } time_t now = time(nullptr); FlagSpecificData &thisflag = perflag[requestedFlags]; thisflag.cacheHits++; if (force || thisflag.cacheHits * 400 > (thisflag.cache.size() * thisflag.cache.size()) || (thisflag.cacheHits * thisflag.cacheHits * 20 > thisflag.cache.size() && (now - thisflag.cacheTime > 5))) { std::set ips; db.GetIPs(ips, requestedFlags, 1000, nets); dbQueries++; thisflag.cache.clear(); thisflag.nIPv4 = 0; thisflag.nIPv6 = 0; thisflag.cache.reserve(ips.size()); for (auto &ip : ips) { struct in_addr addr; struct in6_addr addr6; if (ip.GetInAddr(&addr)) { addr_t a; a.v = 4; memcpy(&a.data.v4, &addr, 4); thisflag.cache.push_back(a); thisflag.nIPv4++; } else if (ip.GetIn6Addr(&addr6)) { addr_t a; a.v = 6; memcpy(&a.data.v6, &addr6, 16); thisflag.cache.push_back(a); thisflag.nIPv6++; } } thisflag.cacheHits = 0; thisflag.cacheTime = now; } } CDnsThread(CDnsSeedOpts *opts, int idIn) : id(idIn) { dns_opt.host = opts->host; dns_opt.ns = opts->ns; dns_opt.mbox = opts->mbox; dns_opt.datattl = 3600; dns_opt.nsttl = 40000; dns_opt.cb = GetIPList; dns_opt.port = opts->nPort; dns_opt.nRequests = 0; dbQueries = 0; perflag.clear(); filterWhitelist = opts->filter_whitelist; } void run() { dnsserver(&dns_opt); } }; extern "C" int GetIPList(void *data, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6) { CDnsThread *thread = (CDnsThread *)data; uint64_t requestedFlags = 0; int hostlen = strlen(requestedHostname); if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') { char *pEnd; uint64_t flags = (uint64_t)strtoull(requestedHostname + 1, &pEnd, 16); if (*pEnd == '.' && pEnd <= requestedHostname + 17 && std::find(thread->filterWhitelist.begin(), thread->filterWhitelist.end(), flags) != thread->filterWhitelist.end()) requestedFlags = flags; else return 0; } else if (strcasecmp(requestedHostname, thread->dns_opt.host)) return 0; thread->cacheHit(requestedFlags); auto &thisflag = thread->perflag[requestedFlags]; unsigned int size = thisflag.cache.size(); unsigned int maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0); if (max > size) max = size; if (max > maxmax) max = maxmax; int i = 0; while (i < max) { int j = i + (rand() % (size - i)); do { bool ok = (ipv4 && thisflag.cache[j].v == 4) || (ipv6 && thisflag.cache[j].v == 6); if (ok) break; j++; if (j == size) j = i; } while (1); addr[i] = thisflag.cache[j]; thisflag.cache[j] = thisflag.cache[i]; thisflag.cache[i] = addr[i]; i++; } return max; } std::vector dnsThread; extern "C" void *ThreadDNS(void *arg) { CDnsThread *thread = (CDnsThread *)arg; thread->run(); return nullptr; } int StatCompare(const CAddrReport &a, const CAddrReport &b) { if (a.uptime[4] == b.uptime[4]) { if (a.uptime[3] == b.uptime[3]) { return a.clientVersion > b.clientVersion; } else { return a.uptime[3] > b.uptime[3]; } } else { return a.uptime[4] > b.uptime[4]; } } extern "C" void *ThreadDumper(void *) { int count = 0; do { // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever Sleep(100000 << count); if (count < 5) { count++; } { std::vector v = db.GetAll(); sort(v.begin(), v.end(), StatCompare); FILE *f = fopen("dnsseed.dat.new", "w+"); if (f) { { - CAutoFile cf(f); + CAutoFile cf(f, SER_DISK, CLIENT_VERSION); cf << db; } rename("dnsseed.dat.new", "dnsseed.dat"); } FILE *d = fopen("dnsseed.dump", "w"); fprintf(d, "# address good " "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) " "%%(30d) blocks svcs version\n"); double stat[5] = {0, 0, 0, 0, 0}; for (CAddrReport rep : v) { fprintf( d, "%-47s %4d %11" PRId64 " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 " %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0 * rep.uptime[0], 100.0 * rep.uptime[1], 100.0 * rep.uptime[2], 100.0 * rep.uptime[3], 100.0 * rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); stat[0] += rep.uptime[0]; stat[1] += rep.uptime[1]; stat[2] += rep.uptime[2]; stat[3] += rep.uptime[3]; stat[4] += rep.uptime[4]; } fclose(d); FILE *ff = fopen("dnsstats.log", "a"); fprintf(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(nullptr)), stat[0], stat[1], stat[2], stat[3], stat[4]); fclose(ff); } } while (1); return nullptr; } extern "C" void *ThreadStats(void *) { bool first = true; do { char c[256]; time_t tim = time(nullptr); struct tm *tmp = localtime(&tim); strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); CAddrDbStats stats; db.GetStats(stats); if (first) { first = false; printf("\n\n\n\x1b[3A"); } else printf("\x1b[2K\x1b[u"); printf("\x1b[s"); uint64_t requests = 0; uint64_t queries = 0; for (unsigned int i = 0; i < dnsThread.size(); i++) { requests += dnsThread[i]->dns_opt.nRequests; queries += dnsThread[i]->dbQueries; } printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i " "banned; %llu DNS requests, %llu db queries", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)requests, (unsigned long long)queries); Sleep(1000); } while (1); return nullptr; } static const std::string mainnet_seeds[] = { "seed.bitcoinabc.org", "seed-abc.bitcoinforks.org", "seed.bitprim.org", "seed.deadalnix.me", "seeder.criptolayer.net", ""}; static const std::string testnet_seeds[] = { - "testnet-seed.bitcoinabc.org", - "testnet-seed-abc.bitcoinforks.org", - "testnet-seed.bitprim.org", - "testnet-seed.deadalnix.me", - "testnet-seeder.criptolayer.net", - ""}; + "testnet-seed.bitcoinabc.org", "testnet-seed-abc.bitcoinforks.org", + "testnet-seed.bitprim.org", "testnet-seed.deadalnix.me", + "testnet-seeder.criptolayer.net", ""}; static const std::string *seeds = mainnet_seeds; extern "C" void *ThreadSeeder(void *) { if (!fTestNet) { db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true); } do { for (int i = 0; seeds[i] != ""; i++) { std::vector ips; LookupHost(seeds[i].c_str(), ips); for (auto &ip : ips) { db.Add(CService(ip, GetDefaultPort()), true); } } Sleep(1800000); } while (1); return nullptr; } int main(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); setbuf(stdout, nullptr); CDnsSeedOpts opts; opts.ParseCommandLine(argc, argv); printf("Supporting whitelisted filters: "); for (std::set::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) { if (it != opts.filter_whitelist.begin()) { printf(","); } printf("0x%lx", (unsigned long)*it); } printf("\n"); if (opts.tor) { CService service(opts.tor, 9050); if (service.IsValid()) { printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_TOR, service); } } if (opts.ipv4_proxy) { CService service(opts.ipv4_proxy, 9050); if (service.IsValid()) { printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_IPV4, service); } } if (opts.ipv6_proxy) { CService service(opts.ipv6_proxy, 9050); if (service.IsValid()) { printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_IPV6, service); } } bool fDNS = true; if (opts.fUseTestNet) { printf("Using testnet.\n"); pchMessageStart[0] = 0xf4; pchMessageStart[1] = 0xe5; pchMessageStart[2] = 0xf3; pchMessageStart[3] = 0xf4; seeds = testnet_seeds; fTestNet = true; } if (!opts.ns) { printf("No nameserver set. Not starting DNS server.\n"); fDNS = false; } if (fDNS && !opts.host) { fprintf(stderr, "No hostname set. Please use -h.\n"); exit(1); } if (fDNS && !opts.mbox) { fprintf(stderr, "No e-mail address set. Please use -m.\n"); exit(1); } FILE *f = fopen("dnsseed.dat", "r"); if (f) { printf("Loading dnsseed.dat..."); - CAutoFile cf(f); + CAutoFile cf(f, SER_DISK, CLIENT_VERSION); cf >> db; if (opts.fWipeBan) db.banned.clear(); if (opts.fWipeIgnore) db.ResetIgnores(); printf("done\n"); } pthread_t threadDns, threadSeed, threadDump, threadStats; if (fDNS) { printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort); dnsThread.clear(); for (int i = 0; i < opts.nDnsThreads; i++) { dnsThread.push_back(new CDnsThread(&opts, i)); pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]); printf("."); Sleep(20); } printf("done\n"); } printf("Starting seeder..."); pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); printf("done\n"); printf("Starting %i crawler threads...", opts.nThreads); pthread_attr_t attr_crawler; pthread_attr_init(&attr_crawler); pthread_attr_setstacksize(&attr_crawler, 0x20000); for (int i = 0; i < opts.nThreads; i++) { pthread_t thread; pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); } pthread_attr_destroy(&attr_crawler); printf("done\n"); pthread_create(&threadStats, nullptr, ThreadStats, nullptr); pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); void *res; pthread_join(threadDump, &res); return 0; } diff --git a/src/seeder/netbase.h b/src/seeder/netbase.h index 20b4259de..334c7c795 100644 --- a/src/seeder/netbase.h +++ b/src/seeder/netbase.h @@ -1,149 +1,162 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SEEDER_NETBASE_H #define BITCOIN_SEEDER_NETBASE_H #include "compat.h" #include "serialize.h" #include #include extern int nConnectTimeout; #ifdef WIN32 // In MSVC, this is defined as a macro, undefine it to prevent a compile and // link error #undef SetPort #endif enum Network { NET_UNROUTABLE, NET_IPV4, NET_IPV6, NET_TOR, NET_I2P, NET_MAX, }; extern int nConnectTimeout; extern bool fNameLookup; /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ class CNetAddr { protected: uint8_t ip[16]; // in network byte order public: CNetAddr(); CNetAddr(const struct in_addr &ipv4Addr); explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); void Init(); void SetIP(const CNetAddr &ip); bool SetSpecial(const std::string &strName); // for Tor and I2P addresses bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P) bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, // 192.168.0.0/16, 172.16.0.0/12) bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) bool IsRFC4193() const; // IPv6 unique local (FC00::/15) bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsTor() const; bool IsI2P() const; bool IsLocal() const; bool IsRoutable() const; bool IsValid() const; bool IsMulticast() const; enum Network GetNetwork() const; std::string ToString() const; std::string ToStringIP() const; unsigned int GetByte(int n) const; uint64_t GetHash() const; bool GetInAddr(struct in_addr *pipv4Addr) const; std::vector GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const; void print() const; CNetAddr(const struct in6_addr &pipv6Addr); bool GetIn6Addr(struct in6_addr *pipv6Addr) const; friend bool operator==(const CNetAddr &a, const CNetAddr &b); friend bool operator!=(const CNetAddr &a, const CNetAddr &b); friend bool operator<(const CNetAddr &a, const CNetAddr &b); - IMPLEMENT_SERIALIZE(READWRITE(FLATDATA(ip));) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(FLATDATA(ip)); + } }; /** A combination of a network address (CNetAddr) and a (TCP) port */ class CService : public CNetAddr { protected: unsigned short port; // host order public: CService(); CService(const CNetAddr &ip, unsigned short port); CService(const struct in_addr &ipv4Addr, unsigned short port); CService(const struct sockaddr_in &addr); explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); explicit CService(const char *pszIpPort, bool fAllowLookup = false); explicit CService(const std::string &strIpPort, int portDefault, bool fAllowLookup = false); explicit CService(const std::string &strIpPort, bool fAllowLookup = false); void Init(); void SetPort(unsigned short portIn); unsigned short GetPort() const; bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const; bool SetSockAddr(const struct sockaddr *paddr); friend bool operator==(const CService &a, const CService &b); friend bool operator!=(const CService &a, const CService &b); friend bool operator<(const CService &a, const CService &b); std::vector GetKey() const; std::string ToString() const; std::string ToStringPort() const; std::string ToStringIPPort() const; void print() const; CService(const struct in6_addr &ipv6Addr, unsigned short port); CService(const struct sockaddr_in6 &addr); - IMPLEMENT_SERIALIZE(CService *pthis = const_cast(this); - READWRITE(FLATDATA(ip)); - unsigned short portN = htons(port); READWRITE(portN); - if (fRead) pthis->port = ntohs(portN);) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + CService *pthis = const_cast(this); + READWRITE(FLATDATA(ip)); + unsigned short portN = htons(port); + READWRITE(portN); + if (ser_action.ForRead()) { + pthis->port = ntohs(portN); + } + } }; enum Network ParseNetwork(std::string net); void SplitHostPort(std::string in, int &portOut, std::string &hostOut); bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); bool GetProxy(enum Network net, CService &addrProxy); bool IsProxy(const CNetAddr &addr); bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); bool GetNameProxy(); bool LookupHost(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHostNumeric(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0); bool Lookup(const char *pszName, CService &addr, int portDefault = 0, bool fAllowLookup = true); bool Lookup(const char *pszName, std::vector &vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); bool LookupNumeric(const char *pszName, CService &addr, int portDefault = 0); bool ConnectSocket(const CService &addr, SOCKET &hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocketByName(CService &addr, SOCKET &hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); #endif diff --git a/src/seeder/protocol.cpp b/src/seeder/protocol.cpp index 565bbec09..33f6d64d4 100644 --- a/src/seeder/protocol.cpp +++ b/src/seeder/protocol.cpp @@ -1,134 +1,134 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "protocol.h" #include "netbase.h" #include "util.h" #include #include #ifndef WIN32 #include #endif static const char *ppszTypeName[] = { "ERROR", "tx", "block", }; uint8_t pchMessageStart[4] = {0xe3, 0xe1, 0xf3, 0xe8}; CMessageHeader::CMessageHeader() { memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); memset(pchCommand, 0, sizeof(pchCommand)); pchCommand[1] = 1; nMessageSize = -1; nChecksum = 0; } CMessageHeader::CMessageHeader(const char *pszCommand, unsigned int nMessageSizeIn) { memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); strncpy(pchCommand, pszCommand, COMMAND_SIZE); nMessageSize = nMessageSizeIn; nChecksum = 0; } std::string CMessageHeader::GetCommand() const { if (pchCommand[COMMAND_SIZE - 1] == 0) return std::string(pchCommand, pchCommand + strlen(pchCommand)); else return std::string(pchCommand, pchCommand + COMMAND_SIZE); } bool CMessageHeader::IsValid() const { // Check start string if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) return false; // Check the command string for errors for (const char *p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) { if (*p1 == 0) { // Must be all zeros after the first zero for (; p1 < pchCommand + COMMAND_SIZE; p1++) if (*p1 != 0) return false; } else if (*p1 < ' ' || *p1 > 0x7E) return false; } // Message size if (nMessageSize > MAX_SIZE) { printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > " "MAX_SIZE\n", GetCommand().c_str(), nMessageSize); return false; } return true; } CAddress::CAddress() : CService() { Init(); } CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn) { Init(); nServices = nServicesIn; } void CAddress::Init() { nServices = NODE_NETWORK | NODE_BITCOIN_CASH; nTime = 100000000; } void CAddress::print() const { printf("CAddress(%s)\n", ToString().c_str()); } CInv::CInv() { type = 0; - hash = 0; + hash.SetNull(); } CInv::CInv(int typeIn, const uint256 &hashIn) { type = typeIn; hash = hashIn; } CInv::CInv(const std::string &strType, const uint256 &hashIn) { int i; for (i = 1; i < ARRAYLEN(ppszTypeName); i++) { if (strType == ppszTypeName[i]) { type = i; break; } } if (i == ARRAYLEN(ppszTypeName)) throw std::out_of_range("CInv::CInv(string, uint256) : unknown type"); hash = hashIn; } bool operator<(const CInv &a, const CInv &b) { return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); } bool CInv::IsKnownType() const { return (type >= 1 && type < ARRAYLEN(ppszTypeName)); } const char *CInv::GetCommand() const { if (!IsKnownType()) throw std::out_of_range("CInv::GetCommand() : unknown type"); return ppszTypeName[type]; } std::string CInv::ToString() const { return "CInv()"; } void CInv::print() const { printf("CInv\n"); } diff --git a/src/seeder/protocol.h b/src/seeder/protocol.h index 361c270fe..29509f7c1 100644 --- a/src/seeder/protocol.h +++ b/src/seeder/protocol.h @@ -1,111 +1,136 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef __cplusplus #error This header can only be compiled as C++. #endif #ifndef BITCOIN_SEEDER_PROTOCOL_H #define BITCOIN_SEEDER_PROTOCOL_H #include "netbase.h" #include "serialize.h" #include "uint256.h" #include #include extern bool fTestNet; static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) { return testnet ? 18333 : 8333; } // // Message header // (4) message start // (12) command // (4) size // (4) checksum extern uint8_t pchMessageStart[4]; class CMessageHeader { public: CMessageHeader(); CMessageHeader(const char *pszCommand, unsigned int nMessageSizeIn); std::string GetCommand() const; bool IsValid() const; - IMPLEMENT_SERIALIZE(READWRITE(FLATDATA(pchMessageStart)); - READWRITE(FLATDATA(pchCommand)); - READWRITE(nMessageSize); - if (nVersion >= 209) READWRITE(nChecksum);) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(FLATDATA(pchMessageStart)); + READWRITE(FLATDATA(pchCommand)); + READWRITE(nMessageSize); + if (s.GetVersion() >= 209) { + READWRITE(nChecksum); + } + } // TODO: make private (improves encapsulation) public: enum { COMMAND_SIZE = 12 }; char pchMessageStart[sizeof(::pchMessageStart)]; char pchCommand[COMMAND_SIZE]; unsigned int nMessageSize; unsigned int nChecksum; }; enum ServiceFlags : uint64_t { NODE_NETWORK = (1 << 0), NODE_BLOOM = (1 << 2), NODE_XTHIN = (1 << 4), NODE_BITCOIN_CASH = (1 << 5), }; class CAddress : public CService { public: CAddress(); CAddress(CService ipIn, uint64_t nServicesIn = NODE_NETWORK | NODE_BITCOIN_CASH); void Init(); - IMPLEMENT_SERIALIZE(CAddress *pthis = const_cast(this); - CService *pip = (CService *)pthis; - if (fRead) pthis->Init(); - if (nType & SER_DISK) READWRITE(nVersion); - if ((nType & SER_DISK) || - (nVersion >= 31402 && !(nType & SER_GETHASH))) - READWRITE(nTime); - READWRITE(nServices); READWRITE(*pip);) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + int nVersion = s.GetVersion(); + CAddress *pthis = const_cast(this); + CService *pip = (CService *)pthis; + if (ser_action.ForRead()) { + pthis->Init(); + } + if (s.GetType() & SER_DISK) { + READWRITE(nVersion); + } + if ((s.GetType() & SER_DISK) || + (nVersion >= 31402 && !(s.GetType() & SER_GETHASH))) { + READWRITE(nTime); + } + READWRITE(nServices); + READWRITE(*pip); + } void print() const; // TODO: make private (improves encapsulation) public: uint64_t nServices; // disk and network only unsigned int nTime; }; class CInv { public: CInv(); CInv(int typeIn, const uint256 &hashIn); CInv(const std::string &strType, const uint256 &hashIn); - IMPLEMENT_SERIALIZE(READWRITE(type); READWRITE(hash);) + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream &s, Operation ser_action) { + READWRITE(type); + READWRITE(hash); + } friend bool operator<(const CInv &a, const CInv &b); bool IsKnownType() const; const char *GetCommand() const; std::string ToString() const; void print() const; // TODO: make private (improves encapsulation) public: int type; uint256 hash; }; #endif // __INCLUDED_PROTOCOL_H__ diff --git a/src/seeder/serialize.h b/src/seeder/serialize.h deleted file mode 100644 index 278bb9888..000000000 --- a/src/seeder/serialize.h +++ /dev/null @@ -1,1320 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_SEEDER_SERIALIZE_H -#define BITCOIN_SEEDER_SERIALIZE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define for if (false); else for -#endif - -#ifdef WIN32 -#include -// This is used to attempt to keep keying material out of swap -// Note that VirtualLock does not provide this as a guarantee on Windows, -// but, in practice, memory that has been VirtualLock'd almost never gets -// written to -// the pagefile except in rare circumstances where memory is extremely low. -#include -#define mlock(p, n) VirtualLock((p), (n)); -#define munlock(p, n) VirtualUnlock((p), (n)); -#else -#include -#include -/* This comes from limits.h if it's not defined there set a sane default */ -#ifndef PAGESIZE -#include -#define PAGESIZE sysconf(_SC_PAGESIZE) -#endif -#define mlock(a, b) \ - mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))), \ - (((((size_t)(a)) + (b)-1) | ((PAGESIZE)-1)) + 1) - \ - (((size_t)(a)) & (~((PAGESIZE)-1)))) -#define munlock(a, b) \ - munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))), \ - (((((size_t)(a)) + (b)-1) | ((PAGESIZE)-1)) + 1) - \ - (((size_t)(a)) & (~((PAGESIZE)-1)))) -#endif - -class CScript; -class CDataStream; -class CAutoFile; -static const unsigned int MAX_SIZE = 0x02000000; - -static const int PROTOCOL_VERSION = 60000; - -// Used to bypass the rule against non-const reference to temporary -// where it makes sense with wrappers such as CFlatData or CTxDB -template inline T &REF(const T &val) { - return const_cast(val); -} - -///////////////////////////////////////////////////////////////// -// -// Templates for serializing to anything that looks like a stream, -// i.e. anything that supports .read(char*, int) and .write(char*, int) -// - -enum { - // primary actions - SER_NETWORK = (1 << 0), - SER_DISK = (1 << 1), - SER_GETHASH = (1 << 2), - - // modifiers - SER_SKIPSIG = (1 << 16), - SER_BLOCKHEADERONLY = (1 << 17), -}; - -#define IMPLEMENT_SERIALIZE(statements) \ - unsigned int GetSerializeSize(int nType = 0, \ - int nVersion = PROTOCOL_VERSION) const { \ - CSerActionGetSerializeSize ser_action; \ - const bool fGetSize = true; \ - const bool fWrite = false; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - ser_streamplaceholder s; \ - s.nType = nType; \ - s.nVersion = nVersion; \ - { statements } \ - return nSerSize; \ - } \ - template \ - void Serialize(Stream &s, int nType = 0, int nVersion = PROTOCOL_VERSION) \ - const { \ - CSerActionSerialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = true; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - { statements } \ - } \ - template \ - void Unserialize(Stream &s, int nType = 0, \ - int nVersion = PROTOCOL_VERSION) { \ - CSerActionUnserialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = false; \ - const bool fRead = true; \ - unsigned int nSerSize = 0; \ - { statements } \ - } - -#define READWRITE(obj) \ - (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) - -// -// Basic types -// -#define WRITEDATA(s, obj) s.write((char *)&(obj), sizeof(obj)) -#define READDATA(s, obj) s.read((char *)&(obj), sizeof(obj)) - -inline unsigned int GetSerializeSize(int8_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(uint8_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(int16_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(uint16_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(int32_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(uint32_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(int64_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(uint64_t a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(float a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(double a, int, int = 0) { - return sizeof(a); -} - -template -inline void Serialize(Stream &s, int8_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, uint8_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, int16_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, uint16_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, int32_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, uint32_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, int64_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, uint64_t a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, float a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, double a, int, int = 0) { - WRITEDATA(s, a); -} - -template -inline void Unserialize(Stream &s, int8_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, uint8_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, int16_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, uint16_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, int32_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, uint32_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, int64_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, uint64_t &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, float &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, double &a, int, int = 0) { - READDATA(s, a); -} - -inline unsigned int GetSerializeSize(bool a, int, int = 0) { - return sizeof(char); -} -template -inline void Serialize(Stream &s, bool a, int, int = 0) { - char f = a; - WRITEDATA(s, f); -} -template -inline void Unserialize(Stream &s, bool &a, int, int = 0) { - char f; - READDATA(s, f); - a = f; -} - -// -// Compact size -// size < 253 -- 1 byte -// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) -// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) -// size > UINT_MAX -- 9 bytes (255 + 8 bytes) -// -inline unsigned int GetSizeOfCompactSize(uint64_t nSize) { - if (nSize < 253) - return sizeof(uint8_t); - else if (nSize <= USHRT_MAX) - return sizeof(uint8_t) + sizeof(uint16_t); - else if (nSize <= UINT_MAX) - return sizeof(uint8_t) + sizeof(uint32_t); - else - return sizeof(uint8_t) + sizeof(uint64_t); -} - -template void WriteCompactSize(Stream &os, uint64_t nSize) { - if (nSize < 253) { - uint8_t chSize = nSize; - WRITEDATA(os, chSize); - } else if (nSize <= USHRT_MAX) { - uint8_t chSize = 253; - uint16_t xSize = nSize; - WRITEDATA(os, chSize); - WRITEDATA(os, xSize); - } else if (nSize <= UINT_MAX) { - uint8_t chSize = 254; - uint32_t xSize = nSize; - WRITEDATA(os, chSize); - WRITEDATA(os, xSize); - } else { - uint8_t chSize = 255; - uint64_t xSize = nSize; - WRITEDATA(os, chSize); - WRITEDATA(os, xSize); - } - return; -} - -template uint64_t ReadCompactSize(Stream &is) { - uint8_t chSize; - READDATA(is, chSize); - uint64_t nSizeRet = 0; - if (chSize < 253) { - nSizeRet = chSize; - } else if (chSize == 253) { - uint16_t xSize; - READDATA(is, xSize); - nSizeRet = xSize; - } else if (chSize == 254) { - uint32_t xSize; - READDATA(is, xSize); - nSizeRet = xSize; - } else { - uint64_t xSize; - READDATA(is, xSize); - nSizeRet = xSize; - } - if (nSizeRet > uint64_t(MAX_SIZE)) { - throw std::ios_base::failure("ReadCompactSize() : size too large"); - } - return nSizeRet; -} - -// -// Wrapper for serializing arrays and POD -// There's a clever template way to make arrays serialize normally, but MSVC6 -// doesn't support it -// -#define FLATDATA(obj) \ - REF(CFlatData((char *)&(obj), (char *)&(obj) + sizeof(obj))) -class CFlatData { -protected: - char *pbegin; - char *pend; - -public: - CFlatData(void *pbeginIn, void *pendIn) - : pbegin((char *)pbeginIn), pend((char *)pendIn) {} - char *begin() { return pbegin; } - const char *begin() const { return pbegin; } - char *end() { return pend; } - const char *end() const { return pend; } - - unsigned int GetSerializeSize(int, int = 0) const { return pend - pbegin; } - - template void Serialize(Stream &s, int, int = 0) const { - s.write(pbegin, pend - pbegin); - } - - template void Unserialize(Stream &s, int, int = 0) { - s.read(pbegin, pend - pbegin); - } -}; - -// -// string stored as a fixed length field -// -template class CFixedFieldString { -protected: - const std::string *pcstr; - std::string *pstr; - -public: - explicit CFixedFieldString(const std::string &str) - : pcstr(&str), pstr(nullptr) {} - explicit CFixedFieldString(std::string &str) : pcstr(&str), pstr(&str) {} - - unsigned int GetSerializeSize(int, int = 0) const { return LEN; } - - template void Serialize(Stream &s, int, int = 0) const { - char pszBuf[LEN]; - strncpy(pszBuf, pcstr->c_str(), LEN); - s.write(pszBuf, LEN); - } - - template void Unserialize(Stream &s, int, int = 0) { - if (pstr == nullptr) - throw std::ios_base::failure("CFixedFieldString::Unserialize : " - "trying to unserialize to const " - "string"); - char pszBuf[LEN + 1]; - s.read(pszBuf, LEN); - pszBuf[LEN] = '\0'; - *pstr = pszBuf; - } -}; - -// -// Forward declarations -// - -// string -template -unsigned int GetSerializeSize(const std::basic_string &str, int, int = 0); -template -void Serialize(Stream &os, const std::basic_string &str, int, int = 0); -template -void Unserialize(Stream &is, std::basic_string &str, int, int = 0); - -// vector -template -unsigned int GetSerializeSize_impl(const std::vector &v, int nType, - int nVersion, const boost::true_type &); -template -unsigned int GetSerializeSize_impl(const std::vector &v, int nType, - int nVersion, const boost::false_type &); -template -inline unsigned int GetSerializeSize(const std::vector &v, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize_impl(Stream &os, const std::vector &v, int nType, - int nVersion, const boost::true_type &); -template -void Serialize_impl(Stream &os, const std::vector &v, int nType, - int nVersion, const boost::false_type &); -template -inline void Serialize(Stream &os, const std::vector &v, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, - const boost::true_type &); -template -void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, - const boost::false_type &); -template -inline void Unserialize(Stream &is, std::vector &v, int nType, - int nVersion = PROTOCOL_VERSION); - -// others derived from vector -extern inline unsigned int GetSerializeSize(const CScript &v, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const CScript &v, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, CScript &v, int nType, - int nVersion = PROTOCOL_VERSION); - -// pair -template -unsigned int GetSerializeSize(const std::pair &item, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const std::pair &item, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, std::pair &item, int nType, - int nVersion = PROTOCOL_VERSION); - -// 3 tuple -template -unsigned int GetSerializeSize(const boost::tuple &item, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const boost::tuple &item, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, boost::tuple &item, int nType, - int nVersion = PROTOCOL_VERSION); - -// 4 tuple -template -unsigned int GetSerializeSize(const boost::tuple &item, - int nType, int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const boost::tuple &item, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, boost::tuple &item, int nType, - int nVersion = PROTOCOL_VERSION); - -// map -template -unsigned int GetSerializeSize(const std::map &m, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const std::map &m, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, std::map &m, int nType, - int nVersion = PROTOCOL_VERSION); - -// set -template -unsigned int GetSerializeSize(const std::set &m, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Serialize(Stream &os, const std::set &m, int nType, - int nVersion = PROTOCOL_VERSION); -template -void Unserialize(Stream &is, std::set &m, int nType, - int nVersion = PROTOCOL_VERSION); - -// -// If none of the specialized versions above matched, default to calling member -// function. -// "int nType" is changed to "long nType" to keep from getting an ambiguous -// overload error. -// The compiler will only cast int to long if none of the other templates -// matched. -// Thanks to Boost serialization for this idea. -// -template -inline unsigned int GetSerializeSize(const T &a, long nType, - int nVersion = PROTOCOL_VERSION) { - return a.GetSerializeSize((int)nType, nVersion); -} - -template -inline void Serialize(Stream &os, const T &a, long nType, - int nVersion = PROTOCOL_VERSION) { - a.Serialize(os, (int)nType, nVersion); -} - -template -inline void Unserialize(Stream &is, T &a, long nType, - int nVersion = PROTOCOL_VERSION) { - a.Unserialize(is, (int)nType, nVersion); -} - -// -// string -// -template -unsigned int GetSerializeSize(const std::basic_string &str, int, int) { - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); -} - -template -void Serialize(Stream &os, const std::basic_string &str, int, int) { - WriteCompactSize(os, str.size()); - if (!str.empty()) os.write((char *)&str[0], str.size() * sizeof(str[0])); -} - -template -void Unserialize(Stream &is, std::basic_string &str, int, int) { - unsigned int nSize = ReadCompactSize(is); - str.resize(nSize); - if (nSize != 0) is.read((char *)&str[0], nSize * sizeof(str[0])); -} - -// -// vector -// -template -unsigned int GetSerializeSize_impl(const std::vector &v, int nType, - int nVersion, const boost::true_type &) { - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const std::vector &v, int nType, - int nVersion, const boost::false_type &) { - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename std::vector::const_iterator vi = v.begin(); - vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const std::vector &v, int nType, - int nVersion) { - return GetSerializeSize_impl(v, nType, nVersion, - boost::is_fundamental()); -} - -template -void Serialize_impl(Stream &os, const std::vector &v, int nType, - int nVersion, const boost::true_type &) { - WriteCompactSize(os, v.size()); - if (!v.empty()) os.write((char *)&v[0], v.size() * sizeof(T)); -} - -template -void Serialize_impl(Stream &os, const std::vector &v, int nType, - int nVersion, const boost::false_type &) { - WriteCompactSize(os, v.size()); - for (typename std::vector::const_iterator vi = v.begin(); - vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); -} - -template -inline void Serialize(Stream &os, const std::vector &v, int nType, - int nVersion) { - Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); -} - -template -void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, - const boost::true_type &) { - // unsigned int nSize = ReadCompactSize(is); - // v.resize(nSize); - // is.read((char*)&v[0], nSize * sizeof(T)); - - // Limit size per read so bogus size value won't cause out of memory - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - while (i < nSize) { - unsigned int blk = - std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); - v.resize(i + blk); - is.read((char *)&v[i], blk * sizeof(T)); - i += blk; - } -} - -template -void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, - const boost::false_type &) { - // unsigned int nSize = ReadCompactSize(is); - // v.resize(nSize); - // for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) - // Unserialize(is, (*vi), nType, nVersion); - - v.clear(); - unsigned int nSize = ReadCompactSize(is); - unsigned int i = 0; - unsigned int nMid = 0; - while (nMid < nSize) { - nMid += 5000000 / sizeof(T); - if (nMid > nSize) nMid = nSize; - v.resize(nMid); - for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); - } -} - -template -inline void Unserialize(Stream &is, std::vector &v, int nType, - int nVersion) { - Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); -} - -// -// others derived from vector -// -inline unsigned int GetSerializeSize(const CScript &v, int nType, - int nVersion) { - return GetSerializeSize((const std::vector &)v, nType, nVersion); -} - -template -void Serialize(Stream &os, const CScript &v, int nType, int nVersion) { - Serialize(os, (const std::vector &)v, nType, nVersion); -} - -template -void Unserialize(Stream &is, CScript &v, int nType, int nVersion) { - Unserialize(is, (std::vector &)v, nType, nVersion); -} - -// -// pair -// -template -unsigned int GetSerializeSize(const std::pair &item, int nType, - int nVersion) { - return GetSerializeSize(item.first, nType, nVersion) + - GetSerializeSize(item.second, nType, nVersion); -} - -template -void Serialize(Stream &os, const std::pair &item, int nType, - int nVersion) { - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); -} - -template -void Unserialize(Stream &is, std::pair &item, int nType, int nVersion) { - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); -} - -// -// 3 tuple -// -template -unsigned int GetSerializeSize(const boost::tuple &item, int nType, - int nVersion) { - unsigned int nSize = 0; - nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream &os, const boost::tuple &item, int nType, - int nVersion) { - Serialize(os, boost::get<0>(item), nType, nVersion); - Serialize(os, boost::get<1>(item), nType, nVersion); - Serialize(os, boost::get<2>(item), nType, nVersion); -} - -template -void Unserialize(Stream &is, boost::tuple &item, int nType, - int nVersion) { - Unserialize(is, boost::get<0>(item), nType, nVersion); - Unserialize(is, boost::get<1>(item), nType, nVersion); - Unserialize(is, boost::get<2>(item), nType, nVersion); -} - -// -// 4 tuple -// -template -unsigned int GetSerializeSize(const boost::tuple &item, - int nType, int nVersion) { - unsigned int nSize = 0; - nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream &os, const boost::tuple &item, int nType, - int nVersion) { - Serialize(os, boost::get<0>(item), nType, nVersion); - Serialize(os, boost::get<1>(item), nType, nVersion); - Serialize(os, boost::get<2>(item), nType, nVersion); - Serialize(os, boost::get<3>(item), nType, nVersion); -} - -template -void Unserialize(Stream &is, boost::tuple &item, int nType, - int nVersion) { - Unserialize(is, boost::get<0>(item), nType, nVersion); - Unserialize(is, boost::get<1>(item), nType, nVersion); - Unserialize(is, boost::get<2>(item), nType, nVersion); - Unserialize(is, boost::get<3>(item), nType, nVersion); -} - -// -// map -// -template -unsigned int GetSerializeSize(const std::map &m, int nType, - int nVersion) { - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::map::const_iterator mi = m.begin(); - mi != m.end(); ++mi) - nSize += GetSerializeSize((*mi), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream &os, const std::map &m, int nType, - int nVersion) { - WriteCompactSize(os, m.size()); - for (typename std::map::const_iterator mi = m.begin(); - mi != m.end(); ++mi) - Serialize(os, (*mi), nType, nVersion); -} - -template -void Unserialize(Stream &is, std::map &m, int nType, - int nVersion) { - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::map::iterator mi = m.begin(); - for (unsigned int i = 0; i < nSize; i++) { - std::pair item; - Unserialize(is, item, nType, nVersion); - mi = m.insert(mi, item); - } -} - -// -// set -// -template -unsigned int GetSerializeSize(const std::set &m, int nType, - int nVersion) { - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::set::const_iterator it = m.begin(); - it != m.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - -template -void Serialize(Stream &os, const std::set &m, int nType, - int nVersion) { - WriteCompactSize(os, m.size()); - for (typename std::set::const_iterator it = m.begin(); - it != m.end(); ++it) - Serialize(os, (*it), nType, nVersion); -} - -template -void Unserialize(Stream &is, std::set &m, int nType, int nVersion) { - m.clear(); - unsigned int nSize = ReadCompactSize(is); - typename std::set::iterator it = m.begin(); - for (unsigned int i = 0; i < nSize; i++) { - K key; - Unserialize(is, key, nType, nVersion); - it = m.insert(it, key); - } -} - -// -// Support for IMPLEMENT_SERIALIZE and READWRITE macro -// -class CSerActionGetSerializeSize {}; -class CSerActionSerialize {}; -class CSerActionUnserialize {}; - -template -inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType, - int nVersion, - CSerActionGetSerializeSize ser_action) { - return ::GetSerializeSize(obj, nType, nVersion); -} - -template -inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType, - int nVersion, CSerActionSerialize ser_action) { - ::Serialize(s, obj, nType, nVersion); - return 0; -} - -template -inline unsigned int SerReadWrite(Stream &s, T &obj, int nType, int nVersion, - CSerActionUnserialize ser_action) { - ::Unserialize(s, obj, nType, nVersion); - return 0; -} - -struct ser_streamplaceholder { - int nType; - int nVersion; -}; - -// -// Allocator that locks its contents from being paged -// out of memory and clears its contents before deletion. -// -template struct secure_allocator : public std::allocator { - // MSVC8 default copy constructor is broken - typedef std::allocator base; - typedef typename base::size_type size_type; - typedef typename base::difference_type difference_type; - typedef typename base::pointer pointer; - typedef typename base::const_pointer const_pointer; - typedef typename base::reference reference; - typedef typename base::const_reference const_reference; - typedef typename base::value_type value_type; - secure_allocator() throw() {} - secure_allocator(const secure_allocator &a) throw() : base(a) {} - template - secure_allocator(const secure_allocator &a) throw() : base(a) {} - ~secure_allocator() throw() {} - template struct rebind { - typedef secure_allocator<_Other> other; - }; - - T *allocate(std::size_t n, const void *hint = 0) { - T *p; - p = std::allocator::allocate(n, hint); - if (p != nullptr) mlock(p, sizeof(T) * n); - return p; - } - - void deallocate(T *p, std::size_t n) { - if (p != nullptr) { - memset(p, 0, sizeof(T) * n); - munlock(p, sizeof(T) * n); - } - std::allocator::deallocate(p, n); - } -}; - -// -// Double ended buffer combining vector and stream-like interfaces. -// >> and << read and write unformatted data using the above serialization -// templates. -// Fills with data in linear time; some stringstream implementations take N^2 -// time. -// -class CDataStream { -protected: - typedef std::vector> vector_type; - vector_type vch; - unsigned int nReadPos; - short state; - short exceptmask; - -public: - int nType; - int nVersion; - - typedef vector_type::allocator_type allocator_type; - typedef vector_type::size_type size_type; - typedef vector_type::difference_type difference_type; - typedef vector_type::reference reference; - typedef vector_type::const_reference const_reference; - typedef vector_type::value_type value_type; - typedef vector_type::iterator iterator; - typedef vector_type::const_iterator const_iterator; - typedef vector_type::reverse_iterator reverse_iterator; - - explicit CDataStream(int nTypeIn = SER_NETWORK, - int nVersionIn = PROTOCOL_VERSION) { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const_iterator pbegin, const_iterator pend, - int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) - : vch(pbegin, pend) { - Init(nTypeIn, nVersionIn); - } - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - CDataStream(const char *pbegin, const char *pend, int nTypeIn = SER_NETWORK, - int nVersionIn = PROTOCOL_VERSION) - : vch(pbegin, pend) { - Init(nTypeIn, nVersionIn); - } -#endif - - CDataStream(const vector_type &vchIn, int nTypeIn = SER_NETWORK, - int nVersionIn = PROTOCOL_VERSION) - : vch(vchIn.begin(), vchIn.end()) { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const std::vector &vchIn, int nTypeIn = SER_NETWORK, - int nVersionIn = PROTOCOL_VERSION) - : vch(vchIn.begin(), vchIn.end()) { - Init(nTypeIn, nVersionIn); - } - - CDataStream(const std::vector &vchIn, int nTypeIn = SER_NETWORK, - int nVersionIn = PROTOCOL_VERSION) - : vch((char *)&vchIn.begin()[0], (char *)&vchIn.end()[0]) { - Init(nTypeIn, nVersionIn); - } - - void Init(int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) { - nReadPos = 0; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::ios::failbit; - } - - CDataStream &operator+=(const CDataStream &b) { - vch.insert(vch.end(), b.begin(), b.end()); - return *this; - } - - friend CDataStream operator+(const CDataStream &a, const CDataStream &b) { - CDataStream ret = a; - ret += b; - return (ret); - } - - std::string str() const { return (std::string(begin(), end())); } - - // - // Vector subset - // - const_iterator begin() const { return vch.begin() + nReadPos; } - iterator begin() { return vch.begin() + nReadPos; } - const_iterator end() const { return vch.end(); } - iterator end() { return vch.end(); } - size_type size() const { return vch.size() - nReadPos; } - bool empty() const { return vch.size() == nReadPos; } - void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); } - void reserve(size_type n) { vch.reserve(n + nReadPos); } - const_reference operator[](size_type pos) const { - return vch[pos + nReadPos]; - } - reference operator[](size_type pos) { return vch[pos + nReadPos]; } - void clear() { - vch.clear(); - nReadPos = 0; - } - iterator insert(iterator it, const char &x = char()) { - return vch.insert(it, x); - } - void insert(iterator it, size_type n, const char &x) { - vch.insert(it, n, x); - } - - void insert(iterator it, std::vector::const_iterator first, - std::vector::const_iterator last) { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } else - vch.insert(it, first, last); - } - -#if !defined(_MSC_VER) || _MSC_VER >= 1300 - void insert(iterator it, const char *first, const char *last) { - if (it == vch.begin() + nReadPos && last - first <= nReadPos) { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } else - vch.insert(it, first, last); - } -#endif - - iterator erase(iterator it) { - if (it == vch.begin() + nReadPos) { - // special case for erasing from the front - if (++nReadPos >= vch.size()) { - // whenever we reach the end, we take the opportunity to clear - // the buffer - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - return vch.begin() + nReadPos; - } else - return vch.erase(it); - } - - iterator erase(iterator first, iterator last) { - if (first == vch.begin() + nReadPos) { - // special case for erasing from the front - if (last == vch.end()) { - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } else { - nReadPos = (last - vch.begin()); - return last; - } - } else - return vch.erase(first, last); - } - - inline void Compact() { - vch.erase(vch.begin(), vch.begin() + nReadPos); - nReadPos = 0; - } - - bool Rewind(size_type n) { - // Rewind by n characters if the buffer hasn't been compacted yet - if (n > nReadPos) return false; - nReadPos -= n; - return true; - } - - // - // Stream subset - // - void setstate(short bits, const char *psz) { - state |= bits; - if (state & exceptmask) throw std::ios_base::failure(psz); - } - - bool eof() const { return size() == 0; } - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } - bool good() const { return !eof() && (state == 0); } - void clear(short n) { state = n; } // name conflict with vector clear() - short exceptions() { return exceptmask; } - short exceptions(short mask) { - short prev = exceptmask; - exceptmask = mask; - setstate(0, "CDataStream"); - return prev; - } - CDataStream *rdbuf() { return this; } - int in_avail() { return size(); } - - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CDataStream &read(char *pch, int nSize) { - // Read from the beginning of the buffer - assert(nSize >= 0); - unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) { - if (nReadPosNext > vch.size()) { - setstate(std::ios::failbit, - "CDataStream::read() : end of data"); - memset(pch, 0, nSize); - nSize = vch.size() - nReadPos; - } - memcpy(pch, &vch[nReadPos], nSize); - nReadPos = 0; - vch.clear(); - return (*this); - } - memcpy(pch, &vch[nReadPos], nSize); - nReadPos = nReadPosNext; - return (*this); - } - - CDataStream &ignore(int nSize) { - // Ignore from the beginning of the buffer - assert(nSize >= 0); - unsigned int nReadPosNext = nReadPos + nSize; - if (nReadPosNext >= vch.size()) { - if (nReadPosNext > vch.size()) { - setstate(std::ios::failbit, - "CDataStream::ignore() : end of data"); - nSize = vch.size() - nReadPos; - } - nReadPos = 0; - vch.clear(); - return (*this); - } - nReadPos = nReadPosNext; - return (*this); - } - - CDataStream &write(const char *pch, int nSize) { - // Write to the end of the buffer - assert(nSize >= 0); - vch.insert(vch.end(), pch, pch + nSize); - return (*this); - } - - template - void Serialize(Stream &s, int nType = 0, - int nVersion = PROTOCOL_VERSION) const { - // Special case: stream << stream concatenates like stream += stream - if (!vch.empty()) s.write((char *)&vch[0], vch.size() * sizeof(vch[0])); - } - - template unsigned int GetSerializeSize(const T &obj) { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - - template CDataStream &operator<<(const T &obj) { - // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } - - template CDataStream &operator>>(T &obj) { - // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); - return (*this); - } -}; - -#ifdef TESTCDATASTREAM -// VC6sp6 -// CDataStream: -// n=1000 0 seconds -// n=2000 0 seconds -// n=4000 0 seconds -// n=8000 0 seconds -// n=16000 0 seconds -// n=32000 0 seconds -// n=64000 1 seconds -// n=128000 1 seconds -// n=256000 2 seconds -// n=512000 4 seconds -// n=1024000 8 seconds -// n=2048000 16 seconds -// n=4096000 32 seconds -// stringstream: -// n=1000 1 seconds -// n=2000 1 seconds -// n=4000 13 seconds -// n=8000 87 seconds -// n=16000 400 seconds -// n=32000 1660 seconds -// n=64000 6749 seconds -// n=128000 27241 seconds -// n=256000 109804 seconds -#include -int main(int argc, char *argv[]) { - vector vch(0xcc, 250); - printf("CDataStream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) { - CDataStream ss; - time_t nStart = time(nullptr); - for (int i = 0; i < n; i++) - ss.write((char *)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(nullptr) - nStart); - } - printf("stringstream:\n"); - for (int n = 1000; n <= 4500000; n *= 2) { - stringstream ss; - time_t nStart = time(nullptr); - for (int i = 0; i < n; i++) - ss.write((char *)&vch[0], vch.size()); - printf("n=%-10d %d seconds\n", n, time(nullptr) - nStart); - } -} -#endif - -// -// Automatic closing wrapper for FILE* -// - Will automatically close the file when it goes out of scope if not null. -// - If you're returning the file pointer, return file.release(). -// - If you need to close the file early, use file.fclose() instead of -// fclose(file). -// -class CAutoFile { -protected: - FILE *file; - short state; - short exceptmask; - -public: - int nType; - int nVersion; - - typedef FILE element_type; - - CAutoFile(FILE *filenew = nullptr, int nTypeIn = SER_DISK, - int nVersionIn = PROTOCOL_VERSION) { - file = filenew; - nType = nTypeIn; - nVersion = nVersionIn; - state = 0; - exceptmask = std::ios::badbit | std::ios::failbit; - } - - ~CAutoFile() { fclose(); } - - void fclose() { - if (file != nullptr && file != stdin && file != stdout && - file != stderr) - ::fclose(file); - file = nullptr; - } - - FILE *release() { - FILE *ret = file; - file = nullptr; - return ret; - } - operator FILE *() { return file; } - FILE *operator->() { return file; } - FILE &operator*() { return *file; } - FILE **operator&() { return &file; } - FILE *operator=(FILE *pnew) { return file = pnew; } - bool operator!() { return (file == nullptr); } - - // - // Stream subset - // - void setstate(short bits, const char *psz) { - state |= bits; - if (state & exceptmask) throw std::ios_base::failure(psz); - } - - bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } - bool good() const { return state == 0; } - void clear(short n = 0) { state = n; } - short exceptions() { return exceptmask; } - short exceptions(short mask) { - short prev = exceptmask; - exceptmask = mask; - setstate(0, "CAutoFile"); - return prev; - } - - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } - - CAutoFile &read(char *pch, int nSize) { - if (!file) - throw std::ios_base::failure( - "CAutoFile::read : file handle is nullptr"); - if (fread(pch, 1, nSize, file) != nSize) - setstate(std::ios::failbit, feof(file) - ? "CAutoFile::read : end of file" - : "CAutoFile::read : fread failed"); - return (*this); - } - - CAutoFile &write(const char *pch, int nSize) { - if (!file) - throw std::ios_base::failure( - "CAutoFile::write : file handle is nullptr"); - if (fwrite(pch, 1, nSize, file) != nSize) - setstate(std::ios::failbit, "CAutoFile::write : write failed"); - return (*this); - } - - template unsigned int GetSerializeSize(const T &obj) { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - - template CAutoFile &operator<<(const T &obj) { - // Serialize to this stream - if (!file) - throw std::ios_base::failure( - "CAutoFile::operator<< : file handle is nullptr"); - ::Serialize(*this, obj, nType, nVersion); - return (*this); - } - - template CAutoFile &operator>>(T &obj) { - // Unserialize from this stream - if (!file) - throw std::ios_base::failure( - "CAutoFile::operator>> : file handle is nullptr"); - ::Unserialize(*this, obj, nType, nVersion); - return (*this); - } -}; - -#endif diff --git a/src/seeder/uint256.h b/src/seeder/uint256.h deleted file mode 100644 index 6b5c61e6f..000000000 --- a/src/seeder/uint256.h +++ /dev/null @@ -1,825 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_SEEDER_UINT256_H -#define BITCOIN_SEEDER_UINT256_H - -#include "serialize.h" - -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define for if (false); else for -#endif - -inline int Testuint256AdHoc(std::vector vArg); - -// We have to keep a separate base class without constructors -// so the compiler will let us use it in a union -template class base_uint { -protected: - enum { WIDTH = BITS / 32 }; - unsigned int pn[WIDTH]; - -public: - bool operator!() const { - for (int i = 0; i < WIDTH; i++) - if (pn[i] != 0) return false; - return true; - } - - const base_uint operator~() const { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - return ret; - } - - const base_uint operator-() const { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - ret++; - return ret; - } - - base_uint &operator=(uint64_t b) { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - base_uint &operator^=(const base_uint &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] ^= b.pn[i]; - return *this; - } - - base_uint &operator&=(const base_uint &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] &= b.pn[i]; - return *this; - } - - base_uint &operator|=(const base_uint &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] |= b.pn[i]; - return *this; - } - - base_uint &operator^=(uint64_t b) { - pn[0] ^= (unsigned int)b; - pn[1] ^= (unsigned int)(b >> 32); - return *this; - } - - base_uint &operator&=(uint64_t b) { - pn[0] &= (unsigned int)b; - pn[1] &= (unsigned int)(b >> 32); - return *this; - } - - base_uint &operator|=(uint64_t b) { - pn[0] |= (unsigned int)b; - pn[1] |= (unsigned int)(b >> 32); - return *this; - } - - base_uint &operator<<=(unsigned int shift) { - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i + k + 1 < WIDTH && shift != 0) - pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); - if (i + k < WIDTH) pn[i + k] |= (a.pn[i] << shift); - } - return *this; - } - - base_uint &operator>>=(unsigned int shift) { - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i - k - 1 >= 0 && shift != 0) - pn[i - k - 1] |= (a.pn[i] << (32 - shift)); - if (i - k >= 0) pn[i - k] |= (a.pn[i] >> shift); - } - return *this; - } - - base_uint &operator+=(const base_uint &b) { - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) { - uint64_t n = carry + pn[i] + b.pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; - } - - base_uint &operator-=(const base_uint &b) { - *this += -b; - return *this; - } - - base_uint &operator+=(uint64_t b64) { - base_uint b; - b = b64; - *this += b; - return *this; - } - - base_uint &operator-=(uint64_t b64) { - base_uint b; - b = b64; - *this += -b; - return *this; - } - - base_uint &operator++() { - // prefix operator - int i = 0; - while (++pn[i] == 0 && i < WIDTH - 1) - i++; - return *this; - } - - const base_uint operator++(int) { - // postfix operator - const base_uint ret = *this; - ++(*this); - return ret; - } - - base_uint &operator--() { - // prefix operator - int i = 0; - while (--pn[i] == -1 && i < WIDTH - 1) - i++; - return *this; - } - - const base_uint operator--(int) { - // postfix operator - const base_uint ret = *this; - --(*this); - return ret; - } - - friend inline bool operator<(const base_uint &a, const base_uint &b) { - for (int i = base_uint::WIDTH - 1; i >= 0; i--) { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) - return false; - } - return false; - } - - friend inline bool operator<=(const base_uint &a, const base_uint &b) { - for (int i = base_uint::WIDTH - 1; i >= 0; i--) { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator>(const base_uint &a, const base_uint &b) { - for (int i = base_uint::WIDTH - 1; i >= 0; i--) { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return false; - } - - friend inline bool operator>=(const base_uint &a, const base_uint &b) { - for (int i = base_uint::WIDTH - 1; i >= 0; i--) { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator==(const base_uint &a, const base_uint &b) { - for (int i = 0; i < base_uint::WIDTH; i++) - if (a.pn[i] != b.pn[i]) return false; - return true; - } - - friend inline bool operator==(const base_uint &a, uint64_t b) { - if (a.pn[0] != (unsigned int)b) return false; - if (a.pn[1] != (unsigned int)(b >> 32)) return false; - for (int i = 2; i < base_uint::WIDTH; i++) - if (a.pn[i] != 0) return false; - return true; - } - - friend inline bool operator!=(const base_uint &a, const base_uint &b) { - return (!(a == b)); - } - - friend inline bool operator!=(const base_uint &a, uint64_t b) { - return (!(a == b)); - } - - std::string GetHex() const { - char psz[sizeof(pn) * 2 + 1]; - for (int i = 0; i < sizeof(pn); i++) - sprintf(psz + i * 2, "%02x", ((uint8_t *)pn)[sizeof(pn) - i - 1]); - return std::string(psz, psz + sizeof(pn) * 2); - } - - void SetHex(const char *psz) { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - - // skip leading spaces - while (isspace(*psz)) - psz++; - - // skip 0x - if (psz[0] == '0' && tolower(psz[1]) == 'x') psz += 2; - - // hex string to uint - static char phexdigit[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, - 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - const char *pbegin = psz; - while (phexdigit[(uint8_t)*psz] || *psz == '0') - psz++; - psz--; - uint8_t *p1 = (uint8_t *)pn; - uint8_t *pend = p1 + WIDTH * 4; - while (psz >= pbegin && p1 < pend) { - *p1 = phexdigit[(uint8_t)*psz--]; - if (psz >= pbegin) { - *p1 |= (phexdigit[(uint8_t)*psz--] << 4); - p1++; - } - } - } - - void SetHex(const std::string &str) { SetHex(str.c_str()); } - - std::string ToString() const { return (GetHex()); } - - uint8_t *begin() { return (uint8_t *)&pn[0]; } - - uint8_t *end() { return (uint8_t *)&pn[WIDTH]; } - - unsigned int size() { return sizeof(pn); } - - unsigned int GetSerializeSize(int nType = 0, - int nVersion = PROTOCOL_VERSION) const { - return sizeof(pn); - } - - template - void Serialize(Stream &s, int nType = 0, - int nVersion = PROTOCOL_VERSION) const { - s.write((char *)pn, sizeof(pn)); - } - - template - void Unserialize(Stream &s, int nType = 0, - int nVersion = PROTOCOL_VERSION) { - s.read((char *)pn, sizeof(pn)); - } - - friend class uint160; - friend class uint256; - friend inline int Testuint256AdHoc(std::vector vArg); -}; - -typedef base_uint<160> base_uint160; -typedef base_uint<256> base_uint256; - -// -// uint160 and uint256 could be implemented as templates, but to keep -// compile errors and debugging cleaner, they're copy and pasted. -// - -////////////////////////////////////////////////////////////////////////////// -// -// uint160 -// - -class uint160 : public base_uint160 { -public: - typedef base_uint160 basetype; - - uint160() { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint160(const basetype &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint160 &operator=(const basetype &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint160(uint64_t b) { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint160 &operator=(uint64_t b) { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint160(const std::string &str) { SetHex(str); } - - explicit uint160(const std::vector &vch) { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } -}; - -inline bool operator==(const uint160 &a, uint64_t b) { - return (base_uint160)a == b; -} -inline bool operator!=(const uint160 &a, uint64_t b) { - return (base_uint160)a != b; -} -inline const uint160 operator<<(const base_uint160 &a, unsigned int shift) { - return uint160(a) <<= shift; -} -inline const uint160 operator>>(const base_uint160 &a, unsigned int shift) { - return uint160(a) >>= shift; -} -inline const uint160 operator<<(const uint160 &a, unsigned int shift) { - return uint160(a) <<= shift; -} -inline const uint160 operator>>(const uint160 &a, unsigned int shift) { - return uint160(a) >>= shift; -} - -inline const uint160 operator^(const base_uint160 &a, const base_uint160 &b) { - return uint160(a) ^= b; -} -inline const uint160 operator&(const base_uint160 &a, const base_uint160 &b) { - return uint160(a) &= b; -} -inline const uint160 operator|(const base_uint160 &a, const base_uint160 &b) { - return uint160(a) |= b; -} -inline const uint160 operator+(const base_uint160 &a, const base_uint160 &b) { - return uint160(a) += b; -} -inline const uint160 operator-(const base_uint160 &a, const base_uint160 &b) { - return uint160(a) -= b; -} - -inline bool operator<(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a < (base_uint160)b; -} -inline bool operator<=(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a <= (base_uint160)b; -} -inline bool operator>(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a > (base_uint160)b; -} -inline bool operator>=(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a >= (base_uint160)b; -} -inline bool operator==(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a == (base_uint160)b; -} -inline bool operator!=(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a != (base_uint160)b; -} -inline const uint160 operator^(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a ^ (base_uint160)b; -} -inline const uint160 operator&(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a & (base_uint160)b; -} -inline const uint160 operator|(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a | (base_uint160)b; -} -inline const uint160 operator+(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a + (base_uint160)b; -} -inline const uint160 operator-(const base_uint160 &a, const uint160 &b) { - return (base_uint160)a - (base_uint160)b; -} - -inline bool operator<(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a < (base_uint160)b; -} -inline bool operator<=(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a <= (base_uint160)b; -} -inline bool operator>(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a > (base_uint160)b; -} -inline bool operator>=(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a >= (base_uint160)b; -} -inline bool operator==(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a == (base_uint160)b; -} -inline bool operator!=(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a != (base_uint160)b; -} -inline const uint160 operator^(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a ^ (base_uint160)b; -} -inline const uint160 operator&(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a & (base_uint160)b; -} -inline const uint160 operator|(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a | (base_uint160)b; -} -inline const uint160 operator+(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a + (base_uint160)b; -} -inline const uint160 operator-(const uint160 &a, const base_uint160 &b) { - return (base_uint160)a - (base_uint160)b; -} - -inline bool operator<(const uint160 &a, const uint160 &b) { - return (base_uint160)a < (base_uint160)b; -} -inline bool operator<=(const uint160 &a, const uint160 &b) { - return (base_uint160)a <= (base_uint160)b; -} -inline bool operator>(const uint160 &a, const uint160 &b) { - return (base_uint160)a > (base_uint160)b; -} -inline bool operator>=(const uint160 &a, const uint160 &b) { - return (base_uint160)a >= (base_uint160)b; -} -inline bool operator==(const uint160 &a, const uint160 &b) { - return (base_uint160)a == (base_uint160)b; -} -inline bool operator!=(const uint160 &a, const uint160 &b) { - return (base_uint160)a != (base_uint160)b; -} -inline const uint160 operator^(const uint160 &a, const uint160 &b) { - return (base_uint160)a ^ (base_uint160)b; -} -inline const uint160 operator&(const uint160 &a, const uint160 &b) { - return (base_uint160)a & (base_uint160)b; -} -inline const uint160 operator|(const uint160 &a, const uint160 &b) { - return (base_uint160)a | (base_uint160)b; -} -inline const uint160 operator+(const uint160 &a, const uint160 &b) { - return (base_uint160)a + (base_uint160)b; -} -inline const uint160 operator-(const uint160 &a, const uint160 &b) { - return (base_uint160)a - (base_uint160)b; -} - -////////////////////////////////////////////////////////////////////////////// -// -// uint256 -// - -class uint256 : public base_uint256 { -public: - typedef base_uint256 basetype; - - uint256() { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint256(const basetype &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint256 &operator=(const basetype &b) { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint256(uint64_t b) { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint256 &operator=(uint64_t b) { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint256(const std::string &str) { SetHex(str); } - - explicit uint256(const std::vector &vch) { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } -}; - -inline bool operator==(const uint256 &a, uint64_t b) { - return (base_uint256)a == b; -} -inline bool operator!=(const uint256 &a, uint64_t b) { - return (base_uint256)a != b; -} -inline const uint256 operator<<(const base_uint256 &a, unsigned int shift) { - return uint256(a) <<= shift; -} -inline const uint256 operator>>(const base_uint256 &a, unsigned int shift) { - return uint256(a) >>= shift; -} -inline const uint256 operator<<(const uint256 &a, unsigned int shift) { - return uint256(a) <<= shift; -} -inline const uint256 operator>>(const uint256 &a, unsigned int shift) { - return uint256(a) >>= shift; -} - -inline const uint256 operator^(const base_uint256 &a, const base_uint256 &b) { - return uint256(a) ^= b; -} -inline const uint256 operator&(const base_uint256 &a, const base_uint256 &b) { - return uint256(a) &= b; -} -inline const uint256 operator|(const base_uint256 &a, const base_uint256 &b) { - return uint256(a) |= b; -} -inline const uint256 operator+(const base_uint256 &a, const base_uint256 &b) { - return uint256(a) += b; -} -inline const uint256 operator-(const base_uint256 &a, const base_uint256 &b) { - return uint256(a) -= b; -} - -inline bool operator<(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a < (base_uint256)b; -} -inline bool operator<=(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a <= (base_uint256)b; -} -inline bool operator>(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a > (base_uint256)b; -} -inline bool operator>=(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a >= (base_uint256)b; -} -inline bool operator==(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a == (base_uint256)b; -} -inline bool operator!=(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a != (base_uint256)b; -} -inline const uint256 operator^(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a ^ (base_uint256)b; -} -inline const uint256 operator&(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a & (base_uint256)b; -} -inline const uint256 operator|(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a | (base_uint256)b; -} -inline const uint256 operator+(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a + (base_uint256)b; -} -inline const uint256 operator-(const base_uint256 &a, const uint256 &b) { - return (base_uint256)a - (base_uint256)b; -} - -inline bool operator<(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a < (base_uint256)b; -} -inline bool operator<=(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a <= (base_uint256)b; -} -inline bool operator>(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a > (base_uint256)b; -} -inline bool operator>=(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a >= (base_uint256)b; -} -inline bool operator==(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a == (base_uint256)b; -} -inline bool operator!=(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a != (base_uint256)b; -} -inline const uint256 operator^(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a ^ (base_uint256)b; -} -inline const uint256 operator&(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a & (base_uint256)b; -} -inline const uint256 operator|(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a | (base_uint256)b; -} -inline const uint256 operator+(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a + (base_uint256)b; -} -inline const uint256 operator-(const uint256 &a, const base_uint256 &b) { - return (base_uint256)a - (base_uint256)b; -} - -inline bool operator<(const uint256 &a, const uint256 &b) { - return (base_uint256)a < (base_uint256)b; -} -inline bool operator<=(const uint256 &a, const uint256 &b) { - return (base_uint256)a <= (base_uint256)b; -} -inline bool operator>(const uint256 &a, const uint256 &b) { - return (base_uint256)a > (base_uint256)b; -} -inline bool operator>=(const uint256 &a, const uint256 &b) { - return (base_uint256)a >= (base_uint256)b; -} -inline bool operator==(const uint256 &a, const uint256 &b) { - return (base_uint256)a == (base_uint256)b; -} -inline bool operator!=(const uint256 &a, const uint256 &b) { - return (base_uint256)a != (base_uint256)b; -} -inline const uint256 operator^(const uint256 &a, const uint256 &b) { - return (base_uint256)a ^ (base_uint256)b; -} -inline const uint256 operator&(const uint256 &a, const uint256 &b) { - return (base_uint256)a & (base_uint256)b; -} -inline const uint256 operator|(const uint256 &a, const uint256 &b) { - return (base_uint256)a | (base_uint256)b; -} -inline const uint256 operator+(const uint256 &a, const uint256 &b) { - return (base_uint256)a + (base_uint256)b; -} -inline const uint256 operator-(const uint256 &a, const uint256 &b) { - return (base_uint256)a - (base_uint256)b; -} - -inline int Testuint256AdHoc(std::vector vArg) { - uint256 g(0); - - printf("%s\n", g.ToString().c_str()); - g--; - printf("g--\n"); - printf("%s\n", g.ToString().c_str()); - g--; - printf("g--\n"); - printf("%s\n", g.ToString().c_str()); - g++; - printf("g++\n"); - printf("%s\n", g.ToString().c_str()); - g++; - printf("g++\n"); - printf("%s\n", g.ToString().c_str()); - g++; - printf("g++\n"); - printf("%s\n", g.ToString().c_str()); - g++; - printf("g++\n"); - printf("%s\n", g.ToString().c_str()); - - uint256 a(7); - printf("a=7\n"); - printf("%s\n", a.ToString().c_str()); - - uint256 b; - printf("b undefined\n"); - printf("%s\n", b.ToString().c_str()); - int c = 3; - - a = c; - a.pn[3] = 15; - printf("%s\n", a.ToString().c_str()); - uint256 k(c); - - a = 5; - a.pn[3] = 15; - printf("%s\n", a.ToString().c_str()); - b = 1; - b <<= 52; - - a |= b; - - a ^= 0x500; - - printf("a %s\n", a.ToString().c_str()); - - a = a | b | (uint256)0x1000; - - printf("a %s\n", a.ToString().c_str()); - printf("b %s\n", b.ToString().c_str()); - - a = 0xfffffffe; - a.pn[4] = 9; - - printf("%s\n", a.ToString().c_str()); - a++; - printf("%s\n", a.ToString().c_str()); - a++; - printf("%s\n", a.ToString().c_str()); - a++; - printf("%s\n", a.ToString().c_str()); - a++; - printf("%s\n", a.ToString().c_str()); - - a--; - printf("%s\n", a.ToString().c_str()); - a--; - printf("%s\n", a.ToString().c_str()); - a--; - printf("%s\n", a.ToString().c_str()); - uint256 d = a--; - printf("%s\n", d.ToString().c_str()); - printf("%s\n", a.ToString().c_str()); - a--; - printf("%s\n", a.ToString().c_str()); - a--; - printf("%s\n", a.ToString().c_str()); - - d = a; - - printf("%s\n", d.ToString().c_str()); - for (int i = uint256::WIDTH - 1; i >= 0; i--) - printf("%08x", d.pn[i]); - printf("\n"); - - uint256 neg = d; - neg = ~neg; - printf("%s\n", neg.ToString().c_str()); - - uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111"); - printf("\n"); - printf("%s\n", e.ToString().c_str()); - - printf("\n"); - uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111"); - uint256 x2; - printf("%s\n", x1.ToString().c_str()); - for (int i = 0; i < 270; i += 4) { - x2 = x1 << i; - printf("%s\n", x2.ToString().c_str()); - } - - printf("\n"); - printf("%s\n", x1.ToString().c_str()); - for (int i = 0; i < 270; i += 4) { - x2 = x1; - x2 >>= i; - printf("%s\n", x2.ToString().c_str()); - } - - for (int i = 0; i < 100; i++) { - uint256 k = (~uint256(0) >> i); - printf("%s\n", k.ToString().c_str()); - } - - for (int i = 0; i < 100; i++) { - uint256 k = (~uint256(0) << i); - printf("%s\n", k.ToString().c_str()); - } - - return (0); -} - -#endif