From c66df489fd18a656941470fe388c8d159da0a64f Mon Sep 17 00:00:00 2001 From: JD Date: Thu, 12 Dec 2019 20:42:28 -0800 Subject: [PATCH 0001/1888] v1.0.5.3 --- autogen.sh | 0 configure.ac | 10 +- contrib/macdeploy/custom_dsstore.py | 2 +- depends/packages/qt.mk | 8 +- doc/release-process.md | 5 +- share/qt/Info.plist.in | 2 +- share/ui.rc | 30 +- src/Makefile.am | 1 + src/addrman.cpp | 4 +- src/addrman.h | 13 +- src/chainparams.cpp | 2 + src/chainparams.h | 6 +- src/clientversion.cpp | 7 +- src/clientversion.h | 4 +- src/compat/glibc_compat.cpp | 45 ++ src/init.cpp | 117 +++-- src/init.h | 6 + src/main.cpp | 67 +-- src/main.h | 6 +- src/miner.cpp | 1 + src/net.cpp | 2 +- src/primitives/transaction.h | 2 - src/protocol.cpp | 1 - src/protocol.h | 3 - src/qt/bitcoingui.cpp | 11 +- src/qt/dapscoinstrings.cpp | 3 +- src/qt/entermnemonics.cpp | 10 +- src/qt/forms/historypage.ui | 442 +++++++++--------- src/qt/forms/optionspage.ui | 134 ++---- src/qt/forms/receivecoinsdialog.ui | 542 +++++++++++----------- src/qt/forms/sendcoinsdialog.ui | 676 +++++++++++++++++++++++++++- src/qt/forms/togglebutton.ui | 72 +-- src/qt/forms/txentry.ui | 378 ++++++++-------- src/qt/historypage.cpp | 3 +- src/qt/optionsdialog.cpp | 33 +- src/qt/optionsdialog.h | 5 +- src/qt/optionspage.cpp | 12 +- src/qt/receivecoinsdialog.cpp | 24 +- src/qt/res/css/Dark.css | 1 + src/qt/res/css/Light.css | 1 + src/qt/res/src/bitcoin.svg | 116 ++--- src/qt/sendcoinsdialog.cpp | 250 +++++++++- src/qt/sendcoinsdialog.h | 13 + src/rpcblockchain.cpp | 60 ++- src/rpcclient.cpp | 5 +- src/rpcmining.cpp | 2 +- src/rpcnet.cpp | 10 +- src/rpcserver.cpp | 6 + src/rpcserver.h | 3 + src/rpcwallet.cpp | 63 ++- src/test/accounting_tests.cpp | 8 +- src/util.cpp | 1 - src/util.h | 1 - src/wallet.cpp | 221 ++++----- src/wallet.h | 22 +- src/walletdb.cpp | 8 +- src/walletdb.h | 5 +- 57 files changed, 2278 insertions(+), 1207 deletions(-) mode change 100644 => 100755 autogen.sh diff --git a/autogen.sh b/autogen.sh old mode 100644 new mode 100755 diff --git a/configure.ac b/configure.ac index 9acedc672c..b65afa1fa8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,11 +2,12 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 4) -define(_CLIENT_VERSION_BUILD, 6) +define(_CLIENT_VERSION_REVISION, 5) +define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) -AC_INIT([DAPScoin],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://officialdapscoin.com],[dapscoin]) +AC_INIT([DAPScoin],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_REVISION, m4_if(_CLIENT_VERSION_BUILD, [0], [], _CLIENT_VERSION_BUILD))m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/DAPSCoin/DAPSCoin/issues],[dapscoin],[https://officialdapscoin.com]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/dapscoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) @@ -445,6 +446,8 @@ if test x$use_glibc_compat != xno; then [ fdelt_type="long int"]) AC_MSG_RESULT($fdelt_type) AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"]) + AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"]) fi @@ -1021,6 +1024,7 @@ AC_SUBST(BITCOIN_CLI_NAME) AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) +AC_SUBST(COMPAT_LDFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) AC_SUBST(USE_QRCODE) diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index 43e4f5c511..ef48415cd1 100644 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -14,7 +14,7 @@ ds = DSStore.open(output_file, 'w+') ds['.']['bwsp'] = { 'ShowStatusBar': False, - 'WindowBounds': b'{{300, 280}, {500, 343}}', + 'WindowBounds': '{{300, 280}, {500, 343}}', 'ContainerShowSidebar': False, 'SidebarWidth': 0, 'ShowTabView': False, diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 23cde9ee6d..e3fea4a916 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,9 +1,9 @@ PACKAGE=qt -$(package)_version=5.9.7 +$(package)_version=5.9.8 $(package)_download_path=https://download.qt.io/official_releases/qt/5.9/$($(package)_version)/submodules $(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=36dd9574f006eaa1e5af780e4b33d11fe39d09fd7c12f3b9d83294174bd28f00 +$(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352da0907d $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase @@ -11,10 +11,10 @@ $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=b36da7d93c3ab6fca56b32053bb73bc619c8b192bb89b74e3bcde2705f1c2a14 +$(package)_qttranslations_sha256_hash=fb5a47799754af73d3bf501fe513342cfe2fc37f64e80df5533f6110e804220c $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=d62e0f70d99645d6704dbb8976fb2222443061743689943d40970c52c49367a1 +$(package)_qttools_sha256_hash=a97556eb7b2f30252cdd8a598c396cfce2b2f79d2bae883af6d3b26a2cdcc63c $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) diff --git a/doc/release-process.md b/doc/release-process.md index f1a37096f2..b60b29c4f0 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -3,11 +3,12 @@ Release Process Before every release candidate: -* Update translations (ping Fuzzbawls on Slack) see [translation_process.md](https://github.com/DAPScoin-Project/DAPScoin/blob/master/doc/translation_process.md#synchronising-translations). +* Update translations - see [translation_process.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/doc/translation_process.md#synchronising-translations). +* Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`) Before every minor and major release: -* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) +* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) (don't forget to set `CLIENT_VERSION_RC` to `0`) * Write release notes (see below) Before every major release: diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 4d78cce64a..a32eba6eaa 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -17,7 +17,7 @@ APPL CFBundleGetInfoString - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ The Dash Core developers, 2015-@COPYRIGHT_YEAR@ The Dapscoin Core developers + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ The Dash Core developers, 2015-@COPYRIGHT_YEAR@ The PIVX Core developers, 2018-@COPYRIGHT_YEAR@ The DAPS Project developers CFBundleShortVersionString @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ diff --git a/share/ui.rc b/share/ui.rc index c3cece1ef0..063641cba2 100644 --- a/share/ui.rc +++ b/share/ui.rc @@ -1,15 +1,15 @@ -bitcoin ICON "pixmaps/bitcoin.ico" - -#include "wx/msw/wx.rc" - -check ICON "pixmaps/check.ico" -send16 BITMAP "pixmaps/send16.bmp" -send16mask BITMAP "pixmaps/send16mask.bmp" -send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" -send20 BITMAP "pixmaps/send20.bmp" -send20mask BITMAP "pixmaps/send20mask.bmp" -addressbook16 BITMAP "pixmaps/addressbook16.bmp" -addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" -addressbook20 BITMAP "pixmaps/addressbook20.bmp" -addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" -favicon ICON "pixmaps/favicon.ico" +bitcoin ICON "pixmaps/bitcoin.ico" + +#include "wx/msw/wx.rc" + +check ICON "pixmaps/check.ico" +send16 BITMAP "pixmaps/send16.bmp" +send16mask BITMAP "pixmaps/send16mask.bmp" +send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" +send20 BITMAP "pixmaps/send20.bmp" +send20mask BITMAP "pixmaps/send20mask.bmp" +addressbook16 BITMAP "pixmaps/addressbook16.bmp" +addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" +addressbook20 BITMAP "pixmaps/addressbook20.bmp" +addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" +favicon ICON "pixmaps/favicon.ico" diff --git a/src/Makefile.am b/src/Makefile.am index 4264b657bb..68750a2d6f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -377,6 +377,7 @@ libbitcoin_util_a_SOURCES = \ if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp +AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between dapscoin-cli and dapscoin-qt diff --git a/src/addrman.cpp b/src/addrman.cpp index 168c7600b5..79f8031450 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -336,10 +336,10 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) info.nAttempts++; } -CAddress CAddrMan::Select_() +CAddrInfo CAddrMan::Select_() { if (size() == 0) - return CAddress(); + return CAddrInfo(); // Use a 50% chance for choosing between tried and new table entries. if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) { diff --git a/src/addrman.h b/src/addrman.h index 70d93f4114..a10af3672f 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -22,6 +22,10 @@ */ class CAddrInfo : public CAddress { +public: + //! last try whatsoever by us (memory only) + int64_t nLastTry; + private: //! where knowledge about this address first came from CNetAddr source; @@ -29,9 +33,6 @@ class CAddrInfo : public CAddress //! last successful connection by us int64_t nLastSuccess; - //! last try whatsoever by us: - // int64_t CAddress::nLastTry - //! connection attempts since last successful attempt int nAttempts; @@ -229,7 +230,7 @@ class CAddrMan //! Select an address to connect to. //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) - CAddress Select_(); + CAddrInfo Select_(); #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. @@ -531,9 +532,9 @@ class CAddrMan * Choose an address to connect to. * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). */ - CAddress Select() + CAddrInfo Select() { - CAddress addrRet; + CAddrInfo addrRet; { LOCK(cs); Check(); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 96e16caadd..4aefdd0dcd 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -86,6 +86,8 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (146600, uint256("95c6a698083ddc27a8fb342086b055d3823c040f32f5728c9ded7d8fe675bd8b")) (146700, uint256("ba7a089a31940f6c8569c07ef25915c50d28182dc78d6af2590a2dc65476c9b2")) (146800, uint256("85d7b80f682f4d480e85816786f821576c7f1df182276358ad3917742fa11bd7")) + (146898, uint256("a0e3853d98c6d60febd57ad2c879e590bda09de271527b396efc5be22ab5ce9e")) + (146899, uint256("22c90bbb2ae11c3bd5fd6c716d543f8f207e6379e14d26fc04ba7220681dd13b")) (146900, uint256("a879e6b5f62ed437d2108366a8152130c21df38322556f06dd71ad08854210b8")) (147000, uint256("e60eb87bdbeaee7582826418c8c4504637e51684a3e631b5683390497a4e2535")) (147200, uint256("55fcf4abbd7a1b3aa91460378c3b833f9d1569780b0a1e7e6ee2d1b3a4256b24")) diff --git a/src/chainparams.h b/src/chainparams.h index 1450df70a6..8697e6f6b9 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -120,7 +120,7 @@ class CChainParams int nDefaultPort; int nExtCoinType; uint256 bnProofOfWorkLimit; - int nMaxReorganizationDepth; + mutable int nMaxReorganizationDepth; int nSubsidyHalvingInterval; int nEnforceBlockUpgradeMajority; int nRejectBlockOutdatedMajority; @@ -161,6 +161,10 @@ class CChainParams //For PoA blocks int nPoABlockTime; int nMinNumPoSBlocks; +public: + void ChangeMaxReorg(int num) const { + nMaxReorganizationDepth = num; + } }; /** diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 872079ea7d..14ea2db1e0 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -41,10 +41,11 @@ const std::string CLIENT_NAME("DAPS"); #include "build.h" #endif -//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ +//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. +#define GIT_ARCHIVE 1 #ifdef GIT_ARCHIVE -#define GIT_COMMIT_ID "$Format:%H$" -#define GIT_COMMIT_DATE "$Format:%cD$" +#define GIT_COMMIT_ID "f817001ef362065ac77cab1e39a8657ee4f6174e" +#define GIT_COMMIT_DATE "Tue, 10 Dec 2019 01:12:37 +0700" #endif #define BUILD_DESC_WITH_SUFFIX(maj, min, rev, build, suffix) \ diff --git a/src/clientversion.h b/src/clientversion.h index 8e318f955b..7b947c87f7 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -16,8 +16,8 @@ //! These need to be macros, as clientversion.cpp's and dapscoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 4 -#define CLIENT_VERSION_BUILD 6 +#define CLIENT_VERSION_REVISION 5 +#define CLIENT_VERSION_BUILD 3 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp index 9fa84f15f3..1fde18f23b 100644 --- a/src/compat/glibc_compat.cpp +++ b/src/compat/glibc_compat.cpp @@ -7,6 +7,7 @@ #endif #include +#include #if defined(HAVE_SYS_SELECT_H) #include @@ -27,3 +28,47 @@ extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a) return a / __NFDBITS; } extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn"))); + +#if defined(__i386__) || defined(__arm__) + +extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp); + +extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp) +{ + int32_t c1 = 0, c2 = 0; + int64_t uu = u, vv = v; + int64_t w; + int64_t r; + + if (uu < 0) { + c1 = ~c1, c2 = ~c2, uu = -uu; + } + if (vv < 0) { + c1 = ~c1, vv = -vv; + } + + w = __udivmoddi4(uu, vv, (uint64_t*)&r); + if (c1) + w = -w; + if (c2) + r = -r; + + *rp = r; + return w; +} +#endif + +extern "C" float log2f_old(float x); +#ifdef __i386__ +__asm(".symver log2f_old,log2f@GLIBC_2.1"); +#elif defined(__amd64__) +__asm(".symver log2f_old,log2f@GLIBC_2.2.5"); +#elif defined(__arm__) +__asm(".symver log2f_old,log2f@GLIBC_2.4"); +#elif defined(__aarch64__) +__asm(".symver log2f_old,log2f@GLIBC_2.17"); +#endif +extern "C" float __wrap_log2f(float x) +{ + return log2f_old(x); +} \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 00dfe86116..774303a545 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -291,7 +291,7 @@ void Shutdown() */ void HandleSIGTERM(int) { - fRequestShutdown = true; + StartShutdown(); } void HandleSIGHUP(int) @@ -299,6 +299,17 @@ void HandleSIGHUP(int) fReopenDebugLog = true; } +#ifndef WIN32 +static void registerSignalHandler(int signal, void(*handler)(int)) +{ + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(signal, &sa, nullptr); +} +#endif + bool static InitError(const std::string& str) { uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); @@ -487,6 +498,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default:%u)"), 1)); strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf(_("Limit size of signature cache to entries (default: %u)"), 50000)); } + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in DAPS/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK()))); strUsage += HelpMessageOpt("-printtoconsole", strprintf(_("Send trace/debug info to console instead of debug.log file (default: %u)"), 0)); if (GetBoolArg("-help-debug", false)) { @@ -557,6 +569,8 @@ std::string LicenseInfo() "\n" + FormatParagraph(strprintf(_("Copyright (C) 2014-%i The Dash Core Developers"), COPYRIGHT_YEAR)) + "\n" + "\n" + + FormatParagraph(strprintf(_("Copyright (C) 2015-%i The PIVX Core Developers"), COPYRIGHT_YEAR)) + "\n" + + "\n" + FormatParagraph(strprintf(_("Copyright (C) 2018-%i The DAPS Project developers"), COPYRIGHT_YEAR)) + "\n" + "\n" + FormatParagraph(_("This is experimental software.")) + "\n" + @@ -682,10 +696,20 @@ bool AppInitServers() return true; } -/** Initialize dapscoin. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2(bool isDaemon) +[[noreturn]] static void new_handler_terminate() +{ + // Rather than throwing std::bad-alloc if allocation fails, terminate + // immediately to (try to) avoid chain corruption. + // Since LogPrintf may itself allocate memory, set the handler directly + // to terminate first. + std::set_new_handler(std::terminate); + LogPrintf("Error: Out of memory. Terminating.\n"); + + // The log was successful, terminate now. + std::terminate(); +}; + +bool AppInitBasicSetup() { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -724,26 +748,31 @@ bool AppInit2(bool isDaemon) umask(077); } - - // Clean shutdown on SIGTERM - struct sigaction sa; - sa.sa_handler = HandleSIGTERM; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); + // Clean shutdown on SIGTERMx + registerSignalHandler(SIGTERM, HandleSIGTERM); + registerSignalHandler(SIGINT, HandleSIGTERM); // Reopen debug.log on SIGHUP - struct sigaction sa_hup; - sa_hup.sa_handler = HandleSIGHUP; - sigemptyset(&sa_hup.sa_mask); - sa_hup.sa_flags = 0; - sigaction(SIGHUP, &sa_hup, NULL); + registerSignalHandler(SIGHUP, HandleSIGHUP); // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly signal(SIGPIPE, SIG_IGN); #endif + std::set_new_handler(new_handler_terminate); + + return true; +} + +/** Initialize daps. + * @pre Parameters should be parsed and config file should be read. + */ +bool AppInit2(bool isDaemon) +{ + // ********************************************************* Step 1: setup + if (!AppInitBasicSetup()) + return false; + // ********************************************************* Step 2: parameter interactions // Set this early so that parameter interactions go to console fPrintToConsole = GetBoolArg("-printtoconsole", false); @@ -863,7 +892,6 @@ bool AppInit2(bool isDaemon) else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; - fServer = GetBoolArg("-server", false); setvbuf(stdout, NULL, _IOLBF, 0); /// ***TODO*** do we still need this after -printtoconsole is gone? // Staking needs a CWallet instance, so make sure wallet is enabled @@ -944,6 +972,8 @@ bool AppInit2(bool isDaemon) if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices |= NODE_BLOOM; + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Sanity check @@ -1000,14 +1030,12 @@ bool AppInit2(bool isDaemon) * that the server is there and will be ready later). Warmup mode will * be disabled when initialisation is finished. */ - if (fServer) { + if (GetBoolArg("-server", false)) { uiInterface.InitMessage.connect(SetRPCWarmupStatus); if (!AppInitServers()) return InitError(_("Unable to start HTTP server. See debug log for details.")); } - int64_t nStart; - // ********************************************************* Step 5: Backup wallet and verify wallet database integrity #ifdef ENABLE_WALLET if (!fDisableWallet) { @@ -1185,12 +1213,12 @@ bool AppInit2(bool isDaemon) if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { - return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + return InitError(strprintf(_("Lookup(): Invalid -proxy address or hostname: '%s'"), proxyArg)); } proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); if (!addrProxy.IsValid()) - return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + return InitError(strprintf(_("isValid(): Invalid -proxy address or hostname: '%s'"), proxyArg)); SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV6, addrProxy); @@ -1243,7 +1271,7 @@ bool AppInit2(bool isDaemon) } else { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; - fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE); + fBound |= Bind(CService((in6_addr)IN6ADDR_ANY_INIT, GetListenPort()), BF_NONE); fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE); } if (!fBound) @@ -1298,8 +1326,9 @@ bool AppInit2(bool isDaemon) uiInterface.InitMessage(_("Loading block index...")); - nStart = GetTimeMillis(); do { + const int64_t load_block_index_start_time = GetTimeMillis(); + try { UnloadBlockIndex(); delete pcoinsTip; @@ -1372,6 +1401,7 @@ bool AppInit2(bool isDaemon) fVerifyingBlocks = false; fLoaded = true; + LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time); } while (false); if (!fLoaded && !ShutdownRequested()) { @@ -1383,6 +1413,28 @@ bool AppInit2(bool isDaemon) if (fRet) { fReindex = true; fRequestShutdown = false; + + filesystem::path blocksDir = GetDataDir() / "blocks"; + filesystem::path chainstateDir = GetDataDir() / "chainstate"; + + // We delete in 4 individual steps in case one of the folder is missing already + try { + if (filesystem::exists(blocksDir)){ + boost::filesystem::remove_all(blocksDir); + LogPrintf("-resync: folder deleted: %s\n", blocksDir.string().c_str()); + } + + if (filesystem::exists(chainstateDir)){ + boost::filesystem::remove_all(chainstateDir); + LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); + } + + boost::filesystem::create_directories(blocksDir); + boost::filesystem::create_directories(chainstateDir); + } catch (boost::filesystem::filesystem_error& error) { + LogPrintf("Failed to delete blockchain folders %s\n", error.what()); + } + } else { LogPrintf("Aborted block database rebuild. Exiting.\n"); return false; @@ -1400,7 +1452,6 @@ bool AppInit2(bool isDaemon) LogPrintf("Shutdown requested. Exiting.\n"); return false; } - LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); @@ -1435,7 +1486,7 @@ bool AppInit2(bool isDaemon) uiInterface.InitMessage(_("Loading... Please do not interrupt this process as it could lead to a corrupt wallet.")); fVerifyingBlocks = true; - nStart = GetTimeMillis(); + const int64_t nWalletStartTime = GetTimeMillis(); bool fFirstRun = true; pwalletMain = new CWallet(strWalletFile); DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); @@ -1496,7 +1547,7 @@ bool AppInit2(bool isDaemon) } LogPrintf("%s", strErrors.str()); - LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); + LogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nWalletStartTime); RegisterValidationInterface(pwalletMain); int height = -1; @@ -1522,9 +1573,11 @@ bool AppInit2(bool isDaemon) if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { uiInterface.InitMessage(_("Rescanning...")); LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); - nStart = GetTimeMillis(); - pwalletMain->ScanForWalletTransactions(pindexRescan, true); - LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); + const int64_t nWalletRescanTime = GetTimeMillis(); + if (pwalletMain->ScanForWalletTransactions(pindexRescan, true, true) == -1) { + return error("Shutdown requested over the txs scan. Exiting."); + } + LogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nWalletRescanTime); pwalletMain->SetBestChain(chainActive.GetLocator()); nWalletDBUpdated++; diff --git a/src/init.h b/src/init.h index 17b31dd8ae..168b1fa7cf 100644 --- a/src/init.h +++ b/src/init.h @@ -26,6 +26,12 @@ void Shutdown(); void PrepareShutdown(); bool AppInit2(bool isDaemon); +/** Initialize DAPS: Basic context setup. + * @note This can be done before daemonization. Do not call Shutdown() if this function fails. + * @pre Parameters should be parsed and config file should be read. + */ +bool AppInitBasicSetup(); + /** The help message mode determines what help message to show */ enum HelpMessageMode { HMM_BITCOIND, diff --git a/src/main.cpp b/src/main.cpp index e8859d05ac..0a032f6ab3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,6 +74,9 @@ bool fVerifyingBlocks = false; unsigned int nCoinCacheSize = 5000; bool fAlerts = DEFAULT_ALERTS; +/* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; + unsigned int nStakeMinAge = 60 * 60; int64_t nReserveBalance = 0; @@ -1451,57 +1454,6 @@ int GetIXConfirmations(uint256 nTXHash) return 0; } -// ppcoin: total coin age spent in transaction, in the unit of coin-days. -// Only those coins meeting minimum age requirement counts. As those -// transactions not in main chain are not currently indexed so we -// might not find out about their coin age. Older transactions are -// guaranteed to be in main chain by sync-checkpoint. This rule is -// introduced to help nodes establish a consistent view of the coin -// age (trust score) of competing branches. -bool GetCoinAge(const CTransaction& tx, const unsigned int nTxTime, uint64_t& nCoinAge) -{ - uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds - nCoinAge = 0; - - CBlockIndex* pindex = NULL; - for (const CTxIn& txin : tx.vin) { - // First try finding the previous transaction in database - CTransaction txPrev; - uint256 hashBlockPrev; - if (!GetTransaction(txin.prevout.hash, txPrev, hashBlockPrev)) { - LogPrintf("GetCoinAge: failed to find vin transaction \n"); - continue; // previous transaction not in main chain - } - - BlockMap::iterator it = mapBlockIndex.find(hashBlockPrev); - if (it != mapBlockIndex.end()) - pindex = it->second; - else { - LogPrintf("GetCoinAge() failed to find block index \n"); - continue; - } - - // Read block header - CBlockHeader prevblock = pindex->GetBlockHeader(); - - if (prevblock.nTime + nStakeMinAge > nTxTime) - continue; // only count coins meeting min age requirement - - if (nTxTime < prevblock.nTime) { - LogPrintf("GetCoinAge: Timestamp Violation: txtime less than txPrev.nTime"); - return false; // Transaction timestamp violation - } - - int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue; - bnCentSecond += uint256(nValueIn) * (nTxTime - prevblock.nTime); - } - - uint256 bnCoinDay = bnCentSecond / COIN / (24 * 60 * 60); - LogPrintf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str()); - nCoinAge = bnCoinDay.GetCompact(); - return true; -} - bool IsSerialInBlockchain(const CBigNum& bnSerial, int& nHeightTx) { uint256 txHash = 0; @@ -2426,8 +2378,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < - GetTime() - 6 * 60 * 60); // ~144 blocks behind -> 2 x fork detection time + pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; return state; @@ -4608,8 +4559,11 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis // ppcoin: check proof-of-stake // Limited duplicity on stake: prevents block flood attack // Duplicate stake allowed only when there is orphan child block - if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) /* && !mapOrphanBlocksByPrev.count(hash)*/) - return error("ProcessNewBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, pblock->GetHash().ToString().c_str()); + // Key image will be checked later for duplicate stake + /*if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake())) { + if (IsKeyImageSpend1(pblock->vtx[1].vin[0].keyImage.GetHex(), pblock->hashPrevBlock)) + return error("ProcessNewBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, pblock->GetHash().ToString().c_str()); + }*/ // NovaCoin: check proof-of-stake block signature if (!pblock->IsPoABlockByVersion() && !pblock->CheckBlockSignature()) return error("ProcessNewBlock() : bad proof-of-stake block signature"); @@ -4903,6 +4857,9 @@ bool static LoadBlockIndexDB(string& strError) } sort(vSortedByHeight.begin(), vSortedByHeight.end()); for (const PAIRTYPE(int, CBlockIndex*) & item : vSortedByHeight) { + // Stop if shutdown was requested + if (ShutdownRequested()) return false; + CBlockIndex* pindex = item.second; pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); if (pindex->nStatus & BLOCK_HAVE_DATA) { diff --git a/src/main.h b/src/main.h index 6f94d588f2..56226b0a8c 100644 --- a/src/main.h +++ b/src/main.h @@ -112,6 +112,9 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; /** Enable bloom filter */ static const bool DEFAULT_PEERBLOOMFILTERS = true; +/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; + /** "reject" message codes */ static const unsigned char REJECT_MALFORMED = 0x01; static const unsigned char REJECT_INVALID = 0x10; @@ -148,6 +151,7 @@ extern bool fCheckBlockIndex; extern unsigned int nCoinCacheSize; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern int64_t nMaxTipAge; extern bool fVerifyingBlocks; extern bool fGenerateDapscoins; @@ -156,6 +160,7 @@ extern bool fLargeWorkInvalidChainFound; extern unsigned int nStakeMinAge; extern int64_t nLastCoinStakeSearchInterval; +extern int64_t nConsolidationTime; extern int64_t nLastCoinStakeSearchTime; extern int64_t nReserveBalance; extern const int MIN_RING_SIZE; @@ -286,7 +291,6 @@ bool VerifyShnorrKeyImageTxIn(const CTxIn& txin, uint256 sigHash); int GetInputAge(CTxIn& vin); int GetInputAgeIX(uint256 nTXHash, CTxIn& vin); -bool GetCoinAge(const CTransaction& tx, unsigned int nTxTime, uint64_t& nCoinAge); int GetIXConfirmations(uint256 nTXHash); struct CNodeStateStats { diff --git a/src/miner.cpp b/src/miner.cpp index 5100670fac..ba1935a548 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -61,6 +61,7 @@ class COrphan uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; int64_t nLastCoinStakeSearchInterval = 0; +int64_t nConsolidationTime = 0; // We want to sort transactions by priority and fee rate, so: typedef boost::tuple TxPriority; diff --git a/src/net.cpp b/src/net.cpp index 56eb9be98c..905c4cbf48 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1328,7 +1328,7 @@ void ThreadOpenConnections() { int nTries = 0; while (true) { - CAddress addr = addrman.Select(); + CAddrInfo addr = addrman.Select(); // if we selected an invalid address, restart if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 435e44eca7..762a75ee81 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -381,8 +381,6 @@ class CTransaction return a.hash != b.hash; } std::string ToString() const; - - bool GetCoinAge(uint64_t& nCoinAge) const; // ppcoin: get transaction coin age }; /** A mutable version of CTransaction. */ diff --git a/src/protocol.cpp b/src/protocol.cpp index c4f6c48c42..323646d41a 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -96,7 +96,6 @@ void CAddress::Init() { nServices = NODE_NETWORK; nTime = 100000000; - nLastTry = 0; } CInv::CInv() diff --git a/src/protocol.h b/src/protocol.h index b057d53c3a..53e6678984 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -117,9 +117,6 @@ class CAddress : public CService // disk and network only unsigned int nTime; - - // memory only - int64_t nLastTry; }; /** inv message data */ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ce77eeb98a..64ea4642a7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -114,8 +114,8 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); - this->setMinimumSize(1180, 790); - GUIUtil::restoreWindowGeometry("nWindow", QSize(1180, 790), this); + this->setMinimumSize(1147, 768); + GUIUtil::restoreWindowGeometry("nWindow", QSize(1147, 768), this); QString windowTitle = tr("DAPS Coin") + " "; #ifdef ENABLE_WALLET @@ -246,7 +246,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai QTimer* timerStakingIcon = new QTimer(labelStakingIcon); connect(timerStakingIcon, SIGNAL(timeout()), this, SLOT(setStakingStatus())); - timerStakingIcon->start(10000); + timerStakingIcon->start(1000); setStakingStatus(); } @@ -1114,6 +1114,11 @@ void BitcoinGUI::setStakingStatus() stakingState->setText(tr("Staking Enabled")); stakingState->setToolTip("Staking Enabled"); stakingAction->setIcon(QIcon(":/icons/staking_active")); + } else if (nConsolidationTime > 0) { + nConsolidationTime --; + stakingState->setText(tr("Consolidating Transactions…")); + stakingState->setToolTip("Consolidating Transactions… Please wait few minutes for it to be consolidated."); + stakingAction->setIcon(QIcon(":/icons/staking_active")); } else { stakingState->setText(tr("Enabling Staking...")); stakingState->setToolTip("Enabling Staking... Please wait up to 1.5 hours for it to be properly enabled after consolidation."); diff --git a/src/qt/dapscoinstrings.cpp b/src/qt/dapscoinstrings.cpp index 433318ef84..b477798732 100644 --- a/src/qt/dapscoinstrings.cpp +++ b/src/qt/dapscoinstrings.cpp @@ -253,7 +253,8 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Connect to a node to retrieve peer addresses QT_TRANSLATE_NOOP("dapscoin-core", "Connection options:"), QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2009-%i The Bitcoin Core Developers"), QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2014-%i The Dash Core Developers"), -QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2015-%i The DAPS Project developers"), +QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2015-%i The PIVX Core Developers"), +QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2018-%i The DAPS Project developers"), QT_TRANSLATE_NOOP("dapscoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("dapscoin-core", "Could not parse -rpcbind value %s as network address"), QT_TRANSLATE_NOOP("dapscoin-core", "Could not parse masternode.conf"), diff --git a/src/qt/entermnemonics.cpp b/src/qt/entermnemonics.cpp index db8a828789..1e7d83bca0 100644 --- a/src/qt/entermnemonics.cpp +++ b/src/qt/entermnemonics.cpp @@ -24,14 +24,18 @@ EnterMnemonics::~EnterMnemonics() void EnterMnemonics::on_next() { std::string phrase = ui->mnemonics->toPlainText().toStdString(); + if (ui->mnemonics->toPlainText().endsWith(" ")) { + QMessageBox::warning(this, "Recovery Phrase Invalid", "Recovery phrase has an extra space at the end. Please remove it to properly restore your wallet.", QMessageBox::Ok); + return; + } try { pwalletMain->GenerateNewHDChain(&phrase); - QMessageBox::information(this, "Recovery Phrase Import Succeed", "Your mnemonics has been successfully imported into the wallet. Rescanning will be scheduled to recover all your funds.", QMessageBox::Ok); + QMessageBox::information(this, "Recovery Phrase Import Successful", "Your mnemonics have been successfully imported into the wallet. Rescanning will be scheduled to recover all your funds.", QMessageBox::Ok); CBlockLocator loc = chainActive.GetLocator(chainActive[0]); pwalletMain->SetBestChain(loc); CWalletDB(pwalletMain->strWalletFile).WriteScannedBlockHeight(0); //reschedule to rescan entire chain to recover all funds and history accept(); } catch (std::exception& ex) { - QMessageBox::warning(this, "Recovery phrase invalid", "Recovery phrase is invalid", QMessageBox::Ok); + QMessageBox::warning(this, "Recovery Phrase Invalid", "Recovery phrase is invalid. Please try again and double check all words.", QMessageBox::Ok); } -} \ No newline at end of file +} diff --git a/src/qt/forms/historypage.ui b/src/qt/forms/historypage.ui index cae82ec243..c70ef01da2 100644 --- a/src/qt/forms/historypage.ui +++ b/src/qt/forms/historypage.ui @@ -1,221 +1,221 @@ - - - HistoryPage - - - - 0 - 0 - 1055 - 521 - - - - - 0 - 0 - - - - - 960 - 0 - - - - false - - - - - - - - - - - - - 0 - 0 - - - - true - - - - - - - - 0 - 0 - - - - to - - - - - - - - 0 - 0 - - - - true - - - - - - - - 0 - 0 - - - - - All Types - - - - - Sent - - - - - Received - - - - - Mined - - - - - Minted - - - - - Masternode - - - - - - - - - 0 - 0 - - - - true - - - - - - - - 0 - 0 - - - - Min Amount - - - - - - - - - - - - 0 - 0 - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - true - - - false - - - true - - - false - - - 150 - - - 150 - - - false - - - - Date - - - - - Type - - - - - Address/Description - - - - - Amount (DAPS) - - - - - Confirmations - - - - - - - - - - - + + + HistoryPage + + + + 0 + 0 + 1055 + 521 + + + + + 0 + 0 + + + + + 960 + 0 + + + + false + + + + + + + + + + + + + 0 + 0 + + + + true + + + + + + + + 0 + 0 + + + + to + + + + + + + + 0 + 0 + + + + true + + + + + + + + 0 + 0 + + + + + All Types + + + + + Sent + + + + + Received + + + + + Mined + + + + + Minted + + + + + Masternode + + + + + + + + + 0 + 0 + + + + true + + + + + + + + 0 + 0 + + + + Min Amount + + + + + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + false + + + true + + + false + + + 150 + + + 150 + + + false + + + + Date + + + + + Type + + + + + Address/Description + + + + + Amount (DAPS) + + + + + Confirmations + + + + + + + + + + + diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 0c9d233b65..77a0ab8b16 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -6,8 +6,8 @@ 0 0 - 1042 - 670 + 843 + 533 @@ -33,8 +33,8 @@ 0 0 - 1022 - 650 + 823 + 513 @@ -108,6 +108,26 @@ + + + + + + true + + + + 0 + 0 + + + + Show Seed Phrase + + + + + @@ -437,93 +457,6 @@ - - - - - - true - - - - 0 - 0 - - - - - 11 - - - - Mnemonic Recovery Phrase - - - - - - - true - - - - 0 - 0 - - - - - 10 - - - - We strongly recommend you only view your Mnemonic Phrase in a secure environment safe from video cameras or any wandering eyes. You will be required to enter your passphrase to view it. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 10 - - - - - - - true - - - - 0 - 0 - - - - Show Phrase - - - - - - - - - true - - - - 16777215 - 5 - - - - QFrame::NoFrame - - - - - - @@ -674,6 +607,25 @@ + + + + + true + + + + 16777215 + 5 + + + + QFrame::NoFrame + + + + + diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 8b159d7c24..d1ad465b3d 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -1,271 +1,271 @@ - - - ReceiveCoinsDialog - - - - 0 - 0 - 965 - 708 - - - - - 0 - 0 - - - - - 0 - 0 - - - - false - - - - - - Qt::Vertical - - - - 20 - 10 - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - - - - - - - - - An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the DAPS network. - - - Description (optional) - - - - - - - An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the DAPS network. - - - Description: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - reqID - - - - - - - An optional amount to request. Leave this empty or zero to not request a specific amount. - - - Amount: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - List of addresses to receive with - - - - - - - List of addresses to receive with - - - Address: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 150 - 0 - - - - Submit payment request for address selected above - - - &Submit - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 40 - 20 - - - - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - An optional amount to request. Leave this empty or zero to not request a specific amount. - - - DAPS Amount (optional) - - - - - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - 6 - - - QLayout::SetDefaultConstraint - - - - - Copy Master Account address to clipboard - - - - - - - - - - Master Account address - - - - - - - - - false - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - - - - - - - - - - reqID - receiveButton - - - - + + + ReceiveCoinsDialog + + + + 0 + 0 + 965 + 708 + + + + + 0 + 0 + + + + + 0 + 0 + + + + false + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + + + + + + + + + An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the DAPS network. + + + Description (optional) + + + + + + + An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the DAPS network. + + + Description: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + reqID + + + + + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + Amount: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + List of addresses to receive with + + + + + + + List of addresses to receive with + + + Address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 150 + 0 + + + + Submit payment request for address selected above + + + &Submit + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + DAPS Amount (optional) + + + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 6 + + + QLayout::SetDefaultConstraint + + + + + Copy Master Account address to clipboard + + + + + + + + + + Master Account address + + + + + + + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + + + + + + reqID + receiveButton + + + + diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index ae4b051d42..b3d32f4120 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -13,10 +13,7 @@ Send Coins - - false - - + 8 @@ -42,9 +39,6 @@ - - Your current spendable balance - Balance: @@ -61,11 +55,8 @@ IBeamCursor - - Your current spendable balance - - 0 DAPS + 123.456 DAPS Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse @@ -76,6 +67,629 @@ + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + 0 + + + 10 + + + 10 + + + + + 15 + + + + + + 0 + 0 + + + + + 75 + true + + + + font-weight:bold; + + + Coin Control Features + + + + + + + + + 8 + + + 10 + + + + + + + + Open Coin Control... + + + false + + + + + + + Coins automatically selected + + + 5 + + + + + + + + 75 + true + + + + color:red;font-weight:bold; + + + Insufficient funds! + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 1 + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 0 + + + 10 + + + + + 10 + + + 14 + + + 10 + + + 4 + + + 6 + + + + + + 75 + true + + + + Quantity: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Bytes: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + Amount: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 DAPS + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Priority: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + medium + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + Fee: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 DAPS + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Dust: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + After Fee: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 DAPS + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Change: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 DAPS + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + 5 + + + 5 + + + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + + + + + + + false + + + + 0 + 0 + + + + + + + + Split UTXO + + + + + + + + 50 + 0 + + + + # of outputs + + + + + + + UTXO Size: + + + + + + + 0 DAPS + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + 3 + + + + + + + + + Qt::Vertical + + + + 800 + 1 + + + + + + + + + @@ -87,10 +701,10 @@ 0 0 830 - 561 + 390 - + 0 @@ -137,7 +751,7 @@ Add &Recipient - + :/icons/add:/icons/add @@ -163,6 +777,22 @@ + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + @@ -197,6 +827,10 @@ S&end + + + :/icons/send:/icons/send + false @@ -231,8 +865,16 @@ - - - + + + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
+ + + + diff --git a/src/qt/forms/togglebutton.ui b/src/qt/forms/togglebutton.ui index 9545e9fbe0..d9d25eed56 100644 --- a/src/qt/forms/togglebutton.ui +++ b/src/qt/forms/togglebutton.ui @@ -1,36 +1,36 @@ - - - ToggleButton - - - - - - - - - - - - - - Qt::LeftToRight - - - - - - - - - - - Qt::RightToLeft - - - - - - - - + + + ToggleButton + + + + + + + + + + + + + + Qt::LeftToRight + + + + + + + + + + + Qt::RightToLeft + + + + + + + + diff --git a/src/qt/forms/txentry.ui b/src/qt/forms/txentry.ui index 85a3f42083..6f592c8195 100644 --- a/src/qt/forms/txentry.ui +++ b/src/qt/forms/txentry.ui @@ -1,189 +1,189 @@ - - - TxEntry - - - - 0 - 0 - 424 - 288 - - - - - 0 - 0 - - - - - 0 - - - 0 - - - - - - - true - - - - 0 - 0 - - - - - 0 - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - TxAmount - - - - - - - lableDate - - - - - - - - 0 - 0 - - - - - 32 - 32 - - - - - 32 - 32 - - - - - - - - 32 - 32 - - - - - - - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - false - - - QAbstractItemView::NoEditTriggers - - - false - - - false - - - false - - - QAbstractItemView::NoSelection - - - Qt::ElideMiddle - - - false - - - Qt::NoPen - - - false - - - false - - - false - - - true - - - false - - - false - - - - TRANSACTION ID - - - - - TO - - - - - MM/DD/YYYY - - - - - - - - - - - + + + TxEntry + + + + 0 + 0 + 424 + 288 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + + + + + true + + + + 0 + 0 + + + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + TxAmount + + + + + + + lableDate + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + 32 + 32 + + + + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + false + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + QAbstractItemView::NoSelection + + + Qt::ElideMiddle + + + false + + + Qt::NoPen + + + false + + + false + + + false + + + true + + + false + + + false + + + + TRANSACTION ID + + + + + TO + + + + + MM/DD/YYYY + + + + + + + + + + + diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 61e9a7053f..d25e973658 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -207,7 +207,8 @@ void HistoryPage::updateTableData() void HistoryPage::updateTableData(CWallet* wallet) { - if (!wallet) return; + if (!wallet) return; + if (!wallet || wallet->IsLocked()) return; TRY_LOCK(cs_main, lockMain); if (!lockMain) return; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c65de41e39..31a7a4ce96 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -59,6 +59,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); ui->proxyIp->installEventFilter(this); + ui->proxyPort->installEventFilter(this); /* Window elements init */ #ifdef Q_OS_MAC @@ -117,7 +118,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren mapper->setOrientation(Qt::Vertical); /* setup/change UI elements when proxy IP is invalid/valid */ - connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit*, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit*, int))); + connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit*, QLineEdit*)), this, SLOT(doProxyIpChecks(QValidatedLineEdit*, QLineEdit*))); } OptionsDialog::~OptionsDialog() @@ -266,30 +267,44 @@ void OptionsDialog::clearStatusLabel() ui->statusLabel->clear(); } -void OptionsDialog::doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, int nProxyPort) +void OptionsDialog::doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort) { - Q_UNUSED(nProxyPort); - const std::string strAddrProxy = pUiProxyIp->text().toStdString(); CService addrProxy; - /* Check for a valid IPv4 / IPv6 address */ + // Check for a valid IPv4 / IPv6 address if (!(fProxyIpValid = LookupNumeric(strAddrProxy.c_str(), addrProxy))) { disableOkButton(); pUiProxyIp->setValid(false); ui->statusLabel->setStyleSheet("QLabel { color: red; }"); ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); - } else { - enableOkButton(); - ui->statusLabel->clear(); + return; + } + // Check proxy port + if (!pUiProxyPort->hasAcceptableInput()){ + disableOkButton(); + ui->statusLabel->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel->setText(tr("The supplied proxy port is invalid.")); + return; } + + proxyType checkProxy = proxyType(addrProxy); + if (!checkProxy.IsValid()) { + disableOkButton(); + ui->statusLabel->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel->setText(tr("The supplied proxy settings are invalid.")); + return; + } + + enableOkButton(); + ui->statusLabel->clear(); } bool OptionsDialog::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::FocusOut) { if (object == ui->proxyIp || object == ui->proxyPort) { - emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt()); + emit proxyIpChecks(ui->proxyIp, ui->proxyPort); } } return QDialog::eventFilter(object, event); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 3fc49a818d..de043c857d 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -9,6 +9,7 @@ class OptionsModel; class QValidatedLineEdit; +class QLineEdit; QT_BEGIN_NAMESPACE class QDataWidgetMapper; @@ -47,10 +48,10 @@ private slots: void showRestartWarning(bool fPersistent = false); void clearStatusLabel(); - void doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, int nProxyPort); + void doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); signals: - void proxyIpChecks(QValidatedLineEdit* pUiProxyIp, int nProxyPort); + void proxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); private: Ui::OptionsDialog* ui; diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index b92cb60832..1da4dc3401 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -112,9 +112,14 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu connect(timerStakingToggleSync, SIGNAL(timeout()), this, SLOT(setStakingToggle())); timerStakingToggleSync->start(10000); - if (pwalletMain) { - bool isConsolidatedOn = pwalletMain->IsAutoConsolidateOn(); - ui->addNewFunds->setChecked(isConsolidatedOn); + if (!pwalletMain->IsMasternodeController()) { + if (pwalletMain) { + bool isConsolidatedOn = pwalletMain->IsAutoConsolidateOn(); + ui->addNewFunds->setChecked(isConsolidatedOn); + } + } else { + ui->addNewFunds->setChecked(false); + ui->addNewFunds->setEnabled(false); } connect(ui->addNewFunds, SIGNAL(stateChanged(int)), this, SLOT(setAutoConsolidate(int))); } @@ -481,6 +486,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) CWallet::MINIMUM_STAKE_AMOUNT, CWallet::MINIMUM_STAKE_AMOUNT, nTime); if (success) { + nConsolidationTime = 1800; QString msg = "Consolidation transaction created!"; QMessageBox msgBox; msgBox.setWindowTitle("Information"); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 4b7edb6f91..a6fbab727a 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -22,6 +22,7 @@ #include #include #include +#include ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::ReceiveCoinsDialog), @@ -88,6 +89,10 @@ void ReceiveCoinsDialog::setModel(WalletModel* model) } void ReceiveCoinsDialog::loadAccount() { + QRect rec = QApplication::desktop()->availableGeometry(); + int screenWidth = rec.width(); + QString addr; + //Set reqAddress as the master stealth address std::vector addrList, accountList; CWallet* wl = model->getCWallet(); @@ -96,11 +101,14 @@ void ReceiveCoinsDialog::loadAccount() { for(size_t i = 0; i < addrList.size(); i++) { if (accountList[i] == "masteraccount") continue; bool isDuplicate = false; - QString addr = QString(accountList[i].c_str()) + " - " + QString(addrList[i].substr(0, 30).c_str()) + "..." + - QString(addrList[i].substr(addrList[i].length() - 30, 30).c_str()); + if (screenWidth <= 1280) { + //(truncated for screen with less availableGeometry than 1280px) + addr = QString(accountList[i].c_str()) + " - " + QString(addrList[i].substr(0, 30).c_str()) + "..." + QString(addrList[i].substr(addrList[i].length() - 30, 30).c_str()); + } else { + addr = QString(accountList[i].c_str()) + " - " + QString(addrList[i].c_str()); + } for (size_t i = 0; i < (size_t)ui->reqAddress->count(); i++) { - if (stringsList.contains(QString(addrList[i].substr(0, 30).c_str()) + "..." + - QString(addrList[i].substr(addrList[i].length() - 30, 30).c_str()))) { + if (stringsList.contains(QString(addrList[i].substr(0, 30).c_str()) + "..." + QString(addrList[i].substr(addrList[i].length() - 30, 30).c_str()))) { isDuplicate = true; break; } @@ -111,8 +119,12 @@ void ReceiveCoinsDialog::loadAccount() { } ui->reqAddress->addItems(stringsList); //Set lineEditAddress to Master Account address for copy to clipboard - ui->lineEditAddress->setText(QString(addrList[0].substr(0, 30).c_str()) + "..." + - QString(addrList[0].substr(addrList[0].length() - 30, 30).c_str())); + if (screenWidth <= 1024) { + //(truncated for screen with less availableGeometry than 1024px) + ui->lineEditAddress->setText(QString(addrList[0].substr(0, 30).c_str()) + "..." + QString(addrList[0].substr(addrList[0].length() - 30, 30).c_str())); + } else { + ui->lineEditAddress->setText(QString(addrList[0].c_str())); + } } ReceiveCoinsDialog::~ReceiveCoinsDialog() diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 2b93028cfa..14da4d5609 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -26,6 +26,7 @@ QComboBox:disabled, border: 1px solid rgb(51, 54, 54); }*/ QDialog { + min-width: 500px; background: qlineargradient( x1: 0 y1: 0, x2: 1 y2: 1, diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css index 93fde914e8..948ef84a39 100644 --- a/src/qt/res/css/Light.css +++ b/src/qt/res/css/Light.css @@ -47,6 +47,7 @@ QComboBox:disabled, } QDialog { + min-width: 500px; background-color: white; } diff --git a/src/qt/res/src/bitcoin.svg b/src/qt/res/src/bitcoin.svg index b8c7e19db5..14cf0c5e11 100644 --- a/src/qt/res/src/bitcoin.svg +++ b/src/qt/res/src/bitcoin.svg @@ -1,58 +1,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index eb0e7c440a..1f0f9bf97c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -47,8 +47,46 @@ SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent, Qt::WindowSy connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); - // #HIDE multisend + // Coin Control + connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); + connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); + connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString&)), this, SLOT(coinControlChangeEdited(const QString&))); + + // Coin Control: clipboard actions + QAction* clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction* clipboardAmountAction = new QAction(tr("Copy amount"), this); + QAction* clipboardFeeAction = new QAction(tr("Copy fee"), this); + QAction* clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); + QAction* clipboardBytesAction = new QAction(tr("Copy bytes"), this); + QAction* clipboardPriorityAction = new QAction(tr("Copy priority"), this); + QAction* clipboardLowOutputAction = new QAction(tr("Copy dust"), this); + QAction* clipboardChangeAction = new QAction(tr("Copy change"), this); + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); + connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); + connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee())); + connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee())); + connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes())); + connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority())); + connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput())); + connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange())); + ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); + ui->labelCoinControlAmount->addAction(clipboardAmountAction); + ui->labelCoinControlFee->addAction(clipboardFeeAction); + ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); + ui->labelCoinControlBytes->addAction(clipboardBytesAction); + ui->labelCoinControlPriority->addAction(clipboardPriorityAction); + ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); + ui->labelCoinControlChange->addAction(clipboardChangeAction); + + // #HIDE multisend / unused items ui->addButton->setVisible(false); + ui->checkBoxCoinControlChange->setVisible(false); + ui->lineEditCoinControlChange->setVisible(false); + ui->splitBlockCheckBox->setVisible(false); + ui->splitBlockLineEdit->setVisible(false); + ui->labelBlockSize->setVisible(false); + ui->labelBlockSizeText->setVisible(false); + ui->labelCoinControlInsuffFunds->setVisible(false); } void SendCoinsDialog::setClientModel(ClientModel* clientModel) @@ -92,12 +130,14 @@ SendCoinsDialog::~SendCoinsDialog(){ } void SendCoinsDialog::on_sendButton_clicked(){ - if (!ui->entries->count()) + if (!ui->entries->count()) return; SendCoinsEntry* form = qobject_cast(ui->entries->itemAt(0)->widget()); SendCoinsRecipient recipient = form->getValue(); QString address = recipient.address; + send_address = recipient.address; + send_amount = recipient.amount; bool isValidAddresss = (regex_match(address.toStdString(), regex("[a-zA-z0-9]+")))&&(address.length()==99||address.length()==110); bool isValidAmount = ((recipient.amount>0) && (recipient.amount<=model->getBalance())); @@ -124,10 +164,53 @@ void SendCoinsDialog::on_sendButton_clicked(){ return; } - QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Are You Sure?", "Are you sure you would like to send this transaction?", QMessageBox::Yes|QMessageBox::No); - if (reply == QMessageBox::Yes) { - } else { + // request unlock only if was locked or unlocked for mixing: + // this way we let users unlock by walletpassphrase or by menu + // and make many transactions while unlocking through this dialog + // will call relock + WalletModel::EncryptionStatus encStatus = model->getEncryptionStatus(); + if (encStatus == model->Locked || encStatus == model->UnlockedForAnonymizationOnly) { + WalletModel::UnlockContext ctx(model->requestUnlock(true)); + if (!ctx.isValid()) { + // Unlock wallet was cancelled + return; + } + } + + // Format confirmation message + QStringList formatted; + formatted.append("
"); + QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), recipient.amount)+""; + + QString recipientElement; + recipientElement.append(""+amount+"
"); + recipientElement.append("
to
"); + //if (rcp.label.length() > 0) + //recipientElement.append("
"+tr("Description")+":
"+GUIUtil::HtmlEscape(rcp.label)+"
"); + recipientElement.append("
"+tr("Destination")+":
"+recipient.address+"

"); + + formatted.append(recipientElement); + QString strFee = BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), (pwalletMain->ComputeFee(1, 1, MAX_RING_SIZE))); + QString questionString = "
"+tr("Are you sure you want to send?")+"
"; + questionString.append("%1"); + questionString.append("
"+tr("Estimated Transaction fee")+":
"); + questionString.append(strFee+"
"); + questionString.append("

"); + + CAmount txFee = pwalletMain->ComputeFee(1, 1, MAX_RING_SIZE); + CAmount totalAmount = send_amount + txFee; + + // Show total amount + all alternative units + questionString.append(tr("Total Amount = %1

") + .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + + // Display message box + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm Send Coins"), + questionString.arg(formatted.join("
")), + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + + if (retval != QMessageBox::Yes) { return; } @@ -155,8 +238,6 @@ void SendCoinsDialog::on_sendButton_clicked(){ } } - send_address = recipient.address; - send_amount = recipient.amount; bool status = pwalletMain->Read2FA(); if (!status) { sendTx(); @@ -178,7 +259,7 @@ void SendCoinsDialog::on_sendButton_clicked(){ } void SendCoinsDialog::sendTx() { - CWalletTx resultTx; + CWalletTx resultTx; bool success = false; try { success = pwalletMain->SendToStealthAddress( @@ -274,3 +355,154 @@ SendCoinsEntry* SendCoinsDialog::addEntry() bar->setSliderPosition(bar->maximum()); return entry; } +// Coin Control: copy label "Quantity" to clipboard +void SendCoinsDialog::coinControlClipboardQuantity() +{ + GUIUtil::setClipboard(ui->labelCoinControlQuantity->text()); +} + +// Coin Control: copy label "Amount" to clipboard +void SendCoinsDialog::coinControlClipboardAmount() +{ + GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); +} + +// Coin Control: copy label "Fee" to clipboard +void SendCoinsDialog::coinControlClipboardFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", "")); +} + +// Coin Control: copy label "After fee" to clipboard +void SendCoinsDialog::coinControlClipboardAfterFee() +{ + GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", "")); +} + +// Coin Control: copy label "Bytes" to clipboard +void SendCoinsDialog::coinControlClipboardBytes() +{ + GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); +} + +// Coin Control: copy label "Priority" to clipboard +void SendCoinsDialog::coinControlClipboardPriority() +{ + GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); +} + +// Coin Control: copy label "Dust" to clipboard +void SendCoinsDialog::coinControlClipboardLowOutput() +{ + GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text()); +} + +// Coin Control: copy label "Change" to clipboard +void SendCoinsDialog::coinControlClipboardChange() +{ + GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", "")); +} + +// Coin Control: settings menu - coin control enabled/disabled by user +void SendCoinsDialog::coinControlFeatureChanged(bool checked) +{ + ui->frameCoinControl->setVisible(checked); + + if (!checked && model) // coin control features disabled + CoinControlDialog::coinControl->SetNull(); + + if (checked) + coinControlUpdateLabels(); +} + +// Coin Control: button inputs -> show actual coin control dialog +void SendCoinsDialog::coinControlButtonClicked() +{ + CoinControlDialog dlg; + dlg.setModel(model); + dlg.exec(); + coinControlUpdateLabels(); +} + +// Coin Control: checkbox custom change address +void SendCoinsDialog::coinControlChangeChecked(int state) +{ + if (state == Qt::Unchecked) { + CoinControlDialog::coinControl->destChange = CNoDestination(); + ui->labelCoinControlChangeLabel->clear(); + } else + // use this to re-validate an already entered address + coinControlChangeEdited(ui->lineEditCoinControlChange->text()); + + ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked)); +} + +// Coin Control: custom change address changed +void SendCoinsDialog::coinControlChangeEdited(const QString& text) +{ + if (model && model->getAddressTableModel()) { + // Default to no change address until verified + CoinControlDialog::coinControl->destChange = CNoDestination(); + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); + + CBitcoinAddress addr = CBitcoinAddress(text.toStdString()); + + if (text.isEmpty()) // Nothing entered + { + ui->labelCoinControlChangeLabel->setText(""); + } else if (!addr.IsValid()) // Invalid address + { + ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid PIVX address")); + } else // Valid address + { + CPubKey pubkey; + CKeyID keyid; + addr.GetKeyID(keyid); + if (!model->getPubKey(keyid, pubkey)) // Unknown change address + { + ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); + } else // Known change address + { + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}"); + + // Query label + QString associatedLabel = model->getAddressTableModel()->labelForAddress(text); + if (!associatedLabel.isEmpty()) + ui->labelCoinControlChangeLabel->setText(associatedLabel); + else + ui->labelCoinControlChangeLabel->setText(tr("(no label)")); + + CoinControlDialog::coinControl->destChange = addr.Get(); + } + } + } +} + +// Coin Control: update labels +void SendCoinsDialog::coinControlUpdateLabels() +{ + if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + return; + + // set pay amounts + CoinControlDialog::payAmounts.clear(); + for (int i = 0; i < ui->entries->count(); ++i) { + SendCoinsEntry* entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if (entry) + CoinControlDialog::payAmounts.append(entry->getValue().amount); + } + + if (CoinControlDialog::coinControl->HasSelected()) { + // actual coin control calculation + CoinControlDialog::updateLabels(model, this); + + // show coin control stats + ui->labelCoinControlAutomaticallySelected->hide(); + ui->widgetCoinControl->show(); + } else { + // hide coin control stats + ui->labelCoinControlAutomaticallySelected->show(); + ui->widgetCoinControl->hide(); + ui->labelCoinControlInsuffFunds->hide(); + } +} diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 2810714b35..acffcd991a 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -60,6 +60,19 @@ private slots: void on_sendButton_clicked(); void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + void coinControlFeatureChanged(bool); + void coinControlButtonClicked(); + void coinControlChangeChecked(int); + void coinControlChangeEdited(const QString&); + void coinControlUpdateLabels(); + void coinControlClipboardQuantity(); + void coinControlClipboardAmount(); + void coinControlClipboardFee(); + void coinControlClipboardAfterFee(); + void coinControlClipboardBytes(); + void coinControlClipboardPriority(); + void coinControlClipboardLowOutput(); + void coinControlClipboardChange(); signals: diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 776db1f040..01a695c09f 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -818,6 +818,41 @@ UniValue invalidateblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } + return "Done"; +} + +UniValue resyncfrom(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "resyncfrom \"block height\"\n" + "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" + "\nArguments:\n" + "1. height (numeric, required) the hash of the block to mark as invalid\n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("resyncfrom", "\"height\"") + HelpExampleRpc("resyncfrom", "\"100000\"")); + + int height = params[0].get_int(); + CValidationState state; + + { + LOCK(cs_main); + if (chainActive.Height() < height) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid block height"); + + CBlockIndex* pblockindex = chainActive[height]; + InvalidateBlock(state, pblockindex); + } + + if (state.IsValid()) { + ActivateBestChain(state); + } + + if (!state.IsValid()) { + throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); + } + return NullUniValue; } @@ -855,7 +890,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return NullUniValue; + return "Done"; } UniValue getinvalid (const UniValue& params, bool fHelp) @@ -980,3 +1015,26 @@ UniValue getinvalid (const UniValue& params, bool fHelp) ret.push_back(obj); return ret; } + +UniValue setmaxreorgdepth(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "setmaxreorgdepth \n" + "\nSet max reorganization depth to a value.\n" + "\nArguments:\n" + "1. num (numeric, required) the number of blocks\n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("setmaxreorgdepth", "100") + HelpExampleRpc("setmaxreorgdepth", "100")); + + int num = params[0].get_int(); + if (num <= 5) + throw runtime_error("Invalid number"); + { + LOCK(cs_main); + Params().ChangeMaxReorg(num); + } + + return NullUniValue; +} diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 8933cf7f67..9fef0cdaf7 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -38,6 +38,7 @@ static const CRPCConvertParam vRPCConvertParams[] = {"getnetworkhashps", 0}, {"getnetworkhashps", 1}, {"sendtoaddress", 1}, + {"rescan", 0}, {"rescanwallettransactions", 0}, {"sendtostealthaddress", 1}, {"sendtoaddressix", 1}, @@ -54,6 +55,8 @@ static const CRPCConvertParam vRPCConvertParams[] = {"getbalances", 0}, {"getbalance", 2}, {"getblockhash", 0}, + {"setmaxreorgdepth", 0}, + {"resyncfrom", 0}, {"setdecoyconfirmation", 0}, {"getrawtransactionbyblockheight", 0}, {"move", 2}, @@ -68,7 +71,7 @@ static const CRPCConvertParam vRPCConvertParams[] = {"unlockwallet", 1}, {"unlockwallet", 2}, {"getblocktemplate", 0}, - {"getpoablocktemplate", 0}, + {"getpoablocktemplate", 0}, {"setminingnbits", 0}, {"setminingnbits", 1}, {"generateintegratedaddress", 0}, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 0285c55d11..babce3ee28 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -197,7 +197,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) GenerateDapscoins(fGenerate, pwalletMain, nGenProcLimit); } - return NullUniValue; + return "Done"; } diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index d55ce5c9ac..4783ce240e 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -54,7 +54,7 @@ UniValue ping(const UniValue& params, bool fHelp) pNode->fPingQueued = true; } - return NullUniValue; + return "Done"; } static void CopyNodeStats(std::vector& vstats) @@ -199,7 +199,7 @@ UniValue addnode(const UniValue& params, bool fHelp) vAddedNodes.erase(it); } - return NullUniValue; + return "Done"; } UniValue disconnectnode(const UniValue& params, bool fHelp) @@ -218,7 +218,7 @@ UniValue disconnectnode(const UniValue& params, bool fHelp) if (pNode == NULL) throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); pNode->CloseSocketDisconnect(); - return NullUniValue; + return "Done"; } UniValue getaddednodeinfo(const UniValue& params, bool fHelp) @@ -483,7 +483,7 @@ UniValue setban(const UniValue& params, bool fHelp) } DumpBanlist(); //store banlist to disk uiInterface.BannedListChanged(); - return NullUniValue; + return "Done"; } UniValue listbanned(const UniValue& params, bool fHelp) @@ -525,5 +525,5 @@ UniValue clearbanned(const UniValue& params, bool fHelp) CNode::ClearBanned(); DumpBanlist(); //store banlist to disk uiInterface.BannedListChanged(); - return NullUniValue; + return "Done"; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 3f54cba342..8819719c67 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -107,6 +107,9 @@ static inline int64_t roundint64(double d) { } CAmount AmountFromValue(const UniValue& value) { + if (!value.isNum()) + throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number"); + double dAmount = value.get_real(); if (dAmount <= 0.0 || dAmount > Params().MAX_MONEY) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); @@ -287,6 +290,8 @@ static const CRPCCommand vRPCCommands[] = {"blockchain", "getblockcount", &getblockcount, true, false, false}, {"blockchain", "getblock", &getblock, true, false, false}, {"blockchain", "getblockhash", &getblockhash, true, false, false}, + {"blockchain", "setmaxreorgdepth", &setmaxreorgdepth, true, false, false}, + {"blockchain", "resyncfrom", &resyncfrom, true, false, false}, {"blockchain", "getblockheader", &getblockheader, false, false, false}, {"blockchain", "getchaintips", &getchaintips, true, false, false}, {"blockchain", "getdifficulty", &getdifficulty, true, false, false}, @@ -376,6 +381,7 @@ static const CRPCCommand vRPCCommands[] = {"wallet", "revealviewprivatekey", &revealviewprivatekey, true, false, true}, {"wallet", "revealspendprivatekey", &revealspendprivatekey, true, false, true}, {"wallet", "showtxprivatekeys", &showtxprivatekeys, true, false, true}, + {"wallet", "rescan", &rescan, true, false, true}, {"wallet", "rescanwallettransactions", &rescanwallettransactions, true, false, true}, {"wallet", "setdecoyconfirmation", &setdecoyconfirmation, true, false, true}, {"wallet", "getdecoyconfirmation", &getdecoyconfirmation, true, false, true}, diff --git a/src/rpcserver.h b/src/rpcserver.h index 631a811947..56a8054865 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -251,6 +251,7 @@ extern UniValue importkeys(const UniValue& params, bool fHelp); extern UniValue revealviewprivatekey(const UniValue& params, bool fHelp); extern UniValue revealspendprivatekey(const UniValue& params, bool fHelp); extern UniValue showtxprivatekeys(const UniValue& params, bool fHelp); +extern UniValue rescan(const UniValue& params, bool fHelp); extern UniValue rescanwallettransactions(const UniValue& params, bool fHelp); extern UniValue setdecoyconfirmation(const UniValue& params, bool fHelp); extern UniValue getdecoyconfirmation(const UniValue& params, bool fHelp); @@ -285,6 +286,8 @@ extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); extern UniValue getrawmempool(const UniValue& params, bool fHelp); extern UniValue getblockhash(const UniValue& params, bool fHelp); +extern UniValue setmaxreorgdepth(const UniValue& params, bool fHelp); +extern UniValue resyncfrom(const UniValue& params, bool fHelp); extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getfeeinfo(const UniValue& params, bool fHelp); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 3ed271b77d..a7c01c0ba2 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -797,7 +797,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; - walletdb.WriteAccountingEntry(debit); + pwalletMain->AddAccountingEntry(debit, walletdb); // Credit CAccountingEntry credit; @@ -807,7 +807,7 @@ UniValue movecmd(const UniValue& params, bool fHelp) credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; - walletdb.WriteAccountingEntry(credit); + pwalletMain->AddAccountingEntry(credit, walletdb); if (!walletdb.TxnCommit()) throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); @@ -1353,11 +1353,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - std::list acentries; - CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx* const pwtx = (*it).second.first; if (pwtx != 0) ListTransactions(*pwtx, strAccount, 0, true, ret, filter); @@ -1453,8 +1452,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) } } - list acentries; - CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + const list & acentries = pwalletMain->laccentries; for (const CAccountingEntry& entry : acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; @@ -1637,7 +1635,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) if (!BackupWallet(*pwalletMain, strDest)) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); - return NullUniValue; + return "Done"; } @@ -1723,14 +1721,23 @@ UniValue unlockwallet(const UniValue& params, bool fHelp) if (!pwalletMain->IsLocked() && pwalletMain->fWalletUnlockAnonymizeOnly && anonymizeOnly) throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); + // Get the timeout + int64_t nSleepTime = params[1].get_int64(); + // Timeout cannot be negative, otherwise it will relock immediately + if (nSleepTime < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); + } + // Clamp timeout + constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug? + if (nSleepTime > MAX_SLEEP_TIME) { + nSleepTime = MAX_SLEEP_TIME; + } + if (!pwalletMain->Unlock(strWalletPass, anonymizeOnly)) throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); pwalletMain->TopUpKeyPool(); - int64_t nSleepTime = params[1].get_int64(); - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = GetTime() + nSleepTime; if (nSleepTime > 0) { nWalletUnlockTime = GetTime () + nSleepTime; @@ -2918,19 +2925,45 @@ UniValue showtxprivatekeys(const UniValue& params, bool fHelp) { return ret; } +UniValue rescan(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 0) + throw runtime_error( + "rescan\n" + "\nRescan wallet transactions from the first block.\n" + "\nArguments:\n" + "\nResult:\n" + "\"scanned wallet transactions\" \n" + "\nExamples:\n" + + HelpExampleCli("rescan", "") + HelpExampleCli("rescan", "\"\"") + + HelpExampleRpc("rescan", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + int nHeight = 1; + if (!pwalletMain->RescanAfterUnlock(nHeight)) { + return "Failed to rescan"; + } + return "Done"; +} UniValue rescanwallettransactions(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 1) + if (fHelp || params.size() != 1) throw runtime_error( "rescanwallettransactions \"block height\"\n" - "\nRescan wallet transaction.\n" + "\nRescan wallet transactions from a certain block height.\n" "\nArguments:\n" "\nblock height: block height from which the chain will be rescanned\n" "\nResult:\n" - "\"scanned wallet transaction\" \n" + "\"scanned wallet transactions\" \n" "\nExamples:\n" + HelpExampleCli("rescanwallettransactions", "") + HelpExampleCli("rescanwallettransactions", "\"\"") + - HelpExampleCli("rescanwallettransactions", "") + HelpExampleRpc("rescanwallettransactions", "")); + HelpExampleRpc("rescanwallettransactions", "")); if (!pwalletMain) { //privacy wallet is already created diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 3ca529c3b8..992861b17b 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333333; ae.strOtherAccount = "b"; ae.strComment = ""; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx); @@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333336; ae.strOtherAccount = "c"; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333330; ae.strOtherAccount = "d"; ae.nOrderPos = pwalletMain->IncOrderPosNext(); - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333334; ae.strOtherAccount = "e"; ae.nOrderPos = -1; - walletdb.WriteAccountingEntry(ae); + pwalletMain->AddAccountingEntry(ae, walletdb); GetResults(walletdb, results); diff --git a/src/util.cpp b/src/util.cpp index cf0ceff8cc..61b8a2b95a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -130,7 +130,6 @@ bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; bool fDaemon = false; -bool fServer = false; string strMiscWarning; bool fLogTimestamps = false; bool fLogIPs = false; diff --git a/src/util.h b/src/util.h index ef07c33168..6ddbf7b863 100644 --- a/src/util.h +++ b/src/util.h @@ -49,7 +49,6 @@ extern std::map > mapMultiArgs; extern bool fDebug; extern bool fPrintToConsole; extern bool fPrintToDebugLog; -extern bool fServer; extern std::string strMiscWarning; extern bool fLogTimestamps; extern bool fLogIPs; diff --git a/src/wallet.cpp b/src/wallet.cpp index d2ac8e1dff..16737d0510 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -502,7 +502,7 @@ bool CWallet::RescanAfterUnlock(int fromHeight) return false; } CBlockIndex* pindex; - + if (fromHeight == 0) { LOCK2(cs_main, cs_wallet); //rescan from scanned position stored in database @@ -1004,29 +1004,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB* pwalletdb) return nRet; } -CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, std::string strAccount) -{ - AssertLockHeld(cs_wallet); // mapWallet - CWalletDB walletdb(strWalletFile); - - // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. - TxItems txOrdered; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - CWalletTx* wtx = &((*it).second); - txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); - } - acentries.clear(); - walletdb.ListAccountCreditDebit(strAccount, acentries); - for (CAccountingEntry& entry : acentries) { - txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); - } - - return txOrdered; -} - void CWallet::MarkDirty() { { @@ -1069,7 +1046,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) if (fFromLoadWallet) { mapWallet[hash] = wtxIn; - mapWallet[hash].BindWallet(this); + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); } else { LOCK(cs_wallet); @@ -1081,49 +1060,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) if (fInsertedNew) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(); - - wtx.nTimeSmart = wtx.nTimeReceived; - if (wtxIn.hashBlock != 0) { - if (mapBlockIndex.count(wtxIn.hashBlock)) { - if (mapBlockIndex[wtxIn.hashBlock] != NULL) { - wtx.nTimeReceived = mapBlockIndex[wtxIn.hashBlock]->nTime; - wtx.nTimeSmart = wtx.nTimeReceived; - } - int64_t latestNow = wtx.nTimeReceived; - int64_t latestEntry = 0; - { - // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future - int64_t latestTolerated = latestNow + 300; - std::list acentries; - TxItems txOrdered = OrderedTxItems(acentries); - for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx* const pwtx = (*it).second.first; - if (pwtx == &wtx) - continue; - CAccountingEntry* const pacentry = (*it).second.second; - int64_t nSmartTime; - if (pwtx) { - nSmartTime = pwtx->nTimeSmart; - if (!nSmartTime) - nSmartTime = pwtx->nTimeReceived; - } else - nSmartTime = pacentry->nTime; - if (nSmartTime <= latestTolerated) { - latestEntry = nSmartTime; - if (nSmartTime > latestNow) - latestNow = nSmartTime; - break; - } - } - } - - int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); - wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); - } else - LogPrintf("AddToWallet() : found %s in block %s not in index\n", - wtxIn.GetHash().ToString(), - wtxIn.hashBlock.ToString()); - } + wtx.nTimeSmart = ComputeTimeSmart(wtx); AddToSpends(hash); } @@ -1466,8 +1403,7 @@ int64_t CWalletTx::GetTxTime() const int64_t CWalletTx::GetComputedTxTime() const { LOCK(cs_main); - int64_t nTime = GetTxTime(); - return nTime; + return GetTxTime(); } int CWalletTx::GetRequestCount() const @@ -1592,8 +1528,9 @@ bool CWalletTx::WriteToDisk() * Scan the block chain (starting in pindexStart) for transactions * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. + * @returns -1 if process was cancelled or the number of tx added to the wallet. */ -int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate, int height) +int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate, bool fromStartup, int height) { int ret = 0; int64_t nNow = GetTime(); @@ -1617,6 +1554,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate, i if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); + if (fromStartup && ShutdownRequested()) { + return -1; + } + CBlock block; ReadBlockFromDisk(block, pindex); for (CTransaction& tx : block.vtx) { @@ -1628,6 +1569,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate, i nNow = GetTime(); LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(pindex)); } + if (ShutdownRequested()) { + LogPrintf("Rescan aborted at block %d. Please rescanwallettransactions %f from the Debug Console to continue.\n", pindex->nHeight, pindex->nHeight); + return false; + } } ShowProgress(_("Rescanning... Please do not interrupt this process as it could lead to a corrupt wallet."), 100); // hide progress dialog in GUI } @@ -2270,7 +2215,7 @@ StakingStatusError CWallet::StakingCoinStatus(CAmount& minFee, CAmount& maxFee) // It's possible for these to be conflicted via ancestors which we may never be able to detect if (nDepth <= 0) continue; - + if (pcoin->GetTxTime() > nTime) continue; for (unsigned int i = 0; i < pcoin->vout.size(); i++) { @@ -2349,20 +2294,20 @@ StakingStatusError CWallet::StakingCoinStatus(CAmount& minFee, CAmount& maxFee) if (!selectCoinRet) { //fail to even select coins to consolidation for reserve funds => ask to reduce return StakingStatusError::UNSTAKABLE_BALANCE_RESERVE_TOO_HIGH_CONSOLIDATION_FAILED; - } + } minFee += estimatedFee; maxFee += estimatedFee; return StakingStatusError::STAKABLE_NEED_CONSOLIDATION_WITH_RESERVE_BALANCE; } - + /* if (nReserveBalance == 0 && coinsOverThreshold.empty() && nBalance > MINIMUM_STAKE_AMOUNT) { if (nSpendableBalance < MINIMUM_STAKE_AMOUNT) { return StakingStatusError::UNSTAKABLE_DUE_TO_CONSILIDATION_FAILED; //not enough spendable balance - } + } set > setCoinsRet; CAmount nValueRet; int ringSize = MIN_RING_SIZE + secp256k1_rand32() % (MAX_RING_SIZE - MIN_RING_SIZE + 1); - bool selectCoinRet = SelectCoins(true, ringSize, 1, MINIMUM_STAKE_AMOUNT, setCoinsRet, nValueRet, NULL, AvailableCoinsType::ALL_COINS, false); + bool selectCoinRet = SelectCoins(true, ringSize, 1, MINIMUM_STAKE_AMOUNT, setCoinsRet, nValueRet, NULL, AvailableCoinsType::ALL_COINS, false); if (!selectCoinRet) { return StakingStatusError::UNSTAKABLE_DUE_TO_CONSILIDATION_FAILED; //not enough spendable balance } @@ -2371,12 +2316,12 @@ StakingStatusError CWallet::StakingCoinStatus(CAmount& minFee, CAmount& maxFee) } if (nReserveBalance > 0) { - + }*/ } } - + return ret; } @@ -2435,7 +2380,7 @@ bool CWallet::SelectCoinsMinConf(bool needFee, CAmount& feeNeeded, int ringSize, coinLowestLarger = coin; } } - + if (vValue.size() <= MAX_TX_INPUTS) { if (nTotalLower == nTargetValue + feeNeeded) { for (unsigned int i = 0; i < vValue.size(); ++i) { @@ -2460,7 +2405,7 @@ bool CWallet::SelectCoinsMinConf(bool needFee, CAmount& feeNeeded, int ringSize, nValueRet += coinLowestLarger.first; return true; } else { - CAmount maxFee = ComputeFee(50, numOut, ringSize); + CAmount maxFee = ComputeFee(50, numOut, ringSize); if (vValue.size() <= MAX_TX_INPUTS) { //putting all into the transaction string s = "CWallet::SelectCoinsMinConf best subset: "; @@ -2488,15 +2433,15 @@ bool CWallet::SelectCoinsMinConf(bool needFee, CAmount& feeNeeded, int ringSize, } LogPrintf("%s - total %s\n", s, FormatMoney(nValueRet)); return true; - } + } // Solve subset sum by stochastic approximation sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); //fees for 50 inputs - feeNeeded = ComputeFee(50, numOut, ringSize); + feeNeeded = ComputeFee(50, numOut, ringSize); //check if the sum of first 50 largest UTXOs > nTargetValue + nfeeNeeded for (unsigned int i = 0; i <= MAX_TX_INPUTS; i++) { - nValueRet += vValue[i].first; + nValueRet += vValue[i].first; } if (nValueRet < nTargetValue + feeNeeded) { nValueRet = 0; @@ -3143,12 +3088,12 @@ bool CWallet::CreateTransactionBulletProof(const CKey& txPrivDes, const CPubKey& else if (nReserveBalance <= nTotalValue) strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); } else if (nTotalValue >= nReserveBalance) { - strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); + strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); } else if (setCoins.size() > MAX_TX_INPUTS) { strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount."); } else if (nValueIn == 0) { strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount."); - } + } } else if (coin_type == ONLY_NOT1000000IFMN) { strFailReason = _("Unable to locate enough funds for this transaction that are not equal 10000 DAPS."); } else if (coin_type == ONLY_NONDENOMINATED_NOT1000000IFMN) { @@ -3902,7 +3847,7 @@ bool CWallet::makeRingCT(CTransaction& wtxNew, int ringSize, std::string& strFai bool CWallet::MakeShnorrSignature(CTransaction& wtxNew) { LOCK(cs_wallet); - { + { if (wtxNew.IsCoinAudit() || wtxNew.IsCoinBase()) return true; //this only generates shnorr signature if either wtxNew is a staking transaction or wtxNew only spends collateralized if (!wtxNew.IsCoinStake()) return true; @@ -4101,7 +4046,7 @@ bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringS } } myIndex = secp256k1_rand32() % (tx.vin[0].decoys.size() + 1) - 1; - + for (size_t i = 0; i < tx.vin.size(); i++) { COutPoint prevout = tx.vin[i].prevout; inSpendQueueOutpointsPerSession.push_back(prevout); @@ -4280,6 +4225,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int } for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setStakeCoins) { + // Make sure the wallet is unlocked and shutdown hasn't been requested + if (IsLocked() || ShutdownRequested()) + return false; + //make sure that enough time has elapsed between CBlockIndex* pindex = NULL; BlockMap::iterator it = mapBlockIndex.find(pcoin.first->hashBlock); @@ -4518,6 +4467,10 @@ bool CWallet::CreateCoinAudit(const CKeyStore& keystore, unsigned int nBits, int MilliSleep(10000); for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setAuditCoins) { + // Make sure the wallet is unlocked and shutdown hasn't been requested + if (IsLocked() || ShutdownRequested()) + return false; + //make sure that enough time has elapsed between CBlockIndex* pindex = NULL; BlockMap::iterator it = mapBlockIndex.find(pcoin.first->hashBlock); @@ -4699,6 +4652,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std: return true; } +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +{ + if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + return false; + + laccentries.push_back(acentry); + CAccountingEntry & entry = laccentries.back(); + wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + + return true; +} + CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) { CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes); @@ -5509,6 +5474,48 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off } +unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const +{ + unsigned int nTimeSmart = wtx.nTimeReceived; + if (wtx.hashBlock != 0) { + if (mapBlockIndex.count(wtx.hashBlock)) { + int64_t latestNow = wtx.nTimeReceived; + int64_t latestEntry = 0; + { + // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future + int64_t latestTolerated = latestNow + 300; + TxItems txOrdered = wtxOrdered; + for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { + CWalletTx* const pwtx = (*it).second.first; + if (pwtx == &wtx) + continue; + CAccountingEntry* const pacentry = (*it).second.second; + int64_t nSmartTime; + if (pwtx) { + nSmartTime = pwtx->nTimeSmart; + if (!nSmartTime) + nSmartTime = pwtx->nTimeReceived; + } else + nSmartTime = pacentry->nTime; + if (nSmartTime <= latestTolerated) { + latestEntry = nSmartTime; + if (nSmartTime > latestNow) + latestNow = nSmartTime; + break; + } + } + } + + int64_t blocktime = mapBlockIndex[wtx.hashBlock]->GetBlockTime(); + nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); + } else + LogPrintf("AddToWallet() : found %s in block %s not in index\n", + wtx.GetHash().ToString(), + wtx.hashBlock.ToString()); + } + return nTimeSmart; +} + bool CWallet::AddDestData(const CTxDestination& dest, const std::string& key, const std::string& value) { if (boost::get(&dest)) @@ -6092,8 +6099,8 @@ bool CWallet::estimateStakingConsolidationFees(CAmount& minFee, CAmount& maxFee) maxFee = 0; if (total < MINIMUM_STAKE_AMOUNT) false; //no staking sweeping will be created size_t numUTXOs = vCoins.size(); - - + + } int CWallet::MaxTxSizePerTx() { @@ -6103,7 +6110,8 @@ int CWallet::MaxTxSizePerTx() { bool CWallet::MultiSend() { - if (IsInitialBlockDownload() || IsLocked()) { + // Stop the old blocks from sending multisends + if (chainActive.Tip()->nTime < (GetAdjustedTime() - 300) || IsLocked()) { return false; } @@ -6114,11 +6122,12 @@ bool CWallet::MultiSend() std::vector vCoins; AvailableCoins(vCoins); - int stakeSent = 0; - int mnSent = 0; + + bool stakeSent = false; + bool mnSent = false; for (const COutput& out : vCoins) { //need output with precise confirm count - this is how we identify which is the output to send - if (out.tx->GetDepthInMainChain() != COINBASE_MATURITY + 1) + if (out.tx->GetDepthInMainChain() != Params().COINBASE_MATURITY() + 1) continue; COutPoint outpoint(out.tx->GetHash(), out.i); @@ -6145,10 +6154,10 @@ bool CWallet::MultiSend() } // create new coin control, populate it with the selected utxo, create sending vector - CCoinControl* cControl = new CCoinControl(); + CCoinControl cControl; COutPoint outpt(out.tx->GetHash(), out.i); - cControl->Select(outpt); - cControl->destChange = destMyAddress; + cControl.Select(outpt); + cControl.destChange = destMyAddress; CWalletTx wtx; CReserveKey keyChange(this); // this change address does not end up being used, because change is returned with coin control switch @@ -6170,7 +6179,7 @@ bool CWallet::MultiSend() //get the fee amount CWalletTx wtxdummy; string strErr; - CreateTransaction(vecSend, wtxdummy, keyChange, nFeeRet, strErr, cControl, ALL_COINS, false, CAmount(0)); + CreateTransaction(vecSend, wtxdummy, keyChange, nFeeRet, strErr, &cControl, ALL_COINS, false, CAmount(0)); CAmount nLastSendAmount = vecSend[vecSend.size() - 1].second; if (nLastSendAmount < nFeeRet + 500) { LogPrintf("%s: fee of %d is too large to insert into last output\n", __func__, nFeeRet + 500); @@ -6179,7 +6188,7 @@ bool CWallet::MultiSend() vecSend[vecSend.size() - 1].second = nLastSendAmount - nFeeRet - 500; // Create the transaction and commit it to the network - if (!CreateTransaction(vecSend, wtx, keyChange, nFeeRet, strErr, cControl, ALL_COINS, false, CAmount(0))) { + if (!CreateTransaction(vecSend, wtx, keyChange, nFeeRet, strErr, &cControl, ALL_COINS, false, CAmount(0))) { LogPrintf("MultiSend createtransaction failed\n"); return false; } @@ -6190,8 +6199,6 @@ bool CWallet::MultiSend() } else fMultiSendNotify = true; - delete cControl; - //write nLastMultiSendHeight to DB CWalletDB walletdb(strWalletFile); nLastMultiSendHeight = chainActive.Tip()->nHeight; @@ -6199,17 +6206,15 @@ bool CWallet::MultiSend() LogPrintf("Failed to write MultiSend setting to DB\n"); LogPrintf("MultiSend successfully sent\n"); + + //set which MultiSend triggered if (sendMSOnStake) - stakeSent++; + stakeSent = true; else - mnSent++; + mnSent = true; - //stop iterating if we are done - if (mnSent > 0 && stakeSent > 0) - return true; - if (stakeSent > 0 && !fMultiSendMasternodeReward) - return true; - if (mnSent > 0 && !fMultiSendStake) + //stop iterating if we have sent out all the MultiSend(s) + if ((stakeSent && mnSent) || (stakeSent && !fMultiSendMasternodeReward) || (mnSent && !fMultiSendStake)) return true; } diff --git a/src/wallet.h b/src/wallet.h index 7a8d304e8b..d3086edb47 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -388,6 +388,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface } mutable std::map mapWallet; + std::list laccentries; + + typedef std::pair TxPair; + typedef std::multimap TxItems; + TxItems wtxOrdered; int64_t nOrderPosNext; std::map mapRequestCount; @@ -517,6 +522,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool EncryptWallet(const SecureString& strWalletPassphrase); void GetKeyBirthTimes(std::map& mapKeyBirth) const; + unsigned int ComputeTimeSmart(const CWalletTx& wtx) const; /** * Increment the next transaction order id @@ -524,24 +530,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface */ int64_t IncOrderPosNext(CWalletDB* pwalletdb = NULL); - typedef std::pair TxPair; - typedef std::multimap TxItems; - - std::vector::const_iterator> notAbleToSpend; - - /** - * Get the wallet's activity log - * @return multimap of ordered transactions and accounting entries - * @warning Returned pointers are *only* valid within the scope of passed acentries - */ - TxItems OrderedTxItems(std::list& acentries, std::string strAccount = ""); void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet = false); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); void EraseFromWallet(const uint256& hash); - int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false, int height = -1); + int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false, bool fromStartup = false, int height = -1); void ReacceptWalletTransactions(); void ResendWalletTransactions(); CAmount GetBalance(); @@ -592,6 +587,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount &nFeeRet, std::string &strFailReason, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type = ALL_COINS, bool useIX = false, CAmount nFeePay = 0); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand = "tx"); + bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); std::string PrepareObfuscationDenominate(int minRounds, int maxRounds); int GenerateObfuscationOutputs(int nTotalValue, std::vector& vout); bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); @@ -1307,7 +1303,7 @@ class CWalletTx : public CMerkleTx } // Add masternode collaterals which are handled likc locked coins - if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) { + else if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) { nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); } diff --git a/src/walletdb.cpp b/src/walletdb.cpp index fbc22c664a..5e3124b5a1 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -403,7 +403,7 @@ bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccount return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry); } -bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) +bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry) { return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } @@ -908,6 +908,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (wss.fAnyUnordered) result = ReorderTransactions(pwallet); + pwallet->laccentries.clear(); + ListAccountCreditDebit("*", pwallet->laccentries); + for(CAccountingEntry& entry : pwallet->laccentries) { + pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry))); + } + return result; } diff --git a/src/walletdb.h b/src/walletdb.h index a7844332d1..7242a58278 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -154,6 +154,10 @@ class CWalletDB : public CDB bool WriteMinVersion(int nVersion); + /// This writes directly to the database, and will not update the CWallet's cached accounting entries! + /// Use wallet.AddAccountingEntry instead, to write *and* update its caches. + bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry); + bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); @@ -171,7 +175,6 @@ class CWalletDB : public CDB bool WriteCryptedHDChain(const CHDChain& chain); bool WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta); - bool WriteAccountingEntry(const CAccountingEntry& acentry); CAmount GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list& acentries); From 7ed9f6295bfb8893bf792aeadb84a25adb2d1a68 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 14 Dec 2019 14:48:13 -0500 Subject: [PATCH 0002/1888] Update logging --- src/main.cpp | 10 ++++------ src/masternodeman.cpp | 4 ++-- src/obfuscation.cpp | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0a032f6ab3..d85120a397 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1735,7 +1735,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa view.SetBackend(viewMemPool); // do we already have it? if (view.HaveCoins(hash)) { - LogPrintf("%s: Error: Hash exists in the mempool", __func__); + LogPrintf("%s: Error: Hash exists in the mempool\n", __func__); return false; } @@ -3263,9 +3263,8 @@ void static UpdateTip(CBlockIndex* pindexNew) nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + LogPrintf("UpdateTip: new best=%s height=%d version=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); @@ -3282,8 +3281,7 @@ void static UpdateTip(CBlockIndex* pindexNew) pindex = pindex->pprev; } if (nUpgraded > 0) - LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, - (int)CBlock::CURRENT_VERSION); + LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION); if (nUpgraded > 100 / 2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 8b819a855c..9e2ffeb088 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -864,7 +864,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } if (!VerifyShnorrKeyImageTxIn(vin, GetTxInSignatureHash(vin))) { - LogPrint("masternode","dsee - Shnorr Signature rejected%s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","dsee - Shnorr Signature rejected: %s\n", vin.prevout.hash.ToString()); return; } @@ -1064,7 +1064,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vRecv >> vin >> vchSig >> sigTime >> stop; if (!VerifyShnorrKeyImageTxIn(vin, GetTxInSignatureHash(vin))) { - LogPrintf("dsee - Shnorr Signature rejected%s\n", vin.prevout.hash.ToString()); + LogPrintf("dsee - Shnorr Signature rejected: %s\n", vin.prevout.hash.ToString()); return; } diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index c82d6c77e4..aec4b1bf40 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -2011,6 +2011,7 @@ void ThreadCheckObfuScationPool() // Make this thread recognisable as the wallet flushing thread RenameThread("dapscoin-obfuscation"); + LogPrintf("Masternodes thread started\n"); unsigned int c = 0; From 48df81f5e3202a91e52b3b9f9317f44a6492132d Mon Sep 17 00:00:00 2001 From: nashsclay Date: Sat, 14 Dec 2019 21:57:24 -0700 Subject: [PATCH 0003/1888] Multiple Critical Commits (#2) * Enable Executable for Compiling * Removed generated files * Updated .gitignore * Edited version info and remove Extra Makefile * Security Vulnerability * Allows other directories for data --- .gitignore | 15 +- Makefile1 | 1178 -- autogen.sh | 0 depends/config.guess | 0 depends/config.sub | 0 share/genbuild.sh | 0 src/leveldb/build_detect_platform | 0 src/secp256k1-mw/build-aux/compile | 348 - src/secp256k1-mw/build-aux/config.guess | 1476 --- src/secp256k1-mw/build-aux/config.sub | 1801 --- src/secp256k1-mw/build-aux/depcomp | 791 -- src/secp256k1-mw/build-aux/install-sh | 518 - src/secp256k1-mw/build-aux/ltmain.sh | 11147 ------------------- src/secp256k1-mw/build-aux/m4/libtool.m4 | 8369 -------------- src/secp256k1-mw/build-aux/missing | 215 - src/secp256k1-mw/build-aux/test-driver | 148 - src/secp256k1-mw/libsecp256k1.pc | 13 - src/secp256k1-mw/src/libsecp256k1-config.h | 181 - 18 files changed, 12 insertions(+), 26188 deletions(-) delete mode 100644 Makefile1 mode change 100644 => 100755 autogen.sh mode change 100644 => 100755 depends/config.guess mode change 100644 => 100755 depends/config.sub mode change 100644 => 100755 share/genbuild.sh mode change 100644 => 100755 src/leveldb/build_detect_platform delete mode 100644 src/secp256k1-mw/build-aux/compile delete mode 100644 src/secp256k1-mw/build-aux/config.guess delete mode 100644 src/secp256k1-mw/build-aux/config.sub delete mode 100644 src/secp256k1-mw/build-aux/depcomp delete mode 100644 src/secp256k1-mw/build-aux/install-sh delete mode 100644 src/secp256k1-mw/build-aux/ltmain.sh delete mode 100644 src/secp256k1-mw/build-aux/m4/libtool.m4 delete mode 100644 src/secp256k1-mw/build-aux/missing delete mode 100644 src/secp256k1-mw/build-aux/test-driver delete mode 100644 src/secp256k1-mw/libsecp256k1.pc delete mode 100644 src/secp256k1-mw/src/libsecp256k1-config.h diff --git a/.gitignore b/.gitignore index d524dde1aa..54d167c232 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,18 @@ libtool src/config/dapscoin-config.h src/config/dapscoin-config.h.in src/config/stamp-h1 +src/secp256k1-mw/build-aux/compile +src/secp256k1-mw/build-aux/config.guess +src/secp256k1-mw/build-aux/config.sub +src/secp256k1-mw/build-aux/depcomp +src/secp256k1-mw/build-aux/install-sh +src/secp256k1-mw/build-aux/ltmain.sh +src/secp256k1-mw/build-aux/m4/libtool.m4 +src/secp256k1-mw/build-aux/missing +src/secp256k1-mw/build-aux/test-driver +src/secp256k1-mw/gen_context +src/secp256k1-mw/libsecp256k1.pc +src/secp256k1-mw/src/libsecp256k1-config.h share/setup.nsi share/qt/Info.plist contrib/devtools/split-debug.sh @@ -135,6 +147,3 @@ CMakeLists.txt cmake-build-debug .vscode/* BackupWallet* - -#ChainParams -src/chainparams.cpp diff --git a/Makefile1 b/Makefile1 deleted file mode 100644 index 65563e5369..0000000000 --- a/Makefile1 +++ /dev/null @@ -1,1178 +0,0 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. -# Makefile. Generated from Makefile.in by configure. - -# Copyright (C) 1994-2014 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - - -# 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. - - -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/dapscoin -pkgincludedir = $(includedir)/dapscoin -pkglibdir = $(libdir)/dapscoin -pkglibexecdir = $(libexecdir)/dapscoin -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = x86_64-pc-linux-gnu -host_triplet = x86_64-pc-linux-gnu -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/build-aux/m4/ax_boost_base.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_chrono.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_filesystem.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_program_options.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_system.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_thread.m4 \ - $(top_srcdir)/build-aux/m4/ax_boost_unit_test_framework.m4 \ - $(top_srcdir)/build-aux/m4/ax_check_compile_flag.m4 \ - $(top_srcdir)/build-aux/m4/ax_check_link_flag.m4 \ - $(top_srcdir)/build-aux/m4/ax_check_preproc_flag.m4 \ - $(top_srcdir)/build-aux/m4/ax_cxx_compile_stdcxx.m4 \ - $(top_srcdir)/build-aux/m4/ax_gcc_func_attribute.m4 \ - $(top_srcdir)/build-aux/m4/ax_pthread.m4 \ - $(top_srcdir)/build-aux/m4/bitcoin_find_bdb48.m4 \ - $(top_srcdir)/build-aux/m4/bitcoin_qt.m4 \ - $(top_srcdir)/build-aux/m4/bitcoin_subdir_to_include.m4 \ - $(top_srcdir)/build-aux/m4/libtool.m4 \ - $(top_srcdir)/build-aux/m4/ltoptions.m4 \ - $(top_srcdir)/build-aux/m4/ltsugar.m4 \ - $(top_srcdir)/build-aux/m4/ltversion.m4 \ - $(top_srcdir)/build-aux/m4/lt~obsolete.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(dist_noinst_SCRIPTS) \ - $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/src/config/dapscoin-config.h -CONFIG_CLEAN_FILES = share/setup.nsi share/qt/Info.plist \ - src/test/buildenv.py qa/pull-tester/run-bitcoind-for-test.sh \ - qa/pull-tester/tests-config.sh contrib/devtools/split-debug.sh -CONFIG_CLEAN_VPATH_FILES = -SCRIPTS = $(dist_noinst_SCRIPTS) -AM_V_P = $(am__v_P_$(V)) -am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_$(V)) -am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_$(V)) -am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir dist dist-all distcheck -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope -DIST_SUBDIRS = $(SUBDIRS) -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/compile \ - $(top_srcdir)/build-aux/config.guess \ - $(top_srcdir)/build-aux/config.sub \ - $(top_srcdir)/build-aux/install-sh \ - $(top_srcdir)/build-aux/ltmain.sh \ - $(top_srcdir)/build-aux/missing \ - $(top_srcdir)/contrib/devtools/split-debug.sh.in \ - $(top_srcdir)/qa/pull-tester/run-bitcoind-for-test.sh.in \ - $(top_srcdir)/qa/pull-tester/tests-config.sh.in \ - $(top_srcdir)/share/qt/Info.plist.in \ - $(top_srcdir)/share/setup.nsi.in \ - $(top_srcdir)/src/config/dapscoin-config.h.in \ - $(top_srcdir)/src/test/buildenv.py.in COPYING INSTALL \ - build-aux/compile build-aux/config.guess build-aux/config.sub \ - build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \ - build-aux/missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -DIST_ARCHIVES = $(distdir).tar.gz -DIST_TARGETS = dist-gzip -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = find . -type f -print -ACLOCAL = ${SHELL} /home/dapscoin/DAPS/build-aux/missing aclocal-1.15 -AMTAR = $${TAR-tar} -AM_DEFAULT_VERBOSITY = 0 -AR = /usr/bin/ar -AUTOCONF = ${SHELL} /home/dapscoin/DAPS/build-aux/missing autoconf -AUTOHEADER = ${SHELL} /home/dapscoin/DAPS/build-aux/missing autoheader -AUTOMAKE = ${SHELL} /home/dapscoin/DAPS/build-aux/missing automake-1.15 -AWK = gawk -BDB_CPPFLAGS = -BDB_LIBS = -ldb_cxx-4.8 -BITCOIN_CLI_NAME = dapscoin-cli -BITCOIN_DAEMON_NAME = dapscoind -BITCOIN_GUI_NAME = dapscoin-qt -BITCOIN_TX_NAME = dapscoin-tx -BOOST_CHRONO_LIB = -lboost_chrono -BOOST_CPPFLAGS = -pthread -I/usr/include -BOOST_FILESYSTEM_LIB = -lboost_filesystem -BOOST_LDFLAGS = -L/usr/lib/x86_64-linux-gnu -BOOST_LIBS = -L/usr/lib/x86_64-linux-gnu -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread -lboost_chrono -BOOST_PROGRAM_OPTIONS_LIB = -lboost_program_options -BOOST_SYSTEM_LIB = -lboost_system -BOOST_THREAD_LIB = -lboost_thread -BOOST_UNIT_TEST_FRAMEWORK_LIB = -lboost_unit_test_framework -BREW = -BUILD_QT = -BUILD_TEST = test -BUILD_TEST_QT = -CC = gcc -CCACHE = -CCDEPMODE = depmode=gcc3 -CFLAGS = -g -O2 -CLIENT_VERSION_BUILD = 0 -CLIENT_VERSION_IS_RELEASE = true -CLIENT_VERSION_MAJOR = 3 -CLIENT_VERSION_MINOR = 0 -CLIENT_VERSION_REVISION = 6 -COMPARISON_TOOL_REORG_TESTS = 0 -COPYRIGHT_YEAR = 2017 -CPP = gcc -E -CPPFILT = /usr/bin/c++filt -CPPFLAGS = -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -CRYPTO_CFLAGS = -CRYPTO_LIBS = -lcrypto -CXX = g++ -std=c++11 -CXXCPP = g++ -std=c++11 -E -CXXDEPMODE = depmode=gcc3 -CXXFLAGS = -g -O2 -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wstack-protector -fstack-protector-all -fPIC -fvisibility=hidden -CYGPATH_W = echo -DEFS = -DHAVE_CONFIG_H -DEPDIR = .deps -DLLTOOL = false -DSYMUTIL = -DUMPBIN = -ECHO_C = -ECHO_N = -n -ECHO_T = -EGREP = /bin/grep -E -EVENT_CFLAGS = -EVENT_LIBS = -levent -EVENT_PTHREADS_CFLAGS = -pthread -EVENT_PTHREADS_LIBS = -levent_pthreads -levent -EXEEXT = -FGREP = /bin/grep -F -GCOV = /usr/bin/gcov -GENHTML = -GENISOIMAGE = -GIT = /usr/bin/git -GREP = /bin/grep -HAVE_CXX11 = 1 -HEXDUMP = /usr/bin/hexdump -IMAGEMAGICK_CONVERT = -INSTALL = /usr/bin/install -c -INSTALLNAMETOOL = -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_PROGRAM = ${INSTALL} -INSTALL_SCRIPT = ${INSTALL} -INSTALL_STRIP_PROGRAM = $(install_sh) -c -s -JAVA = -JAVA_COMPARISON_TOOL = -LCOV = -LD = /usr/bin/ld -m elf_x86_64 -LDFLAGS = -L/usr/local/lib -lsecp256k1_2 -static -Wl,-z,relro -Wl,-z,now -LEVELDB_CPPFLAGS = -LEVELDB_TARGET_FLAGS = -LIBLEVELDB = -LIBMEMENV = -LIBOBJS = -LIBS = -LIBTOOL = $(SHELL) $(top_builddir)/libtool -LIBTOOL_APP_LDFLAGS = -LIPO = -LN_S = ln -s -LRELEASE = -LTLIBOBJS = -LT_SYS_LIBRARY_PATH = -LUPDATE = -MAINT = -MAKEINFO = ${SHELL} /home/dapscoin/DAPS/build-aux/missing makeinfo -MAKENSIS = -MANIFEST_TOOL = : -MINIUPNPC_CPPFLAGS = -MINIUPNPC_LIBS = -lminiupnpc -MKDIR_P = /bin/mkdir -p -MOC = -MOC_DEFS = -DHAVE_CONFIG_H -I$(srcdir) -NM = /usr/bin/nm -B -NMEDIT = -OBJCOPY = /usr/bin/objcopy -OBJCXX = g++ -std=c++11 -OBJCXXDEPMODE = depmode=gcc3 -OBJCXXFLAGS = -g -O2 -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter -Wstack-protector -fstack-protector-all -fPIC -OBJDUMP = objdump -OBJEXT = o -OTOOL = -OTOOL64 = -PACKAGE = dapscoin -PACKAGE_BUGREPORT = www.dapscoin.org -PACKAGE_NAME = Dapscoin Core -PACKAGE_STRING = Dapscoin Core 3.0.6 -PACKAGE_TARNAME = dapscoin -PACKAGE_URL = -PACKAGE_VERSION = 3.0.6 -PATH_SEPARATOR = : -PKG_CONFIG = /usr/bin/pkg-config -PKG_CONFIG_LIBDIR = -PKG_CONFIG_PATH = -PORT = -PROTOBUF_CFLAGS = -PROTOBUF_LIBS = -PROTOC = -PTHREAD_CC = gcc -PTHREAD_CFLAGS = -pthread -PTHREAD_LIBS = -PYTHON = /usr/bin/python3 -PYTHONPATH = -QR_CFLAGS = -QR_LIBS = -QTPLATFORM_CFLAGS = -QTPLATFORM_LIBS = -QTPRINT_CFLAGS = -QTPRINT_LIBS = -QTXCBQPA_CFLAGS = -QTXCBQPA_LIBS = -QT_CFLAGS = -QT_DBUS_CFLAGS = -QT_DBUS_INCLUDES = -QT_DBUS_LIBS = -QT_INCLUDES = -QT_LDFLAGS = -QT_LIBS = -QT_PIE_FLAGS = -QT_SELECT = qt5 -QT_TEST_CFLAGS = -QT_TEST_INCLUDES = -QT_TEST_LIBS = -QT_TRANSLATION_DIR = -RANLIB = /usr/bin/ranlib -RCC = -READELF = /usr/bin/readelf -RELDFLAGS = -Wl,--exclude-libs,ALL -RSVG_CONVERT = -SED = /bin/sed -SET_MAKE = -SHELL = /bin/bash -SSL_CFLAGS = -SSL_LIBS = -lssl -STRIP = /usr/bin/strip -TESTDEFS = -TIFFCP = -UIC = -USE_QRCODE = -USE_UPNP = -VERSION = 3.0.6 -WINDOWS_BITS = -WINDRES = -X11XCB_CFLAGS = -X11XCB_LIBS = -XGETTEXT = -ZMQ_CFLAGS = -ZMQ_LIBS = -lzmq -abs_builddir = /home/dapscoin/DAPS -abs_srcdir = /home/dapscoin/DAPS -abs_top_builddir = /home/dapscoin/DAPS -abs_top_srcdir = /home/dapscoin/DAPS -ac_ct_AR = ar -ac_ct_CC = gcc -ac_ct_CXX = g++ -ac_ct_DUMPBIN = -ac_ct_OBJCXX = -am__include = include -am__leading_dot = . -am__quote = -am__tar = $${TAR-tar} chof - "$$tardir" -am__untar = $${TAR-tar} xf - -ax_pthread_config = -bindir = ${exec_prefix}/bin -build = x86_64-pc-linux-gnu -build_alias = -build_cpu = x86_64 -build_os = linux-gnu -build_vendor = pc -builddir = . -datadir = ${datarootdir} -datarootdir = ${prefix}/share -docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} -dvidir = ${docdir} -exec_prefix = ${prefix} -host = x86_64-pc-linux-gnu -host_alias = -host_cpu = x86_64 -host_os = linux-gnu -host_vendor = pc -htmldir = ${docdir} -includedir = ${prefix}/include -infodir = ${datarootdir}/info -install_sh = ${SHELL} /home/dapscoin/DAPS/build-aux/install-sh -libdir = ${exec_prefix}/lib -libexecdir = ${exec_prefix}/libexec -localedir = ${datarootdir}/locale -localstatedir = ${prefix}/var -mandir = ${datarootdir}/man -mkdir_p = $(MKDIR_P) -oldincludedir = /usr/include -pdfdir = ${docdir} -prefix = /usr/local -program_transform_name = s,x,x, -psdir = ${docdir} -runstatedir = ${localstatedir}/run -sbindir = ${exec_prefix}/sbin -sharedstatedir = ${prefix}/com -srcdir = . -subdirs = src/secp256k1 src/secp256k1-mw -sysconfdir = ${prefix}/etc -target_alias = -top_build_prefix = -top_builddir = . -top_srcdir = . -ACLOCAL_AMFLAGS = -I build-aux/m4 -SUBDIRS = src -GZIP_ENV = "-9n" -BITCOIND_BIN = $(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) -BITCOIN_QT_BIN = $(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) -BITCOIN_CLI_BIN = $(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) -BITCOIN_WIN_INSTALLER = $(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) -empty := -space := $(empty) $(empty) -OSX_APP = DAPScoin-Qt.app -OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME)) -OSX_DMG = $(OSX_VOLNAME).dmg -OSX_BACKGROUND_SVG = background.svg -OSX_BACKGROUND_IMAGE = background.tiff -OSX_BACKGROUND_IMAGE_DPIS = 36 72 -OSX_DSSTORE_GEN = $(top_srcdir)/contrib/macdeploy/custom_dsstore.py -OSX_DEPLOY_SCRIPT = $(top_srcdir)/contrib/macdeploy/macdeployqtplus -OSX_FANCY_PLIST = $(top_srcdir)/contrib/macdeploy/fancy.plist -OSX_INSTALLER_ICONS = $(top_srcdir)/src/qt/res/icons/bitcoin.icns -OSX_PLIST = $(top_builddir)/share/qt/Info.plist #not installed -OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW -DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) -WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ - $(top_srcdir)/share/pixmaps/nsis-header.bmp \ - $(top_srcdir)/share/pixmaps/nsis-wizard.bmp \ - $(top_srcdir)/doc/README_windows.txt - -OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ - $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_SVG) \ - $(OSX_DSSTORE_GEN) \ - $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ - $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh - -COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ - leveldb_baseline.info test_dapscoin_filtered.info total_coverage.info \ - baseline_filtered.info block_test_filtered.info \ - leveldb_baseline_filtered.info test_dapscoin_coverage.info test_dapscoin.info - -OSX_APP_BUILT = $(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ - $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ - $(OSX_APP)/Contents/MacOS/DAPScoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings - -APP_DIST_DIR = $(top_builddir)/dist -APP_DIST_EXTRAS = $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications -OSX_BACKGROUND_IMAGE_DPIFILES := $(foreach dpi,$(OSX_BACKGROUND_IMAGE_DPIS),dpi$(dpi).$(OSX_BACKGROUND_IMAGE)) -dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/pull-tester/run-bitcoin-cli qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) -CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) -all: all-recursive - -.SUFFIXES: -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -src/config/dapscoin-config.h: src/config/stamp-h1 - @test -f $@ || rm -f src/config/stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) src/config/stamp-h1 - -src/config/stamp-h1: $(top_srcdir)/src/config/dapscoin-config.h.in $(top_builddir)/config.status - @rm -f src/config/stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status src/config/dapscoin-config.h -$(top_srcdir)/src/config/dapscoin-config.h.in: $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f src/config/stamp-h1 - touch $@ - -distclean-hdr: - -rm -f src/config/dapscoin-config.h src/config/stamp-h1 -share/setup.nsi: $(top_builddir)/config.status $(top_srcdir)/share/setup.nsi.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -share/qt/Info.plist: $(top_builddir)/config.status $(top_srcdir)/share/qt/Info.plist.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -src/test/buildenv.py: $(top_builddir)/config.status $(top_srcdir)/src/test/buildenv.py.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -qa/pull-tester/run-bitcoind-for-test.sh: $(top_builddir)/config.status $(top_srcdir)/qa/pull-tester/run-bitcoind-for-test.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -qa/pull-tester/tests-config.sh: $(top_builddir)/config.status $(top_srcdir)/qa/pull-tester/tests-config.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -contrib/devtools/split-debug.sh: $(top_builddir)/config.status $(top_srcdir)/contrib/devtools/split-debug.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && $(MAKE) $(AM_MAKEFLAGS) distcheck-hook \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am -check: check-recursive -all-am: Makefile $(SCRIPTS) -installdirs: installdirs-recursive -installdirs-am: -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libtool clean-local mostlyclean-am - -distclean: distclean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-generic distclean-hdr \ - distclean-libtool distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: - -.MAKE: $(am__recursive_targets) install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ - am--refresh check check-am clean clean-cscope clean-generic \ - clean-libtool clean-local cscope cscopelist-am ctags ctags-am \ - dist dist-all dist-bzip2 dist-gzip dist-hook dist-lzip \ - dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \ - distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs installdirs-am \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am - -.PRECIOUS: Makefile - -.PHONY: deploy FORCE -export PYTHONPATH - -dist-hook: - -$(MAKE) -C $(top_distdir)/src/leveldb clean - -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean - -$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf - - -distcheck-hook: - $(MKDIR_P) $(top_distdir)/_build/src/leveldb - cp -rf $(top_srcdir)/src/leveldb/* $(top_distdir)/_build/src/leveldb/ - -$(MAKE) -C $(top_distdir)/_build/src/leveldb clean - -distcleancheck: - @: - -$(BITCOIN_WIN_INSTALLER): all-recursive - $(MKDIR_P) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_QT_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release - @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ - echo error: could not build $@ - @echo built $@ - -$(OSX_APP)/Contents/PkgInfo: - $(MKDIR_P) $(@D) - @echo "APPL????" > $@ - -$(OSX_APP)/Contents/Resources/empty.lproj: - $(MKDIR_P) $(@D) - @touch $@ - -$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST) - $(MKDIR_P) $(@D) - $(INSTALL_DATA) $< $@ - -$(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) - $(MKDIR_P) $(@D) - $(INSTALL_DATA) $< $@ - -$(OSX_APP)/Contents/MacOS/DAPScoin-Qt: $(BITCOIN_QT_BIN) - $(MKDIR_P) $(@D) - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ - -$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: - $(MKDIR_P) $(@D) - echo '{ CFBundleDisplayName = "$(PACKAGE_NAME)"; CFBundleName = "$(PACKAGE_NAME)"; }' > $@ - -osx_volname: - echo $(OSX_VOLNAME) >$@ - -#$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE) -# $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) - -#$(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) -# sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@ -#$(OSX_BACKGROUND_IMAGE)@2x.png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) -# sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 72 -p 72 -o $@ -#$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE).png $(OSX_BACKGROUND_IMAGE)@2x.png -# tiffutil -cathidpicheck $^ -out $@ - -#deploydir: $(OSX_DMG) - -$(APP_DIST_DIR)/Applications: - @rm -f $@ - @cd $(@D); $(LN_S) /Applications $(@F) - -$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/DAPScoin-Qt - -$(OSX_DMG): $(APP_DIST_EXTRAS) - $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -apple -o $@ dist - -dpi%.$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_SVG) - sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d $* -p $* | $(IMAGEMAGICK_CONVERT) - $@ -$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIFILES) - $(MKDIR_P) $(@D) - $(TIFFCP) -c none $(OSX_BACKGROUND_IMAGE_DPIFILES) $@ - -$(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) - $(PYTHON) $< "$@" "$(OSX_VOLNAME)" - -$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/DAPScoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) - INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 - -deploydir: $(APP_DIST_EXTRAS) - -#appbundle: $(OSX_APP_BUILT) -#deploy: $(OSX_DMG) -#deploy: $(BITCOIN_WIN_INSTALLER) - -$(BITCOIN_QT_BIN): FORCE - $(MAKE) -C src qt/$(@F) - -$(BITCOIND_BIN): FORCE - $(MAKE) -C src $(@F) - -$(BITCOIN_CLI_BIN): FORCE - $(MAKE) -C src $(@F) - -#baseline.info: -# $(LCOV) -c -i -d $(abs_builddir)/src -o $@ - -#baseline_filtered.info: baseline.info -# $(LCOV) -r $< "/usr/include/*" -o $@ - -#leveldb_baseline.info: baseline_filtered.info -# $(LCOV) -c -i -d $(abs_builddir)/src/leveldb -b $(abs_builddir)/src/leveldb -o $@ - -#leveldb_baseline_filtered.info: leveldb_baseline.info -# $(LCOV) -r $< "/usr/include/*" -o $@ - -#baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info -# $(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@ - -#test_dapscoin.info: baseline_filtered_combined.info -# $(MAKE) -C src/ check -# $(LCOV) -c -d $(abs_builddir)/src -t test_dapscoin -o $@ -# $(LCOV) -z -d $(abs_builddir)/src -# $(LCOV) -z -d $(abs_builddir)/src/leveldb - -#test_dapscoin_filtered.info: test_dapscoin.info -# $(LCOV) -r $< "/usr/include/*" -o $@ - -#block_test.info: test_dapscoin_filtered.info -# $(MKDIR_P) qa/tmp -# -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 -# $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ -# $(LCOV) -z -d $(abs_builddir)/src -# $(LCOV) -z -d $(abs_builddir)/src/leveldb - -#block_test_filtered.info: block_test.info -# $(LCOV) -r $< "/usr/include/*" -o $@ - -#test_dapscoin_coverage.info: baseline_filtered_combined.info test_dapscoin_filtered.info -# $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_dapscoin_filtered.info -o $@ - -#total_coverage.info: baseline_filtered_combined.info test_dapscoin_filtered.info block_test_filtered.info -# $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_dapscoin_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt - -#test_dapscoin.coverage/.dirstamp: test_dapscoin_coverage.info -# $(GENHTML) -s $< -o $(@D) -# @touch $@ - -#total.coverage/.dirstamp: total_coverage.info -# $(GENHTML) -s $< -o $(@D) -# @touch $@ - -#cov: test_dapscoin.coverage/.dirstamp total.coverage/.dirstamp - -.INTERMEDIATE: $(COVERAGE_INFO) - -clean-local: - rm -rf test_dapscoin.coverage/ total.coverage/ $(OSX_APP) - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/autogen.sh b/autogen.sh old mode 100644 new mode 100755 diff --git a/depends/config.guess b/depends/config.guess old mode 100644 new mode 100755 diff --git a/depends/config.sub b/depends/config.sub old mode 100644 new mode 100755 diff --git a/share/genbuild.sh b/share/genbuild.sh old mode 100644 new mode 100755 diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform old mode 100644 new mode 100755 diff --git a/src/secp256k1-mw/build-aux/compile b/src/secp256k1-mw/build-aux/compile deleted file mode 100644 index 99e50524b3..0000000000 --- a/src/secp256k1-mw/build-aux/compile +++ /dev/null @@ -1,348 +0,0 @@ -#! /bin/sh -# Wrapper for compilers which do not understand '-c -o'. - -scriptversion=2018-03-07.03; # UTC - -# Copyright (C) 1999-2018 Free Software Foundation, Inc. -# Written by Tom Tromey . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -nl=' -' - -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent tools from complaining about whitespace usage. -IFS=" "" $nl" - -file_conv= - -# func_file_conv build_file lazy -# Convert a $build file to $host form and store it in $file -# Currently only supports Windows hosts. If the determined conversion -# type is listed in (the comma separated) LAZY, no conversion will -# take place. -func_file_conv () -{ - file=$1 - case $file in - / | /[!/]*) # absolute file, and not a UNC file - if test -z "$file_conv"; then - # lazily determine how to convert abs files - case `uname -s` in - MINGW*) - file_conv=mingw - ;; - CYGWIN*) - file_conv=cygwin - ;; - *) - file_conv=wine - ;; - esac - fi - case $file_conv/,$2, in - *,$file_conv,*) - ;; - mingw/*) - file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` - ;; - cygwin/*) - file=`cygpath -m "$file" || echo "$file"` - ;; - wine/*) - file=`winepath -w "$file" || echo "$file"` - ;; - esac - ;; - esac -} - -# func_cl_dashL linkdir -# Make cl look for libraries in LINKDIR -func_cl_dashL () -{ - func_file_conv "$1" - if test -z "$lib_path"; then - lib_path=$file - else - lib_path="$lib_path;$file" - fi - linker_opts="$linker_opts -LIBPATH:$file" -} - -# func_cl_dashl library -# Do a library search-path lookup for cl -func_cl_dashl () -{ - lib=$1 - found=no - save_IFS=$IFS - IFS=';' - for dir in $lib_path $LIB - do - IFS=$save_IFS - if $shared && test -f "$dir/$lib.dll.lib"; then - found=yes - lib=$dir/$lib.dll.lib - break - fi - if test -f "$dir/$lib.lib"; then - found=yes - lib=$dir/$lib.lib - break - fi - if test -f "$dir/lib$lib.a"; then - found=yes - lib=$dir/lib$lib.a - break - fi - done - IFS=$save_IFS - - if test "$found" != yes; then - lib=$lib.lib - fi -} - -# func_cl_wrapper cl arg... -# Adjust compile command to suit cl -func_cl_wrapper () -{ - # Assume a capable shell - lib_path= - shared=: - linker_opts= - for arg - do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - eat=1 - case $2 in - *.o | *.[oO][bB][jJ]) - func_file_conv "$2" - set x "$@" -Fo"$file" - shift - ;; - *) - func_file_conv "$2" - set x "$@" -Fe"$file" - shift - ;; - esac - ;; - -I) - eat=1 - func_file_conv "$2" mingw - set x "$@" -I"$file" - shift - ;; - -I*) - func_file_conv "${1#-I}" mingw - set x "$@" -I"$file" - shift - ;; - -l) - eat=1 - func_cl_dashl "$2" - set x "$@" "$lib" - shift - ;; - -l*) - func_cl_dashl "${1#-l}" - set x "$@" "$lib" - shift - ;; - -L) - eat=1 - func_cl_dashL "$2" - ;; - -L*) - func_cl_dashL "${1#-L}" - ;; - -static) - shared=false - ;; - -Wl,*) - arg=${1#-Wl,} - save_ifs="$IFS"; IFS=',' - for flag in $arg; do - IFS="$save_ifs" - linker_opts="$linker_opts $flag" - done - IFS="$save_ifs" - ;; - -Xlinker) - eat=1 - linker_opts="$linker_opts $2" - ;; - -*) - set x "$@" "$1" - shift - ;; - *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) - func_file_conv "$1" - set x "$@" -Tp"$file" - shift - ;; - *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) - func_file_conv "$1" mingw - set x "$@" "$file" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift - done - if test -n "$linker_opts"; then - linker_opts="-link$linker_opts" - fi - exec "$@" $linker_opts - exit 1 -} - -eat= - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: compile [--help] [--version] PROGRAM [ARGS] - -Wrapper for compilers which do not understand '-c -o'. -Remove '-o dest.o' from ARGS, run PROGRAM with the remaining -arguments, and rename the output as expected. - -If you are trying to build a whole package this is not the -right script to run: please start by reading the file 'INSTALL'. - -Report bugs to . -EOF - exit $? - ;; - -v | --v*) - echo "compile $scriptversion" - exit $? - ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ - icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) - func_cl_wrapper "$@" # Doesn't return... - ;; -esac - -ofile= -cfile= - -for arg -do - if test -n "$eat"; then - eat= - else - case $1 in - -o) - # configure might choose to run compile as 'compile cc -o foo foo.c'. - # So we strip '-o arg' only if arg is an object. - eat=1 - case $2 in - *.o | *.obj) - ofile=$2 - ;; - *) - set x "$@" -o "$2" - shift - ;; - esac - ;; - *.c) - cfile=$1 - set x "$@" "$1" - shift - ;; - *) - set x "$@" "$1" - shift - ;; - esac - fi - shift -done - -if test -z "$ofile" || test -z "$cfile"; then - # If no '-o' option was seen then we might have been invoked from a - # pattern rule where we don't need one. That is ok -- this is a - # normal compilation that the losing compiler can handle. If no - # '.c' file was seen then we are probably linking. That is also - # ok. - exec "$@" -fi - -# Name of file we expect compiler to create. -cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` - -# Create the lock directory. -# Note: use '[/\\:.-]' here to ensure that we don't use the same name -# that we are using for the .o file. Also, base the name on the expected -# object file name, since that is what matters with a parallel build. -lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d -while true; do - if mkdir "$lockdir" >/dev/null 2>&1; then - break - fi - sleep 1 -done -# FIXME: race condition here if user kills between mkdir and trap. -trap "rmdir '$lockdir'; exit 1" 1 2 15 - -# Run the compile. -"$@" -ret=$? - -if test -f "$cofile"; then - test "$cofile" = "$ofile" || mv "$cofile" "$ofile" -elif test -f "${cofile}bj"; then - test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" -fi - -rmdir "$lockdir" -exit $ret - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/secp256k1-mw/build-aux/config.guess b/src/secp256k1-mw/build-aux/config.guess deleted file mode 100644 index 256083a70d..0000000000 --- a/src/secp256k1-mw/build-aux/config.guess +++ /dev/null @@ -1,1476 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright 1992-2018 Free Software Foundation, Inc. - -timestamp='2018-03-08' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). -# -# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. -# -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess -# -# Please send patches to . - - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright 1992-2018 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > "$dummy.c" ; - for c in cc gcc c89 c99 ; do - if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -case "$UNAME_SYSTEM" in -Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu - - eval "$set_cc_for_build" - cat <<-EOF > "$dummy.c" - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #else - LIBC=gnu - #endif - EOF - eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" - - # If ldd exists, use it to detect musl libc. - if command -v ldd >/dev/null && \ - ldd --version 2>&1 | grep -q ^musl - then - LIBC=musl - fi - ;; -esac - -# Note: order is significant - the case branches are not exclusive. - -case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - "/sbin/$sysctl" 2>/dev/null || \ - "/usr/sbin/$sysctl" 2>/dev/null || \ - echo unknown)` - case "$UNAME_MACHINE_ARCH" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - earmv*) - arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` - machine="${arch}${endian}"-unknown - ;; - *) machine="$UNAME_MACHINE_ARCH"-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently (or will in the future) and ABI. - case "$UNAME_MACHINE_ARCH" in - earm*) - os=netbsdelf - ;; - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval "$set_cc_for_build" - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # Determine ABI tags. - case "$UNAME_MACHINE_ARCH" in - earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "$UNAME_VERSION" in - Debian*) - release='-gnu' - ;; - *) - release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi}" - exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" - exit ;; - *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" - exit ;; - *:MidnightBSD:*:*) - echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" - exit ;; - *:ekkoBSD:*:*) - echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" - exit ;; - *:SolidBSD:*:*) - echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd"$UNAME_RELEASE" - exit ;; - *:MirBSD:*:*) - echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" - exit ;; - *:Sortix:*:*) - echo "$UNAME_MACHINE"-unknown-sortix - exit ;; - *:Redox:*:*) - echo "$UNAME_MACHINE"-unknown-redox - exit ;; - mips:OSF1:*.*) - echo mips-dec-osf1 - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE=alpha ;; - "EV4.5 (21064)") - UNAME_MACHINE=alpha ;; - "LCA4 (21066/21068)") - UNAME_MACHINE=alpha ;; - "EV5 (21164)") - UNAME_MACHINE=alphaev5 ;; - "EV5.6 (21164A)") - UNAME_MACHINE=alphaev56 ;; - "EV5.6 (21164PC)") - UNAME_MACHINE=alphapca56 ;; - "EV5.7 (21164PC)") - UNAME_MACHINE=alphapca57 ;; - "EV6 (21264)") - UNAME_MACHINE=alphaev6 ;; - "EV6.7 (21264A)") - UNAME_MACHINE=alphaev67 ;; - "EV6.8CB (21264C)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8AL (21264B)") - UNAME_MACHINE=alphaev68 ;; - "EV6.8CX (21264D)") - UNAME_MACHINE=alphaev68 ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE=alphaev69 ;; - "EV7 (21364)") - UNAME_MACHINE=alphaev7 ;; - "EV7.9 (21364A)") - UNAME_MACHINE=alphaev79 ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo "$UNAME_MACHINE"-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix"$UNAME_RELEASE" - exit ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - s390x:SunOS:*:*) - echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" - exit ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" - exit ;; - i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux"$UNAME_RELEASE" - exit ;; - i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval "$set_cc_for_build" - SUN_ARCH=i386 - # If there is a compiler, see if it is configured for 64-bit objects. - # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. - # This test works for both compilers. - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - SUN_ARCH=x86_64 - fi - fi - echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos"$UNAME_RELEASE" - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos"$UNAME_RELEASE" - ;; - sun4) - echo sparc-sun-sunos"$UNAME_RELEASE" - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos"$UNAME_RELEASE" - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint"$UNAME_RELEASE" - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint"$UNAME_RELEASE" - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint"$UNAME_RELEASE" - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint"$UNAME_RELEASE" - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten"$UNAME_RELEASE" - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten"$UNAME_RELEASE" - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix"$UNAME_RELEASE" - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix"$UNAME_RELEASE" - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix"$UNAME_RELEASE" - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval "$set_cc_for_build" - sed 's/^ //' << EOF > "$dummy.c" -#ifdef __cplusplus -#include /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && - dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`"$dummy" "$dummyarg"` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos"$UNAME_RELEASE" - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] - then - if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ - [ "$TARGET_BINARY_INTERFACE"x = x ] - then - echo m88k-dg-dgux"$UNAME_RELEASE" - else - echo m88k-dg-dguxbcs"$UNAME_RELEASE" - fi - else - echo i586-dg-dgux"$UNAME_RELEASE" - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" - fi - echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval "$set_cc_for_build" - sed 's/^ //' << EOF > "$dummy.c" - #include - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/lslpp ] ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` - else - IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" - fi - echo "$IBM_ARCH"-ibm-aix"$IBM_REV" - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` - case "$UNAME_MACHINE" in - 9000/31?) HP_ARCH=m68000 ;; - 9000/[34]??) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "$sc_cpu_version" in - 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 - 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "$sc_kernel_bits" in - 32) HP_ARCH=hppa2.0n ;; - 64) HP_ARCH=hppa2.0w ;; - '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "$HP_ARCH" = "" ]; then - eval "$set_cc_for_build" - sed 's/^ //' << EOF > "$dummy.c" - - #define _HPUX_SOURCE - #include - #include - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ "$HP_ARCH" = hppa2.0w ] - then - eval "$set_cc_for_build" - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | - grep -q __LP64__ - then - HP_ARCH=hppa2.0w - else - HP_ARCH=hppa64 - fi - fi - echo "$HP_ARCH"-hp-hpux"$HPUX_REV" - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux"$HPUX_REV" - exit ;; - 3050*:HI-UX:*:*) - eval "$set_cc_for_build" - sed 's/^ //' << EOF > "$dummy.c" - #include - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo "$UNAME_MACHINE"-unknown-osf1mk - else - echo "$UNAME_MACHINE"-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi"$UNAME_RELEASE" - exit ;; - *:BSD/OS:*:*) - echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" - exit ;; - *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` - case "$UNAME_PROCESSOR" in - amd64) - UNAME_PROCESSOR=x86_64 ;; - i386) - UNAME_PROCESSOR=i586 ;; - esac - echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" - exit ;; - i*:CYGWIN*:*) - echo "$UNAME_MACHINE"-pc-cygwin - exit ;; - *:MINGW64*:*) - echo "$UNAME_MACHINE"-pc-mingw64 - exit ;; - *:MINGW*:*) - echo "$UNAME_MACHINE"-pc-mingw32 - exit ;; - *:MSYS*:*) - echo "$UNAME_MACHINE"-pc-msys - exit ;; - i*:PW*:*) - echo "$UNAME_MACHINE"-pc-pw32 - exit ;; - *:Interix*:*) - case "$UNAME_MACHINE" in - x86) - echo i586-pc-interix"$UNAME_RELEASE" - exit ;; - authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix"$UNAME_RELEASE" - exit ;; - IA64) - echo ia64-unknown-interix"$UNAME_RELEASE" - exit ;; - esac ;; - i*:UWIN*:*) - echo "$UNAME_MACHINE"-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" - exit ;; - *:GNU:*:*) - # the GNU system - echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" - exit ;; - i*86:Minix:*:*) - echo "$UNAME_MACHINE"-pc-minix - exit ;; - aarch64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - aarch64_be:Linux:*:*) - UNAME_MACHINE=aarch64_be - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - arm*:Linux:*:*) - eval "$set_cc_for_build" - if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_EABI__ - then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - else - if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ARM_PCS_VFP - then - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi - else - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf - fi - fi - exit ;; - avr32*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - cris:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; - crisv32:Linux:*:*) - echo "$UNAME_MACHINE"-axis-linux-"$LIBC" - exit ;; - e2k:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - frv:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - hexagon:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - i*86:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; - ia64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - k1om:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - m32r*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - m68*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - mips:Linux:*:* | mips64:Linux:*:*) - eval "$set_cc_for_build" - sed 's/^ //' << EOF > "$dummy.c" - #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" - test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } - ;; - mips64el:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - openrisc*:Linux:*:*) - echo or1k-unknown-linux-"$LIBC" - exit ;; - or32:Linux:*:* | or1k*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - padre:Linux:*:*) - echo sparc-unknown-linux-"$LIBC" - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-"$LIBC" - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; - PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; - *) echo hppa-unknown-linux-"$LIBC" ;; - esac - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-"$LIBC" - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-"$LIBC" - exit ;; - ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-"$LIBC" - exit ;; - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-"$LIBC" - exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" - exit ;; - sh64*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - sh*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - tile*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - vax:Linux:*:*) - echo "$UNAME_MACHINE"-dec-linux-"$LIBC" - exit ;; - x86_64:Linux:*:*) - echo "$UNAME_MACHINE"-pc-linux-"$LIBC" - exit ;; - xtensa*:Linux:*:*) - echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" - exit ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo "$UNAME_MACHINE"-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo "$UNAME_MACHINE"-unknown-stop - exit ;; - i*86:atheos:*:*) - echo "$UNAME_MACHINE"-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo "$UNAME_MACHINE"-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos"$UNAME_RELEASE" - exit ;; - i*86:*DOS:*:*) - echo "$UNAME_MACHINE"-pc-msdosdjgpp - exit ;; - i*86:*:4.*:*) - UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" - else - echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" - else - echo "$UNAME_MACHINE"-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. - # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configure will decide that - # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - NCR*:*:4.2:* | MPRAS*:*:4.2:*) - OS_REL='.3' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } - /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos"$UNAME_RELEASE" - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos"$UNAME_RELEASE" - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos"$UNAME_RELEASE" - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos"$UNAME_RELEASE" - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv"$UNAME_RELEASE" - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo "$UNAME_MACHINE"-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo "$UNAME_MACHINE"-stratus-vos - exit ;; - *:VOS:*:*) - # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux"$UNAME_RELEASE" - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv"$UNAME_RELEASE" - else - echo mips-unknown-sysv"$UNAME_RELEASE" - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux"$UNAME_RELEASE" - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux"$UNAME_RELEASE" - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux"$UNAME_RELEASE" - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux"$UNAME_RELEASE" - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux"$UNAME_RELEASE" - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux"$UNAME_RELEASE" - exit ;; - SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux"$UNAME_RELEASE" - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody"$UNAME_RELEASE" - exit ;; - *:Rhapsody:*:*) - echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval "$set_cc_for_build" - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc - fi - if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc - if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_PPC >/dev/null - then - UNAME_PROCESSOR=powerpc - fi - fi - elif test "$UNAME_PROCESSOR" = i386 ; then - # Avoid executing cc on OS X 10.9, as it ships with a stub - # that puts up a graphical alert prompting to install - # developer tools. Any system running Mac OS X 10.7 or - # later (Darwin 11 and later) is required to have a 64-bit - # processor. This is not true of the ARM version of Darwin - # that Apple uses in portable devices. - UNAME_PROCESSOR=x86_64 - fi - echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = x86; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-*:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSR-*:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSV-*:NONSTOP_KERNEL:*:*) - echo nsv-tandem-nsk"$UNAME_RELEASE" - exit ;; - NSX-*:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk"$UNAME_RELEASE" - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = 386; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo "$UNAME_MACHINE"-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux"$UNAME_RELEASE" - exit ;; - *:DragonFly:*:*) - echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "$UNAME_MACHINE" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" - exit ;; - i*86:rdos:*:*) - echo "$UNAME_MACHINE"-pc-rdos - exit ;; - i*86:AROS:*:*) - echo "$UNAME_MACHINE"-pc-aros - exit ;; - x86_64:VMkernel:*:*) - echo "$UNAME_MACHINE"-unknown-esx - exit ;; - amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; -esac - -echo "$0: unable to guess system type" >&2 - -case "$UNAME_MACHINE:$UNAME_SYSTEM" in - mips:Linux | mips64:Linux) - # If we got here on MIPS GNU/Linux, output extra information. - cat >&2 <&2 </dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = "$UNAME_MACHINE" -UNAME_RELEASE = "$UNAME_RELEASE" -UNAME_SYSTEM = "$UNAME_SYSTEM" -UNAME_VERSION = "$UNAME_VERSION" -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/src/secp256k1-mw/build-aux/config.sub b/src/secp256k1-mw/build-aux/config.sub deleted file mode 100644 index 9ccf09a7a3..0000000000 --- a/src/secp256k1-mw/build-aux/config.sub +++ /dev/null @@ -1,1801 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2018 Free Software Foundation, Inc. - -timestamp='2018-03-08' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to . -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Options: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2018 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo "$1" - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo "$1" | sed 's/-[^-]*$//'` - if [ "$basic_machine" != "$1" ] - then os=`echo "$1" | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 - ;; - -bluegene*) - os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia16 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pru \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | wasm32 \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) - ;; - ms1) - basic_machine=mt-unknown - ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pru-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | wasm32-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-pc - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2*) - basic_machine=m68k-bull - os=-sysv3 - ;; - e500v[12]) - basic_machine=powerpc-unknown - os=$os"spe" - ;; - e500v[12]-*) - basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=$os"spe" - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - nsv-tandem) - basic_machine=nsv-tandem - ;; - nsx-tandem) - basic_machine=nsx-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - x64) - basic_machine=x86_64-pc - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases that might get confused - # with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux - ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # es1800 is here to avoid being matched by es* (a different OS) - -es1800*) - os=-ose - ;; - # Now accept the basic system types. - # The portable systems comes first. - # Each alternative MUST end in a * to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \ - | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ - | -midnightbsd*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -xray | -os68k* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo "$os" | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo "$os" | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo "$os" | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4*) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; - -pikeos*) - # Until real need of OS specific support for - # particular features comes up, bare metal - # configurations are quite functional. - case $basic_machine in - arm*) - os=-eabi - ;; - *) - os=-elf - ;; - esac - ;; - -nacl*) - ;; - -ios) - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - c8051-*) - os=-elf - ;; - hexagon-*) - os=-elf - ;; - tic54x-*) - os=-coff - ;; - tic55x-*) - os=-coff - ;; - tic6x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - pru-*) - os=-elf - ;; - *-be) - os=-beos - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -cnk*|-aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` - ;; -esac - -echo "$basic_machine$os" -exit - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/src/secp256k1-mw/build-aux/depcomp b/src/secp256k1-mw/build-aux/depcomp deleted file mode 100644 index 65cbf7093a..0000000000 --- a/src/secp256k1-mw/build-aux/depcomp +++ /dev/null @@ -1,791 +0,0 @@ -#! /bin/sh -# depcomp - compile a program generating dependencies as side-effects - -scriptversion=2018-03-07.03; # UTC - -# Copyright (C) 1999-2018 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Originally written by Alexandre Oliva . - -case $1 in - '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; - -h | --h*) - cat <<\EOF -Usage: depcomp [--help] [--version] PROGRAM [ARGS] - -Run PROGRAMS ARGS to compile a file, generating dependencies -as side-effects. - -Environment variables: - depmode Dependency tracking mode. - source Source file read by 'PROGRAMS ARGS'. - object Object file output by 'PROGRAMS ARGS'. - DEPDIR directory where to store dependencies. - depfile Dependency file to output. - tmpdepfile Temporary file to use when outputting dependencies. - libtool Whether libtool is used (yes/no). - -Report bugs to . -EOF - exit $? - ;; - -v | --v*) - echo "depcomp $scriptversion" - exit $? - ;; -esac - -# Get the directory component of the given path, and save it in the -# global variables '$dir'. Note that this directory component will -# be either empty or ending with a '/' character. This is deliberate. -set_dir_from () -{ - case $1 in - */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; - *) dir=;; - esac -} - -# Get the suffix-stripped basename of the given path, and save it the -# global variable '$base'. -set_base_from () -{ - base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` -} - -# If no dependency file was actually created by the compiler invocation, -# we still have to create a dummy depfile, to avoid errors with the -# Makefile "include basename.Plo" scheme. -make_dummy_depfile () -{ - echo "#dummy" > "$depfile" -} - -# Factor out some common post-processing of the generated depfile. -# Requires the auxiliary global variable '$tmpdepfile' to be set. -aix_post_process_depfile () -{ - # If the compiler actually managed to produce a dependency file, - # post-process it. - if test -f "$tmpdepfile"; then - # Each line is of the form 'foo.o: dependency.h'. - # Do two passes, one to just change these to - # $object: dependency.h - # and one to simply output - # dependency.h: - # which is needed to avoid the deleted-header problem. - { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" - sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" - } > "$depfile" - rm -f "$tmpdepfile" - else - make_dummy_depfile - fi -} - -# A tabulation character. -tab=' ' -# A newline character. -nl=' -' -# Character ranges might be problematic outside the C locale. -# These definitions help. -upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ -lower=abcdefghijklmnopqrstuvwxyz -digits=0123456789 -alpha=${upper}${lower} - -if test -z "$depmode" || test -z "$source" || test -z "$object"; then - echo "depcomp: Variables source, object and depmode must be set" 1>&2 - exit 1 -fi - -# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. -depfile=${depfile-`echo "$object" | - sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} -tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} - -rm -f "$tmpdepfile" - -# Avoid interferences from the environment. -gccflag= dashmflag= - -# Some modes work just like other modes, but use different flags. We -# parameterize here, but still list the modes in the big case below, -# to make depend.m4 easier to write. Note that we *cannot* use a case -# here, because this file can only contain one case statement. -if test "$depmode" = hp; then - # HP compiler uses -M and no extra arg. - gccflag=-M - depmode=gcc -fi - -if test "$depmode" = dashXmstdout; then - # This is just like dashmstdout with a different argument. - dashmflag=-xM - depmode=dashmstdout -fi - -cygpath_u="cygpath -u -f -" -if test "$depmode" = msvcmsys; then - # This is just like msvisualcpp but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvisualcpp -fi - -if test "$depmode" = msvc7msys; then - # This is just like msvc7 but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvc7 -fi - -if test "$depmode" = xlc; then - # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. - gccflag=-qmakedep=gcc,-MF - depmode=gcc -fi - -case "$depmode" in -gcc3) -## gcc 3 implements dependency tracking that does exactly what -## we want. Yay! Note: for some reason libtool 1.4 doesn't like -## it if -MD -MP comes after the -MF stuff. Hmm. -## Unfortunately, FreeBSD c89 acceptance of flags depends upon -## the command line argument order; so add the flags where they -## appear in depend2.am. Note that the slowdown incurred here -## affects only configure: in makefiles, %FASTDEP% shortcuts this. - for arg - do - case $arg in - -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; - *) set fnord "$@" "$arg" ;; - esac - shift # fnord - shift # $arg - done - "$@" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - mv "$tmpdepfile" "$depfile" - ;; - -gcc) -## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. -## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. -## (see the conditional assignment to $gccflag above). -## There are various ways to get dependency output from gcc. Here's -## why we pick this rather obscure method: -## - Don't want to use -MD because we'd like the dependencies to end -## up in a subdir. Having to rename by hand is ugly. -## (We might end up doing this anyway to support other compilers.) -## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like -## -MM, not -M (despite what the docs say). Also, it might not be -## supported by the other compilers which use the 'gcc' depmode. -## - Using -M directly means running the compiler twice (even worse -## than renaming). - if test -z "$gccflag"; then - gccflag=-MD, - fi - "$@" -Wp,"$gccflag$tmpdepfile" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - # The second -e expression handles DOS-style file names with drive - # letters. - sed -e 's/^[^:]*: / /' \ - -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" -## This next piece of magic avoids the "deleted header file" problem. -## The problem is that when a header file which appears in a .P file -## is deleted, the dependency causes make to die (because there is -## typically no way to rebuild the header). We avoid this by adding -## dummy dependencies for each header file. Too bad gcc doesn't do -## this for us directly. -## Some versions of gcc put a space before the ':'. On the theory -## that the space means something, we add a space to the output as -## well. hp depmode also adds that space, but also prefixes the VPATH -## to the object. Take care to not repeat it in the output. -## Some versions of the HPUX 10.20 sed can't process this invocation -## correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -sgi) - if test "$libtool" = yes; then - "$@" "-Wp,-MDupdate,$tmpdepfile" - else - "$@" -MDupdate "$tmpdepfile" - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - - if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files - echo "$object : \\" > "$depfile" - # Clip off the initial element (the dependent). Don't try to be - # clever and replace this with sed code, as IRIX sed won't handle - # lines with more than a fixed number of characters (4096 in - # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; - # the IRIX cc adds comments like '#:fec' to the end of the - # dependency line. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ - | tr "$nl" ' ' >> "$depfile" - echo >> "$depfile" - # The second pass generates a dummy entry for each header file. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ - >> "$depfile" - else - make_dummy_depfile - fi - rm -f "$tmpdepfile" - ;; - -xlc) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -aix) - # The C for AIX Compiler uses -M and outputs the dependencies - # in a .u file. In older versions, this file always lives in the - # current directory. Also, the AIX compiler puts '$object:' at the - # start of each line; $object doesn't have directory information. - # Version 6 uses the directory in both cases. - set_dir_from "$object" - set_base_from "$object" - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.u - tmpdepfile2=$base.u - tmpdepfile3=$dir.libs/$base.u - "$@" -Wc,-M - else - tmpdepfile1=$dir$base.u - tmpdepfile2=$dir$base.u - tmpdepfile3=$dir$base.u - "$@" -M - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - aix_post_process_depfile - ;; - -tcc) - # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 - # FIXME: That version still under development at the moment of writing. - # Make that this statement remains true also for stable, released - # versions. - # It will wrap lines (doesn't matter whether long or short) with a - # trailing '\', as in: - # - # foo.o : \ - # foo.c \ - # foo.h \ - # - # It will put a trailing '\' even on the last line, and will use leading - # spaces rather than leading tabs (at least since its commit 0394caf7 - # "Emit spaces for -MD"). - "$@" -MD -MF "$tmpdepfile" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. - # We have to change lines of the first kind to '$object: \'. - sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" - # And for each line of the second kind, we have to emit a 'dep.h:' - # dummy dependency, to avoid the deleted-header problem. - sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" - rm -f "$tmpdepfile" - ;; - -## The order of this option in the case statement is important, since the -## shell code in configure will try each of these formats in the order -## listed in this file. A plain '-MD' option would be understood by many -## compilers, so we must ensure this comes after the gcc and icc options. -pgcc) - # Portland's C compiler understands '-MD'. - # Will always output deps to 'file.d' where file is the root name of the - # source file under compilation, even if file resides in a subdirectory. - # The object file name does not affect the name of the '.d' file. - # pgcc 10.2 will output - # foo.o: sub/foo.c sub/foo.h - # and will wrap long lines using '\' : - # foo.o: sub/foo.c ... \ - # sub/foo.h ... \ - # ... - set_dir_from "$object" - # Use the source, not the object, to determine the base name, since - # that's sadly what pgcc will do too. - set_base_from "$source" - tmpdepfile=$base.d - - # For projects that build the same source file twice into different object - # files, the pgcc approach of using the *source* file root name can cause - # problems in parallel builds. Use a locking strategy to avoid stomping on - # the same $tmpdepfile. - lockdir=$base.d-lock - trap " - echo '$0: caught signal, cleaning up...' >&2 - rmdir '$lockdir' - exit 1 - " 1 2 13 15 - numtries=100 - i=$numtries - while test $i -gt 0; do - # mkdir is a portable test-and-set. - if mkdir "$lockdir" 2>/dev/null; then - # This process acquired the lock. - "$@" -MD - stat=$? - # Release the lock. - rmdir "$lockdir" - break - else - # If the lock is being held by a different process, wait - # until the winning process is done or we timeout. - while test -d "$lockdir" && test $i -gt 0; do - sleep 1 - i=`expr $i - 1` - done - fi - i=`expr $i - 1` - done - trap - 1 2 13 15 - if test $i -le 0; then - echo "$0: failed to acquire lock after $numtries attempts" >&2 - echo "$0: check lockdir '$lockdir'" >&2 - exit 1 - fi - - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - # Each line is of the form `foo.o: dependent.h', - # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. - # Do two passes, one to just change these to - # `$object: dependent.h' and one to simply `dependent.h:'. - sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -hp2) - # The "hp" stanza above does not work with aCC (C++) and HP's ia64 - # compilers, which have integrated preprocessors. The correct option - # to use with these is +Maked; it writes dependencies to a file named - # 'foo.d', which lands next to the object file, wherever that - # happens to be. - # Much of this is similar to the tru64 case; see comments there. - set_dir_from "$object" - set_base_from "$object" - if test "$libtool" = yes; then - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir.libs/$base.d - "$@" -Wc,+Maked - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - "$@" +Maked - fi - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" - do - test -f "$tmpdepfile" && break - done - if test -f "$tmpdepfile"; then - sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" - # Add 'dependent.h:' lines. - sed -ne '2,${ - s/^ *// - s/ \\*$// - s/$/:/ - p - }' "$tmpdepfile" >> "$depfile" - else - make_dummy_depfile - fi - rm -f "$tmpdepfile" "$tmpdepfile2" - ;; - -tru64) - # The Tru64 compiler uses -MD to generate dependencies as a side - # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. - # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put - # dependencies in 'foo.d' instead, so we check for that too. - # Subdirectories are respected. - set_dir_from "$object" - set_base_from "$object" - - if test "$libtool" = yes; then - # Libtool generates 2 separate objects for the 2 libraries. These - # two compilations output dependencies in $dir.libs/$base.o.d and - # in $dir$base.o.d. We have to check for both files, because - # one of the two compilations can be disabled. We should prefer - # $dir$base.o.d over $dir.libs/$base.o.d because the latter is - # automatically cleaned when .libs/ is deleted, while ignoring - # the former would cause a distcleancheck panic. - tmpdepfile1=$dir$base.o.d # libtool 1.5 - tmpdepfile2=$dir.libs/$base.o.d # Likewise. - tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 - "$@" -Wc,-MD - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - tmpdepfile3=$dir$base.d - "$@" -MD - fi - - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - # Same post-processing that is required for AIX mode. - aix_post_process_depfile - ;; - -msvc7) - if test "$libtool" = yes; then - showIncludes=-Wc,-showIncludes - else - showIncludes=-showIncludes - fi - "$@" $showIncludes > "$tmpdepfile" - stat=$? - grep -v '^Note: including file: ' "$tmpdepfile" - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat - fi - rm -f "$depfile" - echo "$object : \\" > "$depfile" - # The first sed program below extracts the file names and escapes - # backslashes for cygpath. The second sed program outputs the file - # name when reading, but also accumulates all include files in the - # hold buffer in order to output them again at the end. This only - # works with sed implementations that can handle large buffers. - sed < "$tmpdepfile" -n ' -/^Note: including file: *\(.*\)/ { - s//\1/ - s/\\/\\\\/g - p -}' | $cygpath_u | sort -u | sed -n ' -s/ /\\ /g -s/\(.*\)/'"$tab"'\1 \\/p -s/.\(.*\) \\/\1:/ -H -$ { - s/.*/'"$tab"'/ - G - p -}' >> "$depfile" - echo >> "$depfile" # make sure the fragment doesn't end with a backslash - rm -f "$tmpdepfile" - ;; - -msvc7msys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -#nosideeffect) - # This comment above is used by automake to tell side-effect - # dependency tracking mechanisms from slower ones. - -dashmstdout) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout, regardless of -o. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - test -z "$dashmflag" && dashmflag=-M - # Require at least two characters before searching for ':' - # in the target name. This is to cope with DOS-style filenames: - # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. - "$@" $dashmflag | - sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" - rm -f "$depfile" - cat < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this sed invocation - # correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -dashXmstdout) - # This case only exists to satisfy depend.m4. It is never actually - # run, as this mode is specially recognized in the preamble. - exit 1 - ;; - -makedepend) - "$@" || exit $? - # Remove any Libtool call - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - # X makedepend - shift - cleared=no eat=no - for arg - do - case $cleared in - no) - set ""; shift - cleared=yes ;; - esac - if test $eat = yes; then - eat=no - continue - fi - case "$arg" in - -D*|-I*) - set fnord "$@" "$arg"; shift ;; - # Strip any option that makedepend may not understand. Remove - # the object too, otherwise makedepend will parse it as a source file. - -arch) - eat=yes ;; - -*|$object) - ;; - *) - set fnord "$@" "$arg"; shift ;; - esac - done - obj_suffix=`echo "$object" | sed 's/^.*\././'` - touch "$tmpdepfile" - ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" - rm -f "$depfile" - # makedepend may prepend the VPATH from the source file name to the object. - # No need to regex-escape $object, excess matching of '.' is harmless. - sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process the last invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed '1,2d' "$tmpdepfile" \ - | tr ' ' "$nl" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" "$tmpdepfile".bak - ;; - -cpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - # Remove '-o $object'. - IFS=" " - for arg - do - case $arg in - -o) - shift - ;; - $object) - shift - ;; - *) - set fnord "$@" "$arg" - shift # fnord - shift # $arg - ;; - esac - done - - "$@" -E \ - | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - | sed '$ s: \\$::' > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - cat < "$tmpdepfile" >> "$depfile" - sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvisualcpp) - # Important note: in order to support this mode, a compiler *must* - # always write the preprocessed file to stdout. - "$@" || exit $? - - # Remove the call to Libtool. - if test "$libtool" = yes; then - while test "X$1" != 'X--mode=compile'; do - shift - done - shift - fi - - IFS=" " - for arg - do - case "$arg" in - -o) - shift - ;; - $object) - shift - ;; - "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") - set fnord "$@" - shift - shift - ;; - *) - set fnord "$@" "$arg" - shift - shift - ;; - esac - done - "$@" -E 2>/dev/null | - sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" - rm -f "$depfile" - echo "$object : \\" > "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" - echo "$tab" >> "$depfile" - sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" - rm -f "$tmpdepfile" - ;; - -msvcmsys) - # This case exists only to let depend.m4 do its work. It works by - # looking at the text of this script. This case will never be run, - # since it is checked for above. - exit 1 - ;; - -none) - exec "$@" - ;; - -*) - echo "Unknown depmode $depmode" 1>&2 - exit 1 - ;; -esac - -exit 0 - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/secp256k1-mw/build-aux/install-sh b/src/secp256k1-mw/build-aux/install-sh deleted file mode 100644 index 8175c640fe..0000000000 --- a/src/secp256k1-mw/build-aux/install-sh +++ /dev/null @@ -1,518 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2018-03-11.20; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dstbase=`basename "$src"` - case $dst in - */) dst=$dst$dstbase;; - *) dst=$dst/$dstbase;; - esac - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - case $dstdir in - */) dstdirslash=$dstdir;; - *) dstdirslash=$dstdir/;; - esac - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - # Note that $RANDOM variable is not portable (e.g. dash); Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p' feature. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=${dstdirslash}_inst.$$_ - rmtmp=${dstdirslash}_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/secp256k1-mw/build-aux/ltmain.sh b/src/secp256k1-mw/build-aux/ltmain.sh deleted file mode 100644 index 0f0a2da3f9..0000000000 --- a/src/secp256k1-mw/build-aux/ltmain.sh +++ /dev/null @@ -1,11147 +0,0 @@ -#! /bin/sh -## DO NOT EDIT - This file generated from ./build-aux/ltmain.in -## by inline-source v2014-01-03.01 - -# libtool (GNU libtool) 2.4.6 -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit , 1996 - -# Copyright (C) 1996-2015 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -PROGRAM=libtool -PACKAGE=libtool -VERSION=2.4.6 -package_revision=2.4.6 - - -## ------ ## -## Usage. ## -## ------ ## - -# Run './libtool --help' for help with using this script from the -# command line. - - -## ------------------------------- ## -## User overridable command paths. ## -## ------------------------------- ## - -# After configure completes, it has a better idea of some of the -# shell tools we need than the defaults used by the functions shared -# with bootstrap, so set those here where they can still be over- -# ridden by the user, but otherwise take precedence. - -: ${AUTOCONF="autoconf"} -: ${AUTOMAKE="automake"} - - -## -------------------------- ## -## Source external libraries. ## -## -------------------------- ## - -# Much of our low-level functionality needs to be sourced from external -# libraries, which are installed to $pkgauxdir. - -# Set a version string for this script. -scriptversion=2015-01-20.17; # UTC - -# General shell script boiler plate, and helper functions. -# Written by Gary V. Vaughan, 2004 - -# Copyright (C) 2004-2015 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. - -# As a special exception to the GNU General Public License, if you distribute -# this file as part of a program or library that is built using GNU Libtool, -# you may include this file under the same distribution terms that you use -# for the rest of that program. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Please report bugs or propose patches to gary@gnu.org. - - -## ------ ## -## Usage. ## -## ------ ## - -# Evaluate this file near the top of your script to gain access to -# the functions and variables defined here: -# -# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh -# -# If you need to override any of the default environment variable -# settings, do that before evaluating this file. - - -## -------------------- ## -## Shell normalisation. ## -## -------------------- ## - -# Some shells need a little help to be as Bourne compatible as possible. -# Before doing anything else, make sure all that help has been provided! - -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac -fi - -# NLS nuisances: We save the old values in case they are required later. -_G_user_locale= -_G_safe_locale= -for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES -do - eval "if test set = \"\${$_G_var+set}\"; then - save_$_G_var=\$$_G_var - $_G_var=C - export $_G_var - _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" - _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" - fi" -done - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Make sure IFS has a sensible default -sp=' ' -nl=' -' -IFS="$sp $nl" - -# There are apparently some retarded systems that use ';' as a PATH separator! -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - - -## ------------------------- ## -## Locate command utilities. ## -## ------------------------- ## - - -# func_executable_p FILE -# ---------------------- -# Check that FILE is an executable regular file. -func_executable_p () -{ - test -f "$1" && test -x "$1" -} - - -# func_path_progs PROGS_LIST CHECK_FUNC [PATH] -# -------------------------------------------- -# Search for either a program that responds to --version with output -# containing "GNU", or else returned by CHECK_FUNC otherwise, by -# trying all the directories in PATH with each of the elements of -# PROGS_LIST. -# -# CHECK_FUNC should accept the path to a candidate program, and -# set $func_check_prog_result if it truncates its output less than -# $_G_path_prog_max characters. -func_path_progs () -{ - _G_progs_list=$1 - _G_check_func=$2 - _G_PATH=${3-"$PATH"} - - _G_path_prog_max=0 - _G_path_prog_found=false - _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} - for _G_dir in $_G_PATH; do - IFS=$_G_save_IFS - test -z "$_G_dir" && _G_dir=. - for _G_prog_name in $_G_progs_list; do - for _exeext in '' .EXE; do - _G_path_prog=$_G_dir/$_G_prog_name$_exeext - func_executable_p "$_G_path_prog" || continue - case `"$_G_path_prog" --version 2>&1` in - *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; - *) $_G_check_func $_G_path_prog - func_path_progs_result=$func_check_prog_result - ;; - esac - $_G_path_prog_found && break 3 - done - done - done - IFS=$_G_save_IFS - test -z "$func_path_progs_result" && { - echo "no acceptable sed could be found in \$PATH" >&2 - exit 1 - } -} - - -# We want to be able to use the functions in this file before configure -# has figured out where the best binaries are kept, which means we have -# to search for them ourselves - except when the results are already set -# where we skip the searches. - -# Unless the user overrides by setting SED, search the path for either GNU -# sed, or the sed that truncates its output the least. -test -z "$SED" && { - _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for _G_i in 1 2 3 4 5 6 7; do - _G_sed_script=$_G_sed_script$nl$_G_sed_script - done - echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed - _G_sed_script= - - func_check_prog_sed () - { - _G_path_prog=$1 - - _G_count=0 - printf 0123456789 >conftest.in - while : - do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo '' >> conftest.nl - "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break - diff conftest.out conftest.nl >/dev/null 2>&1 || break - _G_count=`expr $_G_count + 1` - if test "$_G_count" -gt "$_G_path_prog_max"; then - # Best one so far, save it but keep looking for a better one - func_check_prog_result=$_G_path_prog - _G_path_prog_max=$_G_count - fi - # 10*(2^10) chars as input seems more than enough - test 10 -lt "$_G_count" && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out - } - - func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin - rm -f conftest.sed - SED=$func_path_progs_result -} - - -# Unless the user overrides by setting GREP, search the path for either GNU -# grep, or the grep that truncates its output the least. -test -z "$GREP" && { - func_check_prog_grep () - { - _G_path_prog=$1 - - _G_count=0 - _G_path_prog_max=0 - printf 0123456789 >conftest.in - while : - do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo 'GREP' >> conftest.nl - "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break - diff conftest.out conftest.nl >/dev/null 2>&1 || break - _G_count=`expr $_G_count + 1` - if test "$_G_count" -gt "$_G_path_prog_max"; then - # Best one so far, save it but keep looking for a better one - func_check_prog_result=$_G_path_prog - _G_path_prog_max=$_G_count - fi - # 10*(2^10) chars as input seems more than enough - test 10 -lt "$_G_count" && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out - } - - func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin - GREP=$func_path_progs_result -} - - -## ------------------------------- ## -## User overridable command paths. ## -## ------------------------------- ## - -# All uppercase variable names are used for environment variables. These -# variables can be overridden by the user before calling a script that -# uses them if a suitable command of that name is not already available -# in the command search PATH. - -: ${CP="cp -f"} -: ${ECHO="printf %s\n"} -: ${EGREP="$GREP -E"} -: ${FGREP="$GREP -F"} -: ${LN_S="ln -s"} -: ${MAKE="make"} -: ${MKDIR="mkdir"} -: ${MV="mv -f"} -: ${RM="rm -f"} -: ${SHELL="${CONFIG_SHELL-/bin/sh}"} - - -## -------------------- ## -## Useful sed snippets. ## -## -------------------- ## - -sed_dirname='s|/[^/]*$||' -sed_basename='s|^.*/||' - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='s|\([`"$\\]\)|\\\1|g' - -# Same as above, but do not quote variable references. -sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution that turns a string into a regex matching for the -# string literally. -sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' - -# Sed substitution that converts a w32 file name or path -# that contains forward slashes, into one that contains -# (escaped) backslashes. A very naive implementation. -sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - -# Re-'\' parameter expansions in output of sed_double_quote_subst that -# were '\'-ed in input to the same. If an odd number of '\' preceded a -# '$' in input to sed_double_quote_subst, that '$' was protected from -# expansion. Since each input '\' is now two '\'s, look for any number -# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. -_G_bs='\\' -_G_bs2='\\\\' -_G_bs4='\\\\\\\\' -_G_dollar='\$' -sed_double_backslash="\ - s/$_G_bs4/&\\ -/g - s/^$_G_bs2$_G_dollar/$_G_bs&/ - s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g - s/\n//g" - - -## ----------------- ## -## Global variables. ## -## ----------------- ## - -# Except for the global variables explicitly listed below, the following -# functions in the '^func_' namespace, and the '^require_' namespace -# variables initialised in the 'Resource management' section, sourcing -# this file will not pollute your global namespace with anything -# else. There's no portable way to scope variables in Bourne shell -# though, so actually running these functions will sometimes place -# results into a variable named after the function, and often use -# temporary variables in the '^_G_' namespace. If you are careful to -# avoid using those namespaces casually in your sourcing script, things -# should continue to work as you expect. And, of course, you can freely -# overwrite any of the functions or variables defined here before -# calling anything to customize them. - -EXIT_SUCCESS=0 -EXIT_FAILURE=1 -EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. -EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. - -# Allow overriding, eg assuming that you follow the convention of -# putting '$debug_cmd' at the start of all your functions, you can get -# bash to show function call trace with: -# -# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name -debug_cmd=${debug_cmd-":"} -exit_cmd=: - -# By convention, finish your script with: -# -# exit $exit_status -# -# so that you can set exit_status to non-zero if you want to indicate -# something went wrong during execution without actually bailing out at -# the point of failure. -exit_status=$EXIT_SUCCESS - -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath=$0 - -# The name of this program. -progname=`$ECHO "$progpath" |$SED "$sed_basename"` - -# Make sure we have an absolute progpath for reexecution: -case $progpath in - [\\/]*|[A-Za-z]:\\*) ;; - *[\\/]*) - progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` - progdir=`cd "$progdir" && pwd` - progpath=$progdir/$progname - ;; - *) - _G_IFS=$IFS - IFS=${PATH_SEPARATOR-:} - for progdir in $PATH; do - IFS=$_G_IFS - test -x "$progdir/$progname" && break - done - IFS=$_G_IFS - test -n "$progdir" || progdir=`pwd` - progpath=$progdir/$progname - ;; -esac - - -## ----------------- ## -## Standard options. ## -## ----------------- ## - -# The following options affect the operation of the functions defined -# below, and should be set appropriately depending on run-time para- -# meters passed on the command line. - -opt_dry_run=false -opt_quiet=false -opt_verbose=false - -# Categories 'all' and 'none' are always available. Append any others -# you will pass as the first argument to func_warning from your own -# code. -warning_categories= - -# By default, display warnings according to 'opt_warning_types'. Set -# 'warning_func' to ':' to elide all warnings, or func_fatal_error to -# treat the next displayed warning as a fatal error. -warning_func=func_warn_and_continue - -# Set to 'all' to display all warnings, 'none' to suppress all -# warnings, or a space delimited list of some subset of -# 'warning_categories' to display only the listed warnings. -opt_warning_types=all - - -## -------------------- ## -## Resource management. ## -## -------------------- ## - -# This section contains definitions for functions that each ensure a -# particular resource (a file, or a non-empty configuration variable for -# example) is available, and if appropriate to extract default values -# from pertinent package files. Call them using their associated -# 'require_*' variable to ensure that they are executed, at most, once. -# -# It's entirely deliberate that calling these functions can set -# variables that don't obey the namespace limitations obeyed by the rest -# of this file, in order that that they be as useful as possible to -# callers. - - -# require_term_colors -# ------------------- -# Allow display of bold text on terminals that support it. -require_term_colors=func_require_term_colors -func_require_term_colors () -{ - $debug_cmd - - test -t 1 && { - # COLORTERM and USE_ANSI_COLORS environment variables take - # precedence, because most terminfo databases neglect to describe - # whether color sequences are supported. - test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} - - if test 1 = "$USE_ANSI_COLORS"; then - # Standard ANSI escape sequences - tc_reset='' - tc_bold=''; tc_standout='' - tc_red=''; tc_green='' - tc_blue=''; tc_cyan='' - else - # Otherwise trust the terminfo database after all. - test -n "`tput sgr0 2>/dev/null`" && { - tc_reset=`tput sgr0` - test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` - tc_standout=$tc_bold - test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` - test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` - test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` - test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` - test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` - } - fi - } - - require_term_colors=: -} - - -## ----------------- ## -## Function library. ## -## ----------------- ## - -# This section contains a variety of useful functions to call in your -# scripts. Take note of the portable wrappers for features provided by -# some modern shells, which will fall back to slower equivalents on -# less featureful shells. - - -# func_append VAR VALUE -# --------------------- -# Append VALUE onto the existing contents of VAR. - - # We should try to minimise forks, especially on Windows where they are - # unreasonably slow, so skip the feature probes when bash or zsh are - # being used: - if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then - : ${_G_HAVE_ARITH_OP="yes"} - : ${_G_HAVE_XSI_OPS="yes"} - # The += operator was introduced in bash 3.1 - case $BASH_VERSION in - [12].* | 3.0 | 3.0*) ;; - *) - : ${_G_HAVE_PLUSEQ_OP="yes"} - ;; - esac - fi - - # _G_HAVE_PLUSEQ_OP - # Can be empty, in which case the shell is probed, "yes" if += is - # useable or anything else if it does not work. - test -z "$_G_HAVE_PLUSEQ_OP" \ - && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ - && _G_HAVE_PLUSEQ_OP=yes - -if test yes = "$_G_HAVE_PLUSEQ_OP" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_append () - { - $debug_cmd - - eval "$1+=\$2" - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_append () - { - $debug_cmd - - eval "$1=\$$1\$2" - } -fi - - -# func_append_quoted VAR VALUE -# ---------------------------- -# Quote VALUE and append to the end of shell variable VAR, separated -# by a space. -if test yes = "$_G_HAVE_PLUSEQ_OP"; then - eval 'func_append_quoted () - { - $debug_cmd - - func_quote_for_eval "$2" - eval "$1+=\\ \$func_quote_for_eval_result" - }' -else - func_append_quoted () - { - $debug_cmd - - func_quote_for_eval "$2" - eval "$1=\$$1\\ \$func_quote_for_eval_result" - } -fi - - -# func_append_uniq VAR VALUE -# -------------------------- -# Append unique VALUE onto the existing contents of VAR, assuming -# entries are delimited by the first character of VALUE. For example: -# -# func_append_uniq options " --another-option option-argument" -# -# will only append to $options if " --another-option option-argument " -# is not already present somewhere in $options already (note spaces at -# each end implied by leading space in second argument). -func_append_uniq () -{ - $debug_cmd - - eval _G_current_value='`$ECHO $'$1'`' - _G_delim=`expr "$2" : '\(.\)'` - - case $_G_delim$_G_current_value$_G_delim in - *"$2$_G_delim"*) ;; - *) func_append "$@" ;; - esac -} - - -# func_arith TERM... -# ------------------ -# Set func_arith_result to the result of evaluating TERMs. - test -z "$_G_HAVE_ARITH_OP" \ - && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ - && _G_HAVE_ARITH_OP=yes - -if test yes = "$_G_HAVE_ARITH_OP"; then - eval 'func_arith () - { - $debug_cmd - - func_arith_result=$(( $* )) - }' -else - func_arith () - { - $debug_cmd - - func_arith_result=`expr "$@"` - } -fi - - -# func_basename FILE -# ------------------ -# Set func_basename_result to FILE with everything up to and including -# the last / stripped. -if test yes = "$_G_HAVE_XSI_OPS"; then - # If this shell supports suffix pattern removal, then use it to avoid - # forking. Hide the definitions single quotes in case the shell chokes - # on unsupported syntax... - _b='func_basename_result=${1##*/}' - _d='case $1 in - */*) func_dirname_result=${1%/*}$2 ;; - * ) func_dirname_result=$3 ;; - esac' - -else - # ...otherwise fall back to using sed. - _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' - _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` - if test "X$func_dirname_result" = "X$1"; then - func_dirname_result=$3 - else - func_append func_dirname_result "$2" - fi' -fi - -eval 'func_basename () -{ - $debug_cmd - - '"$_b"' -}' - - -# func_dirname FILE APPEND NONDIR_REPLACEMENT -# ------------------------------------------- -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -eval 'func_dirname () -{ - $debug_cmd - - '"$_d"' -}' - - -# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT -# -------------------------------------------------------- -# Perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value retuned in "$func_basename_result" -# For efficiency, we do not delegate to the functions above but instead -# duplicate the functionality here. -eval 'func_dirname_and_basename () -{ - $debug_cmd - - '"$_b"' - '"$_d"' -}' - - -# func_echo ARG... -# ---------------- -# Echo program name prefixed message. -func_echo () -{ - $debug_cmd - - _G_message=$* - - func_echo_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_IFS - $ECHO "$progname: $_G_line" - done - IFS=$func_echo_IFS -} - - -# func_echo_all ARG... -# -------------------- -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "$*" -} - - -# func_echo_infix_1 INFIX ARG... -# ------------------------------ -# Echo program name, followed by INFIX on the first line, with any -# additional lines not showing INFIX. -func_echo_infix_1 () -{ - $debug_cmd - - $require_term_colors - - _G_infix=$1; shift - _G_indent=$_G_infix - _G_prefix="$progname: $_G_infix: " - _G_message=$* - - # Strip color escape sequences before counting printable length - for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" - do - test -n "$_G_tc" && { - _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` - _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` - } - done - _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes - - func_echo_infix_1_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_infix_1_IFS - $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 - _G_prefix=$_G_indent - done - IFS=$func_echo_infix_1_IFS -} - - -# func_error ARG... -# ----------------- -# Echo program name prefixed message to standard error. -func_error () -{ - $debug_cmd - - $require_term_colors - - func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 -} - - -# func_fatal_error ARG... -# ----------------------- -# Echo program name prefixed message to standard error, and exit. -func_fatal_error () -{ - $debug_cmd - - func_error "$*" - exit $EXIT_FAILURE -} - - -# func_grep EXPRESSION FILENAME -# ----------------------------- -# Check whether EXPRESSION matches any line of FILENAME, without output. -func_grep () -{ - $debug_cmd - - $GREP "$1" "$2" >/dev/null 2>&1 -} - - -# func_len STRING -# --------------- -# Set func_len_result to the length of STRING. STRING may not -# start with a hyphen. - test -z "$_G_HAVE_XSI_OPS" \ - && (eval 'x=a/b/c; - test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ - && _G_HAVE_XSI_OPS=yes - -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_len () - { - $debug_cmd - - func_len_result=${#1} - }' -else - func_len () - { - $debug_cmd - - func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` - } -fi - - -# func_mkdir_p DIRECTORY-PATH -# --------------------------- -# Make sure the entire path to DIRECTORY-PATH is available. -func_mkdir_p () -{ - $debug_cmd - - _G_directory_path=$1 - _G_dir_list= - - if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then - - # Protect directory names starting with '-' - case $_G_directory_path in - -*) _G_directory_path=./$_G_directory_path ;; - esac - - # While some portion of DIR does not yet exist... - while test ! -d "$_G_directory_path"; do - # ...make a list in topmost first order. Use a colon delimited - # list incase some portion of path contains whitespace. - _G_dir_list=$_G_directory_path:$_G_dir_list - - # If the last portion added has no slash in it, the list is done - case $_G_directory_path in */*) ;; *) break ;; esac - - # ...otherwise throw away the child directory and loop - _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` - done - _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` - - func_mkdir_p_IFS=$IFS; IFS=: - for _G_dir in $_G_dir_list; do - IFS=$func_mkdir_p_IFS - # mkdir can fail with a 'File exist' error if two processes - # try to create one of the directories concurrently. Don't - # stop in that case! - $MKDIR "$_G_dir" 2>/dev/null || : - done - IFS=$func_mkdir_p_IFS - - # Bail out if we (or some other process) failed to create a directory. - test -d "$_G_directory_path" || \ - func_fatal_error "Failed to create '$1'" - fi -} - - -# func_mktempdir [BASENAME] -# ------------------------- -# Make a temporary directory that won't clash with other running -# libtool processes, and avoids race conditions if possible. If -# given, BASENAME is the basename for that directory. -func_mktempdir () -{ - $debug_cmd - - _G_template=${TMPDIR-/tmp}/${1-$progname} - - if test : = "$opt_dry_run"; then - # Return a directory name, but don't create it in dry-run mode - _G_tmpdir=$_G_template-$$ - else - - # If mktemp works, use that first and foremost - _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` - - if test ! -d "$_G_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - _G_tmpdir=$_G_template-${RANDOM-0}$$ - - func_mktempdir_umask=`umask` - umask 0077 - $MKDIR "$_G_tmpdir" - umask $func_mktempdir_umask - fi - - # If we're not in dry-run mode, bomb out on failure - test -d "$_G_tmpdir" || \ - func_fatal_error "cannot create temporary directory '$_G_tmpdir'" - fi - - $ECHO "$_G_tmpdir" -} - - -# func_normal_abspath PATH -# ------------------------ -# Remove doubled-up and trailing slashes, "." path components, -# and cancel out any ".." path components in PATH after making -# it an absolute path. -func_normal_abspath () -{ - $debug_cmd - - # These SED scripts presuppose an absolute path with a trailing slash. - _G_pathcar='s|^/\([^/]*\).*$|\1|' - _G_pathcdr='s|^/[^/]*||' - _G_removedotparts=':dotsl - s|/\./|/|g - t dotsl - s|/\.$|/|' - _G_collapseslashes='s|/\{1,\}|/|g' - _G_finalslash='s|/*$|/|' - - # Start from root dir and reassemble the path. - func_normal_abspath_result= - func_normal_abspath_tpath=$1 - func_normal_abspath_altnamespace= - case $func_normal_abspath_tpath in - "") - # Empty path, that just means $cwd. - func_stripname '' '/' "`pwd`" - func_normal_abspath_result=$func_stripname_result - return - ;; - # The next three entries are used to spot a run of precisely - # two leading slashes without using negated character classes; - # we take advantage of case's first-match behaviour. - ///*) - # Unusual form of absolute path, do nothing. - ;; - //*) - # Not necessarily an ordinary path; POSIX reserves leading '//' - # and for example Cygwin uses it to access remote file shares - # over CIFS/SMB, so we conserve a leading double slash if found. - func_normal_abspath_altnamespace=/ - ;; - /*) - # Absolute path, do nothing. - ;; - *) - # Relative path, prepend $cwd. - func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath - ;; - esac - - # Cancel out all the simple stuff to save iterations. We also want - # the path to end with a slash for ease of parsing, so make sure - # there is one (and only one) here. - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` - while :; do - # Processed it all yet? - if test / = "$func_normal_abspath_tpath"; then - # If we ascended to the root using ".." the result may be empty now. - if test -z "$func_normal_abspath_result"; then - func_normal_abspath_result=/ - fi - break - fi - func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_pathcar"` - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$_G_pathcdr"` - # Figure out what to do with it - case $func_normal_abspath_tcomponent in - "") - # Trailing empty path component, ignore it. - ;; - ..) - # Parent dir; strip last assembled component from result. - func_dirname "$func_normal_abspath_result" - func_normal_abspath_result=$func_dirname_result - ;; - *) - # Actual path component, append it. - func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" - ;; - esac - done - # Restore leading double-slash if one was found on entry. - func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result -} - - -# func_notquiet ARG... -# -------------------- -# Echo program name prefixed message only when not in quiet mode. -func_notquiet () -{ - $debug_cmd - - $opt_quiet || func_echo ${1+"$@"} - - # A bug in bash halts the script if the last line of a function - # fails when set -e is in force, so we need another command to - # work around that: - : -} - - -# func_relative_path SRCDIR DSTDIR -# -------------------------------- -# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. -func_relative_path () -{ - $debug_cmd - - func_relative_path_result= - func_normal_abspath "$1" - func_relative_path_tlibdir=$func_normal_abspath_result - func_normal_abspath "$2" - func_relative_path_tbindir=$func_normal_abspath_result - - # Ascend the tree starting from libdir - while :; do - # check if we have found a prefix of bindir - case $func_relative_path_tbindir in - $func_relative_path_tlibdir) - # found an exact match - func_relative_path_tcancelled= - break - ;; - $func_relative_path_tlibdir*) - # found a matching prefix - func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" - func_relative_path_tcancelled=$func_stripname_result - if test -z "$func_relative_path_result"; then - func_relative_path_result=. - fi - break - ;; - *) - func_dirname $func_relative_path_tlibdir - func_relative_path_tlibdir=$func_dirname_result - if test -z "$func_relative_path_tlibdir"; then - # Have to descend all the way to the root! - func_relative_path_result=../$func_relative_path_result - func_relative_path_tcancelled=$func_relative_path_tbindir - break - fi - func_relative_path_result=../$func_relative_path_result - ;; - esac - done - - # Now calculate path; take care to avoid doubling-up slashes. - func_stripname '' '/' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - func_stripname '/' '/' "$func_relative_path_tcancelled" - if test -n "$func_stripname_result"; then - func_append func_relative_path_result "/$func_stripname_result" - fi - - # Normalisation. If bindir is libdir, return '.' else relative path. - if test -n "$func_relative_path_result"; then - func_stripname './' '' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - fi - - test -n "$func_relative_path_result" || func_relative_path_result=. - - : -} - - -# func_quote_for_eval ARG... -# -------------------------- -# Aesthetically quote ARGs to be evaled later. -# This function returns two values: -# i) func_quote_for_eval_result -# double-quoted, suitable for a subsequent eval -# ii) func_quote_for_eval_unquoted_result -# has all characters that are still active within double -# quotes backslashified. -func_quote_for_eval () -{ - $debug_cmd - - func_quote_for_eval_unquoted_result= - func_quote_for_eval_result= - while test 0 -lt $#; do - case $1 in - *[\\\`\"\$]*) - _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; - *) - _G_unquoted_arg=$1 ;; - esac - if test -n "$func_quote_for_eval_unquoted_result"; then - func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" - else - func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" - fi - - case $_G_unquoted_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting, command substitution and variable expansion - # for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - _G_quoted_arg=\"$_G_unquoted_arg\" - ;; - *) - _G_quoted_arg=$_G_unquoted_arg - ;; - esac - - if test -n "$func_quote_for_eval_result"; then - func_append func_quote_for_eval_result " $_G_quoted_arg" - else - func_append func_quote_for_eval_result "$_G_quoted_arg" - fi - shift - done -} - - -# func_quote_for_expand ARG -# ------------------------- -# Aesthetically quote ARG to be evaled later; same as above, -# but do not quote variable references. -func_quote_for_expand () -{ - $debug_cmd - - case $1 in - *[\\\`\"]*) - _G_arg=`$ECHO "$1" | $SED \ - -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; - *) - _G_arg=$1 ;; - esac - - case $_G_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting and command substitution for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - _G_arg=\"$_G_arg\" - ;; - esac - - func_quote_for_expand_result=$_G_arg -} - - -# func_stripname PREFIX SUFFIX NAME -# --------------------------------- -# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_stripname () - { - $debug_cmd - - # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are - # positional parameters, so assign one to ordinary variable first. - func_stripname_result=$3 - func_stripname_result=${func_stripname_result#"$1"} - func_stripname_result=${func_stripname_result%"$2"} - }' -else - func_stripname () - { - $debug_cmd - - case $2 in - .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; - *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; - esac - } -fi - - -# func_show_eval CMD [FAIL_EXP] -# ----------------------------- -# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. -func_show_eval () -{ - $debug_cmd - - _G_cmd=$1 - _G_fail_exp=${2-':'} - - func_quote_for_expand "$_G_cmd" - eval "func_notquiet $func_quote_for_expand_result" - - $opt_dry_run || { - eval "$_G_cmd" - _G_status=$? - if test 0 -ne "$_G_status"; then - eval "(exit $_G_status); $_G_fail_exp" - fi - } -} - - -# func_show_eval_locale CMD [FAIL_EXP] -# ------------------------------------ -# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. Use the saved locale for evaluation. -func_show_eval_locale () -{ - $debug_cmd - - _G_cmd=$1 - _G_fail_exp=${2-':'} - - $opt_quiet || { - func_quote_for_expand "$_G_cmd" - eval "func_echo $func_quote_for_expand_result" - } - - $opt_dry_run || { - eval "$_G_user_locale - $_G_cmd" - _G_status=$? - eval "$_G_safe_locale" - if test 0 -ne "$_G_status"; then - eval "(exit $_G_status); $_G_fail_exp" - fi - } -} - - -# func_tr_sh -# ---------- -# Turn $1 into a string suitable for a shell variable name. -# Result is stored in $func_tr_sh_result. All characters -# not in the set a-zA-Z0-9_ are replaced with '_'. Further, -# if $1 begins with a digit, a '_' is prepended as well. -func_tr_sh () -{ - $debug_cmd - - case $1 in - [0-9]* | *[!a-zA-Z0-9_]*) - func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` - ;; - * ) - func_tr_sh_result=$1 - ;; - esac -} - - -# func_verbose ARG... -# ------------------- -# Echo program name prefixed message in verbose mode only. -func_verbose () -{ - $debug_cmd - - $opt_verbose && func_echo "$*" - - : -} - - -# func_warn_and_continue ARG... -# ----------------------------- -# Echo program name prefixed warning message to standard error. -func_warn_and_continue () -{ - $debug_cmd - - $require_term_colors - - func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 -} - - -# func_warning CATEGORY ARG... -# ---------------------------- -# Echo program name prefixed warning message to standard error. Warning -# messages can be filtered according to CATEGORY, where this function -# elides messages where CATEGORY is not listed in the global variable -# 'opt_warning_types'. -func_warning () -{ - $debug_cmd - - # CATEGORY must be in the warning_categories list! - case " $warning_categories " in - *" $1 "*) ;; - *) func_internal_error "invalid warning category '$1'" ;; - esac - - _G_category=$1 - shift - - case " $opt_warning_types " in - *" $_G_category "*) $warning_func ${1+"$@"} ;; - esac -} - - -# func_sort_ver VER1 VER2 -# ----------------------- -# 'sort -V' is not generally available. -# Note this deviates from the version comparison in automake -# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a -# but this should suffice as we won't be specifying old -# version formats or redundant trailing .0 in bootstrap.conf. -# If we did want full compatibility then we should probably -# use m4_version_compare from autoconf. -func_sort_ver () -{ - $debug_cmd - - printf '%s\n%s\n' "$1" "$2" \ - | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n -} - -# func_lt_ver PREV CURR -# --------------------- -# Return true if PREV and CURR are in the correct order according to -# func_sort_ver, otherwise false. Use it like this: -# -# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." -func_lt_ver () -{ - $debug_cmd - - test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` -} - - -# Local variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" -# time-stamp-time-zone: "UTC" -# End: -#! /bin/sh - -# Set a version string for this script. -scriptversion=2014-01-07.03; # UTC - -# A portable, pluggable option parser for Bourne shell. -# Written by Gary V. Vaughan, 2010 - -# Copyright (C) 2010-2015 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Please report bugs or propose patches to gary@gnu.org. - - -## ------ ## -## Usage. ## -## ------ ## - -# This file is a library for parsing options in your shell scripts along -# with assorted other useful supporting features that you can make use -# of too. -# -# For the simplest scripts you might need only: -# -# #!/bin/sh -# . relative/path/to/funclib.sh -# . relative/path/to/options-parser -# scriptversion=1.0 -# func_options ${1+"$@"} -# eval set dummy "$func_options_result"; shift -# ...rest of your script... -# -# In order for the '--version' option to work, you will need to have a -# suitably formatted comment like the one at the top of this file -# starting with '# Written by ' and ending with '# warranty; '. -# -# For '-h' and '--help' to work, you will also need a one line -# description of your script's purpose in a comment directly above the -# '# Written by ' line, like the one at the top of this file. -# -# The default options also support '--debug', which will turn on shell -# execution tracing (see the comment above debug_cmd below for another -# use), and '--verbose' and the func_verbose function to allow your script -# to display verbose messages only when your user has specified -# '--verbose'. -# -# After sourcing this file, you can plug processing for additional -# options by amending the variables from the 'Configuration' section -# below, and following the instructions in the 'Option parsing' -# section further down. - -## -------------- ## -## Configuration. ## -## -------------- ## - -# You should override these variables in your script after sourcing this -# file so that they reflect the customisations you have added to the -# option parser. - -# The usage line for option parsing errors and the start of '-h' and -# '--help' output messages. You can embed shell variables for delayed -# expansion at the time the message is displayed, but you will need to -# quote other shell meta-characters carefully to prevent them being -# expanded when the contents are evaled. -usage='$progpath [OPTION]...' - -# Short help message in response to '-h' and '--help'. Add to this or -# override it after sourcing this library to reflect the full set of -# options your script accepts. -usage_message="\ - --debug enable verbose shell tracing - -W, --warnings=CATEGORY - report the warnings falling in CATEGORY [all] - -v, --verbose verbosely report processing - --version print version information and exit - -h, --help print short or long help message and exit -" - -# Additional text appended to 'usage_message' in response to '--help'. -long_help_message=" -Warning categories include: - 'all' show all warnings - 'none' turn off all the warnings - 'error' warnings are treated as fatal errors" - -# Help message printed before fatal option parsing errors. -fatal_help="Try '\$progname --help' for more information." - - - -## ------------------------- ## -## Hook function management. ## -## ------------------------- ## - -# This section contains functions for adding, removing, and running hooks -# to the main code. A hook is just a named list of of function, that can -# be run in order later on. - -# func_hookable FUNC_NAME -# ----------------------- -# Declare that FUNC_NAME will run hooks added with -# 'func_add_hook FUNC_NAME ...'. -func_hookable () -{ - $debug_cmd - - func_append hookable_fns " $1" -} - - -# func_add_hook FUNC_NAME HOOK_FUNC -# --------------------------------- -# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must -# first have been declared "hookable" by a call to 'func_hookable'. -func_add_hook () -{ - $debug_cmd - - case " $hookable_fns " in - *" $1 "*) ;; - *) func_fatal_error "'$1' does not accept hook functions." ;; - esac - - eval func_append ${1}_hooks '" $2"' -} - - -# func_remove_hook FUNC_NAME HOOK_FUNC -# ------------------------------------ -# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. -func_remove_hook () -{ - $debug_cmd - - eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' -} - - -# func_run_hooks FUNC_NAME [ARG]... -# --------------------------------- -# Run all hook functions registered to FUNC_NAME. -# It is assumed that the list of hook functions contains nothing more -# than a whitespace-delimited list of legal shell function names, and -# no effort is wasted trying to catch shell meta-characters or preserve -# whitespace. -func_run_hooks () -{ - $debug_cmd - - case " $hookable_fns " in - *" $1 "*) ;; - *) func_fatal_error "'$1' does not support hook funcions.n" ;; - esac - - eval _G_hook_fns=\$$1_hooks; shift - - for _G_hook in $_G_hook_fns; do - eval $_G_hook '"$@"' - - # store returned options list back into positional - # parameters for next 'cmd' execution. - eval _G_hook_result=\$${_G_hook}_result - eval set dummy "$_G_hook_result"; shift - done - - func_quote_for_eval ${1+"$@"} - func_run_hooks_result=$func_quote_for_eval_result -} - - - -## --------------- ## -## Option parsing. ## -## --------------- ## - -# In order to add your own option parsing hooks, you must accept the -# full positional parameter list in your hook function, remove any -# options that you action, and then pass back the remaining unprocessed -# options in '_result', escaped suitably for -# 'eval'. Like this: -# -# my_options_prep () -# { -# $debug_cmd -# -# # Extend the existing usage message. -# usage_message=$usage_message' -# -s, --silent don'\''t print informational messages -# ' -# -# func_quote_for_eval ${1+"$@"} -# my_options_prep_result=$func_quote_for_eval_result -# } -# func_add_hook func_options_prep my_options_prep -# -# -# my_silent_option () -# { -# $debug_cmd -# -# # Note that for efficiency, we parse as many options as we can -# # recognise in a loop before passing the remainder back to the -# # caller on the first unrecognised argument we encounter. -# while test $# -gt 0; do -# opt=$1; shift -# case $opt in -# --silent|-s) opt_silent=: ;; -# # Separate non-argument short options: -# -s*) func_split_short_opt "$_G_opt" -# set dummy "$func_split_short_opt_name" \ -# "-$func_split_short_opt_arg" ${1+"$@"} -# shift -# ;; -# *) set dummy "$_G_opt" "$*"; shift; break ;; -# esac -# done -# -# func_quote_for_eval ${1+"$@"} -# my_silent_option_result=$func_quote_for_eval_result -# } -# func_add_hook func_parse_options my_silent_option -# -# -# my_option_validation () -# { -# $debug_cmd -# -# $opt_silent && $opt_verbose && func_fatal_help "\ -# '--silent' and '--verbose' options are mutually exclusive." -# -# func_quote_for_eval ${1+"$@"} -# my_option_validation_result=$func_quote_for_eval_result -# } -# func_add_hook func_validate_options my_option_validation -# -# You'll alse need to manually amend $usage_message to reflect the extra -# options you parse. It's preferable to append if you can, so that -# multiple option parsing hooks can be added safely. - - -# func_options [ARG]... -# --------------------- -# All the functions called inside func_options are hookable. See the -# individual implementations for details. -func_hookable func_options -func_options () -{ - $debug_cmd - - func_options_prep ${1+"$@"} - eval func_parse_options \ - ${func_options_prep_result+"$func_options_prep_result"} - eval func_validate_options \ - ${func_parse_options_result+"$func_parse_options_result"} - - eval func_run_hooks func_options \ - ${func_validate_options_result+"$func_validate_options_result"} - - # save modified positional parameters for caller - func_options_result=$func_run_hooks_result -} - - -# func_options_prep [ARG]... -# -------------------------- -# All initialisations required before starting the option parse loop. -# Note that when calling hook functions, we pass through the list of -# positional parameters. If a hook function modifies that list, and -# needs to propogate that back to rest of this script, then the complete -# modified list must be put in 'func_run_hooks_result' before -# returning. -func_hookable func_options_prep -func_options_prep () -{ - $debug_cmd - - # Option defaults: - opt_verbose=false - opt_warning_types= - - func_run_hooks func_options_prep ${1+"$@"} - - # save modified positional parameters for caller - func_options_prep_result=$func_run_hooks_result -} - - -# func_parse_options [ARG]... -# --------------------------- -# The main option parsing loop. -func_hookable func_parse_options -func_parse_options () -{ - $debug_cmd - - func_parse_options_result= - - # this just eases exit handling - while test $# -gt 0; do - # Defer to hook functions for initial option parsing, so they - # get priority in the event of reusing an option name. - func_run_hooks func_parse_options ${1+"$@"} - - # Adjust func_parse_options positional parameters to match - eval set dummy "$func_run_hooks_result"; shift - - # Break out of the loop if we already parsed every option. - test $# -gt 0 || break - - _G_opt=$1 - shift - case $_G_opt in - --debug|-x) debug_cmd='set -x' - func_echo "enabling shell trace mode" - $debug_cmd - ;; - - --no-warnings|--no-warning|--no-warn) - set dummy --warnings none ${1+"$@"} - shift - ;; - - --warnings|--warning|-W) - test $# = 0 && func_missing_arg $_G_opt && break - case " $warning_categories $1" in - *" $1 "*) - # trailing space prevents matching last $1 above - func_append_uniq opt_warning_types " $1" - ;; - *all) - opt_warning_types=$warning_categories - ;; - *none) - opt_warning_types=none - warning_func=: - ;; - *error) - opt_warning_types=$warning_categories - warning_func=func_fatal_error - ;; - *) - func_fatal_error \ - "unsupported warning category: '$1'" - ;; - esac - shift - ;; - - --verbose|-v) opt_verbose=: ;; - --version) func_version ;; - -\?|-h) func_usage ;; - --help) func_help ;; - - # Separate optargs to long options (plugins may need this): - --*=*) func_split_equals "$_G_opt" - set dummy "$func_split_equals_lhs" \ - "$func_split_equals_rhs" ${1+"$@"} - shift - ;; - - # Separate optargs to short options: - -W*) - func_split_short_opt "$_G_opt" - set dummy "$func_split_short_opt_name" \ - "$func_split_short_opt_arg" ${1+"$@"} - shift - ;; - - # Separate non-argument short options: - -\?*|-h*|-v*|-x*) - func_split_short_opt "$_G_opt" - set dummy "$func_split_short_opt_name" \ - "-$func_split_short_opt_arg" ${1+"$@"} - shift - ;; - - --) break ;; - -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; - esac - done - - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - func_parse_options_result=$func_quote_for_eval_result -} - - -# func_validate_options [ARG]... -# ------------------------------ -# Perform any sanity checks on option settings and/or unconsumed -# arguments. -func_hookable func_validate_options -func_validate_options () -{ - $debug_cmd - - # Display all warnings if -W was not given. - test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" - - func_run_hooks func_validate_options ${1+"$@"} - - # Bail if the options were screwed! - $exit_cmd $EXIT_FAILURE - - # save modified positional parameters for caller - func_validate_options_result=$func_run_hooks_result -} - - - -## ----------------- ## -## Helper functions. ## -## ----------------- ## - -# This section contains the helper functions used by the rest of the -# hookable option parser framework in ascii-betical order. - - -# func_fatal_help ARG... -# ---------------------- -# Echo program name prefixed message to standard error, followed by -# a help hint, and exit. -func_fatal_help () -{ - $debug_cmd - - eval \$ECHO \""Usage: $usage"\" - eval \$ECHO \""$fatal_help"\" - func_error ${1+"$@"} - exit $EXIT_FAILURE -} - - -# func_help -# --------- -# Echo long help message to standard output and exit. -func_help () -{ - $debug_cmd - - func_usage_message - $ECHO "$long_help_message" - exit 0 -} - - -# func_missing_arg ARGNAME -# ------------------------ -# Echo program name prefixed message to standard error and set global -# exit_cmd. -func_missing_arg () -{ - $debug_cmd - - func_error "Missing argument for '$1'." - exit_cmd=exit -} - - -# func_split_equals STRING -# ------------------------ -# Set func_split_equals_lhs and func_split_equals_rhs shell variables after -# splitting STRING at the '=' sign. -test -z "$_G_HAVE_XSI_OPS" \ - && (eval 'x=a/b/c; - test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ - && _G_HAVE_XSI_OPS=yes - -if test yes = "$_G_HAVE_XSI_OPS" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_split_equals () - { - $debug_cmd - - func_split_equals_lhs=${1%%=*} - func_split_equals_rhs=${1#*=} - test "x$func_split_equals_lhs" = "x$1" \ - && func_split_equals_rhs= - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_split_equals () - { - $debug_cmd - - func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` - func_split_equals_rhs= - test "x$func_split_equals_lhs" = "x$1" \ - || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` - } -fi #func_split_equals - - -# func_split_short_opt SHORTOPT -# ----------------------------- -# Set func_split_short_opt_name and func_split_short_opt_arg shell -# variables after splitting SHORTOPT after the 2nd character. -if test yes = "$_G_HAVE_XSI_OPS" -then - # This is an XSI compatible shell, allowing a faster implementation... - eval 'func_split_short_opt () - { - $debug_cmd - - func_split_short_opt_arg=${1#??} - func_split_short_opt_name=${1%"$func_split_short_opt_arg"} - }' -else - # ...otherwise fall back to using expr, which is often a shell builtin. - func_split_short_opt () - { - $debug_cmd - - func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` - func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` - } -fi #func_split_short_opt - - -# func_usage -# ---------- -# Echo short help message to standard output and exit. -func_usage () -{ - $debug_cmd - - func_usage_message - $ECHO "Run '$progname --help |${PAGER-more}' for full usage" - exit 0 -} - - -# func_usage_message -# ------------------ -# Echo short help message to standard output. -func_usage_message () -{ - $debug_cmd - - eval \$ECHO \""Usage: $usage"\" - echo - $SED -n 's|^# || - /^Written by/{ - x;p;x - } - h - /^Written by/q' < "$progpath" - echo - eval \$ECHO \""$usage_message"\" -} - - -# func_version -# ------------ -# Echo version message to standard output and exit. -func_version () -{ - $debug_cmd - - printf '%s\n' "$progname $scriptversion" - $SED -n ' - /(C)/!b go - :more - /\./!{ - N - s|\n# | | - b more - } - :go - /^# Written by /,/# warranty; / { - s|^# || - s|^# *$|| - s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| - p - } - /^# Written by / { - s|^# || - p - } - /^warranty; /q' < "$progpath" - - exit $? -} - - -# Local variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" -# time-stamp-time-zone: "UTC" -# End: - -# Set a version string. -scriptversion='(GNU libtool) 2.4.6' - - -# func_echo ARG... -# ---------------- -# Libtool also displays the current mode in messages, so override -# funclib.sh func_echo with this custom definition. -func_echo () -{ - $debug_cmd - - _G_message=$* - - func_echo_IFS=$IFS - IFS=$nl - for _G_line in $_G_message; do - IFS=$func_echo_IFS - $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" - done - IFS=$func_echo_IFS -} - - -# func_warning ARG... -# ------------------- -# Libtool warnings are not categorized, so override funclib.sh -# func_warning with this simpler definition. -func_warning () -{ - $debug_cmd - - $warning_func ${1+"$@"} -} - - -## ---------------- ## -## Options parsing. ## -## ---------------- ## - -# Hook in the functions to make sure our own options are parsed during -# the option parsing loop. - -usage='$progpath [OPTION]... [MODE-ARG]...' - -# Short help message in response to '-h'. -usage_message="Options: - --config show all configuration variables - --debug enable verbose shell tracing - -n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --mode=MODE use operation mode MODE - --no-warnings equivalent to '-Wnone' - --preserve-dup-deps don't remove duplicate dependency libraries - --quiet, --silent don't print informational messages - --tag=TAG use configuration variables from tag TAG - -v, --verbose print more informational messages than default - --version print version information - -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] - -h, --help, --help-all print short, long, or detailed help message -" - -# Additional text appended to 'usage_message' in response to '--help'. -func_help () -{ - $debug_cmd - - func_usage_message - $ECHO "$long_help_message - -MODE must be one of the following: - - clean remove files from the build directory - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. When passed as first option, -'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. -Try '$progname --help --mode=MODE' for a more detailed description of MODE. - -When reporting a bug, please describe a test case to reproduce it and -include the following information: - - host-triplet: $host - shell: $SHELL - compiler: $LTCC - compiler flags: $LTCFLAGS - linker: $LD (gnu? $with_gnu_ld) - version: $progname (GNU libtool) 2.4.6 - automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` - autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` - -Report bugs to . -GNU libtool home page: . -General help using GNU software: ." - exit 0 -} - - -# func_lo2o OBJECT-NAME -# --------------------- -# Transform OBJECT-NAME from a '.lo' suffix to the platform specific -# object suffix. - -lo2o=s/\\.lo\$/.$objext/ -o2lo=s/\\.$objext\$/.lo/ - -if test yes = "$_G_HAVE_XSI_OPS"; then - eval 'func_lo2o () - { - case $1 in - *.lo) func_lo2o_result=${1%.lo}.$objext ;; - * ) func_lo2o_result=$1 ;; - esac - }' - - # func_xform LIBOBJ-OR-SOURCE - # --------------------------- - # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) - # suffix to a '.lo' libtool-object suffix. - eval 'func_xform () - { - func_xform_result=${1%.*}.lo - }' -else - # ...otherwise fall back to using sed. - func_lo2o () - { - func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` - } - - func_xform () - { - func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` - } -fi - - -# func_fatal_configuration ARG... -# ------------------------------- -# Echo program name prefixed message to standard error, followed by -# a configuration failure hint, and exit. -func_fatal_configuration () -{ - func__fatal_error ${1+"$@"} \ - "See the $PACKAGE documentation for more information." \ - "Fatal configuration error." -} - - -# func_config -# ----------- -# Display the configuration for all the tags in this script. -func_config () -{ - re_begincf='^# ### BEGIN LIBTOOL' - re_endcf='^# ### END LIBTOOL' - - # Default configuration. - $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" - - # Now print the configurations for the tags. - for tagname in $taglist; do - $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" - done - - exit $? -} - - -# func_features -# ------------- -# Display the features supported by this script. -func_features () -{ - echo "host: $host" - if test yes = "$build_libtool_libs"; then - echo "enable shared libraries" - else - echo "disable shared libraries" - fi - if test yes = "$build_old_libs"; then - echo "enable static libraries" - else - echo "disable static libraries" - fi - - exit $? -} - - -# func_enable_tag TAGNAME -# ----------------------- -# Verify that TAGNAME is valid, and either flag an error and exit, or -# enable the TAGNAME tag. We also add TAGNAME to the global $taglist -# variable here. -func_enable_tag () -{ - # Global variable: - tagname=$1 - - re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" - re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" - sed_extractcf=/$re_begincf/,/$re_endcf/p - - # Validate tagname. - case $tagname in - *[!-_A-Za-z0-9,/]*) - func_fatal_error "invalid tag name: $tagname" - ;; - esac - - # Don't test for the "default" C tag, as we know it's - # there but not specially marked. - case $tagname in - CC) ;; - *) - if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then - taglist="$taglist $tagname" - - # Evaluate the configuration. Be careful to quote the path - # and the sed script, to avoid splitting on whitespace, but - # also don't use non-portable quotes within backquotes within - # quotes we have to do it in 2 steps: - extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` - eval "$extractedcf" - else - func_error "ignoring unknown tag $tagname" - fi - ;; - esac -} - - -# func_check_version_match -# ------------------------ -# Ensure that we are using m4 macros, and libtool script from the same -# release of libtool. -func_check_version_match () -{ - if test "$package_revision" != "$macro_revision"; then - if test "$VERSION" != "$macro_version"; then - if test -z "$macro_version"; then - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from an older release. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - fi - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, -$progname: but the definition of this LT_INIT comes from revision $macro_revision. -$progname: You should recreate aclocal.m4 with macros from revision $package_revision -$progname: of $PACKAGE $VERSION and run autoconf again. -_LT_EOF - fi - - exit $EXIT_MISMATCH - fi -} - - -# libtool_options_prep [ARG]... -# ----------------------------- -# Preparation for options parsed by libtool. -libtool_options_prep () -{ - $debug_mode - - # Option defaults: - opt_config=false - opt_dlopen= - opt_dry_run=false - opt_help=false - opt_mode= - opt_preserve_dup_deps=false - opt_quiet=false - - nonopt= - preserve_args= - - # Shorthand for --mode=foo, only valid as the first argument - case $1 in - clean|clea|cle|cl) - shift; set dummy --mode clean ${1+"$@"}; shift - ;; - compile|compil|compi|comp|com|co|c) - shift; set dummy --mode compile ${1+"$@"}; shift - ;; - execute|execut|execu|exec|exe|ex|e) - shift; set dummy --mode execute ${1+"$@"}; shift - ;; - finish|finis|fini|fin|fi|f) - shift; set dummy --mode finish ${1+"$@"}; shift - ;; - install|instal|insta|inst|ins|in|i) - shift; set dummy --mode install ${1+"$@"}; shift - ;; - link|lin|li|l) - shift; set dummy --mode link ${1+"$@"}; shift - ;; - uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) - shift; set dummy --mode uninstall ${1+"$@"}; shift - ;; - esac - - # Pass back the list of options. - func_quote_for_eval ${1+"$@"} - libtool_options_prep_result=$func_quote_for_eval_result -} -func_add_hook func_options_prep libtool_options_prep - - -# libtool_parse_options [ARG]... -# --------------------------------- -# Provide handling for libtool specific options. -libtool_parse_options () -{ - $debug_cmd - - # Perform our own loop to consume as many options as possible in - # each iteration. - while test $# -gt 0; do - _G_opt=$1 - shift - case $_G_opt in - --dry-run|--dryrun|-n) - opt_dry_run=: - ;; - - --config) func_config ;; - - --dlopen|-dlopen) - opt_dlopen="${opt_dlopen+$opt_dlopen -}$1" - shift - ;; - - --preserve-dup-deps) - opt_preserve_dup_deps=: ;; - - --features) func_features ;; - - --finish) set dummy --mode finish ${1+"$@"}; shift ;; - - --help) opt_help=: ;; - - --help-all) opt_help=': help-all' ;; - - --mode) test $# = 0 && func_missing_arg $_G_opt && break - opt_mode=$1 - case $1 in - # Valid mode arguments: - clean|compile|execute|finish|install|link|relink|uninstall) ;; - - # Catch anything else as an error - *) func_error "invalid argument for $_G_opt" - exit_cmd=exit - break - ;; - esac - shift - ;; - - --no-silent|--no-quiet) - opt_quiet=false - func_append preserve_args " $_G_opt" - ;; - - --no-warnings|--no-warning|--no-warn) - opt_warning=false - func_append preserve_args " $_G_opt" - ;; - - --no-verbose) - opt_verbose=false - func_append preserve_args " $_G_opt" - ;; - - --silent|--quiet) - opt_quiet=: - opt_verbose=false - func_append preserve_args " $_G_opt" - ;; - - --tag) test $# = 0 && func_missing_arg $_G_opt && break - opt_tag=$1 - func_append preserve_args " $_G_opt $1" - func_enable_tag "$1" - shift - ;; - - --verbose|-v) opt_quiet=false - opt_verbose=: - func_append preserve_args " $_G_opt" - ;; - - # An option not handled by this hook function: - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; - esac - done - - - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - libtool_parse_options_result=$func_quote_for_eval_result -} -func_add_hook func_parse_options libtool_parse_options - - - -# libtool_validate_options [ARG]... -# --------------------------------- -# Perform any sanity checks on option settings and/or unconsumed -# arguments. -libtool_validate_options () -{ - # save first non-option argument - if test 0 -lt $#; then - nonopt=$1 - shift - fi - - # preserve --debug - test : = "$debug_cmd" || func_append preserve_args " --debug" - - case $host in - # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 - # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) - # don't eliminate duplications in $postdeps and $predeps - opt_duplicate_compiler_generated_deps=: - ;; - *) - opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps - ;; - esac - - $opt_help || { - # Sanity checks first: - func_check_version_match - - test yes != "$build_libtool_libs" \ - && test yes != "$build_old_libs" \ - && func_fatal_configuration "not configured to build any kind of library" - - # Darwin sucks - eval std_shrext=\"$shrext_cmds\" - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$opt_dlopen" && test execute != "$opt_mode"; then - func_error "unrecognized option '-dlopen'" - $ECHO "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Change the help message to a mode-specific one. - generic_help=$help - help="Try '$progname --help --mode=$opt_mode' for more information." - } - - # Pass back the unparsed argument list - func_quote_for_eval ${1+"$@"} - libtool_validate_options_result=$func_quote_for_eval_result -} -func_add_hook func_validate_options libtool_validate_options - - -# Process options as early as possible so that --help and --version -# can return quickly. -func_options ${1+"$@"} -eval set dummy "$func_options_result"; shift - - - -## ----------- ## -## Main. ## -## ----------- ## - -magic='%%%MAGIC variable%%%' -magic_exe='%%%MAGIC EXE variable%%%' - -# Global variables. -extracted_archives= -extracted_serial=0 - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - -# func_generated_by_libtool -# True iff stdin has been generated by Libtool. This function is only -# a basic sanity check; it will hardly flush out determined imposters. -func_generated_by_libtool_p () -{ - $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 -} - -# func_lalib_p file -# True iff FILE is a libtool '.la' library or '.lo' object file. -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_lalib_p () -{ - test -f "$1" && - $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p -} - -# func_lalib_unsafe_p file -# True iff FILE is a libtool '.la' library or '.lo' object file. -# This function implements the same check as func_lalib_p without -# resorting to external programs. To this end, it redirects stdin and -# closes it afterwards, without saving the original file descriptor. -# As a safety measure, use it only where a negative result would be -# fatal anyway. Works if 'file' does not exist. -func_lalib_unsafe_p () -{ - lalib_p=no - if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then - for lalib_p_l in 1 2 3 4 - do - read lalib_p_line - case $lalib_p_line in - \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; - esac - done - exec 0<&5 5<&- - fi - test yes = "$lalib_p" -} - -# func_ltwrapper_script_p file -# True iff FILE is a libtool wrapper script -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_script_p () -{ - test -f "$1" && - $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p -} - -# func_ltwrapper_executable_p file -# True iff FILE is a libtool wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_executable_p () -{ - func_ltwrapper_exec_suffix= - case $1 in - *.exe) ;; - *) func_ltwrapper_exec_suffix=.exe ;; - esac - $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 -} - -# func_ltwrapper_scriptname file -# Assumes file is an ltwrapper_executable -# uses $file to determine the appropriate filename for a -# temporary ltwrapper_script. -func_ltwrapper_scriptname () -{ - func_dirname_and_basename "$1" "" "." - func_stripname '' '.exe' "$func_basename_result" - func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper -} - -# func_ltwrapper_p file -# True iff FILE is a libtool wrapper script or wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_p () -{ - func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" -} - - -# func_execute_cmds commands fail_cmd -# Execute tilde-delimited COMMANDS. -# If FAIL_CMD is given, eval that upon failure. -# FAIL_CMD may read-access the current command in variable CMD! -func_execute_cmds () -{ - $debug_cmd - - save_ifs=$IFS; IFS='~' - for cmd in $1; do - IFS=$sp$nl - eval cmd=\"$cmd\" - IFS=$save_ifs - func_show_eval "$cmd" "${2-:}" - done - IFS=$save_ifs -} - - -# func_source file -# Source FILE, adding directory component if necessary. -# Note that it is not necessary on cygwin/mingw to append a dot to -# FILE even if both FILE and FILE.exe exist: automatic-append-.exe -# behavior happens only for exec(3), not for open(2)! Also, sourcing -# 'FILE.' does not work on cygwin managed mounts. -func_source () -{ - $debug_cmd - - case $1 in - */* | *\\*) . "$1" ;; - *) . "./$1" ;; - esac -} - - -# func_resolve_sysroot PATH -# Replace a leading = in PATH with a sysroot. Store the result into -# func_resolve_sysroot_result -func_resolve_sysroot () -{ - func_resolve_sysroot_result=$1 - case $func_resolve_sysroot_result in - =*) - func_stripname '=' '' "$func_resolve_sysroot_result" - func_resolve_sysroot_result=$lt_sysroot$func_stripname_result - ;; - esac -} - -# func_replace_sysroot PATH -# If PATH begins with the sysroot, replace it with = and -# store the result into func_replace_sysroot_result. -func_replace_sysroot () -{ - case $lt_sysroot:$1 in - ?*:"$lt_sysroot"*) - func_stripname "$lt_sysroot" '' "$1" - func_replace_sysroot_result='='$func_stripname_result - ;; - *) - # Including no sysroot. - func_replace_sysroot_result=$1 - ;; - esac -} - -# func_infer_tag arg -# Infer tagged configuration to use if any are available and -# if one wasn't chosen via the "--tag" command line option. -# Only attempt this if the compiler in the base compile -# command doesn't match the default compiler. -# arg is usually of the form 'gcc ...' -func_infer_tag () -{ - $debug_cmd - - if test -n "$available_tags" && test -z "$tagname"; then - CC_quoted= - for arg in $CC; do - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case $@ in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then - # Evaluate the configuration. - eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" - CC_quoted= - for arg in $CC; do - # Double-quote args containing other shell metacharacters. - func_append_quoted CC_quoted "$arg" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case "$@ " in - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - func_echo "unable to infer tagged configuration" - func_fatal_error "specify a tag with '--tag'" -# else -# func_verbose "using $tagname tagged configuration" - fi - ;; - esac - fi -} - - - -# func_write_libtool_object output_name pic_name nonpic_name -# Create a libtool object file (analogous to a ".la" file), -# but don't create it if we're doing a dry run. -func_write_libtool_object () -{ - write_libobj=$1 - if test yes = "$build_libtool_libs"; then - write_lobj=\'$2\' - else - write_lobj=none - fi - - if test yes = "$build_old_libs"; then - write_oldobj=\'$3\' - else - write_oldobj=none - fi - - $opt_dry_run || { - cat >${write_libobj}T </dev/null` - if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then - func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | - $SED -e "$sed_naive_backslashify"` - else - func_convert_core_file_wine_to_w32_result= - fi - fi -} -# end: func_convert_core_file_wine_to_w32 - - -# func_convert_core_path_wine_to_w32 ARG -# Helper function used by path conversion functions when $build is *nix, and -# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly -# configured wine environment available, with the winepath program in $build's -# $PATH. Assumes ARG has no leading or trailing path separator characters. -# -# ARG is path to be converted from $build format to win32. -# Result is available in $func_convert_core_path_wine_to_w32_result. -# Unconvertible file (directory) names in ARG are skipped; if no directory names -# are convertible, then the result may be empty. -func_convert_core_path_wine_to_w32 () -{ - $debug_cmd - - # unfortunately, winepath doesn't convert paths, only file names - func_convert_core_path_wine_to_w32_result= - if test -n "$1"; then - oldIFS=$IFS - IFS=: - for func_convert_core_path_wine_to_w32_f in $1; do - IFS=$oldIFS - func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" - if test -n "$func_convert_core_file_wine_to_w32_result"; then - if test -z "$func_convert_core_path_wine_to_w32_result"; then - func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result - else - func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" - fi - fi - done - IFS=$oldIFS - fi -} -# end: func_convert_core_path_wine_to_w32 - - -# func_cygpath ARGS... -# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when -# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) -# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or -# (2), returns the Cygwin file name or path in func_cygpath_result (input -# file name or path is assumed to be in w32 format, as previously converted -# from $build's *nix or MSYS format). In case (3), returns the w32 file name -# or path in func_cygpath_result (input file name or path is assumed to be in -# Cygwin format). Returns an empty string on error. -# -# ARGS are passed to cygpath, with the last one being the file name or path to -# be converted. -# -# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH -# environment variable; do not put it in $PATH. -func_cygpath () -{ - $debug_cmd - - if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then - func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` - if test "$?" -ne 0; then - # on failure, ensure result is empty - func_cygpath_result= - fi - else - func_cygpath_result= - func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" - fi -} -#end: func_cygpath - - -# func_convert_core_msys_to_w32 ARG -# Convert file name or path ARG from MSYS format to w32 format. Return -# result in func_convert_core_msys_to_w32_result. -func_convert_core_msys_to_w32 () -{ - $debug_cmd - - # awkward: cmd appends spaces to result - func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | - $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` -} -#end: func_convert_core_msys_to_w32 - - -# func_convert_file_check ARG1 ARG2 -# Verify that ARG1 (a file name in $build format) was converted to $host -# format in ARG2. Otherwise, emit an error message, but continue (resetting -# func_to_host_file_result to ARG1). -func_convert_file_check () -{ - $debug_cmd - - if test -z "$2" && test -n "$1"; then - func_error "Could not determine host file name corresponding to" - func_error " '$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback: - func_to_host_file_result=$1 - fi -} -# end func_convert_file_check - - -# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH -# Verify that FROM_PATH (a path in $build format) was converted to $host -# format in TO_PATH. Otherwise, emit an error message, but continue, resetting -# func_to_host_file_result to a simplistic fallback value (see below). -func_convert_path_check () -{ - $debug_cmd - - if test -z "$4" && test -n "$3"; then - func_error "Could not determine the host path corresponding to" - func_error " '$3'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback. This is a deliberately simplistic "conversion" and - # should not be "improved". See libtool.info. - if test "x$1" != "x$2"; then - lt_replace_pathsep_chars="s|$1|$2|g" - func_to_host_path_result=`echo "$3" | - $SED -e "$lt_replace_pathsep_chars"` - else - func_to_host_path_result=$3 - fi - fi -} -# end func_convert_path_check - - -# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG -# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT -# and appending REPL if ORIG matches BACKPAT. -func_convert_path_front_back_pathsep () -{ - $debug_cmd - - case $4 in - $1 ) func_to_host_path_result=$3$func_to_host_path_result - ;; - esac - case $4 in - $2 ) func_append func_to_host_path_result "$3" - ;; - esac -} -# end func_convert_path_front_back_pathsep - - -################################################## -# $build to $host FILE NAME CONVERSION FUNCTIONS # -################################################## -# invoked via '$to_host_file_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# Result will be available in $func_to_host_file_result. - - -# func_to_host_file ARG -# Converts the file name ARG from $build format to $host format. Return result -# in func_to_host_file_result. -func_to_host_file () -{ - $debug_cmd - - $to_host_file_cmd "$1" -} -# end func_to_host_file - - -# func_to_tool_file ARG LAZY -# converts the file name ARG from $build format to toolchain format. Return -# result in func_to_tool_file_result. If the conversion in use is listed -# in (the comma separated) LAZY, no conversion takes place. -func_to_tool_file () -{ - $debug_cmd - - case ,$2, in - *,"$to_tool_file_cmd",*) - func_to_tool_file_result=$1 - ;; - *) - $to_tool_file_cmd "$1" - func_to_tool_file_result=$func_to_host_file_result - ;; - esac -} -# end func_to_tool_file - - -# func_convert_file_noop ARG -# Copy ARG to func_to_host_file_result. -func_convert_file_noop () -{ - func_to_host_file_result=$1 -} -# end func_convert_file_noop - - -# func_convert_file_msys_to_w32 ARG -# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_file_result. -func_convert_file_msys_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_to_host_file_result=$func_convert_core_msys_to_w32_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_w32 - - -# func_convert_file_cygwin_to_w32 ARG -# Convert file name ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_file_cygwin_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - # because $build is cygwin, we call "the" cygpath in $PATH; no need to use - # LT_CYGPATH in this case. - func_to_host_file_result=`cygpath -m "$1"` - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_cygwin_to_w32 - - -# func_convert_file_nix_to_w32 ARG -# Convert file name ARG from *nix to w32 format. Requires a wine environment -# and a working winepath. Returns result in func_to_host_file_result. -func_convert_file_nix_to_w32 () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_file_wine_to_w32 "$1" - func_to_host_file_result=$func_convert_core_file_wine_to_w32_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_w32 - - -# func_convert_file_msys_to_cygwin ARG -# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_file_msys_to_cygwin () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - func_convert_core_msys_to_w32 "$1" - func_cygpath -u "$func_convert_core_msys_to_w32_result" - func_to_host_file_result=$func_cygpath_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_msys_to_cygwin - - -# func_convert_file_nix_to_cygwin ARG -# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed -# in a wine environment, working winepath, and LT_CYGPATH set. Returns result -# in func_to_host_file_result. -func_convert_file_nix_to_cygwin () -{ - $debug_cmd - - func_to_host_file_result=$1 - if test -n "$1"; then - # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. - func_convert_core_file_wine_to_w32 "$1" - func_cygpath -u "$func_convert_core_file_wine_to_w32_result" - func_to_host_file_result=$func_cygpath_result - fi - func_convert_file_check "$1" "$func_to_host_file_result" -} -# end func_convert_file_nix_to_cygwin - - -############################################# -# $build to $host PATH CONVERSION FUNCTIONS # -############################################# -# invoked via '$to_host_path_cmd ARG' -# -# In each case, ARG is the path to be converted from $build to $host format. -# The result will be available in $func_to_host_path_result. -# -# Path separators are also converted from $build format to $host format. If -# ARG begins or ends with a path separator character, it is preserved (but -# converted to $host format) on output. -# -# All path conversion functions are named using the following convention: -# file name conversion function : func_convert_file_X_to_Y () -# path conversion function : func_convert_path_X_to_Y () -# where, for any given $build/$host combination the 'X_to_Y' value is the -# same. If conversion functions are added for new $build/$host combinations, -# the two new functions must follow this pattern, or func_init_to_host_path_cmd -# will break. - - -# func_init_to_host_path_cmd -# Ensures that function "pointer" variable $to_host_path_cmd is set to the -# appropriate value, based on the value of $to_host_file_cmd. -to_host_path_cmd= -func_init_to_host_path_cmd () -{ - $debug_cmd - - if test -z "$to_host_path_cmd"; then - func_stripname 'func_convert_file_' '' "$to_host_file_cmd" - to_host_path_cmd=func_convert_path_$func_stripname_result - fi -} - - -# func_to_host_path ARG -# Converts the path ARG from $build format to $host format. Return result -# in func_to_host_path_result. -func_to_host_path () -{ - $debug_cmd - - func_init_to_host_path_cmd - $to_host_path_cmd "$1" -} -# end func_to_host_path - - -# func_convert_path_noop ARG -# Copy ARG to func_to_host_path_result. -func_convert_path_noop () -{ - func_to_host_path_result=$1 -} -# end func_convert_path_noop - - -# func_convert_path_msys_to_w32 ARG -# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic -# conversion to w32 is not available inside the cwrapper. Returns result in -# func_to_host_path_result. -func_convert_path_msys_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # Remove leading and trailing path separator characters from ARG. MSYS - # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; - # and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result=$func_convert_core_msys_to_w32_result - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_msys_to_w32 - - -# func_convert_path_cygwin_to_w32 ARG -# Convert path ARG from Cygwin to w32 format. Returns result in -# func_to_host_file_result. -func_convert_path_cygwin_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_cygwin_to_w32 - - -# func_convert_path_nix_to_w32 ARG -# Convert path ARG from *nix to w32 format. Requires a wine environment and -# a working winepath. Returns result in func_to_host_file_result. -func_convert_path_nix_to_w32 () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_to_host_path_result=$func_convert_core_path_wine_to_w32_result - func_convert_path_check : ";" \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" - fi -} -# end func_convert_path_nix_to_w32 - - -# func_convert_path_msys_to_cygwin ARG -# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. -# Returns result in func_to_host_file_result. -func_convert_path_msys_to_cygwin () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # See func_convert_path_msys_to_w32: - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_msys_to_w32_result" - func_to_host_path_result=$func_cygpath_result - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_msys_to_cygwin - - -# func_convert_path_nix_to_cygwin ARG -# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a -# a wine environment, working winepath, and LT_CYGPATH set. Returns result in -# func_to_host_file_result. -func_convert_path_nix_to_cygwin () -{ - $debug_cmd - - func_to_host_path_result=$1 - if test -n "$1"; then - # Remove leading and trailing path separator characters from - # ARG. msys behavior is inconsistent here, cygpath turns them - # into '.;' and ';.', and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_path_tmp1=$func_stripname_result - func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" - func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" - func_to_host_path_result=$func_cygpath_result - func_convert_path_check : : \ - "$func_to_host_path_tmp1" "$func_to_host_path_result" - func_convert_path_front_back_pathsep ":*" "*:" : "$1" - fi -} -# end func_convert_path_nix_to_cygwin - - -# func_dll_def_p FILE -# True iff FILE is a Windows DLL '.def' file. -# Keep in sync with _LT_DLL_DEF_P in libtool.m4 -func_dll_def_p () -{ - $debug_cmd - - func_dll_def_p_tmp=`$SED -n \ - -e 's/^[ ]*//' \ - -e '/^\(;.*\)*$/d' \ - -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ - -e q \ - "$1"` - test DEF = "$func_dll_def_p_tmp" -} - - -# func_mode_compile arg... -func_mode_compile () -{ - $debug_cmd - - # Get the compilation command and the source file. - base_compile= - srcfile=$nonopt # always keep a non-empty value in "srcfile" - suppress_opt=yes - suppress_output= - arg_mode=normal - libobj= - later= - pie_flag= - - for arg - do - case $arg_mode in - arg ) - # do not "continue". Instead, add this to base_compile - lastarg=$arg - arg_mode=normal - ;; - - target ) - libobj=$arg - arg_mode=normal - continue - ;; - - normal ) - # Accept any command-line options. - case $arg in - -o) - test -n "$libobj" && \ - func_fatal_error "you cannot specify '-o' more than once" - arg_mode=target - continue - ;; - - -pie | -fpie | -fPIE) - func_append pie_flag " $arg" - continue - ;; - - -shared | -static | -prefer-pic | -prefer-non-pic) - func_append later " $arg" - continue - ;; - - -no-suppress) - suppress_opt=no - continue - ;; - - -Xcompiler) - arg_mode=arg # the next one goes into the "base_compile" arg list - continue # The current "srcfile" will either be retained or - ;; # replaced later. I would guess that would be a bug. - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - lastarg= - save_ifs=$IFS; IFS=, - for arg in $args; do - IFS=$save_ifs - func_append_quoted lastarg "$arg" - done - IFS=$save_ifs - func_stripname ' ' '' "$lastarg" - lastarg=$func_stripname_result - - # Add the arguments to base_compile. - func_append base_compile " $lastarg" - continue - ;; - - *) - # Accept the current argument as the source file. - # The previous "srcfile" becomes the current argument. - # - lastarg=$srcfile - srcfile=$arg - ;; - esac # case $arg - ;; - esac # case $arg_mode - - # Aesthetically quote the previous argument. - func_append_quoted base_compile "$lastarg" - done # for arg - - case $arg_mode in - arg) - func_fatal_error "you must specify an argument for -Xcompile" - ;; - target) - func_fatal_error "you must specify a target with '-o'" - ;; - *) - # Get the name of the library object. - test -z "$libobj" && { - func_basename "$srcfile" - libobj=$func_basename_result - } - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - case $libobj in - *.[cCFSifmso] | \ - *.ada | *.adb | *.ads | *.asm | \ - *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ - *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) - func_xform "$libobj" - libobj=$func_xform_result - ;; - esac - - case $libobj in - *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; - *) - func_fatal_error "cannot determine name of library object from '$libobj'" - ;; - esac - - func_infer_tag $base_compile - - for arg in $later; do - case $arg in - -shared) - test yes = "$build_libtool_libs" \ - || func_fatal_configuration "cannot build a shared library" - build_old_libs=no - continue - ;; - - -static) - build_libtool_libs=no - build_old_libs=yes - continue - ;; - - -prefer-pic) - pic_mode=yes - continue - ;; - - -prefer-non-pic) - pic_mode=no - continue - ;; - esac - done - - func_quote_for_eval "$libobj" - test "X$libobj" != "X$func_quote_for_eval_result" \ - && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ - && func_warning "libobj name '$libobj' may not contain shell special characters." - func_dirname_and_basename "$obj" "/" "" - objname=$func_basename_result - xdir=$func_dirname_result - lobj=$xdir$objdir/$objname - - test -z "$base_compile" && \ - func_fatal_help "you must specify a compilation command" - - # Delete any leftover library objects. - if test yes = "$build_old_libs"; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) - pic_mode=default - ;; - esac - if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test no = "$compiler_c_o"; then - output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext - lockfile=$output_obj.lock - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test yes = "$need_locks"; then - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - elif test warn = "$need_locks"; then - if test -f "$lockfile"; then - $ECHO "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - func_append removelist " $output_obj" - $ECHO "$srcfile" > "$lockfile" - fi - - $opt_dry_run || $RM $removelist - func_append removelist " $lockfile" - trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 - - func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 - srcfile=$func_to_tool_file_result - func_quote_for_eval "$srcfile" - qsrcfile=$func_quote_for_eval_result - - # Only build a PIC object if we are building libtool libraries. - if test yes = "$build_libtool_libs"; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - if test no != "$pic_mode"; then - command="$base_compile $qsrcfile $pic_flag" - else - # Don't build PIC code - command="$base_compile $qsrcfile" - fi - - func_mkdir_p "$xdir$objdir" - - if test -z "$output_obj"; then - # Place PIC objects in $objdir - func_append command " -o $lobj" - fi - - func_show_eval_locale "$command" \ - 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' - - if test warn = "$need_locks" && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - func_show_eval '$MV "$output_obj" "$lobj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - - # Allow error messages only from the first compilation. - if test yes = "$suppress_opt"; then - suppress_output=' >/dev/null 2>&1' - fi - fi - - # Only build a position-dependent object if we build old libraries. - if test yes = "$build_old_libs"; then - if test yes != "$pic_mode"; then - # Don't build PIC code - command="$base_compile $qsrcfile$pie_flag" - else - command="$base_compile $qsrcfile $pic_flag" - fi - if test yes = "$compiler_c_o"; then - func_append command " -o $obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - func_append command "$suppress_output" - func_show_eval_locale "$command" \ - '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' - - if test warn = "$need_locks" && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support '-c' and '-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - func_show_eval '$MV "$output_obj" "$obj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - fi - - $opt_dry_run || { - func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" - - # Unlock the critical section if it was locked - if test no != "$need_locks"; then - removelist=$lockfile - $RM "$lockfile" - fi - } - - exit $EXIT_SUCCESS -} - -$opt_help || { - test compile = "$opt_mode" && func_mode_compile ${1+"$@"} -} - -func_mode_help () -{ - # We need to display help for each of the modes. - case $opt_mode in - "") - # Generic help is extracted from the usage comments - # at the start of this file. - func_help - ;; - - clean) - $ECHO \ -"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - - compile) - $ECHO \ -"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -no-suppress do not suppress compiler output for multiple passes - -prefer-pic try to build PIC objects only - -prefer-non-pic try to build non-PIC objects only - -shared do not build a '.o' file suitable for static linking - -static only build a '.o' file suitable for static linking - -Wc,FLAG pass FLAG directly to the compiler - -COMPILE-COMMAND is a command to be used in creating a 'standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix '.c' with the -library object suffix, '.lo'." - ;; - - execute) - $ECHO \ -"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to '-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - - finish) - $ECHO \ -"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the '--dry-run' option if you just want to see what would be executed." - ;; - - install) - $ECHO \ -"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the 'install' or 'cp' program. - -The following components of INSTALL-COMMAND are treated specially: - - -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - - link) - $ECHO \ -"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -bindir BINDIR specify path to binaries directory (for systems where - libraries must be found in the PATH setting at runtime) - -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE use a list of object files found in FILE to specify objects - -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -shared only do dynamic linking of libtool libraries - -shrext SUFFIX override the standard shared library file extension - -static do not do any dynamic linking of uninstalled libtool libraries - -static-libtool-libs - do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -weak LIBNAME declare that the target provides the LIBNAME interface - -Wc,FLAG - -Xcompiler FLAG pass linker-specific FLAG directly to the compiler - -Wl,FLAG - -Xlinker FLAG pass linker-specific FLAG directly to the linker - -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) - -All other options (arguments beginning with '-') are ignored. - -Every other argument is treated as a filename. Files ending in '.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in '.la', then a libtool library is created, -only library objects ('.lo' files) may be specified, and '-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created -using 'ar' and 'ranlib', or on Windows using 'lib'. - -If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file -is created, otherwise an executable program is created." - ;; - - uninstall) - $ECHO \ -"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - - *) - func_fatal_help "invalid operation mode '$opt_mode'" - ;; - esac - - echo - $ECHO "Try '$progname --help' for more information about other modes." -} - -# Now that we've collected a possible --mode arg, show help if necessary -if $opt_help; then - if test : = "$opt_help"; then - func_mode_help - else - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - func_mode_help - done - } | $SED -n '1p; 2,$s/^Usage:/ or: /p' - { - func_help noexit - for opt_mode in compile link execute install finish uninstall clean; do - echo - func_mode_help - done - } | - $SED '1d - /^When reporting/,/^Report/{ - H - d - } - $x - /information about other modes/d - /more detailed .*MODE/d - s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' - fi - exit $? -fi - - -# func_mode_execute arg... -func_mode_execute () -{ - $debug_cmd - - # The first argument is the command name. - cmd=$nonopt - test -z "$cmd" && \ - func_fatal_help "you must specify a COMMAND" - - # Handle -dlopen flags immediately. - for file in $opt_dlopen; do - test -f "$file" \ - || func_fatal_help "'$file' is not a file" - - dir= - case $file in - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "'$lib' is not a valid libtool archive" - - # Read the libtool library. - dlname= - library_names= - func_source "$file" - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && \ - func_warning "'$file' was not linked with '-export-dynamic'" - continue - fi - - func_dirname "$file" "" "." - dir=$func_dirname_result - - if test -f "$dir/$objdir/$dlname"; then - func_append dir "/$objdir" - else - if test ! -f "$dir/$dlname"; then - func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" - fi - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - func_dirname "$file" "" "." - dir=$func_dirname_result - ;; - - *) - func_warning "'-dlopen' is ignored for non-libtool libraries and objects" - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir=$absdir - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic=$magic - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -* | *.la | *.lo ) ;; - *) - # Do a test to see if this is really a libtool program. - if func_ltwrapper_script_p "$file"; then - func_source "$file" - # Transform arg to wrapped name. - file=$progdir/$program - elif func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - func_source "$func_ltwrapper_scriptname_result" - # Transform arg to wrapped name. - file=$progdir/$program - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - func_append_quoted args "$file" - done - - if $opt_dry_run; then - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" - echo "export $shlibpath_var" - fi - $ECHO "$cmd$args" - exit $EXIT_SUCCESS - else - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES - do - eval "if test \"\${save_$lt_var+set}\" = set; then - $lt_var=\$save_$lt_var; export $lt_var - else - $lt_unset $lt_var - fi" - done - - # Now prepare to actually exec the command. - exec_cmd=\$cmd$args - fi -} - -test execute = "$opt_mode" && func_mode_execute ${1+"$@"} - - -# func_mode_finish arg... -func_mode_finish () -{ - $debug_cmd - - libs= - libdirs= - admincmds= - - for opt in "$nonopt" ${1+"$@"} - do - if test -d "$opt"; then - func_append libdirs " $opt" - - elif test -f "$opt"; then - if func_lalib_unsafe_p "$opt"; then - func_append libs " $opt" - else - func_warning "'$opt' is not a valid libtool archive" - fi - - else - func_fatal_error "invalid argument '$opt'" - fi - done - - if test -n "$libs"; then - if test -n "$lt_sysroot"; then - sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` - sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" - else - sysroot_cmd= - fi - - # Remove sysroot references - if $opt_dry_run; then - for lib in $libs; do - echo "removing references to $lt_sysroot and '=' prefixes from $lib" - done - else - tmpdir=`func_mktempdir` - for lib in $libs; do - $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ - > $tmpdir/tmp-la - mv -f $tmpdir/tmp-la $lib - done - ${RM}r "$tmpdir" - fi - fi - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - func_execute_cmds "$finish_cmds" 'admincmds="$admincmds -'"$cmd"'"' - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $opt_dry_run || eval "$cmds" || func_append admincmds " - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - $opt_quiet && exit $EXIT_SUCCESS - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - echo "----------------------------------------------------------------------" - echo "Libraries have been installed in:" - for libdir in $libdirs; do - $ECHO " $libdir" - done - echo - echo "If you ever happen to want to link against installed libraries" - echo "in a given directory, LIBDIR, you must either use libtool, and" - echo "specify the full pathname of the library, or use the '-LLIBDIR'" - echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - echo " - add LIBDIR to the '$shlibpath_var' environment variable" - echo " during execution" - fi - if test -n "$runpath_var"; then - echo " - add LIBDIR to the '$runpath_var' environment variable" - echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $ECHO " - use the '$flag' linker flag" - fi - if test -n "$admincmds"; then - $ECHO " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" - fi - echo - - echo "See any operating system documentation about shared libraries for" - case $host in - solaris2.[6789]|solaris2.1[0-9]) - echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" - echo "pages." - ;; - *) - echo "more information, such as the ld(1) and ld.so(8) manual pages." - ;; - esac - echo "----------------------------------------------------------------------" - fi - exit $EXIT_SUCCESS -} - -test finish = "$opt_mode" && func_mode_finish ${1+"$@"} - - -# func_mode_install arg... -func_mode_install () -{ - $debug_cmd - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || - # Allow the use of GNU shtool's install command. - case $nonopt in *shtool*) :;; *) false;; esac - then - # Aesthetically quote it. - func_quote_for_eval "$nonopt" - install_prog="$func_quote_for_eval_result " - arg=$1 - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - func_quote_for_eval "$arg" - func_append install_prog "$func_quote_for_eval_result" - install_shared_prog=$install_prog - case " $install_prog " in - *[\\\ /]cp\ *) install_cp=: ;; - *) install_cp=false ;; - esac - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=false - stripme= - no_mode=: - for arg - do - arg2= - if test -n "$dest"; then - func_append files " $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=: ;; - -f) - if $install_cp; then :; else - prev=$arg - fi - ;; - -g | -m | -o) - prev=$arg - ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - if test X-m = "X$prev" && test -n "$install_override_mode"; then - arg2=$install_override_mode - no_mode=false - fi - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - func_quote_for_eval "$arg" - func_append install_prog " $func_quote_for_eval_result" - if test -n "$arg2"; then - func_quote_for_eval "$arg2" - fi - func_append install_shared_prog " $func_quote_for_eval_result" - done - - test -z "$install_prog" && \ - func_fatal_help "you must specify an install program" - - test -n "$prev" && \ - func_fatal_help "the '$prev' option requires an argument" - - if test -n "$install_override_mode" && $no_mode; then - if $install_cp; then :; else - func_quote_for_eval "$install_override_mode" - func_append install_shared_prog " -m $func_quote_for_eval_result" - fi - fi - - if test -z "$files"; then - if test -z "$dest"; then - func_fatal_help "no file or destination specified" - else - func_fatal_help "you must specify a destination" - fi - fi - - # Strip any trailing slash from the destination. - func_stripname '' '/' "$dest" - dest=$func_stripname_result - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=: - if $isdir; then - destdir=$dest - destname= - else - func_dirname_and_basename "$dest" "" "." - destdir=$func_dirname_result - destname=$func_basename_result - - # Not a directory, so check to see that there is only one file specified. - set dummy $files; shift - test "$#" -gt 1 && \ - func_fatal_help "'$dest' is not a directory" - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - func_fatal_help "'$destdir' must be an absolute directory name" - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic=$magic - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - func_append staticlibs " $file" - ;; - - *.la) - func_resolve_sysroot "$file" - file=$func_resolve_sysroot_result - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "'$file' is not a valid libtool archive" - - library_names= - old_library= - relink_command= - func_source "$file" - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) func_append current_libdirs " $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) func_append future_libdirs " $libdir" ;; - esac - fi - - func_dirname "$file" "/" "" - dir=$func_dirname_result - func_append dir "$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - test "$inst_prefix_dir" = "$destdir" && \ - func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - func_warning "relinking '$file'" - func_show_eval "$relink_command" \ - 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' - fi - - # See the names of the shared library. - set dummy $library_names; shift - if test -n "$1"; then - realname=$1 - shift - - srcname=$realname - test -n "$relink_command" && srcname=${realname}T - - # Install the shared library and build the symlinks. - func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ - 'exit $?' - tstripme=$stripme - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - case $realname in - *.dll.a) - tstripme= - ;; - esac - ;; - os2*) - case $realname in - *_dll.a) - tstripme= - ;; - esac - ;; - esac - if test -n "$tstripme" && test -n "$striplib"; then - func_show_eval "$striplib $destdir/$realname" 'exit $?' - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try 'ln -sf' first, because the 'ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - test "$linkname" != "$realname" \ - && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" - done - fi - - # Do each command in the postinstall commands. - lib=$destdir/$realname - func_execute_cmds "$postinstall_cmds" 'exit $?' - fi - - # Install the pseudo-library for information purposes. - func_basename "$file" - name=$func_basename_result - instname=$dir/${name}i - func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' - - # Maybe install the static library, too. - test -n "$old_library" && func_append staticlibs " $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile=$destdir/$destname - else - func_basename "$file" - destfile=$func_basename_result - destfile=$destdir/$destfile - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - func_lo2o "$destfile" - staticdest=$func_lo2o_result - ;; - *.$objext) - staticdest=$destfile - destfile= - ;; - *) - func_fatal_help "cannot copy a libtool object to '$destfile'" - ;; - esac - - # Install the libtool object if requested. - test -n "$destfile" && \ - func_show_eval "$install_prog $file $destfile" 'exit $?' - - # Install the old object if enabled. - if test yes = "$build_old_libs"; then - # Deduce the name of the old-style object file. - func_lo2o "$file" - staticobj=$func_lo2o_result - func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile=$destdir/$destname - else - func_basename "$file" - destfile=$func_basename_result - destfile=$destdir/$destfile - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext= - case $file in - *.exe) - if test ! -f "$file"; then - func_stripname '' '.exe' "$file" - file=$func_stripname_result - stripped_ext=.exe - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin* | *mingw*) - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - wrapper=$func_ltwrapper_scriptname_result - else - func_stripname '' '.exe' "$file" - wrapper=$func_stripname_result - fi - ;; - *) - wrapper=$file - ;; - esac - if func_ltwrapper_script_p "$wrapper"; then - notinst_deplibs= - relink_command= - - func_source "$wrapper" - - # Check the variables that should have been set. - test -z "$generated_by_libtool_version" && \ - func_fatal_error "invalid libtool wrapper script '$wrapper'" - - finalize=: - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - func_source "$lib" - fi - libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` - if test -n "$libdir" && test ! -f "$libfile"; then - func_warning "'$lib' has not been installed in '$libdir'" - finalize=false - fi - done - - relink_command= - func_source "$wrapper" - - outputname= - if test no = "$fast_install" && test -n "$relink_command"; then - $opt_dry_run || { - if $finalize; then - tmpdir=`func_mktempdir` - func_basename "$file$stripped_ext" - file=$func_basename_result - outputname=$tmpdir/$file - # Replace the output file specification. - relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` - - $opt_quiet || { - func_quote_for_expand "$relink_command" - eval "func_echo $func_quote_for_expand_result" - } - if eval "$relink_command"; then : - else - func_error "error: relink '$file' with the above command before installing it" - $opt_dry_run || ${RM}r "$tmpdir" - continue - fi - file=$outputname - else - func_warning "cannot relink '$file'" - fi - } - else - # Install the binary that we compiled earlier. - file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - func_stripname '' '.exe' "$destfile" - destfile=$func_stripname_result - ;; - esac - ;; - esac - func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' - $opt_dry_run || if test -n "$outputname"; then - ${RM}r "$tmpdir" - fi - ;; - esac - done - - for file in $staticlibs; do - func_basename "$file" - name=$func_basename_result - - # Set up the ranlib parameters. - oldlib=$destdir/$name - func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 - tool_oldlib=$func_to_tool_file_result - - func_show_eval "$install_prog \$file \$oldlib" 'exit $?' - - if test -n "$stripme" && test -n "$old_striplib"; then - func_show_eval "$old_striplib $tool_oldlib" 'exit $?' - fi - - # Do each command in the postinstall commands. - func_execute_cmds "$old_postinstall_cmds" 'exit $?' - done - - test -n "$future_libdirs" && \ - func_warning "remember to run '$progname --finish$future_libdirs'" - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - $opt_dry_run && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi -} - -test install = "$opt_mode" && func_mode_install ${1+"$@"} - - -# func_generate_dlsyms outputname originator pic_p -# Extract symbols from dlprefiles and create ${outputname}S.o with -# a dlpreopen symbol table. -func_generate_dlsyms () -{ - $debug_cmd - - my_outputname=$1 - my_originator=$2 - my_pic_p=${3-false} - my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` - my_dlsyms= - - if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - my_dlsyms=${my_outputname}S.c - else - func_error "not configured to extract global symbols from dlpreopened files" - fi - fi - - if test -n "$my_dlsyms"; then - case $my_dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist=$output_objdir/$my_outputname.nm - - func_show_eval "$RM $nlist ${nlist}S ${nlist}T" - - # Parse the name list into a source file. - func_verbose "creating $output_objdir/$my_dlsyms" - - $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ -/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ -/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) -#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" -#endif - -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) - -/* External symbol declarations for the compiler. */\ -" - - if test yes = "$dlself"; then - func_verbose "generating symbol list for '$output'" - - $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` - for progfile in $progfiles; do - func_to_tool_file "$progfile" func_convert_file_msys_to_w32 - func_verbose "extracting global C symbols from '$func_to_tool_file_result'" - $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $opt_dry_run || { - eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - if test -n "$export_symbols_regex"; then - $opt_dry_run || { - eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - } - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols=$output_objdir/$outputname.exp - $opt_dry_run || { - $RM $export_symbols - eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - case $host in - *cygwin* | *mingw* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' - ;; - esac - } - else - $opt_dry_run || { - eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' - eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' - eval '$MV "$nlist"T "$nlist"' - case $host in - *cygwin* | *mingw* | *cegcc* ) - eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' - eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' - ;; - esac - } - fi - fi - - for dlprefile in $dlprefiles; do - func_verbose "extracting global C symbols from '$dlprefile'" - func_basename "$dlprefile" - name=$func_basename_result - case $host in - *cygwin* | *mingw* | *cegcc* ) - # if an import library, we need to obtain dlname - if func_win32_import_lib_p "$dlprefile"; then - func_tr_sh "$dlprefile" - eval "curr_lafile=\$libfile_$func_tr_sh_result" - dlprefile_dlbasename= - if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then - # Use subshell, to avoid clobbering current variable values - dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` - if test -n "$dlprefile_dlname"; then - func_basename "$dlprefile_dlname" - dlprefile_dlbasename=$func_basename_result - else - # no lafile. user explicitly requested -dlpreopen . - $sharedlib_from_linklib_cmd "$dlprefile" - dlprefile_dlbasename=$sharedlib_from_linklib_result - fi - fi - $opt_dry_run || { - if test -n "$dlprefile_dlbasename"; then - eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' - else - func_warning "Could not compute DLL name from $name" - eval '$ECHO ": $name " >> "$nlist"' - fi - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | - $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" - } - else # not an import lib - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - fi - ;; - *) - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - ;; - esac - done - - $opt_dry_run || { - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if $GREP -v "^: " < "$nlist" | - if sort -k 3 /dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - $GREP -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' - else - echo '/* NONE */' >> "$output_objdir/$my_dlsyms" - fi - - func_show_eval '$RM "${nlist}I"' - if test -n "$global_symbol_to_import"; then - eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' - fi - - echo >> "$output_objdir/$my_dlsyms" "\ - -/* The mapping between symbol names and symbols. */ -typedef struct { - const char *name; - void *address; -} lt_dlsymlist; -extern LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[];\ -" - - if test -s "$nlist"I; then - echo >> "$output_objdir/$my_dlsyms" "\ -static void lt_syminit(void) -{ - LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; - for (; symbol->name; ++symbol) - {" - $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" - echo >> "$output_objdir/$my_dlsyms" "\ - } -}" - fi - echo >> "$output_objdir/$my_dlsyms" "\ -LT_DLSYM_CONST lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[] = -{ {\"$my_originator\", (void *) 0}," - - if test -s "$nlist"I; then - echo >> "$output_objdir/$my_dlsyms" "\ - {\"@INIT@\", (void *) <_syminit}," - fi - - case $need_lib_prefix in - no) - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - *) - eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - esac - echo >> "$output_objdir/$my_dlsyms" "\ - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_${my_prefix}_LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - } # !$opt_dry_run - - pic_flag_for_symtable= - case "$compile_command " in - *" -static "*) ;; - *) - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; - *-*-hpux*) - pic_flag_for_symtable=" $pic_flag" ;; - *) - $my_pic_p && pic_flag_for_symtable=" $pic_flag" - ;; - esac - ;; - esac - symtab_cflags= - for arg in $LTCFLAGS; do - case $arg in - -pie | -fpie | -fPIE) ;; - *) func_append symtab_cflags " $arg" ;; - esac - done - - # Now compile the dynamic symbol file. - func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' - - # Clean up the generated files. - func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' - - # Transform the symbol file into the correct name. - symfileobj=$output_objdir/${my_outputname}S.$objext - case $host in - *cygwin* | *mingw* | *cegcc* ) - if test -f "$output_objdir/$my_outputname.def"; then - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - else - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - fi - ;; - *) - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - ;; - esac - ;; - *) - func_fatal_error "unknown suffix for '$my_dlsyms'" - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` - fi -} - -# func_cygming_gnu_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is a GNU/binutils-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_gnu_implib_p () -{ - $debug_cmd - - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` - test -n "$func_cygming_gnu_implib_tmp" -} - -# func_cygming_ms_implib_p ARG -# This predicate returns with zero status (TRUE) if -# ARG is an MS-style import library. Returns -# with nonzero status (FALSE) otherwise. -func_cygming_ms_implib_p () -{ - $debug_cmd - - func_to_tool_file "$1" func_convert_file_msys_to_w32 - func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` - test -n "$func_cygming_ms_implib_tmp" -} - -# func_win32_libid arg -# return the library type of file 'arg' -# -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -# Despite the name, also deal with 64 bit binaries. -func_win32_libid () -{ - $debug_cmd - - win32_libid_type=unknown - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. - if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | - $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then - case $nm_interface in - "MS dumpbin") - if func_cygming_ms_implib_p "$1" || - func_cygming_gnu_implib_p "$1" - then - win32_nmres=import - else - win32_nmres= - fi - ;; - *) - func_to_tool_file "$1" func_convert_file_msys_to_w32 - win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | - $SED -n -e ' - 1,100{ - / I /{ - s|.*|import| - p - q - } - }'` - ;; - esac - case $win32_nmres in - import*) win32_libid_type="x86 archive import";; - *) win32_libid_type="x86 archive static";; - esac - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $ECHO "$win32_libid_type" -} - -# func_cygming_dll_for_implib ARG -# -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib () -{ - $debug_cmd - - sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` -} - -# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs -# -# The is the core of a fallback implementation of a -# platform-specific function to extract the name of the -# DLL associated with the specified import library LIBNAME. -# -# SECTION_NAME is either .idata$6 or .idata$7, depending -# on the platform and compiler that created the implib. -# -# Echos the name of the DLL associated with the -# specified import library. -func_cygming_dll_for_implib_fallback_core () -{ - $debug_cmd - - match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` - $OBJDUMP -s --section "$1" "$2" 2>/dev/null | - $SED '/^Contents of section '"$match_literal"':/{ - # Place marker at beginning of archive member dllname section - s/.*/====MARK====/ - p - d - } - # These lines can sometimes be longer than 43 characters, but - # are always uninteresting - /:[ ]*file format pe[i]\{,1\}-/d - /^In archive [^:]*:/d - # Ensure marker is printed - /^====MARK====/p - # Remove all lines with less than 43 characters - /^.\{43\}/!d - # From remaining lines, remove first 43 characters - s/^.\{43\}//' | - $SED -n ' - # Join marker and all lines until next marker into a single line - /^====MARK====/ b para - H - $ b para - b - :para - x - s/\n//g - # Remove the marker - s/^====MARK====// - # Remove trailing dots and whitespace - s/[\. \t]*$// - # Print - /./p' | - # we now have a list, one entry per line, of the stringified - # contents of the appropriate section of all members of the - # archive that possess that section. Heuristic: eliminate - # all those that have a first or second character that is - # a '.' (that is, objdump's representation of an unprintable - # character.) This should work for all archives with less than - # 0x302f exports -- but will fail for DLLs whose name actually - # begins with a literal '.' or a single character followed by - # a '.'. - # - # Of those that remain, print the first one. - $SED -e '/^\./d;/^.\./d;q' -} - -# func_cygming_dll_for_implib_fallback ARG -# Platform-specific function to extract the -# name of the DLL associated with the specified -# import library ARG. -# -# This fallback implementation is for use when $DLLTOOL -# does not support the --identify-strict option. -# Invoked by eval'ing the libtool variable -# $sharedlib_from_linklib_cmd -# Result is available in the variable -# $sharedlib_from_linklib_result -func_cygming_dll_for_implib_fallback () -{ - $debug_cmd - - if func_cygming_gnu_implib_p "$1"; then - # binutils import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` - elif func_cygming_ms_implib_p "$1"; then - # ms-generated import library - sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` - else - # unknown - sharedlib_from_linklib_result= - fi -} - - -# func_extract_an_archive dir oldlib -func_extract_an_archive () -{ - $debug_cmd - - f_ex_an_ar_dir=$1; shift - f_ex_an_ar_oldlib=$1 - if test yes = "$lock_old_archive_extraction"; then - lockfile=$f_ex_an_ar_oldlib.lock - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - fi - func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ - 'stat=$?; rm -f "$lockfile"; exit $stat' - if test yes = "$lock_old_archive_extraction"; then - $opt_dry_run || rm -f "$lockfile" - fi - if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then - : - else - func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" - fi -} - - -# func_extract_archives gentop oldlib ... -func_extract_archives () -{ - $debug_cmd - - my_gentop=$1; shift - my_oldlibs=${1+"$@"} - my_oldobjs= - my_xlib= - my_xabs= - my_xdir= - - for my_xlib in $my_oldlibs; do - # Extract the objects. - case $my_xlib in - [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; - *) my_xabs=`pwd`"/$my_xlib" ;; - esac - func_basename "$my_xlib" - my_xlib=$func_basename_result - my_xlib_u=$my_xlib - while :; do - case " $extracted_archives " in - *" $my_xlib_u "*) - func_arith $extracted_serial + 1 - extracted_serial=$func_arith_result - my_xlib_u=lt$extracted_serial-$my_xlib ;; - *) break ;; - esac - done - extracted_archives="$extracted_archives $my_xlib_u" - my_xdir=$my_gentop/$my_xlib_u - - func_mkdir_p "$my_xdir" - - case $host in - *-darwin*) - func_verbose "Extracting $my_xabs" - # Do not bother doing anything if just a dry run - $opt_dry_run || { - darwin_orig_dir=`pwd` - cd $my_xdir || exit $? - darwin_archive=$my_xabs - darwin_curdir=`pwd` - func_basename "$darwin_archive" - darwin_base_archive=$func_basename_result - darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` - if test -n "$darwin_arches"; then - darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` - darwin_arch= - func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" - for darwin_arch in $darwin_arches; do - func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" - $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" - cd "unfat-$$/$darwin_base_archive-$darwin_arch" - func_extract_an_archive "`pwd`" "$darwin_base_archive" - cd "$darwin_curdir" - $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" - done # $darwin_arches - ## Okay now we've a bunch of thin objects, gotta fatten them up :) - darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` - darwin_file= - darwin_files= - for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` - $LIPO -create -output "$darwin_file" $darwin_files - done # $darwin_filelist - $RM -rf unfat-$$ - cd "$darwin_orig_dir" - else - cd $darwin_orig_dir - func_extract_an_archive "$my_xdir" "$my_xabs" - fi # $darwin_arches - } # !$opt_dry_run - ;; - *) - func_extract_an_archive "$my_xdir" "$my_xabs" - ;; - esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` - done - - func_extract_archives_result=$my_oldobjs -} - - -# func_emit_wrapper [arg=no] -# -# Emit a libtool wrapper script on stdout. -# Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw -# wrapper executable. Must ONLY be called from within -# func_mode_link because it depends on a number of variables -# set therein. -# -# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR -# variable will take. If 'yes', then the emitted script -# will assume that the directory where it is stored is -# the $objdir directory. This is a cygwin/mingw-specific -# behavior. -func_emit_wrapper () -{ - func_emit_wrapper_arg1=${1-no} - - $ECHO "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM (GNU $PACKAGE) $VERSION -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='$sed_quote_subst' - -# Be Bourne compatible -if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variables: - generated_by_libtool_version='$macro_version' - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$ECHO are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - file=\"\$0\"" - - qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` - $ECHO "\ - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - ECHO=\"$qECHO\" - fi - -# Very basic option parsing. These options are (a) specific to -# the libtool wrapper, (b) are identical between the wrapper -# /script/ and the wrapper /executable/ that is used only on -# windows platforms, and (c) all begin with the string "--lt-" -# (application programs are unlikely to have options that match -# this pattern). -# -# There are only two supported options: --lt-debug and -# --lt-dump-script. There is, deliberately, no --lt-help. -# -# The first argument to this parsing function should be the -# script's $0 value, followed by "$@". -lt_option_debug= -func_parse_lt_options () -{ - lt_script_arg0=\$0 - shift - for lt_opt - do - case \"\$lt_opt\" in - --lt-debug) lt_option_debug=1 ;; - --lt-dump-script) - lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` - test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. - lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` - cat \"\$lt_dump_D/\$lt_dump_F\" - exit 0 - ;; - --lt-*) - \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 - exit 1 - ;; - esac - done - - # Print the debug banner immediately: - if test -n \"\$lt_option_debug\"; then - echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 - fi -} - -# Used when --lt-debug. Prints its arguments to stdout -# (redirection is the responsibility of the caller) -func_lt_dump_args () -{ - lt_dump_args_N=1; - for lt_arg - do - \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" - lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` - done -} - -# Core function for launching the target application -func_exec_program_core () -{ -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $ECHO "\ - if test -n \"\$lt_option_debug\"; then - \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 - func_lt_dump_args \${1+\"\$@\"} 1>&2 - fi - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $ECHO "\ - \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 - exit 1 -} - -# A function to encapsulate launching the target application -# Strips options in the --lt-* namespace from \$@ and -# launches target application with the remaining arguments. -func_exec_program () -{ - case \" \$* \" in - *\\ --lt-*) - for lt_wr_arg - do - case \$lt_wr_arg in - --lt-*) ;; - *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; - esac - shift - done ;; - esac - func_exec_program_core \${1+\"\$@\"} -} - - # Parse options - func_parse_lt_options \"\$0\" \${1+\"\$@\"} - - # Find the directory that this script lives in. - thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` - done - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 - if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then - # special case for '.' - if test \"\$thisdir\" = \".\"; then - thisdir=\`pwd\` - fi - # remove .libs from thisdir - case \"\$thisdir\" in - *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; - $objdir ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test yes = "$fast_install"; then - $ECHO "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $MKDIR \"\$progdir\" - else - $RM \"\$progdir/\$file\" - fi" - - $ECHO "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - \$ECHO \"\$relink_command_output\" >&2 - $RM \"\$progdir/\$file\" - exit 1 - fi - fi - - $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $RM \"\$progdir/\$program\"; - $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $RM \"\$progdir/\$file\" - fi" - else - $ECHO "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $ECHO "\ - - if test -f \"\$progdir/\$program\"; then" - - # fixup the dll searchpath if we need to. - # - # Fix the DLL searchpath if we need to. Do this before prepending - # to shlibpath, because on Windows, both are PATH and uninstalled - # libraries must come first. - if test -n "$dllsearchpath"; then - $ECHO "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - # Export our shlibpath_var if we have one. - if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $ECHO "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` - - export $shlibpath_var -" - fi - - $ECHO "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. - func_exec_program \${1+\"\$@\"} - fi - else - # The program doesn't exist. - \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 - \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 - \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" -} - - -# func_emit_cwrapperexe_src -# emit the source code for a wrapper executable on stdout -# Must ONLY be called from within func_mode_link because -# it depends on a number of variable set therein. -func_emit_cwrapperexe_src () -{ - cat < -#include -#ifdef _MSC_VER -# include -# include -# include -#else -# include -# include -# ifdef __CYGWIN__ -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) - -/* declarations of non-ANSI functions */ -#if defined __MINGW32__ -# ifdef __STRICT_ANSI__ -int _putenv (const char *); -# endif -#elif defined __CYGWIN__ -# ifdef __STRICT_ANSI__ -char *realpath (const char *, char *); -int putenv (char *); -int setenv (const char *, const char *, int); -# endif -/* #elif defined other_platform || defined ... */ -#endif - -/* portability defines, excluding path handling macros */ -#if defined _MSC_VER -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -# define S_IXUSR _S_IEXEC -#elif defined __MINGW32__ -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -#elif defined __CYGWIN__ -# define HAVE_SETENV -# define FOPEN_WB "wb" -/* #elif defined other platforms ... */ -#endif - -#if defined PATH_MAX -# define LT_PATHMAX PATH_MAX -#elif defined MAXPATHLEN -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef S_IXOTH -# define S_IXOTH 0 -#endif -#ifndef S_IXGRP -# define S_IXGRP 0 -#endif - -/* path handling portability macros */ -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ - defined __OS2__ -# define HAVE_DOS_BASED_FILE_SYSTEM -# define FOPEN_WB "wb" -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#ifndef FOPEN_WB -# define FOPEN_WB "w" -#endif -#ifndef _O_BINARY -# define _O_BINARY 0 -#endif - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free (stale); stale = 0; } \ -} while (0) - -#if defined LT_DEBUGWRAPPER -static int lt_debug = 1; -#else -static int lt_debug = 0; -#endif - -const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ - -void *xmalloc (size_t num); -char *xstrdup (const char *string); -const char *base_name (const char *name); -char *find_executable (const char *wrapper); -char *chase_symlinks (const char *pathspec); -int make_executable (const char *path); -int check_executable (const char *path); -char *strendzap (char *str, const char *pat); -void lt_debugprintf (const char *file, int line, const char *fmt, ...); -void lt_fatal (const char *file, int line, const char *message, ...); -static const char *nonnull (const char *s); -static const char *nonempty (const char *s); -void lt_setenv (const char *name, const char *value); -char *lt_extend_str (const char *orig_value, const char *add, int to_end); -void lt_update_exe_path (const char *name, const char *value); -void lt_update_lib_path (const char *name, const char *value); -char **prepare_spawn (char **argv); -void lt_dump_script (FILE *f); -EOF - - cat <= 0) - && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) - return 1; - else - return 0; -} - -int -make_executable (const char *path) -{ - int rval = 0; - struct stat st; - - lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", - nonempty (path)); - if ((!path) || (!*path)) - return 0; - - if (stat (path, &st) >= 0) - { - rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); - } - return rval; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise - Does not chase symlinks, even on platforms that support them. -*/ -char * -find_executable (const char *wrapper) -{ - int has_slash = 0; - const char *p; - const char *p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - size_t tmp_len; - char *concat_name; - - lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", - nonempty (wrapper)); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined HAVE_DOS_BASED_FILE_SYSTEM - if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } -#if defined HAVE_DOS_BASED_FILE_SYSTEM - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char *path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char *q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR (*q)) - break; - p_len = (size_t) (q - p); - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = - XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = - XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", - nonnull (strerror (errno))); - tmp_len = strlen (tmp); - concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - return NULL; -} - -char * -chase_symlinks (const char *pathspec) -{ -#ifndef S_ISLNK - return xstrdup (pathspec); -#else - char buf[LT_PATHMAX]; - struct stat s; - char *tmp_pathspec = xstrdup (pathspec); - char *p; - int has_symlinks = 0; - while (strlen (tmp_pathspec) && !has_symlinks) - { - lt_debugprintf (__FILE__, __LINE__, - "checking path component for symlinks: %s\n", - tmp_pathspec); - if (lstat (tmp_pathspec, &s) == 0) - { - if (S_ISLNK (s.st_mode) != 0) - { - has_symlinks = 1; - break; - } - - /* search backwards for last DIR_SEPARATOR */ - p = tmp_pathspec + strlen (tmp_pathspec) - 1; - while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - p--; - if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - { - /* no more DIR_SEPARATORS left */ - break; - } - *p = '\0'; - } - else - { - lt_fatal (__FILE__, __LINE__, - "error accessing file \"%s\": %s", - tmp_pathspec, nonnull (strerror (errno))); - } - } - XFREE (tmp_pathspec); - - if (!has_symlinks) - { - return xstrdup (pathspec); - } - - tmp_pathspec = realpath (pathspec, buf); - if (tmp_pathspec == 0) - { - lt_fatal (__FILE__, __LINE__, - "could not follow symlinks for %s", pathspec); - } - return xstrdup (tmp_pathspec); -#endif -} - -char * -strendzap (char *str, const char *pat) -{ - size_t len, patlen; - - assert (str != NULL); - assert (pat != NULL); - - len = strlen (str); - patlen = strlen (pat); - - if (patlen <= len) - { - str += len - patlen; - if (STREQ (str, pat)) - *str = '\0'; - } - return str; -} - -void -lt_debugprintf (const char *file, int line, const char *fmt, ...) -{ - va_list args; - if (lt_debug) - { - (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); - va_start (args, fmt); - (void) vfprintf (stderr, fmt, args); - va_end (args); - } -} - -static void -lt_error_core (int exit_status, const char *file, - int line, const char *mode, - const char *message, va_list ap) -{ - fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *file, int line, const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); - va_end (ap); -} - -static const char * -nonnull (const char *s) -{ - return s ? s : "(null)"; -} - -static const char * -nonempty (const char *s) -{ - return (s && !*s) ? "(empty)" : nonnull (s); -} - -void -lt_setenv (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_setenv) setting '%s' to '%s'\n", - nonnull (name), nonnull (value)); - { -#ifdef HAVE_SETENV - /* always make a copy, for consistency with !HAVE_SETENV */ - char *str = xstrdup (value); - setenv (name, str, 1); -#else - size_t len = strlen (name) + 1 + strlen (value) + 1; - char *str = XMALLOC (char, len); - sprintf (str, "%s=%s", name, value); - if (putenv (str) != EXIT_SUCCESS) - { - XFREE (str); - } -#endif - } -} - -char * -lt_extend_str (const char *orig_value, const char *add, int to_end) -{ - char *new_value; - if (orig_value && *orig_value) - { - size_t orig_value_len = strlen (orig_value); - size_t add_len = strlen (add); - new_value = XMALLOC (char, add_len + orig_value_len + 1); - if (to_end) - { - strcpy (new_value, orig_value); - strcpy (new_value + orig_value_len, add); - } - else - { - strcpy (new_value, add); - strcpy (new_value + add_len, orig_value); - } - } - else - { - new_value = xstrdup (add); - } - return new_value; -} - -void -lt_update_exe_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - /* some systems can't cope with a ':'-terminated path #' */ - size_t len = strlen (new_value); - while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) - { - new_value[--len] = '\0'; - } - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -void -lt_update_lib_path (const char *name, const char *value) -{ - lt_debugprintf (__FILE__, __LINE__, - "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", - nonnull (name), nonnull (value)); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -EOF - case $host_os in - mingw*) - cat <<"EOF" - -/* Prepares an argument vector before calling spawn(). - Note that spawn() does not by itself call the command interpreter - (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : - ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&v); - v.dwPlatformId == VER_PLATFORM_WIN32_NT; - }) ? "cmd.exe" : "command.com"). - Instead it simply concatenates the arguments, separated by ' ', and calls - CreateProcess(). We must quote the arguments since Win32 CreateProcess() - interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a - special way: - - Space and tab are interpreted as delimiters. They are not treated as - delimiters if they are surrounded by double quotes: "...". - - Unescaped double quotes are removed from the input. Their only effect is - that within double quotes, space and tab are treated like normal - characters. - - Backslashes not followed by double quotes are not special. - - But 2*n+1 backslashes followed by a double quote become - n backslashes followed by a double quote (n >= 0): - \" -> " - \\\" -> \" - \\\\\" -> \\" - */ -#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -char ** -prepare_spawn (char **argv) -{ - size_t argc; - char **new_argv; - size_t i; - - /* Count number of arguments. */ - for (argc = 0; argv[argc] != NULL; argc++) - ; - - /* Allocate new argument vector. */ - new_argv = XMALLOC (char *, argc + 1); - - /* Put quoted arguments into the new argument vector. */ - for (i = 0; i < argc; i++) - { - const char *string = argv[i]; - - if (string[0] == '\0') - new_argv[i] = xstrdup ("\"\""); - else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) - { - int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); - size_t length; - unsigned int backslashes; - const char *s; - char *quoted_string; - char *p; - - length = 0; - backslashes = 0; - if (quote_around) - length++; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - length += backslashes + 1; - length++; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - length += backslashes + 1; - - quoted_string = XMALLOC (char, length + 1); - - p = quoted_string; - backslashes = 0; - if (quote_around) - *p++ = '"'; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - { - unsigned int j; - for (j = backslashes + 1; j > 0; j--) - *p++ = '\\'; - } - *p++ = c; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - { - unsigned int j; - for (j = backslashes; j > 0; j--) - *p++ = '\\'; - *p++ = '"'; - } - *p = '\0'; - - new_argv[i] = quoted_string; - } - else - new_argv[i] = (char *) string; - } - new_argv[argc] = NULL; - - return new_argv; -} -EOF - ;; - esac - - cat <<"EOF" -void lt_dump_script (FILE* f) -{ -EOF - func_emit_wrapper yes | - $SED -n -e ' -s/^\(.\{79\}\)\(..*\)/\1\ -\2/ -h -s/\([\\"]\)/\\\1/g -s/$/\\n/ -s/\([^\n]*\).*/ fputs ("\1", f);/p -g -D' - cat <<"EOF" -} -EOF -} -# end: func_emit_cwrapperexe_src - -# func_win32_import_lib_p ARG -# True if ARG is an import lib, as indicated by $file_magic_cmd -func_win32_import_lib_p () -{ - $debug_cmd - - case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in - *import*) : ;; - *) false ;; - esac -} - -# func_suncc_cstd_abi -# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! -# Several compiler flags select an ABI that is incompatible with the -# Cstd library. Avoid specifying it if any are in CXXFLAGS. -func_suncc_cstd_abi () -{ - $debug_cmd - - case " $compile_command " in - *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) - suncc_use_cstd_abi=no - ;; - *) - suncc_use_cstd_abi=yes - ;; - esac -} - -# func_mode_link arg... -func_mode_link () -{ - $debug_cmd - - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # what system we are compiling for in order to pass an extra - # flag for every libtool invocation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll that has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - ;; - *) - allow_undefined=yes - ;; - esac - libtool_args=$nonopt - base_compile="$nonopt $@" - compile_command=$nonopt - finalize_command=$nonopt - - compile_rpath= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - old_deplibs= - compiler_flags= - linker_flags= - dllsearchpath= - lib_search_path=`pwd` - inst_prefix_dir= - new_inherited_linker_flags= - - avoid_version=no - bindir= - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - ltlibs= - module=no - no_install=no - objs= - os2dllname= - non_pic_objects= - precious_files_regex= - prefer_static_libs=no - preload=false - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - thread_safe=no - vinfo= - vinfo_number=no - weak_libs= - single_module=$wl-single_module - func_infer_tag $base_compile - - # We need to know -static, to get the right output filenames. - for arg - do - case $arg in - -shared) - test yes != "$build_libtool_libs" \ - && func_fatal_configuration "cannot build a shared library" - build_old_libs=no - break - ;; - -all-static | -static | -static-libtool-libs) - case $arg in - -all-static) - if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then - func_warning "complete static linking is impossible in this configuration" - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - -static) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=built - ;; - -static-libtool-libs) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - esac - build_libtool_libs=no - build_old_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg=$1 - shift - func_quote_for_eval "$arg" - qarg=$func_quote_for_eval_unquoted_result - func_append libtool_args " $func_quote_for_eval_result" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - func_append compile_command " @OUTPUT@" - func_append finalize_command " @OUTPUT@" - ;; - esac - - case $prev in - bindir) - bindir=$arg - prev= - continue - ;; - dlfiles|dlprefiles) - $preload || { - # Add the symbol object into the linking commands. - func_append compile_command " @SYMFILE@" - func_append finalize_command " @SYMFILE@" - preload=: - } - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test no = "$dlself"; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test dlprefiles = "$prev"; then - dlself=yes - elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test dlfiles = "$prev"; then - func_append dlfiles " $arg" - else - func_append dlprefiles " $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols=$arg - test -f "$arg" \ - || func_fatal_error "symbol file '$arg' does not exist" - prev= - continue - ;; - expsyms_regex) - export_symbols_regex=$arg - prev= - continue - ;; - framework) - case $host in - *-*-darwin*) - case "$deplibs " in - *" $qarg.ltframework "*) ;; - *) func_append deplibs " $qarg.ltframework" # this is fixed later - ;; - esac - ;; - esac - prev= - continue - ;; - inst_prefix) - inst_prefix_dir=$arg - prev= - continue - ;; - mllvm) - # Clang does not use LLVM to link, so we can simply discard any - # '-mllvm $arg' options when doing the link step. - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat "$save_arg"` - do -# func_append moreargs " $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test none = "$pic_object" && - test none = "$non_pic_object"; then - func_fatal_error "cannot find name of object for '$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - if test none != "$pic_object"; then - # Prepend the subdirectory the object is found in. - pic_object=$xdir$pic_object - - if test dlfiles = "$prev"; then - if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then - func_append dlfiles " $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test dlprefiles = "$prev"; then - # Preload the old-style object. - func_append dlprefiles " $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg=$pic_object - fi - - # Non-PIC object. - if test none != "$non_pic_object"; then - # Prepend the subdirectory the object is found in. - non_pic_object=$xdir$non_pic_object - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test none = "$pic_object"; then - arg=$non_pic_object - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object=$pic_object - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "'$arg' is not a valid libtool object" - fi - fi - done - else - func_fatal_error "link input file '$arg' does not exist" - fi - arg=$save_arg - prev= - continue - ;; - os2dllname) - os2dllname=$arg - prev= - continue - ;; - precious_regex) - precious_files_regex=$arg - prev= - continue - ;; - release) - release=-$arg - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - if test rpath = "$prev"; then - case "$rpath " in - *" $arg "*) ;; - *) func_append rpath " $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) func_append xrpath " $arg" ;; - esac - fi - prev= - continue - ;; - shrext) - shrext_cmds=$arg - prev= - continue - ;; - weak) - func_append weak_libs " $arg" - prev= - continue - ;; - xcclinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xcompiler) - func_append compiler_flags " $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xlinker) - func_append linker_flags " $qarg" - func_append compiler_flags " $wl$qarg" - prev= - func_append compile_command " $wl$qarg" - func_append finalize_command " $wl$qarg" - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg=$arg - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - # See comment for -static flag below, for more details. - func_append compile_command " $link_static_flag" - func_append finalize_command " $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - func_fatal_error "'-allow-undefined' must not be used because it is the default" - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -bindir) - prev=bindir - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - func_fatal_error "more than one -exported-symbols argument is not allowed" - fi - if test X-export-symbols = "X$arg"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -framework) - prev=framework - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - func_append compile_command " $arg" - func_append finalize_command " $arg" - ;; - esac - continue - ;; - - -L*) - func_stripname "-L" '' "$arg" - if test -z "$func_stripname_result"; then - if test "$#" -gt 0; then - func_fatal_error "require no space between '-L' and '$1'" - else - func_fatal_error "need path for '-L' option" - fi - fi - func_resolve_sysroot "$func_stripname_result" - dir=$func_resolve_sysroot_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - test -z "$absdir" && \ - func_fatal_error "cannot determine absolute directory name of '$dir'" - dir=$absdir - ;; - esac - case "$deplibs " in - *" -L$dir "* | *" $arg "*) - # Will only happen for absolute or sysroot arguments - ;; - *) - # Preserve sysroot, but never include relative directories - case $dir in - [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; - *) func_append deplibs " -L$dir" ;; - esac - func_append lib_search_path " $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$dir:"*) ;; - ::) dllsearchpath=$dir;; - *) func_append dllsearchpath ":$dir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) func_append dllsearchpath ":$testbindir";; - esac - ;; - esac - continue - ;; - - -l*) - if test X-lc = "X$arg" || test X-lm = "X$arg"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-os2*) - # These systems don't actually have a C library (as such) - test X-lc = "X$arg" && continue - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) - # Do not include libc due to us having libc/libc_r. - test X-lc = "X$arg" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - func_append deplibs " System.ltframework" - continue - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - test X-lc = "X$arg" && continue - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - test X-lc = "X$arg" && continue - ;; - esac - elif test X-lc_r = "X$arg"; then - case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - func_append deplibs " $arg" - continue - ;; - - -mllvm) - prev=mllvm - continue - ;; - - -module) - module=yes - continue - ;; - - # Tru64 UNIX uses -model [arg] to determine the layout of C++ - # classes, name mangling, and exception handling. - # Darwin uses the -arch flag to determine output architecture. - -model|-arch|-isysroot|--sysroot) - func_append compiler_flags " $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - prev=xcompiler - continue - ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) - func_append compiler_flags " $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - case "$new_inherited_linker_flags " in - *" $arg "*) ;; - * ) func_append new_inherited_linker_flags " $arg" ;; - esac - continue - ;; - - -multi_module) - single_module=$wl-multi_module - continue - ;; - - -no-fast-install) - fast_install=no - continue - ;; - - -no-install) - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) - # The PATH hackery in wrapper scripts is required on Windows - # and Darwin in order for the loader to find any dlls it needs. - func_warning "'-no-install' is ignored for $host" - func_warning "assuming '-no-fast-install' instead" - fast_install=no - ;; - *) no_install=yes ;; - esac - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -objectlist) - prev=objectlist - continue - ;; - - -os2dllname) - prev=os2dllname - continue - ;; - - -o) prev=output ;; - - -precious-files-regex) - prev=precious_regex - continue - ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - func_stripname '-R' '' "$arg" - dir=$func_stripname_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - =*) - func_stripname '=' '' "$dir" - dir=$lt_sysroot$func_stripname_result - ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) func_append xrpath " $dir" ;; - esac - continue - ;; - - -shared) - # The effects of -shared are defined in a previous loop. - continue - ;; - - -shrext) - prev=shrext - continue - ;; - - -static | -static-libtool-libs) - # The effects of -static are defined in a previous loop. - # We used to do the same as -all-static on platforms that - # didn't have a PIC flag, but the assumption that the effects - # would be equivalent was wrong. It would break on at least - # Digital Unix and AIX. - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - - -version-number) - prev=vinfo - vinfo_number=yes - continue - ;; - - -weak) - prev=weak - continue - ;; - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs=$IFS; IFS=, - for flag in $args; do - IFS=$save_ifs - func_quote_for_eval "$flag" - func_append arg " $func_quote_for_eval_result" - func_append compiler_flags " $func_quote_for_eval_result" - done - IFS=$save_ifs - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Wl,*) - func_stripname '-Wl,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs=$IFS; IFS=, - for flag in $args; do - IFS=$save_ifs - func_quote_for_eval "$flag" - func_append arg " $wl$func_quote_for_eval_result" - func_append compiler_flags " $wl$func_quote_for_eval_result" - func_append linker_flags " $func_quote_for_eval_result" - done - IFS=$save_ifs - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Xcompiler) - prev=xcompiler - continue - ;; - - -Xlinker) - prev=xlinker - continue - ;; - - -XCClinker) - prev=xcclinker - continue - ;; - - # -msg_* for osf cc - -msg_*) - func_quote_for_eval "$arg" - arg=$func_quote_for_eval_result - ;; - - # Flags to be passed through unchanged, with rationale: - # -64, -mips[0-9] enable 64-bit mode for the SGI compiler - # -r[0-9][0-9]* specify processor for the SGI compiler - # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler - # +DA*, +DD* enable 64-bit mode for the HP compiler - # -q* compiler args for the IBM compiler - # -m*, -t[45]*, -txscale* architecture-specific flags for GCC - # -F/path path to uninstalled frameworks, gcc on darwin - # -p, -pg, --coverage, -fprofile-* profiling flags for GCC - # -fstack-protector* stack protector flags for GCC - # @file GCC response files - # -tp=* Portland pgcc target processor selection - # --sysroot=* for sysroot support - # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization - # -stdlib=* select c++ std lib with clang - -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ - -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ - -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*) - func_quote_for_eval "$arg" - arg=$func_quote_for_eval_result - func_append compile_command " $arg" - func_append finalize_command " $arg" - func_append compiler_flags " $arg" - continue - ;; - - -Z*) - if test os2 = "`expr $host : '.*\(os2\)'`"; then - # OS/2 uses -Zxxx to specify OS/2-specific options - compiler_flags="$compiler_flags $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - case $arg in - -Zlinker | -Zstack) - prev=xcompiler - ;; - esac - continue - else - # Otherwise treat like 'Some other compiler flag' below - func_quote_for_eval "$arg" - arg=$func_quote_for_eval_result - fi - ;; - - # Some other compiler flag. - -* | +*) - func_quote_for_eval "$arg" - arg=$func_quote_for_eval_result - ;; - - *.$objext) - # A standard object. - func_append objs " $arg" - ;; - - *.lo) - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test none = "$pic_object" && - test none = "$non_pic_object"; then - func_fatal_error "cannot find name of object for '$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - test none = "$pic_object" || { - # Prepend the subdirectory the object is found in. - pic_object=$xdir$pic_object - - if test dlfiles = "$prev"; then - if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then - func_append dlfiles " $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test dlprefiles = "$prev"; then - # Preload the old-style object. - func_append dlprefiles " $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg=$pic_object - } - - # Non-PIC object. - if test none != "$non_pic_object"; then - # Prepend the subdirectory the object is found in. - non_pic_object=$xdir$non_pic_object - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test none = "$pic_object"; then - arg=$non_pic_object - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object=$pic_object - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir=$func_dirname_result - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "'$arg' is not a valid libtool object" - fi - fi - ;; - - *.$libext) - # An archive. - func_append deplibs " $arg" - func_append old_deplibs " $arg" - continue - ;; - - *.la) - # A libtool-controlled library. - - func_resolve_sysroot "$arg" - if test dlfiles = "$prev"; then - # This library was specified with -dlopen. - func_append dlfiles " $func_resolve_sysroot_result" - prev= - elif test dlprefiles = "$prev"; then - # The library was specified with -dlpreopen. - func_append dlprefiles " $func_resolve_sysroot_result" - prev= - else - func_append deplibs " $func_resolve_sysroot_result" - fi - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - func_quote_for_eval "$arg" - arg=$func_quote_for_eval_result - ;; - esac # arg - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - done # argument parsing loop - - test -n "$prev" && \ - func_fatal_help "the '$prevarg' option requires an argument" - - if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then - eval arg=\"$export_dynamic_flag_spec\" - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - func_basename "$output" - outputname=$func_basename_result - libobjs_save=$libobjs - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` - else - shlib_search_path= - fi - eval sys_lib_search_path=\"$sys_lib_search_path_spec\" - eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" - - # Definition is injected by LT_CONFIG during libtool generation. - func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" - - func_dirname "$output" "/" "" - output_objdir=$func_dirname_result$objdir - func_to_tool_file "$output_objdir/" - tool_output_objdir=$func_to_tool_file_result - # Create the object directory. - func_mkdir_p "$output_objdir" - - # Determine the type of output - case $output in - "") - func_fatal_help "you must specify an output file" - ;; - *.$libext) linkmode=oldlib ;; - *.lo | *.$objext) linkmode=obj ;; - *.la) linkmode=lib ;; - *) linkmode=prog ;; # Anything else should be a program. - esac - - specialdeplibs= - - libs= - # Find all interdependent deplibs by searching for libraries - # that are linked more than once (e.g. -la -lb -la) - for deplib in $deplibs; do - if $opt_preserve_dup_deps; then - case "$libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append libs " $deplib" - done - - if test lib = "$linkmode"; then - libs="$predeps $libs $compiler_lib_search_path $postdeps" - - # Compute libraries that are listed more than once in $predeps - # $postdeps and mark them as special (i.e., whose duplicates are - # not to be eliminated). - pre_post_deps= - if $opt_duplicate_compiler_generated_deps; then - for pre_post_dep in $predeps $postdeps; do - case "$pre_post_deps " in - *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; - esac - func_append pre_post_deps " $pre_post_dep" - done - fi - pre_post_deps= - fi - - deplibs= - newdependency_libs= - newlib_search_path= - need_relink=no # whether we're linking any uninstalled libtool libraries - notinst_deplibs= # not-installed libtool libraries - notinst_path= # paths that contain not-installed libtool libraries - - case $linkmode in - lib) - passes="conv dlpreopen link" - for file in $dlfiles $dlprefiles; do - case $file in - *.la) ;; - *) - func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" - ;; - esac - done - ;; - prog) - compile_deplibs= - finalize_deplibs= - alldeplibs=false - newdlfiles= - newdlprefiles= - passes="conv scan dlopen dlpreopen link" - ;; - *) passes="conv" - ;; - esac - - for pass in $passes; do - # The preopen pass in lib mode reverses $deplibs; put it back here - # so that -L comes before libs that need it for instance... - if test lib,link = "$linkmode,$pass"; then - ## FIXME: Find the place where the list is rebuilt in the wrong - ## order, and fix it there properly - tmp_deplibs= - for deplib in $deplibs; do - tmp_deplibs="$deplib $tmp_deplibs" - done - deplibs=$tmp_deplibs - fi - - if test lib,link = "$linkmode,$pass" || - test prog,scan = "$linkmode,$pass"; then - libs=$deplibs - deplibs= - fi - if test prog = "$linkmode"; then - case $pass in - dlopen) libs=$dlfiles ;; - dlpreopen) libs=$dlprefiles ;; - link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; - esac - fi - if test lib,dlpreopen = "$linkmode,$pass"; then - # Collect and forward deplibs of preopened libtool libs - for lib in $dlprefiles; do - # Ignore non-libtool-libs - dependency_libs= - func_resolve_sysroot "$lib" - case $lib in - *.la) func_source "$func_resolve_sysroot_result" ;; - esac - - # Collect preopened libtool deplibs, except any this library - # has declared as weak libs - for deplib in $dependency_libs; do - func_basename "$deplib" - deplib_base=$func_basename_result - case " $weak_libs " in - *" $deplib_base "*) ;; - *) func_append deplibs " $deplib" ;; - esac - done - done - libs=$dlprefiles - fi - if test dlopen = "$pass"; then - # Collect dlpreopened libraries - save_deplibs=$deplibs - deplibs= - fi - - for deplib in $libs; do - lib= - found=false - case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ - |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) - if test prog,link = "$linkmode,$pass"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - func_append compiler_flags " $deplib" - if test lib = "$linkmode"; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) func_append new_inherited_linker_flags " $deplib" ;; - esac - fi - fi - continue - ;; - -l*) - if test lib != "$linkmode" && test prog != "$linkmode"; then - func_warning "'-l' is ignored for archives/objects" - continue - fi - func_stripname '-l' '' "$deplib" - name=$func_stripname_result - if test lib = "$linkmode"; then - searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" - else - searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" - fi - for searchdir in $searchdirs; do - for search_ext in .la $std_shrext .so .a; do - # Search the libtool library - lib=$searchdir/lib$name$search_ext - if test -f "$lib"; then - if test .la = "$search_ext"; then - found=: - else - found=false - fi - break 2 - fi - done - done - if $found; then - # deplib is a libtool library - # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, - # We need to do some special things here, and not later. - if test yes = "$allow_libtool_libs_with_static_runtimes"; then - case " $predeps $postdeps " in - *" $deplib "*) - if func_lalib_p "$lib"; then - library_names= - old_library= - func_source "$lib" - for l in $old_library $library_names; do - ll=$l - done - if test "X$ll" = "X$old_library"; then # only static version available - found=false - func_dirname "$lib" "" "." - ladir=$func_dirname_result - lib=$ladir/$old_library - if test prog,link = "$linkmode,$pass"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - fi - ;; - *) ;; - esac - fi - else - # deplib doesn't seem to be a libtool library - if test prog,link = "$linkmode,$pass"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - ;; # -l - *.ltframework) - if test prog,link = "$linkmode,$pass"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - if test lib = "$linkmode"; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) func_append new_inherited_linker_flags " $deplib" ;; - esac - fi - fi - continue - ;; - -L*) - case $linkmode in - lib) - deplibs="$deplib $deplibs" - test conv = "$pass" && continue - newdependency_libs="$deplib $newdependency_libs" - func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - prog) - if test conv = "$pass"; then - deplibs="$deplib $deplibs" - continue - fi - if test scan = "$pass"; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - *) - func_warning "'-L' is ignored for archives/objects" - ;; - esac # linkmode - continue - ;; # -L - -R*) - if test link = "$pass"; then - func_stripname '-R' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - dir=$func_resolve_sysroot_result - # Make sure the xrpath contains only unique directories. - case "$xrpath " in - *" $dir "*) ;; - *) func_append xrpath " $dir" ;; - esac - fi - deplibs="$deplib $deplibs" - continue - ;; - *.la) - func_resolve_sysroot "$deplib" - lib=$func_resolve_sysroot_result - ;; - *.$libext) - if test conv = "$pass"; then - deplibs="$deplib $deplibs" - continue - fi - case $linkmode in - lib) - # Linking convenience modules into shared libraries is allowed, - # but linking other static libraries is non-portable. - case " $dlpreconveniencelibs " in - *" $deplib "*) ;; - *) - valid_a_lib=false - case $deplibs_check_method in - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - valid_a_lib=: - fi - ;; - pass_all) - valid_a_lib=: - ;; - esac - if $valid_a_lib; then - echo - $ECHO "*** Warning: Linking the shared library $output against the" - $ECHO "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - else - echo - $ECHO "*** Warning: Trying to link with static lib archive $deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because the file extensions .$libext of this argument makes me believe" - echo "*** that it is just a static archive that I should not use here." - fi - ;; - esac - continue - ;; - prog) - if test link != "$pass"; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - continue - ;; - esac # linkmode - ;; # *.$libext - *.lo | *.$objext) - if test conv = "$pass"; then - deplibs="$deplib $deplibs" - elif test prog = "$linkmode"; then - if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then - # If there is no dlopen support or we're linking statically, - # we need to preload. - func_append newdlprefiles " $deplib" - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - func_append newdlfiles " $deplib" - fi - fi - continue - ;; - %DEPLIBS%) - alldeplibs=: - continue - ;; - esac # case $deplib - - $found || test -f "$lib" \ - || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$lib" \ - || func_fatal_error "'$lib' is not a valid libtool archive" - - func_dirname "$lib" "" "." - ladir=$func_dirname_result - - dlname= - dlopen= - dlpreopen= - libdir= - library_names= - old_library= - inherited_linker_flags= - # If the library was installed with an old release of libtool, - # it will not redefine variables installed, or shouldnotlink - installed=yes - shouldnotlink=no - avoidtemprpath= - - - # Read the .la file - func_source "$lib" - - # Convert "-framework foo" to "foo.ltframework" - if test -n "$inherited_linker_flags"; then - tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` - for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do - case " $new_inherited_linker_flags " in - *" $tmp_inherited_linker_flag "*) ;; - *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; - esac - done - fi - dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - if test lib,link = "$linkmode,$pass" || - test prog,scan = "$linkmode,$pass" || - { test prog != "$linkmode" && test lib != "$linkmode"; }; then - test -n "$dlopen" && func_append dlfiles " $dlopen" - test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" - fi - - if test conv = "$pass"; then - # Only check for convenience libraries - deplibs="$lib $deplibs" - if test -z "$libdir"; then - if test -z "$old_library"; then - func_fatal_error "cannot find name of link library for '$lib'" - fi - # It is a libtool convenience library, so add in its objects. - func_append convenience " $ladir/$objdir/$old_library" - func_append old_convenience " $ladir/$objdir/$old_library" - elif test prog != "$linkmode" && test lib != "$linkmode"; then - func_fatal_error "'$lib' is not a convenience library" - fi - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if $opt_preserve_dup_deps; then - case "$tmp_libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append tmp_libs " $deplib" - done - continue - fi # $pass = conv - - - # Get the name of the library we link against. - linklib= - if test -n "$old_library" && - { test yes = "$prefer_static_libs" || - test built,no = "$prefer_static_libs,$installed"; }; then - linklib=$old_library - else - for l in $old_library $library_names; do - linklib=$l - done - fi - if test -z "$linklib"; then - func_fatal_error "cannot find name of link library for '$lib'" - fi - - # This library was specified with -dlopen. - if test dlopen = "$pass"; then - test -z "$libdir" \ - && func_fatal_error "cannot -dlopen a convenience library: '$lib'" - if test -z "$dlname" || - test yes != "$dlopen_support" || - test no = "$build_libtool_libs" - then - # If there is no dlname, no dlopen support or we're linking - # statically, we need to preload. We also need to preload any - # dependent libraries so libltdl's deplib preloader doesn't - # bomb out in the load deplibs phase. - func_append dlprefiles " $lib $dependency_libs" - else - func_append newdlfiles " $lib" - fi - continue - fi # $pass = dlopen - - # We need an absolute path. - case $ladir in - [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; - *) - abs_ladir=`cd "$ladir" && pwd` - if test -z "$abs_ladir"; then - func_warning "cannot determine absolute directory name of '$ladir'" - func_warning "passing it literally to the linker, although it might fail" - abs_ladir=$ladir - fi - ;; - esac - func_basename "$lib" - laname=$func_basename_result - - # Find the relevant object directory and library name. - if test yes = "$installed"; then - if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then - func_warning "library '$lib' was moved." - dir=$ladir - absdir=$abs_ladir - libdir=$abs_ladir - else - dir=$lt_sysroot$libdir - absdir=$lt_sysroot$libdir - fi - test yes = "$hardcode_automatic" && avoidtemprpath=yes - else - if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then - dir=$ladir - absdir=$abs_ladir - # Remove this search path later - func_append notinst_path " $abs_ladir" - else - dir=$ladir/$objdir - absdir=$abs_ladir/$objdir - # Remove this search path later - func_append notinst_path " $abs_ladir" - fi - fi # $installed = yes - func_stripname 'lib' '.la' "$laname" - name=$func_stripname_result - - # This library was specified with -dlpreopen. - if test dlpreopen = "$pass"; then - if test -z "$libdir" && test prog = "$linkmode"; then - func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" - fi - case $host in - # special handling for platforms with PE-DLLs. - *cygwin* | *mingw* | *cegcc* ) - # Linker will automatically link against shared library if both - # static and shared are present. Therefore, ensure we extract - # symbols from the import library if a shared library is present - # (otherwise, the dlopen module name will be incorrect). We do - # this by putting the import library name into $newdlprefiles. - # We recover the dlopen module name by 'saving' the la file - # name in a special purpose variable, and (later) extracting the - # dlname from the la file. - if test -n "$dlname"; then - func_tr_sh "$dir/$linklib" - eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" - func_append newdlprefiles " $dir/$linklib" - else - func_append newdlprefiles " $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - func_append dlpreconveniencelibs " $dir/$old_library" - fi - ;; - * ) - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - func_append newdlprefiles " $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - func_append dlpreconveniencelibs " $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - func_append newdlprefiles " $dir/$dlname" - else - func_append newdlprefiles " $dir/$linklib" - fi - ;; - esac - fi # $pass = dlpreopen - - if test -z "$libdir"; then - # Link the convenience library - if test lib = "$linkmode"; then - deplibs="$dir/$old_library $deplibs" - elif test prog,link = "$linkmode,$pass"; then - compile_deplibs="$dir/$old_library $compile_deplibs" - finalize_deplibs="$dir/$old_library $finalize_deplibs" - else - deplibs="$lib $deplibs" # used for prog,scan pass - fi - continue - fi - - - if test prog = "$linkmode" && test link != "$pass"; then - func_append newlib_search_path " $ladir" - deplibs="$lib $deplibs" - - linkalldeplibs=false - if test no != "$link_all_deplibs" || test -z "$library_names" || - test no = "$build_libtool_libs"; then - linkalldeplibs=: - fi - - tmp_libs= - for deplib in $dependency_libs; do - case $deplib in - -L*) func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result" - func_append newlib_search_path " $func_resolve_sysroot_result" - ;; - esac - # Need to link against all dependency_libs? - if $linkalldeplibs; then - deplibs="$deplib $deplibs" - else - # Need to hardcode shared library paths - # or/and link against static libraries - newdependency_libs="$deplib $newdependency_libs" - fi - if $opt_preserve_dup_deps; then - case "$tmp_libs " in - *" $deplib "*) func_append specialdeplibs " $deplib" ;; - esac - fi - func_append tmp_libs " $deplib" - done # for deplib - continue - fi # $linkmode = prog... - - if test prog,link = "$linkmode,$pass"; then - if test -n "$library_names" && - { { test no = "$prefer_static_libs" || - test built,yes = "$prefer_static_libs,$installed"; } || - test -z "$old_library"; }; then - # We need to hardcode the library path - if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then - # Make sure the rpath contains only unique directories. - case $temp_rpath: in - *"$absdir:"*) ;; - *) func_append temp_rpath "$absdir:" ;; - esac - fi - - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) func_append compile_rpath " $absdir" ;; - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - ;; - esac - fi # $linkmode,$pass = prog,link... - - if $alldeplibs && - { test pass_all = "$deplibs_check_method" || - { test yes = "$build_libtool_libs" && - test -n "$library_names"; }; }; then - # We only need to search for static libraries - continue - fi - fi - - link_static=no # Whether the deplib will be linked statically - use_static_libs=$prefer_static_libs - if test built = "$use_static_libs" && test yes = "$installed"; then - use_static_libs=no - fi - if test -n "$library_names" && - { test no = "$use_static_libs" || test -z "$old_library"; }; then - case $host in - *cygwin* | *mingw* | *cegcc* | *os2*) - # No point in relinking DLLs because paths are not encoded - func_append notinst_deplibs " $lib" - need_relink=no - ;; - *) - if test no = "$installed"; then - func_append notinst_deplibs " $lib" - need_relink=yes - fi - ;; - esac - # This is a shared library - - # Warn about portability, can't link against -module's on some - # systems (darwin). Don't bleat about dlopened modules though! - dlopenmodule= - for dlpremoduletest in $dlprefiles; do - if test "X$dlpremoduletest" = "X$lib"; then - dlopenmodule=$dlpremoduletest - break - fi - done - if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then - echo - if test prog = "$linkmode"; then - $ECHO "*** Warning: Linking the executable $output against the loadable module" - else - $ECHO "*** Warning: Linking the shared library $output against the loadable module" - fi - $ECHO "*** $linklib is not portable!" - fi - if test lib = "$linkmode" && - test yes = "$hardcode_into_libs"; then - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) func_append compile_rpath " $absdir" ;; - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - ;; - esac - fi - - if test -n "$old_archive_from_expsyms_cmds"; then - # figure out the soname - set dummy $library_names - shift - realname=$1 - shift - libname=`eval "\\$ECHO \"$libname_spec\""` - # use dlname if we got it. it's perfectly good, no? - if test -n "$dlname"; then - soname=$dlname - elif test -n "$soname_spec"; then - # bleh windows - case $host in - *cygwin* | mingw* | *cegcc* | *os2*) - func_arith $current - $age - major=$func_arith_result - versuffix=-$major - ;; - esac - eval soname=\"$soname_spec\" - else - soname=$realname - fi - - # Make a new name for the extract_expsyms_cmds to use - soroot=$soname - func_basename "$soroot" - soname=$func_basename_result - func_stripname 'lib' '.dll' "$soname" - newlib=libimp-$func_stripname_result.a - - # If the library has no export list, then create one now - if test -f "$output_objdir/$soname-def"; then : - else - func_verbose "extracting exported symbol list from '$soname'" - func_execute_cmds "$extract_expsyms_cmds" 'exit $?' - fi - - # Create $newlib - if test -f "$output_objdir/$newlib"; then :; else - func_verbose "generating import library for '$soname'" - func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' - fi - # make sure the library variables are pointing to the new library - dir=$output_objdir - linklib=$newlib - fi # test -n "$old_archive_from_expsyms_cmds" - - if test prog = "$linkmode" || test relink != "$opt_mode"; then - add_shlibpath= - add_dir= - add= - lib_linked=yes - case $hardcode_action in - immediate | unsupported) - if test no = "$hardcode_direct"; then - add=$dir/$linklib - case $host in - *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; - *-*-sysv4*uw2*) add_dir=-L$dir ;; - *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ - *-*-unixware7*) add_dir=-L$dir ;; - *-*-darwin* ) - # if the lib is a (non-dlopened) module then we cannot - # link against it, someone is ignoring the earlier warnings - if /usr/bin/file -L $add 2> /dev/null | - $GREP ": [^:]* bundle" >/dev/null; then - if test "X$dlopenmodule" != "X$lib"; then - $ECHO "*** Warning: lib $linklib is a module, not a shared library" - if test -z "$old_library"; then - echo - echo "*** And there doesn't seem to be a static archive available" - echo "*** The link will probably fail, sorry" - else - add=$dir/$old_library - fi - elif test -n "$old_library"; then - add=$dir/$old_library - fi - fi - esac - elif test no = "$hardcode_minus_L"; then - case $host in - *-*-sunos*) add_shlibpath=$dir ;; - esac - add_dir=-L$dir - add=-l$name - elif test no = "$hardcode_shlibpath_var"; then - add_shlibpath=$dir - add=-l$name - else - lib_linked=no - fi - ;; - relink) - if test yes = "$hardcode_direct" && - test no = "$hardcode_direct_absolute"; then - add=$dir/$linklib - elif test yes = "$hardcode_minus_L"; then - add_dir=-L$absdir - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - func_append add_dir " -L$inst_prefix_dir$libdir" - ;; - esac - fi - add=-l$name - elif test yes = "$hardcode_shlibpath_var"; then - add_shlibpath=$dir - add=-l$name - else - lib_linked=no - fi - ;; - *) lib_linked=no ;; - esac - - if test yes != "$lib_linked"; then - func_fatal_configuration "unsupported hardcode properties" - fi - - if test -n "$add_shlibpath"; then - case :$compile_shlibpath: in - *":$add_shlibpath:"*) ;; - *) func_append compile_shlibpath "$add_shlibpath:" ;; - esac - fi - if test prog = "$linkmode"; then - test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" - test -n "$add" && compile_deplibs="$add $compile_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - if test yes != "$hardcode_direct" && - test yes != "$hardcode_minus_L" && - test yes = "$hardcode_shlibpath_var"; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) func_append finalize_shlibpath "$libdir:" ;; - esac - fi - fi - fi - - if test prog = "$linkmode" || test relink = "$opt_mode"; then - add_shlibpath= - add_dir= - add= - # Finalize command for both is simple: just hardcode it. - if test yes = "$hardcode_direct" && - test no = "$hardcode_direct_absolute"; then - add=$libdir/$linklib - elif test yes = "$hardcode_minus_L"; then - add_dir=-L$libdir - add=-l$name - elif test yes = "$hardcode_shlibpath_var"; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) func_append finalize_shlibpath "$libdir:" ;; - esac - add=-l$name - elif test yes = "$hardcode_automatic"; then - if test -n "$inst_prefix_dir" && - test -f "$inst_prefix_dir$libdir/$linklib"; then - add=$inst_prefix_dir$libdir/$linklib - else - add=$libdir/$linklib - fi - else - # We cannot seem to hardcode it, guess we'll fake it. - add_dir=-L$libdir - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - func_append add_dir " -L$inst_prefix_dir$libdir" - ;; - esac - fi - add=-l$name - fi - - if test prog = "$linkmode"; then - test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" - test -n "$add" && finalize_deplibs="$add $finalize_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - fi - fi - elif test prog = "$linkmode"; then - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test unsupported != "$hardcode_direct"; then - test -n "$old_library" && linklib=$old_library - compile_deplibs="$dir/$linklib $compile_deplibs" - finalize_deplibs="$dir/$linklib $finalize_deplibs" - else - compile_deplibs="-l$name -L$dir $compile_deplibs" - finalize_deplibs="-l$name -L$dir $finalize_deplibs" - fi - elif test yes = "$build_libtool_libs"; then - # Not a shared library - if test pass_all != "$deplibs_check_method"; then - # We're trying link a shared library against a static one - # but the system doesn't support it. - - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - echo - $ECHO "*** Warning: This system cannot link to static lib archive $lib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - if test yes = "$module"; then - echo "*** But as you try to build a module library, libtool will still create " - echo "*** a static module, that should work as long as the dlopening application" - echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using 'nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** 'nm' from GNU binutils and a full rebuild may help." - fi - if test no = "$build_old_libs"; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test lib = "$linkmode"; then - if test -n "$dependency_libs" && - { test yes != "$hardcode_into_libs" || - test yes = "$build_old_libs" || - test yes = "$link_static"; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) func_stripname '-R' '' "$libdir" - temp_xrpath=$func_stripname_result - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) func_append xrpath " $temp_xrpath";; - esac;; - *) func_append temp_deplibs " $libdir";; - esac - done - dependency_libs=$temp_deplibs - fi - - func_append newlib_search_path " $absdir" - # Link against this library - test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - case $deplib in - -L*) func_stripname '-L' '' "$deplib" - func_resolve_sysroot "$func_stripname_result";; - *) func_resolve_sysroot "$deplib" ;; - esac - if $opt_preserve_dup_deps; then - case "$tmp_libs " in - *" $func_resolve_sysroot_result "*) - func_append specialdeplibs " $func_resolve_sysroot_result" ;; - esac - fi - func_append tmp_libs " $func_resolve_sysroot_result" - done - - if test no != "$link_all_deplibs"; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - path= - case $deplib in - -L*) path=$deplib ;; - *.la) - func_resolve_sysroot "$deplib" - deplib=$func_resolve_sysroot_result - func_dirname "$deplib" "" "." - dir=$func_dirname_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - func_warning "cannot determine absolute directory name of '$dir'" - absdir=$dir - fi - ;; - esac - if $GREP "^installed=no" $deplib > /dev/null; then - case $host in - *-*-darwin*) - depdepl= - eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names"; then - for tmp in $deplibrary_names; do - depdepl=$tmp - done - if test -f "$absdir/$objdir/$depdepl"; then - depdepl=$absdir/$objdir/$depdepl - darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - if test -z "$darwin_install_name"; then - darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - fi - func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" - func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" - path= - fi - fi - ;; - *) - path=-L$absdir/$objdir - ;; - esac - else - eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - test -z "$libdir" && \ - func_fatal_error "'$deplib' is not a valid libtool archive" - test "$absdir" != "$libdir" && \ - func_warning "'$deplib' seems to be moved" - - path=-L$absdir - fi - ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$path $deplibs" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - if test link = "$pass"; then - if test prog = "$linkmode"; then - compile_deplibs="$new_inherited_linker_flags $compile_deplibs" - finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" - else - compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - fi - fi - dependency_libs=$newdependency_libs - if test dlpreopen = "$pass"; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test dlopen != "$pass"; then - test conv = "$pass" || { - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) func_append lib_search_path " $dir" ;; - esac - done - newlib_search_path= - } - - if test prog,link = "$linkmode,$pass"; then - vars="compile_deplibs finalize_deplibs" - else - vars=deplibs - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\"\$$var\" - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) func_append tmp_libs " $deplib" ;; - esac - ;; - *) func_append tmp_libs " $deplib" ;; - esac - done - eval $var=\"$tmp_libs\" - done # for var - fi - - # Add Sun CC postdeps if required: - test CXX = "$tagname" && { - case $host_os in - linux*) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C++ 5.9 - func_suncc_cstd_abi - - if test no != "$suncc_use_cstd_abi"; then - func_append postdeps ' -library=Cstd -library=Crun' - fi - ;; - esac - ;; - - solaris*) - func_cc_basename "$CC" - case $func_cc_basename_result in - CC* | sunCC*) - func_suncc_cstd_abi - - if test no != "$suncc_use_cstd_abi"; then - func_append postdeps ' -library=Cstd -library=Crun' - fi - ;; - esac - ;; - esac - } - - # Last step: remove runtime libs from dependency_libs - # (they stay in deplibs) - tmp_libs= - for i in $dependency_libs; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i= - ;; - esac - if test -n "$i"; then - func_append tmp_libs " $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test prog = "$linkmode"; then - dlfiles=$newdlfiles - fi - if test prog = "$linkmode" || test lib = "$linkmode"; then - dlprefiles=$newdlprefiles - fi - - case $linkmode in - oldlib) - if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then - func_warning "'-dlopen' is ignored for archives" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "'-l' and '-L' are ignored for archives" ;; - esac - - test -n "$rpath" && \ - func_warning "'-rpath' is ignored for archives" - - test -n "$xrpath" && \ - func_warning "'-R' is ignored for archives" - - test -n "$vinfo" && \ - func_warning "'-version-info/-version-number' is ignored for archives" - - test -n "$release" && \ - func_warning "'-release' is ignored for archives" - - test -n "$export_symbols$export_symbols_regex" && \ - func_warning "'-export-symbols' is ignored for archives" - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs=$output - func_append objs "$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form 'libNAME.la'. - case $outputname in - lib*) - func_stripname 'lib' '.la' "$outputname" - name=$func_stripname_result - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - ;; - *) - test no = "$module" \ - && func_fatal_help "libtool library '$output' must begin with 'lib'" - - if test no != "$need_lib_prefix"; then - # Add the "lib" prefix for modules if required - func_stripname '' '.la' "$outputname" - name=$func_stripname_result - eval shared_ext=\"$shrext_cmds\" - eval libname=\"$libname_spec\" - else - func_stripname '' '.la' "$outputname" - libname=$func_stripname_result - fi - ;; - esac - - if test -n "$objs"; then - if test pass_all != "$deplibs_check_method"; then - func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" - else - echo - $ECHO "*** Warning: Linking the shared library $output against the non-libtool" - $ECHO "*** objects $objs is not portable!" - func_append libobjs " $objs" - fi - fi - - test no = "$dlself" \ - || func_warning "'-dlopen self' is ignored for libtool libraries" - - set dummy $rpath - shift - test 1 -lt "$#" \ - && func_warning "ignoring multiple '-rpath's for a libtool library" - - install_libdir=$1 - - oldlibs= - if test -z "$rpath"; then - if test yes = "$build_libtool_libs"; then - # Building a libtool convenience library. - # Some compilers have problems with a '.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - test -n "$vinfo" && \ - func_warning "'-version-info/-version-number' is ignored for convenience libraries" - - test -n "$release" && \ - func_warning "'-release' is ignored for convenience libraries" - else - - # Parse the version information argument. - save_ifs=$IFS; IFS=: - set dummy $vinfo 0 0 0 - shift - IFS=$save_ifs - - test -n "$7" && \ - func_fatal_help "too many parameters to '-version-info'" - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major=$1 - number_minor=$2 - number_revision=$3 - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # that has an extra 1 added just for fun - # - case $version_type in - # correct linux to gnu/linux during the next big refactor - darwin|freebsd-elf|linux|osf|windows|none) - func_arith $number_major + $number_minor - current=$func_arith_result - age=$number_minor - revision=$number_revision - ;; - freebsd-aout|qnx|sunos) - current=$number_major - revision=$number_minor - age=0 - ;; - irix|nonstopux) - func_arith $number_major + $number_minor - current=$func_arith_result - age=$number_minor - revision=$number_minor - lt_irix_increment=no - ;; - esac - ;; - no) - current=$1 - revision=$2 - age=$3 - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "CURRENT '$current' must be a nonnegative integer" - func_fatal_error "'$vinfo' is not valid version information" - ;; - esac - - case $revision in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "REVISION '$revision' must be a nonnegative integer" - func_fatal_error "'$vinfo' is not valid version information" - ;; - esac - - case $age in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "AGE '$age' must be a nonnegative integer" - func_fatal_error "'$vinfo' is not valid version information" - ;; - esac - - if test "$age" -gt "$current"; then - func_error "AGE '$age' is greater than the current interface number '$current'" - func_fatal_error "'$vinfo' is not valid version information" - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - func_arith $current - $age - major=.$func_arith_result - versuffix=$major.$age.$revision - # Darwin ld doesn't like 0 for these options... - func_arith $current + 1 - minor_current=$func_arith_result - xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - # On Darwin other compilers - case $CC in - nagfor*) - verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" - ;; - *) - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - ;; - esac - ;; - - freebsd-aout) - major=.$current - versuffix=.$current.$revision - ;; - - freebsd-elf) - func_arith $current - $age - major=.$func_arith_result - versuffix=$major.$age.$revision - ;; - - irix | nonstopux) - if test no = "$lt_irix_increment"; then - func_arith $current - $age - else - func_arith $current - $age + 1 - fi - major=$func_arith_result - - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring=$verstring_prefix$major.$revision - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test 0 -ne "$loop"; do - func_arith $revision - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring=$verstring_prefix$major.$iface:$verstring - done - - # Before this point, $major must not contain '.'. - major=.$major - versuffix=$major.$revision - ;; - - linux) # correct to gnu/linux during the next big refactor - func_arith $current - $age - major=.$func_arith_result - versuffix=$major.$age.$revision - ;; - - osf) - func_arith $current - $age - major=.$func_arith_result - versuffix=.$current.$age.$revision - verstring=$current.$age.$revision - - # Add in all the interfaces that we are compatible with. - loop=$age - while test 0 -ne "$loop"; do - func_arith $current - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring=$verstring:$iface.0 - done - - # Make executables depend on our current version. - func_append verstring ":$current.0" - ;; - - qnx) - major=.$current - versuffix=.$current - ;; - - sco) - major=.$current - versuffix=.$current - ;; - - sunos) - major=.$current - versuffix=.$current.$revision - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 file systems. - func_arith $current - $age - major=$func_arith_result - versuffix=-$major - ;; - - *) - func_fatal_configuration "unknown library version type '$version_type'" - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring=0.0 - ;; - esac - if test no = "$need_version"; then - versuffix= - else - versuffix=.0.0 - fi - fi - - # Remove version info from name if versioning should be avoided - if test yes,no = "$avoid_version,$need_version"; then - major= - versuffix= - verstring= - fi - - # Check to see if the archive will have undefined symbols. - if test yes = "$allow_undefined"; then - if test unsupported = "$allow_undefined_flag"; then - if test yes = "$build_old_libs"; then - func_warning "undefined symbols not allowed in $host shared libraries; building static only" - build_libtool_libs=no - else - func_fatal_error "can't build $host shared library unless -no-undefined is specified" - fi - fi - else - # Don't allow undefined symbols. - allow_undefined_flag=$no_undefined_flag - fi - - fi - - func_generate_dlsyms "$libname" "$libname" : - func_append libobjs " $symfileobj" - test " " = "$libobjs" && libobjs= - - if test relink != "$opt_mode"; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$ECHO "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext | *.gcno) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) - if test -n "$precious_files_regex"; then - if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - fi - func_append removelist " $p" - ;; - *) ;; - esac - done - test -n "$removelist" && \ - func_show_eval "${RM}r \$removelist" - fi - - # Now set the variables for building old libraries. - if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then - func_append oldlibs " $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - #for path in $notinst_path; do - # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` - # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` - # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` - #done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - func_replace_sysroot "$libdir" - func_append temp_xrpath " -R$func_replace_sysroot_result" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - done - if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles=$dlfiles - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) func_append dlfiles " $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles=$dlprefiles - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) func_append dlprefiles " $lib" ;; - esac - done - - if test yes = "$build_libtool_libs"; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - func_append deplibs " System.ltframework" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test yes = "$build_libtool_need_lc"; then - func_append deplibs " -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release= - versuffix= - major= - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $opt_dry_run || $RM conftest.c - cat > conftest.c </dev/null` - $nocaseglob - else - potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` - fi - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null | - $GREP " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib=$potent_lib - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | $SED 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; - *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; - esac - done - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | - $SED -e 10q | - $EGREP "$file_magic_regex" > /dev/null; then - func_append newdeplibs " $a_deplib" - a_deplib= - break 2 - fi - done - done - fi - if test -n "$a_deplib"; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib"; then - $ECHO "*** with $libname but no candidates were found. (...for file magic test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a file magic. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - func_append newdeplibs " $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - for a_deplib in $deplibs; do - case $a_deplib in - -l*) - func_stripname -l '' "$a_deplib" - name=$func_stripname_result - if test yes = "$allow_libtool_libs_with_static_runtimes"; then - case " $predeps $postdeps " in - *" $a_deplib "*) - func_append newdeplibs " $a_deplib" - a_deplib= - ;; - esac - fi - if test -n "$a_deplib"; then - libname=`eval "\\$ECHO \"$libname_spec\""` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib=$potent_lib # see symlink-check above in file_magic test - if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ - $EGREP "$match_pattern_regex" > /dev/null; then - func_append newdeplibs " $a_deplib" - a_deplib= - break 2 - fi - done - done - fi - if test -n "$a_deplib"; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib"; then - $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a regex pattern. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - func_append newdeplibs " $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs= - tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` - if test yes = "$allow_libtool_libs_with_static_runtimes"; then - for i in $predeps $postdeps; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` - done - fi - case $tmp_deplibs in - *[!\ \ ]*) - echo - if test none = "$deplibs_check_method"; then - echo "*** Warning: inter-library dependencies are not supported in this platform." - else - echo "*** Warning: inter-library dependencies are not known to be supported." - fi - echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - ;; - esac - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library with the System framework - newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - if test yes = "$droppeddeps"; then - if test yes = "$module"; then - echo - echo "*** Warning: libtool could not satisfy all declared inter-library" - $ECHO "*** dependencies of module $libname. Therefore, libtool will create" - echo "*** a static module, that should work as long as the dlopening" - echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using 'nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** 'nm' from GNU binutils and a full rebuild may help." - fi - if test no = "$build_old_libs"; then - oldlibs=$output_objdir/$libname.$libext - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - echo "*** The inter-library dependencies that have been dropped here will be" - echo "*** automatically added whenever a program is linked with this library" - echo "*** or is declared to -dlopen it." - - if test no = "$allow_undefined"; then - echo - echo "*** Since this library must not contain undefined symbols," - echo "*** because either the platform does not support them or" - echo "*** it was explicitly requested with -no-undefined," - echo "*** libtool will only create a static version of it." - if test no = "$build_old_libs"; then - oldlibs=$output_objdir/$libname.$libext - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - case $host in - *-*-darwin*) - newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $deplibs " in - *" -L$path/$objdir "*) - func_append new_libs " -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) func_append new_libs " $deplib" ;; - esac - ;; - *) func_append new_libs " $deplib" ;; - esac - done - deplibs=$new_libs - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test yes = "$build_libtool_libs"; then - # Remove $wl instances when linking with ld. - # FIXME: should test the right _cmds variable. - case $archive_cmds in - *\$LD\ *) wl= ;; - esac - if test yes = "$hardcode_into_libs"; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath=$finalize_rpath - test relink = "$opt_mode" || rpath=$compile_rpath$rpath - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - func_replace_sysroot "$libdir" - libdir=$func_replace_sysroot_result - if test -z "$hardcode_libdirs"; then - hardcode_libdirs=$libdir - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append dep_rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) func_append perm_rpath " $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir=$hardcode_libdirs - eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - func_append rpath "$dir:" - done - eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath=$finalize_shlibpath - test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath - if test -n "$shlibpath"; then - eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" - fi - - # Get the real and link names of the library. - eval shared_ext=\"$shrext_cmds\" - eval library_names=\"$library_names_spec\" - set dummy $library_names - shift - realname=$1 - shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname=$realname - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib=$output_objdir/$realname - linknames= - for link - do - func_append linknames " $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` - test "X$libobjs" = "X " && libobjs= - - delfiles= - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" - export_symbols=$output_objdir/$libname.uexp - func_append delfiles " $export_symbols" - fi - - orig_export_symbols= - case $host_os in - cygwin* | mingw* | cegcc*) - if test -n "$export_symbols" && test -z "$export_symbols_regex"; then - # exporting using user supplied symfile - func_dll_def_p "$export_symbols" || { - # and it's NOT already a .def file. Must figure out - # which of the given symbols are data symbols and tag - # them as such. So, trigger use of export_symbols_cmds. - # export_symbols gets reassigned inside the "prepare - # the list of exported symbols" if statement, so the - # include_expsyms logic still works. - orig_export_symbols=$export_symbols - export_symbols= - always_export_symbols=yes - } - fi - ;; - esac - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then - func_verbose "generating symbol list for '$libname.la'" - export_symbols=$output_objdir/$libname.exp - $opt_dry_run || $RM $export_symbols - cmds=$export_symbols_cmds - save_ifs=$IFS; IFS='~' - for cmd1 in $cmds; do - IFS=$save_ifs - # Take the normal branch if the nm_file_list_spec branch - # doesn't work or if tool conversion is not needed. - case $nm_file_list_spec~$to_tool_file_cmd in - *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) - try_normal_branch=yes - eval cmd=\"$cmd1\" - func_len " $cmd" - len=$func_len_result - ;; - *) - try_normal_branch=no - ;; - esac - if test yes = "$try_normal_branch" \ - && { test "$len" -lt "$max_cmd_len" \ - || test "$max_cmd_len" -le -1; } - then - func_show_eval "$cmd" 'exit $?' - skipped_export=false - elif test -n "$nm_file_list_spec"; then - func_basename "$output" - output_la=$func_basename_result - save_libobjs=$libobjs - save_output=$output - output=$output_objdir/$output_la.nm - func_to_tool_file "$output" - libobjs=$nm_file_list_spec$func_to_tool_file_result - func_append delfiles " $output" - func_verbose "creating $NM input file list: $output" - for obj in $save_libobjs; do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" - done > "$output" - eval cmd=\"$cmd1\" - func_show_eval "$cmd" 'exit $?' - output=$save_output - libobjs=$save_libobjs - skipped_export=false - else - # The command line is too long to execute in one step. - func_verbose "using reloadable object file for export list..." - skipped_export=: - # Break out early, otherwise skipped_export may be - # set to false by a later but shorter cmd. - break - fi - done - IFS=$save_ifs - if test -n "$export_symbols_regex" && test : != "$skipped_export"; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols=$export_symbols - test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols - $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' - fi - - if test : != "$skipped_export" && test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for '$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands, which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - func_append delfiles " $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - func_append tmp_deplibs " $test_deplib" - ;; - esac - done - deplibs=$tmp_deplibs - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec" && - test yes = "$compiler_needs_object" && - test -z "$libobjs"; then - # extract the archives, so we have objects to list. - # TODO: could optimize this to just extract one archive. - whole_archive_flag_spec= - fi - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - test "X$libobjs" = "X " && libobjs= - else - gentop=$output_objdir/${outputname}x - func_append generated " $gentop" - - func_extract_archives $gentop $convenience - func_append libobjs " $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - fi - - if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - func_append linker_flags " $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test relink = "$opt_mode"; then - $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? - fi - - # Do each of the archive commands. - if test yes = "$module" && test -n "$module_cmds"; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval test_cmds=\"$module_expsym_cmds\" - cmds=$module_expsym_cmds - else - eval test_cmds=\"$module_cmds\" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds - fi - fi - - if test : != "$skipped_export" && - func_len " $test_cmds" && - len=$func_len_result && - test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise - # or, if using GNU ld and skipped_export is not :, use a linker - # script. - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - func_basename "$output" - output_la=$func_basename_result - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - last_robj= - k=1 - - if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then - output=$output_objdir/$output_la.lnkscript - func_verbose "creating GNU ld script: $output" - echo 'INPUT (' > $output - for obj in $save_libobjs - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" >> $output - done - echo ')' >> $output - func_append delfiles " $output" - func_to_tool_file "$output" - output=$func_to_tool_file_result - elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then - output=$output_objdir/$output_la.lnk - func_verbose "creating linker input file list: $output" - : > $output - set x $save_libobjs - shift - firstobj= - if test yes = "$compiler_needs_object"; then - firstobj="$1 " - shift - fi - for obj - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" >> $output - done - func_append delfiles " $output" - func_to_tool_file "$output" - output=$firstobj\"$file_list_spec$func_to_tool_file_result\" - else - if test -n "$save_libobjs"; then - func_verbose "creating reloadable object files..." - output=$output_objdir/$output_la-$k.$objext - eval test_cmds=\"$reload_cmds\" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - if test -z "$objlist" || - test "$len" -lt "$max_cmd_len"; then - func_append objlist " $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test 1 -eq "$k"; then - # The first file doesn't have a previous command to add. - reload_objs=$objlist - eval concat_cmds=\"$reload_cmds\" - else - # All subsequent reloadable object files will link in - # the last one created. - reload_objs="$objlist $last_robj" - eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" - fi - last_robj=$output_objdir/$output_la-$k.$objext - func_arith $k + 1 - k=$func_arith_result - output=$output_objdir/$output_la-$k.$objext - objlist=" $obj" - func_len " $last_robj" - func_arith $len0 + $func_len_result - len=$func_arith_result - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - reload_objs="$objlist $last_robj" - eval concat_cmds=\"\$concat_cmds$reload_cmds\" - if test -n "$last_robj"; then - eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" - fi - func_append delfiles " $output" - - else - output= - fi - - ${skipped_export-false} && { - func_verbose "generating symbol list for '$libname.la'" - export_symbols=$output_objdir/$libname.exp - $opt_dry_run || $RM $export_symbols - libobjs=$output - # Append the command to create the export file. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" - if test -n "$last_robj"; then - eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" - fi - } - - test -n "$save_libobjs" && - func_verbose "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs=$IFS; IFS='~' - for cmd in $concat_cmds; do - IFS=$save_ifs - $opt_quiet || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test relink = "$opt_mode"; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS=$save_ifs - - if test -n "$export_symbols_regex" && ${skipped_export-false}; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - - ${skipped_export-false} && { - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols=$export_symbols - test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols - $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' - fi - - if test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for '$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands, which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - func_append delfiles " $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - } - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - test "X$libobjs" = "X " && libobjs= - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test yes = "$module" && test -n "$module_cmds"; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - fi - - if test -n "$delfiles"; then - # Append the command to remove temporary files to $cmds. - eval cmds=\"\$cmds~\$RM $delfiles\" - fi - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop=$output_objdir/${outputname}x - func_append generated " $gentop" - - func_extract_archives $gentop $dlprefiles - func_append libobjs " $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - - save_ifs=$IFS; IFS='~' - for cmd in $cmds; do - IFS=$sp$nl - eval cmd=\"$cmd\" - IFS=$save_ifs - $opt_quiet || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test relink = "$opt_mode"; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS=$save_ifs - - # Restore the uninstalled library and exit - if test relink = "$opt_mode"; then - $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? - - if test -n "$convenience"; then - if test -z "$whole_archive_flag_spec"; then - func_show_eval '${RM}r "$gentop"' - fi - fi - - exit $EXIT_SUCCESS - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test yes = "$module" || test yes = "$export_dynamic"; then - # On all known operating systems, these are identical. - dlname=$soname - fi - fi - ;; - - obj) - if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then - func_warning "'-dlopen' is ignored for objects" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "'-l' and '-L' are ignored for objects" ;; - esac - - test -n "$rpath" && \ - func_warning "'-rpath' is ignored for objects" - - test -n "$xrpath" && \ - func_warning "'-R' is ignored for objects" - - test -n "$vinfo" && \ - func_warning "'-version-info' is ignored for objects" - - test -n "$release" && \ - func_warning "'-release' is ignored for objects" - - case $output in - *.lo) - test -n "$objs$old_deplibs" && \ - func_fatal_error "cannot build library object '$output' from non-libtool objects" - - libobj=$output - func_lo2o "$libobj" - obj=$func_lo2o_result - ;; - *) - libobj= - obj=$output - ;; - esac - - # Delete the old objects. - $opt_dry_run || $RM $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # if reload_cmds runs $LD directly, get rid of -Wl from - # whole_archive_flag_spec and hope we can get by with turning comma - # into space. - case $reload_cmds in - *\$LD[\ \$]*) wl= ;; - esac - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" - test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` - reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags - else - gentop=$output_objdir/${obj}x - func_append generated " $gentop" - - func_extract_archives $gentop $convenience - reload_conv_objs="$reload_objs $func_extract_archives_result" - fi - fi - - # If we're not building shared, we need to use non_pic_objs - test yes = "$build_libtool_libs" || libobjs=$non_pic_objects - - # Create the old-style object. - reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs - - output=$obj - func_execute_cmds "$reload_cmds" 'exit $?' - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - fi - - test yes = "$build_libtool_libs" || { - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? - exit $EXIT_SUCCESS - } - - if test -n "$pic_flag" || test default != "$pic_mode"; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output=$libobj - func_execute_cmds "$reload_cmds" 'exit $?' - fi - - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - ;; - - prog) - case $host in - *cygwin*) func_stripname '' '.exe' "$output" - output=$func_stripname_result.exe;; - esac - test -n "$vinfo" && \ - func_warning "'-version-info' is ignored for programs" - - test -n "$release" && \ - func_warning "'-release' is ignored for programs" - - $preload \ - && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ - && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - case $host in - *-*-darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - # But is supposedly fixed on 10.4 or later (yay!). - if test CXX = "$tagname"; then - case ${MACOSX_DEPLOYMENT_TARGET-10.0} in - 10.[0123]) - func_append compile_command " $wl-bind_at_load" - func_append finalize_command " $wl-bind_at_load" - ;; - esac - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $compile_deplibs " in - *" -L$path/$objdir "*) - func_append new_libs " -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $compile_deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) func_append new_libs " $deplib" ;; - esac - ;; - *) func_append new_libs " $deplib" ;; - esac - done - compile_deplibs=$new_libs - - - func_append compile_command " $compile_deplibs" - func_append finalize_command " $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) func_append finalize_rpath " $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs=$libdir - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) func_append perm_rpath " $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$libdir:"*) ;; - ::) dllsearchpath=$libdir;; - *) func_append dllsearchpath ":$libdir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) func_append dllsearchpath ":$testbindir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir=$hardcode_libdirs - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath=$rpath - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs=$libdir - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - func_append rpath " $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) func_append finalize_perm_rpath " $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir=$hardcode_libdirs - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath=$rpath - - if test -n "$libobjs" && test yes = "$build_old_libs"; then - # Transform all the library objects into standard objects. - compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - fi - - func_generate_dlsyms "$outputname" "@PROGRAM@" false - - # template prelinking step - if test -n "$prelink_cmds"; then - func_execute_cmds "$prelink_cmds" 'exit $?' - fi - - wrappers_required=: - case $host in - *cegcc* | *mingw32ce*) - # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. - wrappers_required=false - ;; - *cygwin* | *mingw* ) - test yes = "$build_libtool_libs" || wrappers_required=false - ;; - *) - if test no = "$need_relink" || test yes != "$build_libtool_libs"; then - wrappers_required=false - fi - ;; - esac - $wrappers_required || { - # Replace the output file specification. - compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - link_command=$compile_command$compile_rpath - - # We have no uninstalled library dependencies, so finalize right now. - exit_status=0 - func_show_eval "$link_command" 'exit_status=$?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - # Delete the generated files. - if test -f "$output_objdir/${outputname}S.$objext"; then - func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' - fi - - exit $exit_status - } - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - func_append rpath "$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - func_append rpath "$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test yes = "$no_install"; then - # We don't need to create a wrapper script. - link_command=$compile_var$compile_command$compile_rpath - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $opt_dry_run || $RM $output - # Link the executable and exit - func_show_eval "$link_command" 'exit $?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - exit $EXIT_SUCCESS - fi - - case $hardcode_action,$fast_install in - relink,*) - # Fast installation is not supported - link_command=$compile_var$compile_command$compile_rpath - relink_command=$finalize_var$finalize_command$finalize_rpath - - func_warning "this platform does not like uninstalled shared libraries" - func_warning "'$output' will be relinked during installation" - ;; - *,yes) - link_command=$finalize_var$compile_command$finalize_rpath - relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` - ;; - *,no) - link_command=$compile_var$compile_command$compile_rpath - relink_command=$finalize_var$finalize_command$finalize_rpath - ;; - *,needless) - link_command=$finalize_var$compile_command$finalize_rpath - relink_command= - ;; - esac - - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname - - func_show_eval "$link_command" 'exit $?' - - if test -n "$postlink_cmds"; then - func_to_tool_file "$output_objdir/$outputname" - postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` - func_execute_cmds "$postlink_cmds" 'exit $?' - fi - - # Now create the wrapper script. - func_verbose "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - fi - - # Only actually do things if not in dry run mode. - $opt_dry_run || { - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) func_stripname '' '.exe' "$output" - output=$func_stripname_result ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - func_stripname '' '.exe' "$outputname" - outputname=$func_stripname_result ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - func_dirname_and_basename "$output" "" "." - output_name=$func_basename_result - output_path=$func_dirname_result - cwrappersource=$output_path/$objdir/lt-$output_name.c - cwrapper=$output_path/$output_name.exe - $RM $cwrappersource $cwrapper - trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 - - func_emit_cwrapperexe_src > $cwrappersource - - # The wrapper executable is built using the $host compiler, - # because it contains $host paths and files. If cross- - # compiling, it, like the target executable, must be - # executed on the $host or under an emulation environment. - $opt_dry_run || { - $LTCC $LTCFLAGS -o $cwrapper $cwrappersource - $STRIP $cwrapper - } - - # Now, create the wrapper script for func_source use: - func_ltwrapper_scriptname $cwrapper - $RM $func_ltwrapper_scriptname_result - trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 - $opt_dry_run || { - # note: this script will not be executed, so do not chmod. - if test "x$build" = "x$host"; then - $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result - else - func_emit_wrapper no > $func_ltwrapper_scriptname_result - fi - } - ;; - * ) - $RM $output - trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 - - func_emit_wrapper no > $output - chmod +x $output - ;; - esac - } - exit $EXIT_SUCCESS - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - case $build_libtool_libs in - convenience) - oldobjs="$libobjs_save $symfileobj" - addlibs=$convenience - build_libtool_libs=no - ;; - module) - oldobjs=$libobjs_save - addlibs=$old_convenience - build_libtool_libs=no - ;; - *) - oldobjs="$old_deplibs $non_pic_objects" - $preload && test -f "$symfileobj" \ - && func_append oldobjs " $symfileobj" - addlibs=$old_convenience - ;; - esac - - if test -n "$addlibs"; then - gentop=$output_objdir/${outputname}x - func_append generated " $gentop" - - func_extract_archives $gentop $addlibs - func_append oldobjs " $func_extract_archives_result" - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then - cmds=$old_archive_from_new_cmds - else - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop=$output_objdir/${outputname}x - func_append generated " $gentop" - - func_extract_archives $gentop $dlprefiles - func_append oldobjs " $func_extract_archives_result" - fi - - # POSIX demands no paths to be encoded in archives. We have - # to avoid creating archives with duplicate basenames if we - # might have to extract them afterwards, e.g., when creating a - # static archive out of a convenience library, or when linking - # the entirety of a libtool archive into another (currently - # not supported by libtool). - if (for obj in $oldobjs - do - func_basename "$obj" - $ECHO "$func_basename_result" - done | sort | sort -uc >/dev/null 2>&1); then - : - else - echo "copying selected object files to avoid basename conflicts..." - gentop=$output_objdir/${outputname}x - func_append generated " $gentop" - func_mkdir_p "$gentop" - save_oldobjs=$oldobjs - oldobjs= - counter=1 - for obj in $save_oldobjs - do - func_basename "$obj" - objbase=$func_basename_result - case " $oldobjs " in - " ") oldobjs=$obj ;; - *[\ /]"$objbase "*) - while :; do - # Make sure we don't pick an alternate name that also - # overlaps. - newobj=lt$counter-$objbase - func_arith $counter + 1 - counter=$func_arith_result - case " $oldobjs " in - *[\ /]"$newobj "*) ;; - *) if test ! -f "$gentop/$newobj"; then break; fi ;; - esac - done - func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - func_append oldobjs " $gentop/$newobj" - ;; - *) func_append oldobjs " $obj" ;; - esac - done - fi - func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 - tool_oldlib=$func_to_tool_file_result - eval cmds=\"$old_archive_cmds\" - - func_len " $cmds" - len=$func_len_result - if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - elif test -n "$archiver_list_spec"; then - func_verbose "using command file archive linking..." - for obj in $oldobjs - do - func_to_tool_file "$obj" - $ECHO "$func_to_tool_file_result" - done > $output_objdir/$libname.libcmd - func_to_tool_file "$output_objdir/$libname.libcmd" - oldobjs=" $archiver_list_spec$func_to_tool_file_result" - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - func_verbose "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - oldobjs= - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - eval test_cmds=\"$old_archive_cmds\" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - for obj in $save_oldobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - func_append objlist " $obj" - if test "$len" -lt "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj"; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" - objlist= - len=$len0 - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test -z "$oldobjs"; then - eval cmds=\"\$concat_cmds\" - else - eval cmds=\"\$concat_cmds~\$old_archive_cmds\" - fi - fi - fi - func_execute_cmds "$cmds" 'exit $?' - done - - test -n "$generated" && \ - func_show_eval "${RM}r$generated" - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test yes = "$build_old_libs" && old_library=$libname.$libext - func_verbose "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - if test yes = "$hardcode_automatic"; then - relink_command= - fi - - # Only create the output if not a dry run. - $opt_dry_run || { - for installed in no yes; do - if test yes = "$installed"; then - if test -z "$install_libdir"; then - break - fi - output=$output_objdir/${outputname}i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - func_basename "$deplib" - name=$func_basename_result - func_resolve_sysroot "$deplib" - eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` - test -z "$libdir" && \ - func_fatal_error "'$deplib' is not a valid libtool archive" - func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" - ;; - -L*) - func_stripname -L '' "$deplib" - func_replace_sysroot "$func_stripname_result" - func_append newdependency_libs " -L$func_replace_sysroot_result" - ;; - -R*) - func_stripname -R '' "$deplib" - func_replace_sysroot "$func_stripname_result" - func_append newdependency_libs " -R$func_replace_sysroot_result" - ;; - *) func_append newdependency_libs " $deplib" ;; - esac - done - dependency_libs=$newdependency_libs - newdlfiles= - - for lib in $dlfiles; do - case $lib in - *.la) - func_basename "$lib" - name=$func_basename_result - eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "'$lib' is not a valid libtool archive" - func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" - ;; - *) func_append newdlfiles " $lib" ;; - esac - done - dlfiles=$newdlfiles - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - *.la) - # Only pass preopened files to the pseudo-archive (for - # eventual linking with the app. that links it) if we - # didn't already link the preopened objects directly into - # the library: - func_basename "$lib" - name=$func_basename_result - eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "'$lib' is not a valid libtool archive" - func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" - ;; - esac - done - dlprefiles=$newdlprefiles - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; - *) abs=`pwd`"/$lib" ;; - esac - func_append newdlfiles " $abs" - done - dlfiles=$newdlfiles - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; - *) abs=`pwd`"/$lib" ;; - esac - func_append newdlprefiles " $abs" - done - dlprefiles=$newdlprefiles - fi - $RM $output - # place dlname in correct position for cygwin - # In fact, it would be nice if we could use this code for all target - # systems that can't hard-code library paths into their executables - # and that have no shared library path variable independent of PATH, - # but it turns out we can't easily determine that from inspecting - # libtool variables, so we have to hard-code the OSs to which it - # applies here; at the moment, that means platforms that use the PE - # object format with DLL files. See the long comment at the top of - # tests/bindir.at for full details. - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) - # If a -bindir argument was supplied, place the dll there. - if test -n "$bindir"; then - func_relative_path "$install_libdir" "$bindir" - tdlname=$func_relative_path_result/$dlname - else - # Otherwise fall back on heuristic. - tdlname=../bin/$dlname - fi - ;; - esac - $ECHO > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM (GNU $PACKAGE) $VERSION -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Linker flags that cannot go in dependency_libs. -inherited_linker_flags='$new_inherited_linker_flags' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Names of additional weak libraries provided by this library -weak_library_names='$weak_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test no,yes = "$installed,$need_relink"; then - $ECHO >> $output "\ -relink_command=\"$relink_command\"" - fi - done - } - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' - ;; - esac - exit $EXIT_SUCCESS -} - -if test link = "$opt_mode" || test relink = "$opt_mode"; then - func_mode_link ${1+"$@"} -fi - - -# func_mode_uninstall arg... -func_mode_uninstall () -{ - $debug_cmd - - RM=$nonopt - files= - rmforce=false - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic=$magic - - for arg - do - case $arg in - -f) func_append RM " $arg"; rmforce=: ;; - -*) func_append RM " $arg" ;; - *) func_append files " $arg" ;; - esac - done - - test -z "$RM" && \ - func_fatal_help "you must specify an RM program" - - rmdirs= - - for file in $files; do - func_dirname "$file" "" "." - dir=$func_dirname_result - if test . = "$dir"; then - odir=$objdir - else - odir=$dir/$objdir - fi - func_basename "$file" - name=$func_basename_result - test uninstall = "$opt_mode" && odir=$dir - - # Remember odir for removal later, being careful to avoid duplicates - if test clean = "$opt_mode"; then - case " $rmdirs " in - *" $odir "*) ;; - *) func_append rmdirs " $odir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if { test -L "$file"; } >/dev/null 2>&1 || - { test -h "$file"; } >/dev/null 2>&1 || - test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif $rmforce; then - continue - fi - - rmfiles=$file - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if func_lalib_p "$file"; then - func_source $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - func_append rmfiles " $odir/$n" - done - test -n "$old_library" && func_append rmfiles " $odir/$old_library" - - case $opt_mode in - clean) - case " $library_names " in - *" $dlname "*) ;; - *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; - esac - test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" - ;; - uninstall) - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' - fi - # FIXME: should reinstall the best remaining shared library. - ;; - esac - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if func_lalib_p "$file"; then - - # Read the .lo file - func_source $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" && test none != "$pic_object"; then - func_append rmfiles " $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" && test none != "$non_pic_object"; then - func_append rmfiles " $dir/$non_pic_object" - fi - fi - ;; - - *) - if test clean = "$opt_mode"; then - noexename=$name - case $file in - *.exe) - func_stripname '' '.exe' "$file" - file=$func_stripname_result - func_stripname '' '.exe' "$name" - noexename=$func_stripname_result - # $file with .exe has already been added to rmfiles, - # add $file without .exe - func_append rmfiles " $file" - ;; - esac - # Do a test to see if this is a libtool program. - if func_ltwrapper_p "$file"; then - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - relink_command= - func_source $func_ltwrapper_scriptname_result - func_append rmfiles " $func_ltwrapper_scriptname_result" - else - relink_command= - func_source $dir/$noexename - fi - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - func_append rmfiles " $odir/$name $odir/${name}S.$objext" - if test yes = "$fast_install" && test -n "$relink_command"; then - func_append rmfiles " $odir/lt-$name" - fi - if test "X$noexename" != "X$name"; then - func_append rmfiles " $odir/lt-$noexename.c" - fi - fi - fi - ;; - esac - func_show_eval "$RM $rmfiles" 'exit_status=1' - done - - # Try to remove the $objdir's in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - func_show_eval "rmdir $dir >/dev/null 2>&1" - fi - done - - exit $exit_status -} - -if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then - func_mode_uninstall ${1+"$@"} -fi - -test -z "$opt_mode" && { - help=$generic_help - func_fatal_help "you must specify a MODE" -} - -test -z "$exec_cmd" && \ - func_fatal_help "invalid operation mode '$opt_mode'" - -if test -n "$exec_cmd"; then - eval exec "$exec_cmd" - exit $EXIT_FAILURE -fi - -exit $exit_status - - -# The TAGs below are defined such that we never get into a situation -# where we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -build_libtool_libs=no -build_old_libs=yes -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: diff --git a/src/secp256k1-mw/build-aux/m4/libtool.m4 b/src/secp256k1-mw/build-aux/m4/libtool.m4 deleted file mode 100644 index a3bc337b79..0000000000 --- a/src/secp256k1-mw/build-aux/m4/libtool.m4 +++ /dev/null @@ -1,8369 +0,0 @@ -# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- -# -# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. -# Written by Gordon Matzigkeit, 1996 -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -m4_define([_LT_COPYING], [dnl -# Copyright (C) 2014 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program or library that is built -# using GNU Libtool, you may include this file under the same -# distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -]) - -# serial 58 LT_INIT - - -# LT_PREREQ(VERSION) -# ------------------ -# Complain and exit if this libtool version is less that VERSION. -m4_defun([LT_PREREQ], -[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, - [m4_default([$3], - [m4_fatal([Libtool version $1 or higher is required], - 63)])], - [$2])]) - - -# _LT_CHECK_BUILDDIR -# ------------------ -# Complain if the absolute build directory name contains unusual characters -m4_defun([_LT_CHECK_BUILDDIR], -[case `pwd` in - *\ * | *\ *) - AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; -esac -]) - - -# LT_INIT([OPTIONS]) -# ------------------ -AC_DEFUN([LT_INIT], -[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK -AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -AC_BEFORE([$0], [LT_LANG])dnl -AC_BEFORE([$0], [LT_OUTPUT])dnl -AC_BEFORE([$0], [LTDL_INIT])dnl -m4_require([_LT_CHECK_BUILDDIR])dnl - -dnl Autoconf doesn't catch unexpanded LT_ macros by default: -m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl -m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl -dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 -dnl unless we require an AC_DEFUNed macro: -AC_REQUIRE([LTOPTIONS_VERSION])dnl -AC_REQUIRE([LTSUGAR_VERSION])dnl -AC_REQUIRE([LTVERSION_VERSION])dnl -AC_REQUIRE([LTOBSOLETE_VERSION])dnl -m4_require([_LT_PROG_LTMAIN])dnl - -_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) - -dnl Parse OPTIONS -_LT_SET_OPTIONS([$0], [$1]) - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS=$ltmain - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' -AC_SUBST(LIBTOOL)dnl - -_LT_SETUP - -# Only expand once: -m4_define([LT_INIT]) -])# LT_INIT - -# Old names: -AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) -AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_PROG_LIBTOOL], []) -dnl AC_DEFUN([AM_PROG_LIBTOOL], []) - - -# _LT_PREPARE_CC_BASENAME -# ----------------------- -m4_defun([_LT_PREPARE_CC_BASENAME], [ -# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. -func_cc_basename () -{ - for cc_temp in @S|@*""; do - case $cc_temp in - compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; - distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; - \-*) ;; - *) break;; - esac - done - func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` -} -])# _LT_PREPARE_CC_BASENAME - - -# _LT_CC_BASENAME(CC) -# ------------------- -# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, -# but that macro is also expanded into generated libtool script, which -# arranges for $SED and $ECHO to be set by different means. -m4_defun([_LT_CC_BASENAME], -[m4_require([_LT_PREPARE_CC_BASENAME])dnl -AC_REQUIRE([_LT_DECL_SED])dnl -AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl -func_cc_basename $1 -cc_basename=$func_cc_basename_result -]) - - -# _LT_FILEUTILS_DEFAULTS -# ---------------------- -# It is okay to use these file commands and assume they have been set -# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. -m4_defun([_LT_FILEUTILS_DEFAULTS], -[: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} -])# _LT_FILEUTILS_DEFAULTS - - -# _LT_SETUP -# --------- -m4_defun([_LT_SETUP], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl -AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl - -_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl -dnl -_LT_DECL([], [host_alias], [0], [The host system])dnl -_LT_DECL([], [host], [0])dnl -_LT_DECL([], [host_os], [0])dnl -dnl -_LT_DECL([], [build_alias], [0], [The build system])dnl -_LT_DECL([], [build], [0])dnl -_LT_DECL([], [build_os], [0])dnl -dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([LT_PATH_LD])dnl -AC_REQUIRE([LT_PATH_NM])dnl -dnl -AC_REQUIRE([AC_PROG_LN_S])dnl -test -z "$LN_S" && LN_S="ln -s" -_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl -dnl -AC_REQUIRE([LT_CMD_MAX_LEN])dnl -_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl -_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl -dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_CHECK_SHELL_FEATURES])dnl -m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl -m4_require([_LT_CMD_RELOAD])dnl -m4_require([_LT_CHECK_MAGIC_METHOD])dnl -m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl -m4_require([_LT_CMD_OLD_ARCHIVE])dnl -m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -m4_require([_LT_WITH_SYSROOT])dnl -m4_require([_LT_CMD_TRUNCATE])dnl - -_LT_CONFIG_LIBTOOL_INIT([ -# See if we are running on zsh, and set the options that allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi -]) -if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST -fi - -_LT_CHECK_OBJDIR - -m4_require([_LT_TAG_COMPILER])dnl - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a '.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a - -with_gnu_ld=$lt_cv_prog_gnu_ld - -old_CC=$CC -old_CFLAGS=$CFLAGS - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -_LT_CC_BASENAME([$compiler]) - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - _LT_PATH_MAGIC - fi - ;; -esac - -# Use C for the default configuration in the libtool script -LT_SUPPORTED_TAG([CC]) -_LT_LANG_C_CONFIG -_LT_LANG_DEFAULT_CONFIG -_LT_CONFIG_COMMANDS -])# _LT_SETUP - - -# _LT_PREPARE_SED_QUOTE_VARS -# -------------------------- -# Define a few sed substitution that help us do robust quoting. -m4_defun([_LT_PREPARE_SED_QUOTE_VARS], -[# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\([["`\\]]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' -]) - -# _LT_PROG_LTMAIN -# --------------- -# Note that this code is called both from 'configure', and 'config.status' -# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, -# 'config.status' has no value for ac_aux_dir unless we are using Automake, -# so we pass a copy along to make sure it has a sensible value anyway. -m4_defun([_LT_PROG_LTMAIN], -[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl -_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) -ltmain=$ac_aux_dir/ltmain.sh -])# _LT_PROG_LTMAIN - - -## ------------------------------------- ## -## Accumulate code for creating libtool. ## -## ------------------------------------- ## - -# So that we can recreate a full libtool script including additional -# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS -# in macros and then make a single call at the end using the 'libtool' -# label. - - -# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) -# ---------------------------------------- -# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. -m4_define([_LT_CONFIG_LIBTOOL_INIT], -[m4_ifval([$1], - [m4_append([_LT_OUTPUT_LIBTOOL_INIT], - [$1 -])])]) - -# Initialize. -m4_define([_LT_OUTPUT_LIBTOOL_INIT]) - - -# _LT_CONFIG_LIBTOOL([COMMANDS]) -# ------------------------------ -# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. -m4_define([_LT_CONFIG_LIBTOOL], -[m4_ifval([$1], - [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], - [$1 -])])]) - -# Initialize. -m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) - - -# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) -# ----------------------------------------------------- -m4_defun([_LT_CONFIG_SAVE_COMMANDS], -[_LT_CONFIG_LIBTOOL([$1]) -_LT_CONFIG_LIBTOOL_INIT([$2]) -]) - - -# _LT_FORMAT_COMMENT([COMMENT]) -# ----------------------------- -# Add leading comment marks to the start of each line, and a trailing -# full-stop to the whole comment if one is not present already. -m4_define([_LT_FORMAT_COMMENT], -[m4_ifval([$1], [ -m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], - [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) -)]) - - - -## ------------------------ ## -## FIXME: Eliminate VARNAME ## -## ------------------------ ## - - -# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) -# ------------------------------------------------------------------- -# CONFIGNAME is the name given to the value in the libtool script. -# VARNAME is the (base) name used in the configure script. -# VALUE may be 0, 1 or 2 for a computed quote escaped value based on -# VARNAME. Any other value will be used directly. -m4_define([_LT_DECL], -[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], - [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], - [m4_ifval([$1], [$1], [$2])]) - lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) - m4_ifval([$4], - [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) - lt_dict_add_subkey([lt_decl_dict], [$2], - [tagged?], [m4_ifval([$5], [yes], [no])])]) -]) - - -# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) -# -------------------------------------------------------- -m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) - - -# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) -# ------------------------------------------------ -m4_define([lt_decl_tag_varnames], -[_lt_decl_filter([tagged?], [yes], $@)]) - - -# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) -# --------------------------------------------------------- -m4_define([_lt_decl_filter], -[m4_case([$#], - [0], [m4_fatal([$0: too few arguments: $#])], - [1], [m4_fatal([$0: too few arguments: $#: $1])], - [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], - [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], - [lt_dict_filter([lt_decl_dict], $@)])[]dnl -]) - - -# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) -# -------------------------------------------------- -m4_define([lt_decl_quote_varnames], -[_lt_decl_filter([value], [1], $@)]) - - -# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) -# --------------------------------------------------- -m4_define([lt_decl_dquote_varnames], -[_lt_decl_filter([value], [2], $@)]) - - -# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) -# --------------------------------------------------- -m4_define([lt_decl_varnames_tagged], -[m4_assert([$# <= 2])dnl -_$0(m4_quote(m4_default([$1], [[, ]])), - m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), - m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) -m4_define([_lt_decl_varnames_tagged], -[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) - - -# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) -# ------------------------------------------------ -m4_define([lt_decl_all_varnames], -[_$0(m4_quote(m4_default([$1], [[, ]])), - m4_if([$2], [], - m4_quote(lt_decl_varnames), - m4_quote(m4_shift($@))))[]dnl -]) -m4_define([_lt_decl_all_varnames], -[lt_join($@, lt_decl_varnames_tagged([$1], - lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl -]) - - -# _LT_CONFIG_STATUS_DECLARE([VARNAME]) -# ------------------------------------ -# Quote a variable value, and forward it to 'config.status' so that its -# declaration there will have the same value as in 'configure'. VARNAME -# must have a single quote delimited value for this to work. -m4_define([_LT_CONFIG_STATUS_DECLARE], -[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) - - -# _LT_CONFIG_STATUS_DECLARATIONS -# ------------------------------ -# We delimit libtool config variables with single quotes, so when -# we write them to config.status, we have to be sure to quote all -# embedded single quotes properly. In configure, this macro expands -# each variable declared with _LT_DECL (and _LT_TAGDECL) into: -# -# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' -m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], -[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), - [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) - - -# _LT_LIBTOOL_TAGS -# ---------------- -# Output comment and list of tags supported by the script -m4_defun([_LT_LIBTOOL_TAGS], -[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl -available_tags='_LT_TAGS'dnl -]) - - -# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) -# ----------------------------------- -# Extract the dictionary values for VARNAME (optionally with TAG) and -# expand to a commented shell variable setting: -# -# # Some comment about what VAR is for. -# visible_name=$lt_internal_name -m4_define([_LT_LIBTOOL_DECLARE], -[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], - [description])))[]dnl -m4_pushdef([_libtool_name], - m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl -m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), - [0], [_libtool_name=[$]$1], - [1], [_libtool_name=$lt_[]$1], - [2], [_libtool_name=$lt_[]$1], - [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl -m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl -]) - - -# _LT_LIBTOOL_CONFIG_VARS -# ----------------------- -# Produce commented declarations of non-tagged libtool config variables -# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' -# script. Tagged libtool config variables (even for the LIBTOOL CONFIG -# section) are produced by _LT_LIBTOOL_TAG_VARS. -m4_defun([_LT_LIBTOOL_CONFIG_VARS], -[m4_foreach([_lt_var], - m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), - [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) - - -# _LT_LIBTOOL_TAG_VARS(TAG) -# ------------------------- -m4_define([_LT_LIBTOOL_TAG_VARS], -[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), - [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) - - -# _LT_TAGVAR(VARNAME, [TAGNAME]) -# ------------------------------ -m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) - - -# _LT_CONFIG_COMMANDS -# ------------------- -# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of -# variables for single and double quote escaping we saved from calls -# to _LT_DECL, we can put quote escaped variables declarations -# into 'config.status', and then the shell code to quote escape them in -# for loops in 'config.status'. Finally, any additional code accumulated -# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. -m4_defun([_LT_CONFIG_COMMANDS], -[AC_PROVIDE_IFELSE([LT_OUTPUT], - dnl If the libtool generation code has been placed in $CONFIG_LT, - dnl instead of duplicating it all over again into config.status, - dnl then we will have config.status run $CONFIG_LT later, so it - dnl needs to know what name is stored there: - [AC_CONFIG_COMMANDS([libtool], - [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], - dnl If the libtool generation code is destined for config.status, - dnl expand the accumulated commands and init code now: - [AC_CONFIG_COMMANDS([libtool], - [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) -])#_LT_CONFIG_COMMANDS - - -# Initialize. -m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], -[ - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -_LT_CONFIG_STATUS_DECLARATIONS -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$[]1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in lt_decl_all_varnames([[ \ -]], lt_decl_quote_varnames); do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[[\\\\\\\`\\"\\\$]]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in lt_decl_all_varnames([[ \ -]], lt_decl_dquote_varnames); do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[[\\\\\\\`\\"\\\$]]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -_LT_OUTPUT_LIBTOOL_INIT -]) - -# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) -# ------------------------------------ -# Generate a child script FILE with all initialization necessary to -# reuse the environment learned by the parent script, and make the -# file executable. If COMMENT is supplied, it is inserted after the -# '#!' sequence but before initialization text begins. After this -# macro, additional text can be appended to FILE to form the body of -# the child script. The macro ends with non-zero status if the -# file could not be fully written (such as if the disk is full). -m4_ifdef([AS_INIT_GENERATED], -[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], -[m4_defun([_LT_GENERATED_FILE_INIT], -[m4_require([AS_PREPARE])]dnl -[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl -[lt_write_fail=0 -cat >$1 <<_ASEOF || lt_write_fail=1 -#! $SHELL -# Generated by $as_me. -$2 -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$1 <<\_ASEOF || lt_write_fail=1 -AS_SHELL_SANITIZE -_AS_PREPARE -exec AS_MESSAGE_FD>&1 -_ASEOF -test 0 = "$lt_write_fail" && chmod +x $1[]dnl -m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT - -# LT_OUTPUT -# --------- -# This macro allows early generation of the libtool script (before -# AC_OUTPUT is called), incase it is used in configure for compilation -# tests. -AC_DEFUN([LT_OUTPUT], -[: ${CONFIG_LT=./config.lt} -AC_MSG_NOTICE([creating $CONFIG_LT]) -_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], -[# Run this file to recreate a libtool stub with the current configuration.]) - -cat >>"$CONFIG_LT" <<\_LTEOF -lt_cl_silent=false -exec AS_MESSAGE_LOG_FD>>config.log -{ - echo - AS_BOX([Running $as_me.]) -} >&AS_MESSAGE_LOG_FD - -lt_cl_help="\ -'$as_me' creates a local libtool stub from the current configuration, -for use in further configure time tests before the real libtool is -generated. - -Usage: $[0] [[OPTIONS]] - - -h, --help print this help, then exit - -V, --version print version number, then exit - -q, --quiet do not print progress messages - -d, --debug don't remove temporary files - -Report bugs to ." - -lt_cl_version="\ -m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl -m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) -configured by $[0], generated by m4_PACKAGE_STRING. - -Copyright (C) 2011 Free Software Foundation, Inc. -This config.lt script is free software; the Free Software Foundation -gives unlimited permision to copy, distribute and modify it." - -while test 0 != $[#] -do - case $[1] in - --version | --v* | -V ) - echo "$lt_cl_version"; exit 0 ;; - --help | --h* | -h ) - echo "$lt_cl_help"; exit 0 ;; - --debug | --d* | -d ) - debug=: ;; - --quiet | --q* | --silent | --s* | -q ) - lt_cl_silent=: ;; - - -*) AC_MSG_ERROR([unrecognized option: $[1] -Try '$[0] --help' for more information.]) ;; - - *) AC_MSG_ERROR([unrecognized argument: $[1] -Try '$[0] --help' for more information.]) ;; - esac - shift -done - -if $lt_cl_silent; then - exec AS_MESSAGE_FD>/dev/null -fi -_LTEOF - -cat >>"$CONFIG_LT" <<_LTEOF -_LT_OUTPUT_LIBTOOL_COMMANDS_INIT -_LTEOF - -cat >>"$CONFIG_LT" <<\_LTEOF -AC_MSG_NOTICE([creating $ofile]) -_LT_OUTPUT_LIBTOOL_COMMANDS -AS_EXIT(0) -_LTEOF -chmod +x "$CONFIG_LT" - -# configure is writing to config.log, but config.lt does its own redirection, -# appending to config.log, which fails on DOS, as config.log is still kept -# open by configure. Here we exec the FD to /dev/null, effectively closing -# config.log, so it can be properly (re)opened and appended to by config.lt. -lt_cl_success=: -test yes = "$silent" && - lt_config_lt_args="$lt_config_lt_args --quiet" -exec AS_MESSAGE_LOG_FD>/dev/null -$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false -exec AS_MESSAGE_LOG_FD>>config.log -$lt_cl_success || AS_EXIT(1) -])# LT_OUTPUT - - -# _LT_CONFIG(TAG) -# --------------- -# If TAG is the built-in tag, create an initial libtool script with a -# default configuration from the untagged config vars. Otherwise add code -# to config.status for appending the configuration named by TAG from the -# matching tagged config vars. -m4_defun([_LT_CONFIG], -[m4_require([_LT_FILEUTILS_DEFAULTS])dnl -_LT_CONFIG_SAVE_COMMANDS([ - m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl - m4_if(_LT_TAG, [C], [ - # See if we are running on zsh, and set the options that allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}"; then - setopt NO_GLOB_SUBST - fi - - cfgfile=${ofile}T - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL -# Generated automatically by $as_me ($PACKAGE) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# NOTE: Changes made to this file will be lost: look at ltmain.sh. - -# Provide generalized library-building support services. -# Written by Gordon Matzigkeit, 1996 - -_LT_COPYING -_LT_LIBTOOL_TAGS - -# Configured defaults for sys_lib_dlsearch_path munging. -: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} - -# ### BEGIN LIBTOOL CONFIG -_LT_LIBTOOL_CONFIG_VARS -_LT_LIBTOOL_TAG_VARS -# ### END LIBTOOL CONFIG - -_LT_EOF - - cat <<'_LT_EOF' >> "$cfgfile" - -# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE - -_LT_PREPARE_MUNGE_PATH_LIST -_LT_PREPARE_CC_BASENAME - -# ### END FUNCTIONS SHARED WITH CONFIGURE - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test set != "${COLLECT_NAMES+set}"; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - _LT_PROG_LTMAIN - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" -], -[cat <<_LT_EOF >> "$ofile" - -dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded -dnl in a comment (ie after a #). -# ### BEGIN LIBTOOL TAG CONFIG: $1 -_LT_LIBTOOL_TAG_VARS(_LT_TAG) -# ### END LIBTOOL TAG CONFIG: $1 -_LT_EOF -])dnl /m4_if -], -[m4_if([$1], [], [ - PACKAGE='$PACKAGE' - VERSION='$VERSION' - RM='$RM' - ofile='$ofile'], []) -])dnl /_LT_CONFIG_SAVE_COMMANDS -])# _LT_CONFIG - - -# LT_SUPPORTED_TAG(TAG) -# --------------------- -# Trace this macro to discover what tags are supported by the libtool -# --tag option, using: -# autoconf --trace 'LT_SUPPORTED_TAG:$1' -AC_DEFUN([LT_SUPPORTED_TAG], []) - - -# C support is built-in for now -m4_define([_LT_LANG_C_enabled], []) -m4_define([_LT_TAGS], []) - - -# LT_LANG(LANG) -# ------------- -# Enable libtool support for the given language if not already enabled. -AC_DEFUN([LT_LANG], -[AC_BEFORE([$0], [LT_OUTPUT])dnl -m4_case([$1], - [C], [_LT_LANG(C)], - [C++], [_LT_LANG(CXX)], - [Go], [_LT_LANG(GO)], - [Java], [_LT_LANG(GCJ)], - [Fortran 77], [_LT_LANG(F77)], - [Fortran], [_LT_LANG(FC)], - [Windows Resource], [_LT_LANG(RC)], - [m4_ifdef([_LT_LANG_]$1[_CONFIG], - [_LT_LANG($1)], - [m4_fatal([$0: unsupported language: "$1"])])])dnl -])# LT_LANG - - -# _LT_LANG(LANGNAME) -# ------------------ -m4_defun([_LT_LANG], -[m4_ifdef([_LT_LANG_]$1[_enabled], [], - [LT_SUPPORTED_TAG([$1])dnl - m4_append([_LT_TAGS], [$1 ])dnl - m4_define([_LT_LANG_]$1[_enabled], [])dnl - _LT_LANG_$1_CONFIG($1)])dnl -])# _LT_LANG - - -m4_ifndef([AC_PROG_GO], [ -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_GO. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ -m4_defun([AC_PROG_GO], -[AC_LANG_PUSH(Go)dnl -AC_ARG_VAR([GOC], [Go compiler command])dnl -AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl -_AC_ARG_VAR_LDFLAGS()dnl -AC_CHECK_TOOL(GOC, gccgo) -if test -z "$GOC"; then - if test -n "$ac_tool_prefix"; then - AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) - fi -fi -if test -z "$GOC"; then - AC_CHECK_PROG(GOC, gccgo, gccgo, false) -fi -])#m4_defun -])#m4_ifndef - - -# _LT_LANG_DEFAULT_CONFIG -# ----------------------- -m4_defun([_LT_LANG_DEFAULT_CONFIG], -[AC_PROVIDE_IFELSE([AC_PROG_CXX], - [LT_LANG(CXX)], - [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) - -AC_PROVIDE_IFELSE([AC_PROG_F77], - [LT_LANG(F77)], - [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) - -AC_PROVIDE_IFELSE([AC_PROG_FC], - [LT_LANG(FC)], - [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) - -dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal -dnl pulling things in needlessly. -AC_PROVIDE_IFELSE([AC_PROG_GCJ], - [LT_LANG(GCJ)], - [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], - [LT_LANG(GCJ)], - [AC_PROVIDE_IFELSE([LT_PROG_GCJ], - [LT_LANG(GCJ)], - [m4_ifdef([AC_PROG_GCJ], - [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) - m4_ifdef([A][M_PROG_GCJ], - [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) - m4_ifdef([LT_PROG_GCJ], - [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) - -AC_PROVIDE_IFELSE([AC_PROG_GO], - [LT_LANG(GO)], - [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) - -AC_PROVIDE_IFELSE([LT_PROG_RC], - [LT_LANG(RC)], - [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) -])# _LT_LANG_DEFAULT_CONFIG - -# Obsolete macros: -AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) -AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) -AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) -AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) -AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBTOOL_CXX], []) -dnl AC_DEFUN([AC_LIBTOOL_F77], []) -dnl AC_DEFUN([AC_LIBTOOL_FC], []) -dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) -dnl AC_DEFUN([AC_LIBTOOL_RC], []) - - -# _LT_TAG_COMPILER -# ---------------- -m4_defun([_LT_TAG_COMPILER], -[AC_REQUIRE([AC_PROG_CC])dnl - -_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl -_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl -_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl -_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC -])# _LT_TAG_COMPILER - - -# _LT_COMPILER_BOILERPLATE -# ------------------------ -# Check for compiler boilerplate output or warnings with -# the simple compiler test code. -m4_defun([_LT_COMPILER_BOILERPLATE], -[m4_require([_LT_DECL_SED])dnl -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* -])# _LT_COMPILER_BOILERPLATE - - -# _LT_LINKER_BOILERPLATE -# ---------------------- -# Check for linker boilerplate output or warnings with -# the simple link test code. -m4_defun([_LT_LINKER_BOILERPLATE], -[m4_require([_LT_DECL_SED])dnl -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* -])# _LT_LINKER_BOILERPLATE - -# _LT_REQUIRED_DARWIN_CHECKS -# ------------------------- -m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ - case $host_os in - rhapsody* | darwin*) - AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) - AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) - AC_CHECK_TOOL([LIPO], [lipo], [:]) - AC_CHECK_TOOL([OTOOL], [otool], [:]) - AC_CHECK_TOOL([OTOOL64], [otool64], [:]) - _LT_DECL([], [DSYMUTIL], [1], - [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) - _LT_DECL([], [NMEDIT], [1], - [Tool to change global to local symbols on Mac OS X]) - _LT_DECL([], [LIPO], [1], - [Tool to manipulate fat objects and archives on Mac OS X]) - _LT_DECL([], [OTOOL], [1], - [ldd/readelf like tool for Mach-O binaries on Mac OS X]) - _LT_DECL([], [OTOOL64], [1], - [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) - - AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], - [lt_cv_apple_cc_single_mod=no - if test -z "$LT_MULTI_MODULE"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&AS_MESSAGE_LOG_FD - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test 0 = "$_lt_result"; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&AS_MESSAGE_LOG_FD - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi]) - - AC_CACHE_CHECK([for -exported_symbols_list linker flag], - [lt_cv_ld_exported_symbols_list], - [lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], - [lt_cv_ld_exported_symbols_list=yes], - [lt_cv_ld_exported_symbols_list=no]) - LDFLAGS=$save_LDFLAGS - ]) - - AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], - [lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD - echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD - $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD - echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD - $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD - cat > conftest.c << _LT_EOF -int main() { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&AS_MESSAGE_LOG_FD - elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&AS_MESSAGE_LOG_FD - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - ]) - case $host_os in - rhapsody* | darwin1.[[012]]) - _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) # darwin 5.x on - # if running on 10.5 or later, the deployment target defaults - # to the OS version, if on x86, and 10.4, the deployment - # target defaults to 10.4. Don't you love it? - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; - 10.[[012]][[,.]]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - 10.*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; - esac - ;; - esac - if test yes = "$lt_cv_apple_cc_single_mod"; then - _lt_dar_single_mod='$single_module' - fi - if test yes = "$lt_cv_ld_exported_symbols_list"; then - _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' - fi - if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac -]) - - -# _LT_DARWIN_LINKER_FEATURES([TAG]) -# --------------------------------- -# Checks for linker and compiler features on darwin -m4_defun([_LT_DARWIN_LINKER_FEATURES], -[ - m4_require([_LT_REQUIRED_DARWIN_CHECKS]) - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_automatic, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - if test yes = "$lt_cv_ld_force_load"; then - _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], - [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) - else - _LT_TAGVAR(whole_archive_flag_spec, $1)='' - fi - _LT_TAGVAR(link_all_deplibs, $1)=yes - _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined - case $cc_basename in - ifort*|nagfor*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test yes = "$_lt_dar_can_shared"; then - output_verbose_link_cmd=func_echo_all - _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" - _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" - m4_if([$1], [CXX], -[ if test yes != "$lt_cv_apple_cc_single_mod"; then - _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" - _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" - fi -],[]) - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi -]) - -# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) -# ---------------------------------- -# Links a minimal program and checks the executable -# for the system default hardcoded library path. In most cases, -# this is /usr/lib:/lib, but when the MPI compilers are used -# the location of the communication and MPI libs are included too. -# If we don't find anything, use the default library path according -# to the aix ld manual. -# Store the results from the different compilers for each TAGNAME. -# Allow to override them for all tags through lt_cv_aix_libpath. -m4_defun([_LT_SYS_MODULE_PATH_AIX], -[m4_require([_LT_DECL_SED])dnl -if test set = "${lt_cv_aix_libpath+set}"; then - aix_libpath=$lt_cv_aix_libpath -else - AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], - [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ - lt_aix_libpath_sed='[ - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }]' - _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then - _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi],[]) - if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then - _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib - fi - ]) - aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) -fi -])# _LT_SYS_MODULE_PATH_AIX - - -# _LT_SHELL_INIT(ARG) -# ------------------- -m4_define([_LT_SHELL_INIT], -[m4_divert_text([M4SH-INIT], [$1 -])])# _LT_SHELL_INIT - - - -# _LT_PROG_ECHO_BACKSLASH -# ----------------------- -# Find how we can fake an echo command that does not interpret backslash. -# In particular, with Autoconf 2.60 or later we add some code to the start -# of the generated configure script that will find a shell with a builtin -# printf (that we can use as an echo command). -m4_defun([_LT_PROG_ECHO_BACKSLASH], -[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -AC_MSG_CHECKING([how to print strings]) -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$[]1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "$*" -} - -case $ECHO in - printf*) AC_MSG_RESULT([printf]) ;; - print*) AC_MSG_RESULT([print -r]) ;; - *) AC_MSG_RESULT([cat]) ;; -esac - -m4_ifdef([_AS_DETECT_SUGGESTED], -[_AS_DETECT_SUGGESTED([ - test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO - ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test "X`printf %s $ECHO`" = "X$ECHO" \ - || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) - -_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) -_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) -])# _LT_PROG_ECHO_BACKSLASH - - -# _LT_WITH_SYSROOT -# ---------------- -AC_DEFUN([_LT_WITH_SYSROOT], -[AC_MSG_CHECKING([for sysroot]) -AC_ARG_WITH([sysroot], -[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], - [Search for dependent libraries within DIR (or the compiler's sysroot - if not specified).])], -[], [with_sysroot=no]) - -dnl lt_sysroot will always be passed unquoted. We quote it here -dnl in case the user passed a directory name. -lt_sysroot= -case $with_sysroot in #( - yes) - if test yes = "$GCC"; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - AC_MSG_RESULT([$with_sysroot]) - AC_MSG_ERROR([The sysroot must be an absolute path.]) - ;; -esac - - AC_MSG_RESULT([${lt_sysroot:-no}]) -_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl -[dependent libraries, and where our libraries should be installed.])]) - -# _LT_ENABLE_LOCK -# --------------- -m4_defun([_LT_ENABLE_LOCK], -[AC_ARG_ENABLE([libtool-lock], - [AS_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) -test no = "$enable_libtool_lock" || enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out what ABI is being produced by ac_compile, and set mode - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE=32 - ;; - *ELF-64*) - HPUX_IA64_MODE=64 - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - if test yes = "$lt_cv_prog_gnu_ld"; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -mips64*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - emul=elf - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - emul="${emul}32" - ;; - *64-bit*) - emul="${emul}64" - ;; - esac - case `/usr/bin/file conftest.$ac_objext` in - *MSB*) - emul="${emul}btsmip" - ;; - *LSB*) - emul="${emul}ltsmip" - ;; - esac - case `/usr/bin/file conftest.$ac_objext` in - *N32*) - emul="${emul}n32" - ;; - esac - LD="${LD-ld} -m $emul" - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. Note that the listed cases only cover the - # situations where additional linker options are needed (such as when - # doing 32-bit compilation for a host where ld defaults to 64-bit, or - # vice versa); the common cases where no linker options are needed do - # not appear in the list. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - case `/usr/bin/file conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -belf" - AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, - [AC_LANG_PUSH(C) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) - AC_LANG_POP]) - if test yes != "$lt_cv_cc_needs_belf"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS=$SAVE_CFLAGS - fi - ;; -*-*solaris*) - # Find out what ABI is being produced by ac_compile, and set linker - # options accordingly. - echo 'int i;' > conftest.$ac_ext - if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*|x86_64-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD=${LD-ld}_sol2 - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks=$enable_libtool_lock -])# _LT_ENABLE_LOCK - - -# _LT_PROG_AR -# ----------- -m4_defun([_LT_PROG_AR], -[AC_CHECK_TOOLS(AR, [ar], false) -: ${AR=ar} -: ${AR_FLAGS=cru} -_LT_DECL([], [AR], [1], [The archiver]) -_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) - -AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], - [lt_cv_ar_at_file=no - AC_COMPILE_IFELSE([AC_LANG_PROGRAM], - [echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' - AC_TRY_EVAL([lt_ar_try]) - if test 0 -eq "$ac_status"; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - AC_TRY_EVAL([lt_ar_try]) - if test 0 -ne "$ac_status"; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - ]) - ]) - -if test no = "$lt_cv_ar_at_file"; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi -_LT_DECL([], [archiver_list_spec], [1], - [How to feed a file listing to the archiver]) -])# _LT_PROG_AR - - -# _LT_CMD_OLD_ARCHIVE -# ------------------- -m4_defun([_LT_CMD_OLD_ARCHIVE], -[_LT_PROG_AR - -AC_CHECK_TOOL(STRIP, strip, :) -test -z "$STRIP" && STRIP=: -_LT_DECL([], [STRIP], [1], [A symbol stripping program]) - -AC_CHECK_TOOL(RANLIB, ranlib, :) -test -z "$RANLIB" && RANLIB=: -_LT_DECL([], [RANLIB], [1], - [Commands used to install an old-style archive]) - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - bitrig* | openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac -_LT_DECL([], [old_postinstall_cmds], [2]) -_LT_DECL([], [old_postuninstall_cmds], [2]) -_LT_TAGDECL([], [old_archive_cmds], [2], - [Commands used to build an old-style archive]) -_LT_DECL([], [lock_old_archive_extraction], [0], - [Whether to use a lock for old archive extraction]) -])# _LT_CMD_OLD_ARCHIVE - - -# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) -# ---------------------------------------------------------------- -# Check whether the given compiler option works -AC_DEFUN([_LT_COMPILER_OPTION], -[m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - fi - $RM conftest* -]) - -if test yes = "[$]$2"; then - m4_if([$5], , :, [$5]) -else - m4_if([$6], , :, [$6]) -fi -])# _LT_COMPILER_OPTION - -# Old name: -AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) - - -# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [ACTION-SUCCESS], [ACTION-FAILURE]) -# ---------------------------------------------------- -# Check whether the given linker option works -AC_DEFUN([_LT_LINKER_OPTION], -[m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_SED])dnl -AC_CACHE_CHECK([$1], [$2], - [$2=no - save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS $3" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&AS_MESSAGE_LOG_FD - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - $2=yes - fi - else - $2=yes - fi - fi - $RM -r conftest* - LDFLAGS=$save_LDFLAGS -]) - -if test yes = "[$]$2"; then - m4_if([$4], , :, [$4]) -else - m4_if([$5], , :, [$5]) -fi -])# _LT_LINKER_OPTION - -# Old name: -AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) - - -# LT_CMD_MAX_LEN -#--------------- -AC_DEFUN([LT_CMD_MAX_LEN], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -# find the maximum length of command line arguments -AC_MSG_CHECKING([the maximum length of command line arguments]) -AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl - i=0 - teststring=ABCD - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test X`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test 17 != "$i" # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac -]) -if test -n "$lt_cv_sys_max_cmd_len"; then - AC_MSG_RESULT($lt_cv_sys_max_cmd_len) -else - AC_MSG_RESULT(none) -fi -max_cmd_len=$lt_cv_sys_max_cmd_len -_LT_DECL([], [max_cmd_len], [0], - [What is the maximum length of a command?]) -])# LT_CMD_MAX_LEN - -# Old name: -AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) - - -# _LT_HEADER_DLFCN -# ---------------- -m4_defun([_LT_HEADER_DLFCN], -[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl -])# _LT_HEADER_DLFCN - - -# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, -# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) -# ---------------------------------------------------------------- -m4_defun([_LT_TRY_DLOPEN_SELF], -[m4_require([_LT_HEADER_DLFCN])dnl -if test yes = "$cross_compiling"; then : - [$4] -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -[#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisibility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -}] -_LT_EOF - if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then - (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) $1 ;; - x$lt_dlneed_uscore) $2 ;; - x$lt_dlunknown|x*) $3 ;; - esac - else : - # compilation failed - $3 - fi -fi -rm -fr conftest* -])# _LT_TRY_DLOPEN_SELF - - -# LT_SYS_DLOPEN_SELF -# ------------------ -AC_DEFUN([LT_SYS_DLOPEN_SELF], -[m4_require([_LT_HEADER_DLFCN])dnl -if test yes != "$enable_dlopen"; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen=load_add_on - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32* | cegcc*) - lt_cv_dlopen=LoadLibrary - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ - lt_cv_dlopen=dyld - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ]) - ;; - - tpf*) - # Don't try to run any link tests for TPF. We know it's impossible - # because TPF is a cross-compiler, and we know how we open DSOs. - lt_cv_dlopen=dlopen - lt_cv_dlopen_libs= - lt_cv_dlopen_self=no - ;; - - *) - AC_CHECK_FUNC([shl_load], - [lt_cv_dlopen=shl_load], - [AC_CHECK_LIB([dld], [shl_load], - [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], - [AC_CHECK_FUNC([dlopen], - [lt_cv_dlopen=dlopen], - [AC_CHECK_LIB([dl], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], - [AC_CHECK_LIB([svld], [dlopen], - [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], - [AC_CHECK_LIB([dld], [dld_link], - [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) - ]) - ]) - ]) - ]) - ]) - ;; - esac - - if test no = "$lt_cv_dlopen"; then - enable_dlopen=no - else - enable_dlopen=yes - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS=$CPPFLAGS - test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS=$LDFLAGS - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS=$LIBS - LIBS="$lt_cv_dlopen_libs $LIBS" - - AC_CACHE_CHECK([whether a program can dlopen itself], - lt_cv_dlopen_self, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, - lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) - ]) - - if test yes = "$lt_cv_dlopen_self"; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl - _LT_TRY_DLOPEN_SELF( - lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, - lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) - ]) - fi - - CPPFLAGS=$save_CPPFLAGS - LDFLAGS=$save_LDFLAGS - LIBS=$save_LIBS - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi -_LT_DECL([dlopen_support], [enable_dlopen], [0], - [Whether dlopen is supported]) -_LT_DECL([dlopen_self], [enable_dlopen_self], [0], - [Whether dlopen of programs is supported]) -_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], - [Whether dlopen of statically linked programs is supported]) -])# LT_SYS_DLOPEN_SELF - -# Old name: -AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) - - -# _LT_COMPILER_C_O([TAGNAME]) -# --------------------------- -# Check to see if options -c and -o are simultaneously supported by compiler. -# This macro does not hard code the compiler like AC_PROG_CC_C_O. -m4_defun([_LT_COMPILER_C_O], -[m4_require([_LT_DECL_SED])dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_TAG_COMPILER])dnl -AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], - [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], - [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes - fi - fi - chmod u+w . 2>&AS_MESSAGE_LOG_FD - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* -]) -_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], - [Does compiler simultaneously support -c and -o options?]) -])# _LT_COMPILER_C_O - - -# _LT_COMPILER_FILE_LOCKS([TAGNAME]) -# ---------------------------------- -# Check to see if we can do hard links to lock some files if needed -m4_defun([_LT_COMPILER_FILE_LOCKS], -[m4_require([_LT_ENABLE_LOCK])dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl -_LT_COMPILER_C_O([$1]) - -hard_links=nottested -if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then - # do not overwrite the value of need_locks provided by the user - AC_MSG_CHECKING([if we can lock with hard links]) - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - AC_MSG_RESULT([$hard_links]) - if test no = "$hard_links"; then - AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) - need_locks=warn - fi -else - need_locks=no -fi -_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) -])# _LT_COMPILER_FILE_LOCKS - - -# _LT_CHECK_OBJDIR -# ---------------- -m4_defun([_LT_CHECK_OBJDIR], -[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], -[rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null]) -objdir=$lt_cv_objdir -_LT_DECL([], [objdir], [0], - [The name of the directory that contains temporary libtool files])dnl -m4_pattern_allow([LT_OBJDIR])dnl -AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", - [Define to the sub-directory where libtool stores uninstalled libraries.]) -])# _LT_CHECK_OBJDIR - - -# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) -# -------------------------------------- -# Check hardcoding attributes. -m4_defun([_LT_LINKER_HARDCODE_LIBPATH], -[AC_MSG_CHECKING([how to hardcode library paths into programs]) -_LT_TAGVAR(hardcode_action, $1)= -if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || - test -n "$_LT_TAGVAR(runpath_var, $1)" || - test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then - - # We can hardcode non-existent directories. - if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && - test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then - # Linking always hardcodes the temporary library directory. - _LT_TAGVAR(hardcode_action, $1)=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - _LT_TAGVAR(hardcode_action, $1)=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - _LT_TAGVAR(hardcode_action, $1)=unsupported -fi -AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) - -if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || - test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then - # Fast installation is not supported - enable_fast_install=no -elif test yes = "$shlibpath_overrides_runpath" || - test no = "$enable_shared"; then - # Fast installation is not necessary - enable_fast_install=needless -fi -_LT_TAGDECL([], [hardcode_action], [0], - [How to hardcode a shared library path into an executable]) -])# _LT_LINKER_HARDCODE_LIBPATH - - -# _LT_CMD_STRIPLIB -# ---------------- -m4_defun([_LT_CMD_STRIPLIB], -[m4_require([_LT_DECL_EGREP]) -striplib= -old_striplib= -AC_MSG_CHECKING([whether stripping libraries is possible]) -if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - AC_MSG_RESULT([yes]) -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP"; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - ;; - *) - AC_MSG_RESULT([no]) - ;; - esac -fi -_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) -_LT_DECL([], [striplib], [1]) -])# _LT_CMD_STRIPLIB - - -# _LT_PREPARE_MUNGE_PATH_LIST -# --------------------------- -# Make sure func_munge_path_list() is defined correctly. -m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], -[[# func_munge_path_list VARIABLE PATH -# ----------------------------------- -# VARIABLE is name of variable containing _space_ separated list of -# directories to be munged by the contents of PATH, which is string -# having a format: -# "DIR[:DIR]:" -# string "DIR[ DIR]" will be prepended to VARIABLE -# ":DIR[:DIR]" -# string "DIR[ DIR]" will be appended to VARIABLE -# "DIRP[:DIRP]::[DIRA:]DIRA" -# string "DIRP[ DIRP]" will be prepended to VARIABLE and string -# "DIRA[ DIRA]" will be appended to VARIABLE -# "DIR[:DIR]" -# VARIABLE will be replaced by "DIR[ DIR]" -func_munge_path_list () -{ - case x@S|@2 in - x) - ;; - *:) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" - ;; - x:*) - eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - *::*) - eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" - eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" - ;; - *) - eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" - ;; - esac -} -]])# _LT_PREPARE_PATH_LIST - - -# _LT_SYS_DYNAMIC_LINKER([TAG]) -# ----------------------------- -# PORTME Fill in your ld.so characteristics -m4_defun([_LT_SYS_DYNAMIC_LINKER], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_OBJDUMP])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_CHECK_SHELL_FEATURES])dnl -m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl -AC_MSG_CHECKING([dynamic linker characteristics]) -m4_if([$1], - [], [ -if test yes = "$GCC"; then - case $host_os in - darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; - *) lt_awk_arg='/^libraries:/' ;; - esac - case $host_os in - mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; - *) lt_sed_strip_eq='s|=/|/|g' ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary... - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - # ...but if some path component already ends with the multilib dir we assume - # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). - case "$lt_multi_os_dir; $lt_search_path_spec " in - "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) - lt_multi_os_dir= - ;; - esac - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" - elif test -n "$lt_multi_os_dir"; then - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS = " "; FS = "/|\n";} { - lt_foo = ""; - lt_count = 0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo = "/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[[lt_foo]]++; } - if (lt_freq[[lt_foo]] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi]) -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=.so -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -AC_ARG_VAR([LT_SYS_LIBRARY_PATH], -[User-defined run-time library search path.]) - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='$libname$release$shared_ext$major' - ;; - -aix[[4-9]]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test ia64 = "$host_cpu"; then - # AIX 5 supports IA64 - library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line '#! .'. This would cause the generated library to - # depend on '.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[[01]] | aix4.[[01]].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # Using Import Files as archive members, it is possible to support - # filename-based versioning of shared library archives on AIX. While - # this would work for both with and without runtime linking, it will - # prevent static linking of such archives. So we do filename-based - # shared library versioning with .so extension only, which is used - # when both runtime linking and shared linking is enabled. - # Unfortunately, runtime linking may impact performance, so we do - # not want this to be the default eventually. Also, we use the - # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. - # To allow for filename-based versioning support, we need to create - # libNAME.so.V as an archive file, containing: - # *) an Import File, referring to the versioned filename of the - # archive as well as the shared archive member, telling the - # bitwidth (32 or 64) of that shared object, and providing the - # list of exported symbols of that shared object, eventually - # decorated with the 'weak' keyword - # *) the shared object with the F_LOADONLY flag set, to really avoid - # it being seen by the linker. - # At run time we better use the real file rather than another symlink, - # but for link time we create the symlink libNAME.so -> libNAME.so.V - - case $with_aix_soname,$aix_use_runtimelinking in - # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - aix,yes) # traditional libtool - dynamic_linker='AIX unversionable lib.so' - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - aix,no) # traditional AIX only - dynamic_linker='AIX lib.a[(]lib.so.V[)]' - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - ;; - svr4,*) # full svr4 only - dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,yes) # both, prefer svr4 - dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" - library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' - # unpreferred sharedlib libNAME.a needs extra handling - postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' - postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' - # We do not specify a path in Import Files, so LIBPATH fires. - shlibpath_overrides_runpath=yes - ;; - *,no) # both, prefer aix - dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" - library_names_spec='$libname$release.a $libname.a' - soname_spec='$libname$release$shared_ext$major' - # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling - postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' - postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' - ;; - esac - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='$libname$shared_ext' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[[45]]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' -m4_if([$1], [],[ - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' - library_names_spec='$libname.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec=$LIB - if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC wrapper - library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' - soname_spec='$libname$release$major$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' -m4_if([$1], [],[ - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[[23]].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[[01]]* | freebsdelf3.[[01]]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ - freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=no - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - if test 32 = "$HPUX_IA64_MODE"; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - sys_lib_dlsearch_path_spec=/usr/lib/hpux32 - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - sys_lib_dlsearch_path_spec=/usr/lib/hpux64 - fi - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[[3-9]]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test yes = "$lt_cv_prog_gnu_ld"; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" - sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -linux*android*) - version_type=none # Android doesn't support versioned libraries. - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext' - soname_spec='$libname$release$shared_ext' - finish_cmds= - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - dynamic_linker='Android linker' - # Don't embed -rpath directories since the linker doesn't support them. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], - [lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ - LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" - AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], - [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], - [lt_cv_shlibpath_overrides_runpath=yes])]) - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - ]) - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Ideally, we could use ldconfig to report *all* directores which are - # searched for libraries, however this is still not possible. Aside from not - # being certain /sbin/ldconfig is available, command - # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, - # even though it is searched at run-time. Try to do the best guess by - # appending ld.so.conf contents (and includes) to the search path. - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd* | bitrig*) - version_type=sunos - sys_lib_dlsearch_path_spec=/usr/lib - need_lib_prefix=no - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - need_version=no - else - need_version=yes - fi - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -os2*) - libname_spec='$name' - version_type=windows - shrext_cmds=.dll - need_version=no - need_lib_prefix=no - # OS/2 can only load a DLL with a base name of 8 characters or less. - soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; - v=$($ECHO $release$versuffix | tr -d .-); - n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); - $ECHO $n$v`$shared_ext' - library_names_spec='${libname}_dll.$libext' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=BEGINLIBPATH - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='$libname$release$shared_ext$major' - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test yes = "$with_gnu_ld"; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec; then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' - soname_spec='$libname$shared_ext.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=sco - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test yes = "$with_gnu_ld"; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' - soname_spec='$libname$release$shared_ext$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -AC_MSG_RESULT([$dynamic_linker]) -test no = "$dynamic_linker" && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test yes = "$GCC"; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then - sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec -fi - -if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then - sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec -fi - -# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... -configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec - -# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code -func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" - -# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool -configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH - -_LT_DECL([], [variables_saved_for_relink], [1], - [Variables whose values should be saved in libtool wrapper scripts and - restored at link time]) -_LT_DECL([], [need_lib_prefix], [0], - [Do we need the "lib" prefix for modules?]) -_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) -_LT_DECL([], [version_type], [0], [Library versioning type]) -_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) -_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) -_LT_DECL([], [shlibpath_overrides_runpath], [0], - [Is shlibpath searched before the hard-coded library search path?]) -_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) -_LT_DECL([], [library_names_spec], [1], - [[List of archive names. First name is the real one, the rest are links. - The last name is the one that the linker finds with -lNAME]]) -_LT_DECL([], [soname_spec], [1], - [[The coded name of the library, if different from the real name]]) -_LT_DECL([], [install_override_mode], [1], - [Permission mode override for installation of shared libraries]) -_LT_DECL([], [postinstall_cmds], [2], - [Command to use after installation of a shared archive]) -_LT_DECL([], [postuninstall_cmds], [2], - [Command to use after uninstallation of a shared archive]) -_LT_DECL([], [finish_cmds], [2], - [Commands used to finish a libtool library installation in a directory]) -_LT_DECL([], [finish_eval], [1], - [[As "finish_cmds", except a single script fragment to be evaled but - not shown]]) -_LT_DECL([], [hardcode_into_libs], [0], - [Whether we should hardcode library paths into libraries]) -_LT_DECL([], [sys_lib_search_path_spec], [2], - [Compile-time system search path for libraries]) -_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], - [Detected run-time system search path for libraries]) -_LT_DECL([], [configure_time_lt_sys_library_path], [2], - [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) -])# _LT_SYS_DYNAMIC_LINKER - - -# _LT_PATH_TOOL_PREFIX(TOOL) -# -------------------------- -# find a file program that can recognize shared library -AC_DEFUN([_LT_PATH_TOOL_PREFIX], -[m4_require([_LT_DECL_EGREP])dnl -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, -[case $MAGIC_CMD in -[[\\/*] | ?:[\\/]*]) - lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD=$MAGIC_CMD - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR -dnl $ac_dummy forces splitting on constant user-supplied paths. -dnl POSIX.2 word splitting is done only on the output of word expansions, -dnl not every word. This closes a longstanding sh security hole. - ac_dummy="m4_if([$2], , $PATH, [$2])" - for ac_dir in $ac_dummy; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$1"; then - lt_cv_path_MAGIC_CMD=$ac_dir/"$1" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD=$lt_cv_path_MAGIC_CMD - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS=$lt_save_ifs - MAGIC_CMD=$lt_save_MAGIC_CMD - ;; -esac]) -MAGIC_CMD=$lt_cv_path_MAGIC_CMD -if test -n "$MAGIC_CMD"; then - AC_MSG_RESULT($MAGIC_CMD) -else - AC_MSG_RESULT(no) -fi -_LT_DECL([], [MAGIC_CMD], [0], - [Used to examine libraries when file_magic_cmd begins with "file"])dnl -])# _LT_PATH_TOOL_PREFIX - -# Old name: -AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) - - -# _LT_PATH_MAGIC -# -------------- -# find a file program that can recognize a shared library -m4_defun([_LT_PATH_MAGIC], -[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) - else - MAGIC_CMD=: - fi -fi -])# _LT_PATH_MAGIC - - -# LT_PATH_LD -# ---------- -# find the pathname to the GNU or non-GNU linker -AC_DEFUN([LT_PATH_LD], -[AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_PROG_ECHO_BACKSLASH])dnl - -AC_ARG_WITH([gnu-ld], - [AS_HELP_STRING([--with-gnu-ld], - [assume the C compiler uses GNU ld @<:@default=no@:>@])], - [test no = "$withval" || with_gnu_ld=yes], - [with_gnu_ld=no])dnl - -ac_prog=ld -if test yes = "$GCC"; then - # Check if gcc -print-prog-name=ld gives a path. - AC_MSG_CHECKING([for ld used by $CC]) - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return, which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [[\\/]]* | ?:[[\\/]]*) - re_direlt='/[[^/]][[^/]]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD=$ac_prog - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test yes = "$with_gnu_ld"; then - AC_MSG_CHECKING([for GNU ld]) -else - AC_MSG_CHECKING([for non-GNU ld]) -fi -AC_CACHE_VAL(lt_cv_path_LD, -[if test -z "$LD"; then - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD=$ac_dir/$ac_prog - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i -cat conftest.i conftest.i >conftest2.i -: ${lt_DD:=$DD} -AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], -[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: -fi]) -rm -f conftest.i conftest2.i conftest.out]) -])# _LT_PATH_DD - - -# _LT_CMD_TRUNCATE -# ---------------- -# find command to truncate a binary pipe -m4_defun([_LT_CMD_TRUNCATE], -[m4_require([_LT_PATH_DD]) -AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], -[printf 0123456789abcdef0123456789abcdef >conftest.i -cat conftest.i conftest.i >conftest2.i -lt_cv_truncate_bin= -if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then - cmp -s conftest.i conftest.out \ - && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" -fi -rm -f conftest.i conftest2.i conftest.out -test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) -_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], - [Command to truncate a binary pipe]) -])# _LT_CMD_TRUNCATE - - -# _LT_CHECK_MAGIC_METHOD -# ---------------------- -# how to check for library dependencies -# -- PORTME fill in with the dynamic library characteristics -m4_defun([_LT_CHECK_MAGIC_METHOD], -[m4_require([_LT_DECL_EGREP]) -m4_require([_LT_DECL_OBJDUMP]) -AC_CACHE_CHECK([how to recognize dependent libraries], -lt_cv_deplibs_check_method, -[lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# 'unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [[regex]]' -- check by looking for files in library path -# that responds to the $file_magic_cmd with a given extended regex. -# If you have 'file' or equivalent on your system and you're not sure -# whether 'pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[[4-9]]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[[45]]*) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[[3-9]]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd* | bitrig*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -os2*) - lt_cv_deplibs_check_method=pass_all - ;; -esac -]) - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - -_LT_DECL([], [deplibs_check_method], [1], - [Method to check whether dependent libraries are shared objects]) -_LT_DECL([], [file_magic_cmd], [1], - [Command to use when deplibs_check_method = "file_magic"]) -_LT_DECL([], [file_magic_glob], [1], - [How to find potential files when deplibs_check_method = "file_magic"]) -_LT_DECL([], [want_nocaseglob], [1], - [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) -])# _LT_CHECK_MAGIC_METHOD - - -# LT_PATH_NM -# ---------- -# find the pathname to a BSD- or MS-compatible name lister -AC_DEFUN([LT_PATH_NM], -[AC_REQUIRE([AC_PROG_CC])dnl -AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, -[if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM=$NM -else - lt_nm_to_check=${ac_tool_prefix}nm - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS=$lt_save_ifs - test -z "$ac_dir" && ac_dir=. - tmp_nm=$ac_dir/$lt_tmp_nm - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the 'sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty - case $build_os in - mingw*) lt_bad_file=conftest.nm/nofile ;; - *) lt_bad_file=/dev/null ;; - esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in - *$lt_bad_file* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break 2 - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break 2 - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS=$lt_save_ifs - done - : ${lt_cv_path_NM=no} -fi]) -if test no != "$lt_cv_path_NM"; then - NM=$lt_cv_path_NM -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols -headers" - ;; - *) - DUMPBIN=: - ;; - esac - fi - AC_SUBST([DUMPBIN]) - if test : != "$DUMPBIN"; then - NM=$DUMPBIN - fi -fi -test -z "$NM" && NM=nm -AC_SUBST([NM]) -_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl - -AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], - [lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) - cat conftest.out >&AS_MESSAGE_LOG_FD - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest*]) -])# LT_PATH_NM - -# Old names: -AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) -AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AM_PROG_NM], []) -dnl AC_DEFUN([AC_PROG_NM], []) - -# _LT_CHECK_SHAREDLIB_FROM_LINKLIB -# -------------------------------- -# how to determine the name of the shared library -# associated with a specific link library. -# -- PORTME fill in with the dynamic library characteristics -m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], -[m4_require([_LT_DECL_EGREP]) -m4_require([_LT_DECL_OBJDUMP]) -m4_require([_LT_DECL_DLLTOOL]) -AC_CACHE_CHECK([how to associate runtime and link libraries], -lt_cv_sharedlib_from_linklib_cmd, -[lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh; - # decide which one to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd=$ECHO - ;; -esac -]) -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - -_LT_DECL([], [sharedlib_from_linklib_cmd], [1], - [Command to associate shared and link libraries]) -])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB - - -# _LT_PATH_MANIFEST_TOOL -# ---------------------- -# locate the manifest tool -m4_defun([_LT_PATH_MANIFEST_TOOL], -[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], - [lt_cv_path_mainfest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&AS_MESSAGE_LOG_FD - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes - fi - rm -f conftest*]) -if test yes != "$lt_cv_path_mainfest_tool"; then - MANIFEST_TOOL=: -fi -_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl -])# _LT_PATH_MANIFEST_TOOL - - -# _LT_DLL_DEF_P([FILE]) -# --------------------- -# True iff FILE is a Windows DLL '.def' file. -# Keep in sync with func_dll_def_p in the libtool script -AC_DEFUN([_LT_DLL_DEF_P], -[dnl - test DEF = "`$SED -n dnl - -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace - -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments - -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl - -e q dnl Only consider the first "real" line - $1`" dnl -])# _LT_DLL_DEF_P - - -# LT_LIB_M -# -------- -# check for math library -AC_DEFUN([LT_LIB_M], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -LIBM= -case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) - # These system don't have libm, or don't need it - ;; -*-ncr-sysv4.3*) - AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) - AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") - ;; -*) - AC_CHECK_LIB(m, cos, LIBM=-lm) - ;; -esac -AC_SUBST([LIBM]) -])# LT_LIB_M - -# Old name: -AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([AC_CHECK_LIBM], []) - - -# _LT_COMPILER_NO_RTTI([TAGNAME]) -# ------------------------------- -m4_defun([_LT_COMPILER_NO_RTTI], -[m4_require([_LT_TAG_COMPILER])dnl - -_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= - -if test yes = "$GCC"; then - case $cc_basename in - nvcc*) - _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; - *) - _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; - esac - - _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], - lt_cv_prog_compiler_rtti_exceptions, - [-fno-rtti -fno-exceptions], [], - [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) -fi -_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], - [Compiler flag to turn off builtin functions]) -])# _LT_COMPILER_NO_RTTI - - -# _LT_CMD_GLOBAL_SYMBOLS -# ---------------------- -m4_defun([_LT_CMD_GLOBAL_SYMBOLS], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([LT_PATH_NM])dnl -AC_REQUIRE([LT_PATH_LD])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_TAG_COMPILER])dnl - -# Check for command to grab the raw symbol name followed by C symbol from nm. -AC_MSG_CHECKING([command to parse $NM output from $compiler object]) -AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], -[ -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[[BCDEGRST]]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[[BCDT]]' - ;; -cygwin* | mingw* | pw32* | cegcc*) - symcode='[[ABCDGISTW]]' - ;; -hpux*) - if test ia64 = "$host_cpu"; then - symcode='[[ABCDEGRST]]' - fi - ;; -irix* | nonstopux*) - symcode='[[BCDEGRST]]' - ;; -osf*) - symcode='[[BCDEGQRST]]' - ;; -solaris*) - symcode='[[BDRT]]' - ;; -sco3.2v5*) - symcode='[[DT]]' - ;; -sysv4.2uw2*) - symcode='[[DT]]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[[ABDT]]' - ;; -sysv4) - symcode='[[DFNSTU]]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[[ABCDGIRSTW]]' ;; -esac - -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" - # Adjust the below global symbol transforms to fixup imported variables. - lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" - lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" - lt_c_name_lib_hook="\ - -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ - -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" -else - # Disable hooks by default. - lt_cv_sys_global_symbol_to_import= - lt_cdecl_hook= - lt_c_name_hook= - lt_c_name_lib_hook= -fi - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n"\ -$lt_cdecl_hook\ -" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ -$lt_c_name_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" - -# Transform an extracted symbol line into symbol name with lib prefix and -# symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ -$lt_c_name_lib_hook\ -" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ -" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ -" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function, - # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK ['"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ -" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ -" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ -" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ -" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx]" - else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE -/* DATA imports from DLLs on WIN32 can't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT@&t@_DLSYM_CONST -#elif defined __osf__ -/* This system does not cope well with relocations in const data. */ -# define LT@&t@_DLSYM_CONST -#else -# define LT@&t@_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT@&t@_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[[]] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS=conftstm.$ac_objext - CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" - if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD - fi - else - echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test yes = "$pipe_works"; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done -]) -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - AC_MSG_RESULT(failed) -else - AC_MSG_RESULT(ok) -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - -_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], - [Take the output of nm and produce a listing of raw symbols and C names]) -_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], - [Transform the output of nm in a proper C declaration]) -_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], - [Transform the output of nm into a list of symbols to manually relocate]) -_LT_DECL([global_symbol_to_c_name_address], - [lt_cv_sys_global_symbol_to_c_name_address], [1], - [Transform the output of nm in a C name address pair]) -_LT_DECL([global_symbol_to_c_name_address_lib_prefix], - [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], - [Transform the output of nm in a C name address pair when lib prefix is needed]) -_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], - [The name lister interface]) -_LT_DECL([], [nm_file_list_spec], [1], - [Specify filename containing input files for $NM]) -]) # _LT_CMD_GLOBAL_SYMBOLS - - -# _LT_COMPILER_PIC([TAGNAME]) -# --------------------------- -m4_defun([_LT_COMPILER_PIC], -[m4_require([_LT_TAG_COMPILER])dnl -_LT_TAGVAR(lt_prog_compiler_wl, $1)= -_LT_TAGVAR(lt_prog_compiler_pic, $1)= -_LT_TAGVAR(lt_prog_compiler_static, $1)= - -m4_if([$1], [CXX], [ - # C++ specific cases for pic, static, wl, etc. - if test yes = "$GXX"; then - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - m4_if([$1], [GCJ], [], - [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) - case $host_os in - os2*) - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' - ;; - esac - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - _LT_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - _LT_TAGVAR(lt_prog_compiler_static, $1)= - ;; - interix[[3-9]]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - sysv4*MP*) - if test -d /usr/nec; then - _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - else - case $host_os in - aix[[4-9]]*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68*) - # Green Hills C++ Compiler - # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - m4_if([$1], [GCJ], [], - [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) - ;; - dgux*) - case $cc_basename in - ec++*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - ghcx*) - # Green Hills C++ Compiler - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | dragonfly*) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' - if test ia64 != "$host_cpu"; then - _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - fi - ;; - aCC*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - interix*) - # This is c89, which is MS Visual C++ (no shared libs) - # Anyone wants to do a port? - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # KAI C++ Compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - ecpc* ) - # old Intel C++ for x86_64, which still supported -KPIC. - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - icpc* ) - # Intel C++, used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - cxx*) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) - # IBM XL 8.0, 9.0 on PPC and BlueGene - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - esac - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd*) - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' - ;; - RCC*) - # Rational C++ 2.4.1 - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - cxx*) - # Digital/Compaq C++ - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - _LT_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - gcx*) - # Green Hills C++ Compiler - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - lcc*) - # Lucid - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - ;; - *) - ;; - esac - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - case $cc_basename in - CC*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - ;; - *) - ;; - esac - ;; - vxworks*) - ;; - *) - _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -], -[ - if test yes = "$GCC"; then - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the '-m68020' flag to GCC prevents building anything better, - # like '-m68040'. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - m4_if([$1], [GCJ], [], - [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) - case $host_os in - os2*) - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' - ;; - esac - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - _LT_TAGVAR(lt_prog_compiler_static, $1)= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - ;; - - interix[[3-9]]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic - fi - ;; - - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' - if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then - _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - if test ia64 = "$host_cpu"; then - # AIX 5 now supports IA64 processor - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' - case $cc_basename in - nagfor*) - # NAG Fortran compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - esac - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - m4_if([$1], [GCJ], [], - [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) - case $host_os in - os2*) - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' - ;; - esac - ;; - - hpux9* | hpux10* | hpux11*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # PIC (with -KPIC) is the default. - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64, which still supported -KPIC. - ecc*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' - _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' - ;; - nagfor*) - # NAG Fortran compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - ccc*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All Alpha code is PIC. - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='' - ;; - *Sun\ F* | *Sun*Fortran*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - ;; - *Intel*\ [[CF]]*Compiler*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' - ;; - *Portland\ Group*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - # All OSF/1 code is PIC. - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - rdos*) - _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' - ;; - - solaris*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; - *) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; - esac - ;; - - sunos4*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - unicos*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - - uts4*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; - - *) - _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no - ;; - esac - fi -]) -case $host_os in - # For platforms that do not support PIC, -DPIC is meaningless: - *djgpp*) - _LT_TAGVAR(lt_prog_compiler_pic, $1)= - ;; - *) - _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" - ;; -esac - -AC_CACHE_CHECK([for $compiler option to produce PIC], - [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], - [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) -_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then - _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], - [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], - [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], - [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in - "" | " "*) ;; - *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; - esac], - [_LT_TAGVAR(lt_prog_compiler_pic, $1)= - _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) -fi -_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], - [Additional compiler flags for building library objects]) - -_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], - [How to pass a linker flag through the compiler]) -# -# Check to make sure the static flag actually works. -# -wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" -_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], - _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), - $lt_tmp_static_flag, - [], - [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) -_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], - [Compiler flag to prevent dynamic linking]) -])# _LT_COMPILER_PIC - - -# _LT_LINKER_SHLIBS([TAGNAME]) -# ---------------------------- -# See if the linker supports building shared libraries. -m4_defun([_LT_LINKER_SHLIBS], -[AC_REQUIRE([LT_PATH_LD])dnl -AC_REQUIRE([LT_PATH_NM])dnl -m4_require([_LT_PATH_MANIFEST_TOOL])dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_DECL_SED])dnl -m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl -m4_require([_LT_TAG_COMPILER])dnl -AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) -m4_if([$1], [CXX], [ - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] - case $host_os in - aix[[4-9]]*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds - ;; - cygwin* | mingw* | cegcc*) - case $cc_basename in - cl*) - _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - ;; - *) - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' - _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] - ;; - esac - ;; - *) - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac -], [ - runpath_var= - _LT_TAGVAR(allow_undefined_flag, $1)= - _LT_TAGVAR(always_export_symbols, $1)=no - _LT_TAGVAR(archive_cmds, $1)= - _LT_TAGVAR(archive_expsym_cmds, $1)= - _LT_TAGVAR(compiler_needs_object, $1)=no - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no - _LT_TAGVAR(export_dynamic_flag_spec, $1)= - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - _LT_TAGVAR(hardcode_automatic, $1)=no - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_direct_absolute, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_TAGVAR(hardcode_libdir_separator, $1)= - _LT_TAGVAR(hardcode_minus_L, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_TAGVAR(inherit_rpath, $1)=no - _LT_TAGVAR(link_all_deplibs, $1)=unknown - _LT_TAGVAR(module_cmds, $1)= - _LT_TAGVAR(module_expsym_cmds, $1)= - _LT_TAGVAR(old_archive_from_new_cmds, $1)= - _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= - _LT_TAGVAR(thread_safe_flag_spec, $1)= - _LT_TAGVAR(whole_archive_flag_spec, $1)= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - _LT_TAGVAR(include_expsyms, $1)= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ' (' and ')$', so one must not match beginning or - # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', - # as well as any symbol that contains 'd'. - _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. -dnl Note also adjust exclude_expsyms for C++ above. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test yes != "$GCC"; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd* | bitrig*) - with_gnu_ld=no - ;; - esac - - _LT_TAGVAR(ld_shlibs, $1)=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test yes = "$with_gnu_ld"; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; - *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test yes = "$lt_use_gnu_ld_interface"; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='$wl' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - _LT_TAGVAR(whole_archive_flag_spec, $1)= - fi - supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[[3-9]]*) - # On AIX/PPC, the GNU linker is very broken - if test ia64 != "$host_cpu"; then - _LT_TAGVAR(ld_shlibs, $1)=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; - m68k) - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_minus_L, $1)=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=no - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' - _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - haiku*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(link_all_deplibs, $1)=yes - ;; - - os2*) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - shrext_cmds=.dll - _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - - interix[[3-9]]*) - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test linux-dietlibc = "$host_os"; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test no = "$tmp_diet" - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - _LT_TAGVAR(whole_archive_flag_spec, $1)= - tmp_sharedflag='--shared' ;; - nagfor*) # NAGFOR 5.3 - tmp_sharedflag='-Wl,-shared' ;; - xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - _LT_TAGVAR(compiler_needs_object, $1)=yes - ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - _LT_TAGVAR(compiler_needs_object, $1)=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - - if test yes = "$supports_anon_versioning"; then - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - tcc*) - _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' - ;; - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test yes = "$supports_anon_versioning"; then - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - _LT_TAGVAR(ld_shlibs, $1)=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) - _LT_TAGVAR(ld_shlibs, $1)=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - - sunos4*) - _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - - if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then - runpath_var= - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_TAGVAR(export_dynamic_flag_spec, $1)= - _LT_TAGVAR(whole_archive_flag_spec, $1)= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=yes - _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - _LT_TAGVAR(hardcode_minus_L, $1)=yes - if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - _LT_TAGVAR(hardcode_direct, $1)=unsupported - fi - ;; - - aix[[4-9]]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to GNU nm, but means don't demangle to AIX nm. - # Without the "-l" option, or with the "-B" option, AIX nm treats - # weak defined symbols like other global defined symbols, whereas - # GNU nm marks them as "W". - # While the 'weak' keyword is ignored in the Export File, we need - # it in the Import File for the 'aix-soname' feature, so we have - # to replace the "-B" option with "-P" for AIX nm. - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' - else - _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) - for ld_flag in $LDFLAGS; do - if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then - aix_use_runtimelinking=yes - break - fi - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_TAGVAR(archive_cmds, $1)='' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_TAGVAR(link_all_deplibs, $1)=yes - _LT_TAGVAR(file_list_spec, $1)='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # traditional, no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_direct_absolute, $1)=no - ;; - esac - - if test yes = "$GCC"; then - case $host_os in aix4.[[012]]|aix4.[[012]].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - _LT_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)= - fi - ;; - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag="$shared_flag "'$wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - _LT_TAGVAR(always_export_symbols, $1)=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - _LT_TAGVAR(allow_undefined_flag, $1)='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - _LT_SYS_MODULE_PATH_AIX([$1]) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' - _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - _LT_SYS_MODULE_PATH_AIX([$1]) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' - fi - _LT_TAGVAR(archive_cmds_need_lc, $1)=yes - _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared libraries. - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; - m68k) - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_minus_L, $1)=yes - ;; - esac - ;; - - bsdi[[45]]*) - _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl*) - # Native MSVC - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=yes - _LT_TAGVAR(file_list_spec, $1)='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' - _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC wrapper - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' - # FIXME: Should let the user specify the lib program. - _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - esac - ;; - - darwin* | rhapsody*) - _LT_DARWIN_LINKER_FEATURES($1) - ;; - - dgux*) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - hpux9*) - if test yes = "$GCC"; then - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - fi - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(hardcode_direct, $1)=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - ;; - - hpux10*) - if test yes,no = "$GCC,$with_gnu_ld"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test no = "$with_gnu_ld"; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_TAGVAR(hardcode_minus_L, $1)=yes - fi - ;; - - hpux11*) - if test yes,no = "$GCC,$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - m4_if($1, [], [ - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - _LT_LINKER_OPTION([if $CC understands -b], - _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], - [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], - [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], - [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) - ;; - esac - fi - if test no = "$with_gnu_ld"; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - case $host_cpu in - hppa*64*|ia64*) - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - *) - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - _LT_TAGVAR(hardcode_minus_L, $1)=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test yes = "$GCC"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], - [lt_cv_irix_exported_symbol], - [save_LDFLAGS=$LDFLAGS - LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" - AC_LINK_IFELSE( - [AC_LANG_SOURCE( - [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], - [C++], [[int foo (void) { return 0; }]], - [Fortran 77], [[ - subroutine foo - end]], - [Fortran], [[ - subroutine foo - end]])])], - [lt_cv_irix_exported_symbol=yes], - [lt_cv_irix_exported_symbol=no]) - LDFLAGS=$save_LDFLAGS]) - if test yes = "$lt_cv_irix_exported_symbol"; then - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' - fi - else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' - fi - _LT_TAGVAR(archive_cmds_need_lc, $1)='no' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(inherit_rpath, $1)=yes - _LT_TAGVAR(link_all_deplibs, $1)=yes - ;; - - linux*) - case $cc_basename in - tcc*) - # Fabrice Bellard et al's Tiny C Compiler - _LT_TAGVAR(ld_shlibs, $1)=yes - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - newsos6) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *nto* | *qnx*) - ;; - - openbsd* | bitrig*) - if test -f /usr/libexec/ld.so; then - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - fi - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - os2*) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - shrext_cmds=.dll - _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - - osf3*) - if test yes = "$GCC"; then - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - fi - _LT_TAGVAR(archive_cmds_need_lc, $1)='no' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test yes = "$GCC"; then - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - else - _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - fi - _LT_TAGVAR(archive_cmds_need_lc, $1)='no' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - ;; - - solaris*) - _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' - if test yes = "$GCC"; then - wlarc='$wl' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='$wl' - _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. GCC discards it without '$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test yes = "$GCC"; then - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - else - _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' - fi - ;; - esac - _LT_TAGVAR(link_all_deplibs, $1)=yes - ;; - - sunos4*) - if test sequent = "$host_vendor"; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4) - case $host_vendor in - sni) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' - _LT_TAGVAR(hardcode_direct, $1)=no - ;; - motorola) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - sysv4.3*) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - _LT_TAGVAR(ld_shlibs, $1)=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) - _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' - _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_TAGVAR(link_all_deplibs, $1)=yes - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - if test yes = "$GCC"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - - *) - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - - if test sni = "$host_vendor"; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' - ;; - esac - fi - fi -]) -AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) -test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no - -_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld - -_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl -_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl -_LT_DECL([], [extract_expsyms_cmds], [2], - [The commands to extract the exported symbol list from a shared archive]) - -# -# Do we need to explicitly link libc? -# -case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in -x|xyes) - # Assume -lc should be added - _LT_TAGVAR(archive_cmds_need_lc, $1)=yes - - if test yes,yes = "$GCC,$enable_shared"; then - case $_LT_TAGVAR(archive_cmds, $1) in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - AC_CACHE_CHECK([whether -lc should be explicitly linked in], - [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), - [$RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if AC_TRY_EVAL(ac_compile) 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) - pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) - _LT_TAGVAR(allow_undefined_flag, $1)= - if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) - then - lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no - else - lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes - fi - _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - ]) - _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) - ;; - esac - fi - ;; -esac - -_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], - [Whether or not to add -lc for building shared libraries]) -_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], - [enable_shared_with_static_runtimes], [0], - [Whether or not to disallow shared libs when runtime libs are static]) -_LT_TAGDECL([], [export_dynamic_flag_spec], [1], - [Compiler flag to allow reflexive dlopens]) -_LT_TAGDECL([], [whole_archive_flag_spec], [1], - [Compiler flag to generate shared objects directly from archives]) -_LT_TAGDECL([], [compiler_needs_object], [1], - [Whether the compiler copes with passing no objects directly]) -_LT_TAGDECL([], [old_archive_from_new_cmds], [2], - [Create an old-style archive from a shared archive]) -_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], - [Create a temporary old-style archive to link instead of a shared archive]) -_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) -_LT_TAGDECL([], [archive_expsym_cmds], [2]) -_LT_TAGDECL([], [module_cmds], [2], - [Commands used to build a loadable module if different from building - a shared archive.]) -_LT_TAGDECL([], [module_expsym_cmds], [2]) -_LT_TAGDECL([], [with_gnu_ld], [1], - [Whether we are building with GNU ld or not]) -_LT_TAGDECL([], [allow_undefined_flag], [1], - [Flag that allows shared libraries with undefined symbols to be built]) -_LT_TAGDECL([], [no_undefined_flag], [1], - [Flag that enforces no undefined symbols]) -_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], - [Flag to hardcode $libdir into a binary during linking. - This must work even if $libdir does not exist]) -_LT_TAGDECL([], [hardcode_libdir_separator], [1], - [Whether we need a single "-rpath" flag with a separated argument]) -_LT_TAGDECL([], [hardcode_direct], [0], - [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes - DIR into the resulting binary]) -_LT_TAGDECL([], [hardcode_direct_absolute], [0], - [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes - DIR into the resulting binary and the resulting library dependency is - "absolute", i.e impossible to change by setting $shlibpath_var if the - library is relocated]) -_LT_TAGDECL([], [hardcode_minus_L], [0], - [Set to "yes" if using the -LDIR flag during linking hardcodes DIR - into the resulting binary]) -_LT_TAGDECL([], [hardcode_shlibpath_var], [0], - [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR - into the resulting binary]) -_LT_TAGDECL([], [hardcode_automatic], [0], - [Set to "yes" if building a shared library automatically hardcodes DIR - into the library and all subsequent libraries and executables linked - against it]) -_LT_TAGDECL([], [inherit_rpath], [0], - [Set to yes if linker adds runtime paths of dependent libraries - to runtime path list]) -_LT_TAGDECL([], [link_all_deplibs], [0], - [Whether libtool must link a program against all its dependency libraries]) -_LT_TAGDECL([], [always_export_symbols], [0], - [Set to "yes" if exported symbols are required]) -_LT_TAGDECL([], [export_symbols_cmds], [2], - [The commands to list exported symbols]) -_LT_TAGDECL([], [exclude_expsyms], [1], - [Symbols that should not be listed in the preloaded symbols]) -_LT_TAGDECL([], [include_expsyms], [1], - [Symbols that must always be exported]) -_LT_TAGDECL([], [prelink_cmds], [2], - [Commands necessary for linking programs (against libraries) with templates]) -_LT_TAGDECL([], [postlink_cmds], [2], - [Commands necessary for finishing linking programs]) -_LT_TAGDECL([], [file_list_spec], [1], - [Specify filename containing input files]) -dnl FIXME: Not yet implemented -dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], -dnl [Compiler flag to generate thread safe objects]) -])# _LT_LINKER_SHLIBS - - -# _LT_LANG_C_CONFIG([TAG]) -# ------------------------ -# Ensure that the configuration variables for a C compiler are suitably -# defined. These variables are subsequently used by _LT_CONFIG to write -# the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_C_CONFIG], -[m4_require([_LT_DECL_EGREP])dnl -lt_save_CC=$CC -AC_LANG_PUSH(C) - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - -_LT_TAG_COMPILER -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - _LT_COMPILER_NO_RTTI($1) - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_SYS_DYNAMIC_LINKER($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - LT_SYS_DLOPEN_SELF - _LT_CMD_STRIPLIB - - # Report what library types will actually be built - AC_MSG_CHECKING([if libtool supports shared libraries]) - AC_MSG_RESULT([$can_build_shared]) - - AC_MSG_CHECKING([whether to build shared libraries]) - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[[4-9]]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - AC_MSG_RESULT([$enable_shared]) - - AC_MSG_CHECKING([whether to build static libraries]) - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - AC_MSG_RESULT([$enable_static]) - - _LT_CONFIG($1) -fi -AC_LANG_POP -CC=$lt_save_CC -])# _LT_LANG_C_CONFIG - - -# _LT_LANG_CXX_CONFIG([TAG]) -# -------------------------- -# Ensure that the configuration variables for a C++ compiler are suitably -# defined. These variables are subsequently used by _LT_CONFIG to write -# the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_CXX_CONFIG], -[m4_require([_LT_FILEUTILS_DEFAULTS])dnl -m4_require([_LT_DECL_EGREP])dnl -m4_require([_LT_PATH_MANIFEST_TOOL])dnl -if test -n "$CXX" && ( test no != "$CXX" && - ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || - (test g++ != "$CXX"))); then - AC_PROG_CXXCPP -else - _lt_caught_CXX_error=yes -fi - -AC_LANG_PUSH(C++) -_LT_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_TAGVAR(allow_undefined_flag, $1)= -_LT_TAGVAR(always_export_symbols, $1)=no -_LT_TAGVAR(archive_expsym_cmds, $1)= -_LT_TAGVAR(compiler_needs_object, $1)=no -_LT_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_TAGVAR(hardcode_direct, $1)=no -_LT_TAGVAR(hardcode_direct_absolute, $1)=no -_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_separator, $1)= -_LT_TAGVAR(hardcode_minus_L, $1)=no -_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported -_LT_TAGVAR(hardcode_automatic, $1)=no -_LT_TAGVAR(inherit_rpath, $1)=no -_LT_TAGVAR(module_cmds, $1)= -_LT_TAGVAR(module_expsym_cmds, $1)= -_LT_TAGVAR(link_all_deplibs, $1)=unknown -_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_TAGVAR(reload_flag, $1)=$reload_flag -_LT_TAGVAR(reload_cmds, $1)=$reload_cmds -_LT_TAGVAR(no_undefined_flag, $1)= -_LT_TAGVAR(whole_archive_flag_spec, $1)= -_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Source file extension for C++ test sources. -ac_ext=cpp - -# Object file extension for compiled C++ test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# No sense in running all these tests if we already determined that -# the CXX compiler isn't working. Some variables (like enable_shared) -# are currently assumed to apply to all compilers on this platform, -# and will be corrupted by setting them based on a non-working compiler. -if test yes != "$_lt_caught_CXX_error"; then - # Code to be used in simple compile tests - lt_simple_compile_test_code="int some_variable = 0;" - - # Code to be used in simple link tests - lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' - - # ltmain only uses $CC for tagged configurations so make sure $CC is set. - _LT_TAG_COMPILER - - # save warnings/boilerplate of simple test code - _LT_COMPILER_BOILERPLATE - _LT_LINKER_BOILERPLATE - - # Allow CC to be a program name with arguments. - lt_save_CC=$CC - lt_save_CFLAGS=$CFLAGS - lt_save_LD=$LD - lt_save_GCC=$GCC - GCC=$GXX - lt_save_with_gnu_ld=$with_gnu_ld - lt_save_path_LD=$lt_cv_path_LD - if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx - else - $as_unset lt_cv_prog_gnu_ld - fi - if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX - else - $as_unset lt_cv_path_LD - fi - test -z "${LDCXX+set}" || LD=$LDCXX - CC=${CXX-"c++"} - CFLAGS=$CXXFLAGS - compiler=$CC - _LT_TAGVAR(compiler, $1)=$CC - _LT_CC_BASENAME([$compiler]) - - if test -n "$compiler"; then - # We don't want -fno-exception when compiling C++ code, so set the - # no_builtin_flag separately - if test yes = "$GXX"; then - _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' - else - _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= - fi - - if test yes = "$GXX"; then - # Set up default GNU C++ configuration - - LT_PATH_LD - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test yes = "$with_gnu_ld"; then - _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='$wl' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | - $GREP 'no-whole-archive' > /dev/null; then - _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - else - _LT_TAGVAR(whole_archive_flag_spec, $1)= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - GXX=no - with_gnu_ld=no - wlarc= - fi - - # PORTME: fill in a description of your system's C++ link characteristics - AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) - _LT_TAGVAR(ld_shlibs, $1)=yes - case $host_os in - aix3*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - aix[[4-9]]*) - if test ia64 = "$host_cpu"; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag= - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # have runtime linking enabled, and use it for executables. - # For shared libraries, we enable/disable runtime linking - # depending on the kind of the shared library created - - # when "with_aix_soname,aix_use_runtimelinking" is: - # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables - # "aix,yes" lib.so shared, rtl:yes, for executables - # lib.a static archive - # "both,no" lib.so.V(shr.o) shared, rtl:yes - # lib.a(lib.so.V) shared, rtl:no, for executables - # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a(lib.so.V) shared, rtl:no - # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables - # lib.a static archive - case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then - # With aix-soname=svr4, we create the lib.so.V shared archives only, - # so we don't have lib.a shared libs to link our executables. - # We have to force runtime linking in this case. - aix_use_runtimelinking=yes - LDFLAGS="$LDFLAGS -Wl,-brtl" - fi - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - _LT_TAGVAR(archive_cmds, $1)='' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_TAGVAR(link_all_deplibs, $1)=yes - _LT_TAGVAR(file_list_spec, $1)='$wl-f,' - case $with_aix_soname,$aix_use_runtimelinking in - aix,*) ;; # no import file - svr4,* | *,yes) # use import file - # The Import File defines what to hardcode. - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_direct_absolute, $1)=no - ;; - esac - - if test yes = "$GXX"; then - case $host_os in aix4.[[012]]|aix4.[[012]].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`$CC -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - _LT_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)= - fi - esac - shared_flag='-shared' - if test yes = "$aix_use_runtimelinking"; then - shared_flag=$shared_flag' $wl-G' - fi - # Need to ensure runtime linking is disabled for the traditional - # shared library, or the linker may eventually find shared libraries - # /with/ Import File - we do not want to mix them. - shared_flag_aix='-shared' - shared_flag_svr4='-shared $wl-G' - else - # not using gcc - if test ia64 = "$host_cpu"; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test yes = "$aix_use_runtimelinking"; then - shared_flag='$wl-G' - else - shared_flag='$wl-bM:SRE' - fi - shared_flag_aix='$wl-bM:SRE' - shared_flag_svr4='$wl-G' - fi - fi - - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to - # export. - _LT_TAGVAR(always_export_symbols, $1)=yes - if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - # The "-G" linker flag allows undefined symbols. - _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' - # Determine the default libpath from the value encoded in an empty - # executable. - _LT_SYS_MODULE_PATH_AIX([$1]) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" - - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag - else - if test ia64 = "$host_cpu"; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' - _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" - _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - _LT_SYS_MODULE_PATH_AIX([$1]) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' - if test yes = "$with_gnu_ld"; then - # We only use this code for GNU lds that support --whole-archive. - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' - fi - _LT_TAGVAR(archive_cmds_need_lc, $1)=yes - _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' - # -brtl affects multiple linker settings, -berok does not and is overridden later - compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' - if test svr4 != "$with_aix_soname"; then - # This is similar to how AIX traditionally builds its shared - # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' - fi - if test aix != "$with_aix_soname"; then - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' - else - # used by -dlpreopen to get the symbols - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' - fi - _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' - fi - fi - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - cygwin* | mingw* | pw32* | cegcc*) - case $GXX,$cc_basename in - ,cl* | no,cl*) - # Native MSVC - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=yes - _LT_TAGVAR(file_list_spec, $1)='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=.dll - # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' - _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then - cp "$export_symbols" "$output_objdir/$soname.def"; - echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; - else - $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - # Don't use ranlib - _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' - _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile=$lt_outputfile.exe - lt_tool_outputfile=$lt_tool_outputfile.exe - ;; - esac~ - func_to_tool_file "$lt_outputfile"~ - if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # g++ - # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=no - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file, use it as - # is; otherwise, prepend EXPORTS... - _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - darwin* | rhapsody*) - _LT_DARWIN_LINKER_FEATURES($1) - ;; - - os2*) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(hardcode_minus_L, $1)=yes - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - shrext_cmds=.dll - _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ - $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ - $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ - $ECHO EXPORTS >> $output_objdir/$libname.def~ - prefix_cmds="$SED"~ - if test EXPORTS = "`$SED 1q $export_symbols`"; then - prefix_cmds="$prefix_cmds -e 1d"; - fi~ - prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ - cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ - $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ - emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - ;; - - dgux*) - case $cc_basename in - ec++*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - ghcx*) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - freebsd2.*) - # C++ shared libraries reported to be fairly broken before - # switch to ELF - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - - freebsd-elf*) - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - ;; - - freebsd* | dragonfly*) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - _LT_TAGVAR(ld_shlibs, $1)=yes - ;; - - haiku*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(link_all_deplibs, $1)=yes - ;; - - hpux9*) - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - aCC*) - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test yes = "$GXX"; then - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - - hpux10*|hpux11*) - if test no = "$with_gnu_ld"; then - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - case $host_cpu in - hppa*64*|ia64*) - ;; - *) - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - ;; - esac - fi - case $host_cpu in - hppa*64*|ia64*) - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - ;; - *) - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - aCC*) - case $host_cpu in - hppa*64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test yes = "$GXX"; then - if test no = "$with_gnu_ld"; then - case $host_cpu in - hppa*64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - - interix[[3-9]]*) - _LT_TAGVAR(hardcode_direct, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - irix5* | irix6*) - case $cc_basename in - CC*) - # SGI C++ - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test yes = "$GXX"; then - if test no = "$with_gnu_ld"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' - fi - fi - _LT_TAGVAR(link_all_deplibs, $1)=yes - ;; - esac - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - _LT_TAGVAR(inherit_rpath, $1)=yes - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc* | ecpc* ) - # Intel C++ - with_gnu_ld=yes - # version 8.0 and above of icpc choke on multiply defined symbols - # if we add $predep_objects and $postdep_objects, however 7.1 and - # earlier do not add the objects themselves. - case `$CC -V 2>&1` in - *"Version 7."*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 8.0 or newer - tmp_idyn= - case $host_cpu in - ia64*) tmp_idyn=' -i_dynamic';; - esac - _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - case `$CC -V` in - *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) - _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ - compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' - _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ - $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ - $RANLIB $oldlib' - _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 6 and above use weak symbols - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - ;; - cxx*) - # Compaq C++ - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' - ;; - xl* | mpixl* | bgxl*) - # IBM XL 8.0 on PPC, with GNU ld - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' - _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - if test yes = "$supports_anon_versioning"; then - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' - fi - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' - _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - _LT_TAGVAR(compiler_needs_object, $1)=yes - - # Not sure whether something based on - # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 - # would be better. - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' - ;; - esac - ;; - esac - ;; - - lynxos*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - - m88k*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - - mvs*) - case $cc_basename in - cxx*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - - *nto* | *qnx*) - _LT_TAGVAR(ld_shlibs, $1)=yes - ;; - - openbsd* | bitrig*) - if test -f /usr/libexec/ld.so; then - _LT_TAGVAR(hardcode_direct, $1)=yes - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_direct_absolute, $1)=yes - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' - _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' - fi - output_verbose_link_cmd=func_echo_all - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - case $host in - osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; - *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; - esac - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - cxx*) - case $host in - osf3*) - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - ;; - *) - _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ - $RM $lib.exp' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' - ;; - esac - - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test yes,no = "$GXX,$with_gnu_ld"; then - _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' - case $host in - osf3*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' - ;; - esac - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; - esac - ;; - - psos*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - lcc*) - # Lucid - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - _LT_TAGVAR(archive_cmds_need_lc,$1)=yes - _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' - _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands '-z linker_flag'. - # Supported since Solaris 2.6 (maybe 2.5.1?) - _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' - ;; - esac - _LT_TAGVAR(link_all_deplibs, $1)=yes - - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' - ;; - gcx*) - # Green Hills C++ Compiler - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test yes,no = "$GXX,$with_gnu_ld"; then - _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' - if $CC --version | $GREP -v '^2\.7' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - else - # g++ 2.7 appears to require '-G' NOT '-shared' on this - # platform. - _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - fi - - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' - case $host_os in - solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; - *) - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' - ;; - esac - fi - ;; - esac - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) - _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We CANNOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' - _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - _LT_TAGVAR(hardcode_shlibpath_var, $1)=no - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' - _LT_TAGVAR(hardcode_libdir_separator, $1)=':' - _LT_TAGVAR(link_all_deplibs, $1)=yes - _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ - '"$_LT_TAGVAR(old_archive_cmds, $1)" - _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ - '"$_LT_TAGVAR(reload_cmds, $1)" - ;; - *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - ;; - - vxworks*) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - - *) - # FIXME: insert proper C++ library support - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - esac - - AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) - test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no - - _LT_TAGVAR(GCC, $1)=$GXX - _LT_TAGVAR(LD, $1)=$LD - - ## CAVEAT EMPTOR: - ## There is no encapsulation within the following macros, do not change - ## the running order or otherwise move them around unless you know exactly - ## what you are doing... - _LT_SYS_HIDDEN_LIBDEPS($1) - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_SYS_DYNAMIC_LINKER($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - - _LT_CONFIG($1) - fi # test -n "$compiler" - - CC=$lt_save_CC - CFLAGS=$lt_save_CFLAGS - LDCXX=$LD - LD=$lt_save_LD - GCC=$lt_save_GCC - with_gnu_ld=$lt_save_with_gnu_ld - lt_cv_path_LDCXX=$lt_cv_path_LD - lt_cv_path_LD=$lt_save_path_LD - lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld - lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld -fi # test yes != "$_lt_caught_CXX_error" - -AC_LANG_POP -])# _LT_LANG_CXX_CONFIG - - -# _LT_FUNC_STRIPNAME_CNF -# ---------------------- -# func_stripname_cnf prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -# -# This function is identical to the (non-XSI) version of func_stripname, -# except this one can be used by m4 code that may be executed by configure, -# rather than the libtool script. -m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl -AC_REQUIRE([_LT_DECL_SED]) -AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) -func_stripname_cnf () -{ - case @S|@2 in - .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; - *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; - esac -} # func_stripname_cnf -])# _LT_FUNC_STRIPNAME_CNF - - -# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) -# --------------------------------- -# Figure out "hidden" library dependencies from verbose -# compiler output when linking a shared library. -# Parse the compiler output and extract the necessary -# objects, libraries and library flags. -m4_defun([_LT_SYS_HIDDEN_LIBDEPS], -[m4_require([_LT_FILEUTILS_DEFAULTS])dnl -AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl -# Dependencies to place before and after the object being linked: -_LT_TAGVAR(predep_objects, $1)= -_LT_TAGVAR(postdep_objects, $1)= -_LT_TAGVAR(predeps, $1)= -_LT_TAGVAR(postdeps, $1)= -_LT_TAGVAR(compiler_lib_search_path, $1)= - -dnl we can't use the lt_simple_compile_test_code here, -dnl because it contains code intended for an executable, -dnl not a library. It's possible we should let each -dnl tag define a new lt_????_link_test_code variable, -dnl but it's only used here... -m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF -int a; -void foo (void) { a = 0; } -_LT_EOF -], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF -class Foo -{ -public: - Foo (void) { a = 0; } -private: - int a; -}; -_LT_EOF -], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF - subroutine foo - implicit none - integer*4 a - a=0 - return - end -_LT_EOF -], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF - subroutine foo - implicit none - integer a - a=0 - return - end -_LT_EOF -], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF -public class foo { - private int a; - public void bar (void) { - a = 0; - } -}; -_LT_EOF -], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF -package foo -func foo() { -} -_LT_EOF -]) - -_lt_libdeps_save_CFLAGS=$CFLAGS -case "$CC $CFLAGS " in #( -*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; -*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; -*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; -esac - -dnl Parse the compiler output and extract the necessary -dnl objects, libraries and library flags. -if AC_TRY_EVAL(ac_compile); then - # Parse the compiler output and extract the necessary - # objects, libraries and library flags. - - # Sentinel used to keep track of whether or not we are before - # the conftest object file. - pre_test_object_deps_done=no - - for p in `eval "$output_verbose_link_cmd"`; do - case $prev$p in - - -L* | -R* | -l*) - # Some compilers place space between "-{L,R}" and the path. - # Remove the space. - if test x-L = "$p" || - test x-R = "$p"; then - prev=$p - continue - fi - - # Expand the sysroot to ease extracting the directories later. - if test -z "$prev"; then - case $p in - -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; - -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; - -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; - esac - fi - case $p in - =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; - esac - if test no = "$pre_test_object_deps_done"; then - case $prev in - -L | -R) - # Internal compiler library paths should come after those - # provided the user. The postdeps already come after the - # user supplied libs so there is no need to process them. - if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then - _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p - else - _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" - fi - ;; - # The "-l" case would never come before the object being - # linked, so don't bother handling this case. - esac - else - if test -z "$_LT_TAGVAR(postdeps, $1)"; then - _LT_TAGVAR(postdeps, $1)=$prev$p - else - _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" - fi - fi - prev= - ;; - - *.lto.$objext) ;; # Ignore GCC LTO objects - *.$objext) - # This assumes that the test object file only shows up - # once in the compiler output. - if test "$p" = "conftest.$objext"; then - pre_test_object_deps_done=yes - continue - fi - - if test no = "$pre_test_object_deps_done"; then - if test -z "$_LT_TAGVAR(predep_objects, $1)"; then - _LT_TAGVAR(predep_objects, $1)=$p - else - _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" - fi - else - if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then - _LT_TAGVAR(postdep_objects, $1)=$p - else - _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" - fi - fi - ;; - - *) ;; # Ignore the rest. - - esac - done - - # Clean up. - rm -f a.out a.exe -else - echo "libtool.m4: error: problem compiling $1 test program" -fi - -$RM -f confest.$objext -CFLAGS=$_lt_libdeps_save_CFLAGS - -# PORTME: override above test on systems where it is broken -m4_if([$1], [CXX], -[case $host_os in -interix[[3-9]]*) - # Interix 3.5 installs completely hosed .la files for C++, so rather than - # hack all around it, let's just trust "g++" to DTRT. - _LT_TAGVAR(predep_objects,$1)= - _LT_TAGVAR(postdep_objects,$1)= - _LT_TAGVAR(postdeps,$1)= - ;; -esac -]) - -case " $_LT_TAGVAR(postdeps, $1) " in -*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; -esac - _LT_TAGVAR(compiler_lib_search_dirs, $1)= -if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then - _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` -fi -_LT_TAGDECL([], [compiler_lib_search_dirs], [1], - [The directories searched by this compiler when creating a shared library]) -_LT_TAGDECL([], [predep_objects], [1], - [Dependencies to place before and after the objects being linked to - create a shared library]) -_LT_TAGDECL([], [postdep_objects], [1]) -_LT_TAGDECL([], [predeps], [1]) -_LT_TAGDECL([], [postdeps], [1]) -_LT_TAGDECL([], [compiler_lib_search_path], [1], - [The library search path used internally by the compiler when linking - a shared library]) -])# _LT_SYS_HIDDEN_LIBDEPS - - -# _LT_LANG_F77_CONFIG([TAG]) -# -------------------------- -# Ensure that the configuration variables for a Fortran 77 compiler are -# suitably defined. These variables are subsequently used by _LT_CONFIG -# to write the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_F77_CONFIG], -[AC_LANG_PUSH(Fortran 77) -if test -z "$F77" || test no = "$F77"; then - _lt_disable_F77=yes -fi - -_LT_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_TAGVAR(allow_undefined_flag, $1)= -_LT_TAGVAR(always_export_symbols, $1)=no -_LT_TAGVAR(archive_expsym_cmds, $1)= -_LT_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_TAGVAR(hardcode_direct, $1)=no -_LT_TAGVAR(hardcode_direct_absolute, $1)=no -_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_separator, $1)= -_LT_TAGVAR(hardcode_minus_L, $1)=no -_LT_TAGVAR(hardcode_automatic, $1)=no -_LT_TAGVAR(inherit_rpath, $1)=no -_LT_TAGVAR(module_cmds, $1)= -_LT_TAGVAR(module_expsym_cmds, $1)= -_LT_TAGVAR(link_all_deplibs, $1)=unknown -_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_TAGVAR(reload_flag, $1)=$reload_flag -_LT_TAGVAR(reload_cmds, $1)=$reload_cmds -_LT_TAGVAR(no_undefined_flag, $1)= -_LT_TAGVAR(whole_archive_flag_spec, $1)= -_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Source file extension for f77 test sources. -ac_ext=f - -# Object file extension for compiled f77 test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# No sense in running all these tests if we already determined that -# the F77 compiler isn't working. Some variables (like enable_shared) -# are currently assumed to apply to all compilers on this platform, -# and will be corrupted by setting them based on a non-working compiler. -if test yes != "$_lt_disable_F77"; then - # Code to be used in simple compile tests - lt_simple_compile_test_code="\ - subroutine t - return - end -" - - # Code to be used in simple link tests - lt_simple_link_test_code="\ - program t - end -" - - # ltmain only uses $CC for tagged configurations so make sure $CC is set. - _LT_TAG_COMPILER - - # save warnings/boilerplate of simple test code - _LT_COMPILER_BOILERPLATE - _LT_LINKER_BOILERPLATE - - # Allow CC to be a program name with arguments. - lt_save_CC=$CC - lt_save_GCC=$GCC - lt_save_CFLAGS=$CFLAGS - CC=${F77-"f77"} - CFLAGS=$FFLAGS - compiler=$CC - _LT_TAGVAR(compiler, $1)=$CC - _LT_CC_BASENAME([$compiler]) - GCC=$G77 - if test -n "$compiler"; then - AC_MSG_CHECKING([if libtool supports shared libraries]) - AC_MSG_RESULT([$can_build_shared]) - - AC_MSG_CHECKING([whether to build shared libraries]) - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - aix[[4-9]]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - AC_MSG_RESULT([$enable_shared]) - - AC_MSG_CHECKING([whether to build static libraries]) - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - AC_MSG_RESULT([$enable_static]) - - _LT_TAGVAR(GCC, $1)=$G77 - _LT_TAGVAR(LD, $1)=$LD - - ## CAVEAT EMPTOR: - ## There is no encapsulation within the following macros, do not change - ## the running order or otherwise move them around unless you know exactly - ## what you are doing... - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_SYS_DYNAMIC_LINKER($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - - _LT_CONFIG($1) - fi # test -n "$compiler" - - GCC=$lt_save_GCC - CC=$lt_save_CC - CFLAGS=$lt_save_CFLAGS -fi # test yes != "$_lt_disable_F77" - -AC_LANG_POP -])# _LT_LANG_F77_CONFIG - - -# _LT_LANG_FC_CONFIG([TAG]) -# ------------------------- -# Ensure that the configuration variables for a Fortran compiler are -# suitably defined. These variables are subsequently used by _LT_CONFIG -# to write the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_FC_CONFIG], -[AC_LANG_PUSH(Fortran) - -if test -z "$FC" || test no = "$FC"; then - _lt_disable_FC=yes -fi - -_LT_TAGVAR(archive_cmds_need_lc, $1)=no -_LT_TAGVAR(allow_undefined_flag, $1)= -_LT_TAGVAR(always_export_symbols, $1)=no -_LT_TAGVAR(archive_expsym_cmds, $1)= -_LT_TAGVAR(export_dynamic_flag_spec, $1)= -_LT_TAGVAR(hardcode_direct, $1)=no -_LT_TAGVAR(hardcode_direct_absolute, $1)=no -_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_separator, $1)= -_LT_TAGVAR(hardcode_minus_L, $1)=no -_LT_TAGVAR(hardcode_automatic, $1)=no -_LT_TAGVAR(inherit_rpath, $1)=no -_LT_TAGVAR(module_cmds, $1)= -_LT_TAGVAR(module_expsym_cmds, $1)= -_LT_TAGVAR(link_all_deplibs, $1)=unknown -_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_TAGVAR(reload_flag, $1)=$reload_flag -_LT_TAGVAR(reload_cmds, $1)=$reload_cmds -_LT_TAGVAR(no_undefined_flag, $1)= -_LT_TAGVAR(whole_archive_flag_spec, $1)= -_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no - -# Source file extension for fc test sources. -ac_ext=${ac_fc_srcext-f} - -# Object file extension for compiled fc test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# No sense in running all these tests if we already determined that -# the FC compiler isn't working. Some variables (like enable_shared) -# are currently assumed to apply to all compilers on this platform, -# and will be corrupted by setting them based on a non-working compiler. -if test yes != "$_lt_disable_FC"; then - # Code to be used in simple compile tests - lt_simple_compile_test_code="\ - subroutine t - return - end -" - - # Code to be used in simple link tests - lt_simple_link_test_code="\ - program t - end -" - - # ltmain only uses $CC for tagged configurations so make sure $CC is set. - _LT_TAG_COMPILER - - # save warnings/boilerplate of simple test code - _LT_COMPILER_BOILERPLATE - _LT_LINKER_BOILERPLATE - - # Allow CC to be a program name with arguments. - lt_save_CC=$CC - lt_save_GCC=$GCC - lt_save_CFLAGS=$CFLAGS - CC=${FC-"f95"} - CFLAGS=$FCFLAGS - compiler=$CC - GCC=$ac_cv_fc_compiler_gnu - - _LT_TAGVAR(compiler, $1)=$CC - _LT_CC_BASENAME([$compiler]) - - if test -n "$compiler"; then - AC_MSG_CHECKING([if libtool supports shared libraries]) - AC_MSG_RESULT([$can_build_shared]) - - AC_MSG_CHECKING([whether to build shared libraries]) - test no = "$can_build_shared" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test yes = "$enable_shared" && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - aix[[4-9]]*) - if test ia64 != "$host_cpu"; then - case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in - yes,aix,yes) ;; # shared object as lib.so file only - yes,svr4,*) ;; # shared object as lib.so archive member only - yes,*) enable_static=no ;; # shared object in lib.a archive as well - esac - fi - ;; - esac - AC_MSG_RESULT([$enable_shared]) - - AC_MSG_CHECKING([whether to build static libraries]) - # Make sure either enable_shared or enable_static is yes. - test yes = "$enable_shared" || enable_static=yes - AC_MSG_RESULT([$enable_static]) - - _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu - _LT_TAGVAR(LD, $1)=$LD - - ## CAVEAT EMPTOR: - ## There is no encapsulation within the following macros, do not change - ## the running order or otherwise move them around unless you know exactly - ## what you are doing... - _LT_SYS_HIDDEN_LIBDEPS($1) - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_SYS_DYNAMIC_LINKER($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - - _LT_CONFIG($1) - fi # test -n "$compiler" - - GCC=$lt_save_GCC - CC=$lt_save_CC - CFLAGS=$lt_save_CFLAGS -fi # test yes != "$_lt_disable_FC" - -AC_LANG_POP -])# _LT_LANG_FC_CONFIG - - -# _LT_LANG_GCJ_CONFIG([TAG]) -# -------------------------- -# Ensure that the configuration variables for the GNU Java Compiler compiler -# are suitably defined. These variables are subsequently used by _LT_CONFIG -# to write the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_GCJ_CONFIG], -[AC_REQUIRE([LT_PROG_GCJ])dnl -AC_LANG_SAVE - -# Source file extension for Java test sources. -ac_ext=java - -# Object file extension for compiled Java test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="class foo {}" - -# Code to be used in simple link tests -lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_TAG_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_CFLAGS=$CFLAGS -lt_save_GCC=$GCC -GCC=yes -CC=${GCJ-"gcj"} -CFLAGS=$GCJFLAGS -compiler=$CC -_LT_TAGVAR(compiler, $1)=$CC -_LT_TAGVAR(LD, $1)=$LD -_LT_CC_BASENAME([$compiler]) - -# GCJ did not exist at the time GCC didn't implicitly link libc in. -_LT_TAGVAR(archive_cmds_need_lc, $1)=no - -_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_TAGVAR(reload_flag, $1)=$reload_flag -_LT_TAGVAR(reload_cmds, $1)=$reload_cmds - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - _LT_COMPILER_NO_RTTI($1) - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - - _LT_CONFIG($1) -fi - -AC_LANG_RESTORE - -GCC=$lt_save_GCC -CC=$lt_save_CC -CFLAGS=$lt_save_CFLAGS -])# _LT_LANG_GCJ_CONFIG - - -# _LT_LANG_GO_CONFIG([TAG]) -# -------------------------- -# Ensure that the configuration variables for the GNU Go compiler -# are suitably defined. These variables are subsequently used by _LT_CONFIG -# to write the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_GO_CONFIG], -[AC_REQUIRE([LT_PROG_GO])dnl -AC_LANG_SAVE - -# Source file extension for Go test sources. -ac_ext=go - -# Object file extension for compiled Go test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="package main; func main() { }" - -# Code to be used in simple link tests -lt_simple_link_test_code='package main; func main() { }' - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_TAG_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_CFLAGS=$CFLAGS -lt_save_GCC=$GCC -GCC=yes -CC=${GOC-"gccgo"} -CFLAGS=$GOFLAGS -compiler=$CC -_LT_TAGVAR(compiler, $1)=$CC -_LT_TAGVAR(LD, $1)=$LD -_LT_CC_BASENAME([$compiler]) - -# Go did not exist at the time GCC didn't implicitly link libc in. -_LT_TAGVAR(archive_cmds_need_lc, $1)=no - -_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds -_LT_TAGVAR(reload_flag, $1)=$reload_flag -_LT_TAGVAR(reload_cmds, $1)=$reload_cmds - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - _LT_COMPILER_NO_RTTI($1) - _LT_COMPILER_PIC($1) - _LT_COMPILER_C_O($1) - _LT_COMPILER_FILE_LOCKS($1) - _LT_LINKER_SHLIBS($1) - _LT_LINKER_HARDCODE_LIBPATH($1) - - _LT_CONFIG($1) -fi - -AC_LANG_RESTORE - -GCC=$lt_save_GCC -CC=$lt_save_CC -CFLAGS=$lt_save_CFLAGS -])# _LT_LANG_GO_CONFIG - - -# _LT_LANG_RC_CONFIG([TAG]) -# ------------------------- -# Ensure that the configuration variables for the Windows resource compiler -# are suitably defined. These variables are subsequently used by _LT_CONFIG -# to write the compiler configuration to 'libtool'. -m4_defun([_LT_LANG_RC_CONFIG], -[AC_REQUIRE([LT_PROG_RC])dnl -AC_LANG_SAVE - -# Source file extension for RC test sources. -ac_ext=rc - -# Object file extension for compiled RC test sources. -objext=o -_LT_TAGVAR(objext, $1)=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' - -# Code to be used in simple link tests -lt_simple_link_test_code=$lt_simple_compile_test_code - -# ltmain only uses $CC for tagged configurations so make sure $CC is set. -_LT_TAG_COMPILER - -# save warnings/boilerplate of simple test code -_LT_COMPILER_BOILERPLATE -_LT_LINKER_BOILERPLATE - -# Allow CC to be a program name with arguments. -lt_save_CC=$CC -lt_save_CFLAGS=$CFLAGS -lt_save_GCC=$GCC -GCC= -CC=${RC-"windres"} -CFLAGS= -compiler=$CC -_LT_TAGVAR(compiler, $1)=$CC -_LT_CC_BASENAME([$compiler]) -_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes - -if test -n "$compiler"; then - : - _LT_CONFIG($1) -fi - -GCC=$lt_save_GCC -AC_LANG_RESTORE -CC=$lt_save_CC -CFLAGS=$lt_save_CFLAGS -])# _LT_LANG_RC_CONFIG - - -# LT_PROG_GCJ -# ----------- -AC_DEFUN([LT_PROG_GCJ], -[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], - [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], - [AC_CHECK_TOOL(GCJ, gcj,) - test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" - AC_SUBST(GCJFLAGS)])])[]dnl -]) - -# Old name: -AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([LT_AC_PROG_GCJ], []) - - -# LT_PROG_GO -# ---------- -AC_DEFUN([LT_PROG_GO], -[AC_CHECK_TOOL(GOC, gccgo,) -]) - - -# LT_PROG_RC -# ---------- -AC_DEFUN([LT_PROG_RC], -[AC_CHECK_TOOL(RC, windres,) -]) - -# Old name: -AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([LT_AC_PROG_RC], []) - - -# _LT_DECL_EGREP -# -------------- -# If we don't have a new enough Autoconf to choose the best grep -# available, choose the one first in the user's PATH. -m4_defun([_LT_DECL_EGREP], -[AC_REQUIRE([AC_PROG_EGREP])dnl -AC_REQUIRE([AC_PROG_FGREP])dnl -test -z "$GREP" && GREP=grep -_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) -_LT_DECL([], [EGREP], [1], [An ERE matcher]) -_LT_DECL([], [FGREP], [1], [A literal string matcher]) -dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too -AC_SUBST([GREP]) -]) - - -# _LT_DECL_OBJDUMP -# -------------- -# If we don't have a new enough Autoconf to choose the best objdump -# available, choose the one first in the user's PATH. -m4_defun([_LT_DECL_OBJDUMP], -[AC_CHECK_TOOL(OBJDUMP, objdump, false) -test -z "$OBJDUMP" && OBJDUMP=objdump -_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) -AC_SUBST([OBJDUMP]) -]) - -# _LT_DECL_DLLTOOL -# ---------------- -# Ensure DLLTOOL variable is set. -m4_defun([_LT_DECL_DLLTOOL], -[AC_CHECK_TOOL(DLLTOOL, dlltool, false) -test -z "$DLLTOOL" && DLLTOOL=dlltool -_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) -AC_SUBST([DLLTOOL]) -]) - -# _LT_DECL_SED -# ------------ -# Check for a fully-functional sed program, that truncates -# as few characters as possible. Prefer GNU sed if found. -m4_defun([_LT_DECL_SED], -[AC_PROG_SED -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" -_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) -_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], - [Sed that helps us avoid accidentally triggering echo(1) options like -n]) -])# _LT_DECL_SED - -m4_ifndef([AC_PROG_SED], [ -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_SED. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ - -m4_defun([AC_PROG_SED], -[AC_MSG_CHECKING([for a sed that does not truncate output]) -AC_CACHE_VAL(lt_cv_path_SED, -[# Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -IFS=$as_save_IFS -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f "$lt_ac_sed" && continue - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test 10 -lt "$lt_ac_count" && break - lt_ac_count=`expr $lt_ac_count + 1` - if test "$lt_ac_count" -gt "$lt_ac_max"; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done -]) -SED=$lt_cv_path_SED -AC_SUBST([SED]) -AC_MSG_RESULT([$SED]) -])#AC_PROG_SED -])#m4_ifndef - -# Old name: -AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([LT_AC_PROG_SED], []) - - -# _LT_CHECK_SHELL_FEATURES -# ------------------------ -# Find out whether the shell is Bourne or XSI compatible, -# or has some other useful features. -m4_defun([_LT_CHECK_SHELL_FEATURES], -[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi -_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac -_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl -_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl -])# _LT_CHECK_SHELL_FEATURES - - -# _LT_PATH_CONVERSION_FUNCTIONS -# ----------------------------- -# Determine what file name conversion functions should be used by -# func_to_host_file (and, implicitly, by func_to_host_path). These are needed -# for certain cross-compile configurations and native mingw. -m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], -[AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_CANONICAL_BUILD])dnl -AC_MSG_CHECKING([how to convert $build file names to $host format]) -AC_CACHE_VAL(lt_cv_to_host_file_cmd, -[case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac -]) -to_host_file_cmd=$lt_cv_to_host_file_cmd -AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) -_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], - [0], [convert $build file names to $host format])dnl - -AC_MSG_CHECKING([how to convert $build file names to toolchain format]) -AC_CACHE_VAL(lt_cv_to_tool_file_cmd, -[#assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac -]) -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) -_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], - [0], [convert $build files to toolchain format])dnl -])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/src/secp256k1-mw/build-aux/missing b/src/secp256k1-mw/build-aux/missing deleted file mode 100644 index 625aeb1189..0000000000 --- a/src/secp256k1-mw/build-aux/missing +++ /dev/null @@ -1,215 +0,0 @@ -#! /bin/sh -# Common wrapper for a few potentially missing GNU programs. - -scriptversion=2018-03-07.03; # UTC - -# Copyright (C) 1996-2018 Free Software Foundation, Inc. -# Originally written by Fran,cois Pinard , 1996. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -if test $# -eq 0; then - echo 1>&2 "Try '$0 --help' for more information" - exit 1 -fi - -case $1 in - - --is-lightweight) - # Used by our autoconf macros to check whether the available missing - # script is modern enough. - exit 0 - ;; - - --run) - # Back-compat with the calling convention used by older automake. - shift - ;; - - -h|--h|--he|--hel|--help) - echo "\ -$0 [OPTION]... PROGRAM [ARGUMENT]... - -Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due -to PROGRAM being missing or too old. - -Options: - -h, --help display this help and exit - -v, --version output version information and exit - -Supported PROGRAM values: - aclocal autoconf autoheader autom4te automake makeinfo - bison yacc flex lex help2man - -Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and -'g' are ignored when checking the name. - -Send bug reports to ." - exit $? - ;; - - -v|--v|--ve|--ver|--vers|--versi|--versio|--version) - echo "missing $scriptversion (GNU Automake)" - exit $? - ;; - - -*) - echo 1>&2 "$0: unknown '$1' option" - echo 1>&2 "Try '$0 --help' for more information" - exit 1 - ;; - -esac - -# Run the given program, remember its exit status. -"$@"; st=$? - -# If it succeeded, we are done. -test $st -eq 0 && exit 0 - -# Also exit now if we it failed (or wasn't found), and '--version' was -# passed; such an option is passed most likely to detect whether the -# program is present and works. -case $2 in --version|--help) exit $st;; esac - -# Exit code 63 means version mismatch. This often happens when the user -# tries to use an ancient version of a tool on a file that requires a -# minimum version. -if test $st -eq 63; then - msg="probably too old" -elif test $st -eq 127; then - # Program was missing. - msg="missing on your system" -else - # Program was found and executed, but failed. Give up. - exit $st -fi - -perl_URL=https://www.perl.org/ -flex_URL=https://github.com/westes/flex -gnu_software_URL=https://www.gnu.org/software - -program_details () -{ - case $1 in - aclocal|automake) - echo "The '$1' program is part of the GNU Automake package:" - echo "<$gnu_software_URL/automake>" - echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" - echo "<$gnu_software_URL/autoconf>" - echo "<$gnu_software_URL/m4/>" - echo "<$perl_URL>" - ;; - autoconf|autom4te|autoheader) - echo "The '$1' program is part of the GNU Autoconf package:" - echo "<$gnu_software_URL/autoconf/>" - echo "It also requires GNU m4 and Perl in order to run:" - echo "<$gnu_software_URL/m4/>" - echo "<$perl_URL>" - ;; - esac -} - -give_advice () -{ - # Normalize program name to check for. - normalized_program=`echo "$1" | sed ' - s/^gnu-//; t - s/^gnu//; t - s/^g//; t'` - - printf '%s\n' "'$1' is $msg." - - configure_deps="'configure.ac' or m4 files included by 'configure.ac'" - case $normalized_program in - autoconf*) - echo "You should only need it if you modified 'configure.ac'," - echo "or m4 files included by it." - program_details 'autoconf' - ;; - autoheader*) - echo "You should only need it if you modified 'acconfig.h' or" - echo "$configure_deps." - program_details 'autoheader' - ;; - automake*) - echo "You should only need it if you modified 'Makefile.am' or" - echo "$configure_deps." - program_details 'automake' - ;; - aclocal*) - echo "You should only need it if you modified 'acinclude.m4' or" - echo "$configure_deps." - program_details 'aclocal' - ;; - autom4te*) - echo "You might have modified some maintainer files that require" - echo "the 'autom4te' program to be rebuilt." - program_details 'autom4te' - ;; - bison*|yacc*) - echo "You should only need it if you modified a '.y' file." - echo "You may want to install the GNU Bison package:" - echo "<$gnu_software_URL/bison/>" - ;; - lex*|flex*) - echo "You should only need it if you modified a '.l' file." - echo "You may want to install the Fast Lexical Analyzer package:" - echo "<$flex_URL>" - ;; - help2man*) - echo "You should only need it if you modified a dependency" \ - "of a man page." - echo "You may want to install the GNU Help2man package:" - echo "<$gnu_software_URL/help2man/>" - ;; - makeinfo*) - echo "You should only need it if you modified a '.texi' file, or" - echo "any other file indirectly affecting the aspect of the manual." - echo "You might want to install the Texinfo package:" - echo "<$gnu_software_URL/texinfo/>" - echo "The spurious makeinfo call might also be the consequence of" - echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" - echo "want to install GNU make:" - echo "<$gnu_software_URL/make/>" - ;; - *) - echo "You might have modified some files without having the proper" - echo "tools for further handling them. Check the 'README' file, it" - echo "often tells you about the needed prerequisites for installing" - echo "this package. You may also peek at any GNU archive site, in" - echo "case some other package contains this missing '$1' program." - ;; - esac -} - -give_advice "$1" | sed -e '1s/^/WARNING: /' \ - -e '2,$s/^/ /' >&2 - -# Propagate the correct exit status (expected to be 127 for a program -# not found, 63 for a program that failed due to version mismatch). -exit $st - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/secp256k1-mw/build-aux/test-driver b/src/secp256k1-mw/build-aux/test-driver deleted file mode 100644 index b8521a482e..0000000000 --- a/src/secp256k1-mw/build-aux/test-driver +++ /dev/null @@ -1,148 +0,0 @@ -#! /bin/sh -# test-driver - basic testsuite driver script. - -scriptversion=2018-03-07.03; # UTC - -# Copyright (C) 2011-2018 Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -# Make unconditional expansion of undefined variables an error. This -# helps a lot in preventing typo-related bugs. -set -u - -usage_error () -{ - echo "$0: $*" >&2 - print_usage >&2 - exit 2 -} - -print_usage () -{ - cat <$log_file 2>&1 -estatus=$? - -if test $enable_hard_errors = no && test $estatus -eq 99; then - tweaked_estatus=1 -else - tweaked_estatus=$estatus -fi - -case $tweaked_estatus:$expect_failure in - 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; - 0:*) col=$grn res=PASS recheck=no gcopy=no;; - 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; - 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; - *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; - *:*) col=$red res=FAIL recheck=yes gcopy=yes;; -esac - -# Report the test outcome and exit status in the logs, so that one can -# know whether the test passed or failed simply by looking at the '.log' -# file, without the need of also peaking into the corresponding '.trs' -# file (automake bug#11814). -echo "$res $test_name (exit status: $estatus)" >>$log_file - -# Report outcome to console. -echo "${col}${res}${std}: $test_name" - -# Register the test result, and other relevant metadata. -echo ":test-result: $res" > $trs_file -echo ":global-test-result: $res" >> $trs_file -echo ":recheck: $recheck" >> $trs_file -echo ":copy-in-global-log: $gcopy" >> $trs_file - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/secp256k1-mw/libsecp256k1.pc b/src/secp256k1-mw/libsecp256k1.pc deleted file mode 100644 index 9c2ec16091..0000000000 --- a/src/secp256k1-mw/libsecp256k1.pc +++ /dev/null @@ -1,13 +0,0 @@ -prefix=/usr/local -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libsecp256k1 -Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin-core/secp256k1 -Version: 0.1 -Cflags: -I${includedir} -Libs.private: -L/usr/local/opt/gmp/lib -lgmp -Libs: -L${libdir} -lsecp256k1 - diff --git a/src/secp256k1-mw/src/libsecp256k1-config.h b/src/secp256k1-mw/src/libsecp256k1-config.h deleted file mode 100644 index 82fc3f982a..0000000000 --- a/src/secp256k1-mw/src/libsecp256k1-config.h +++ /dev/null @@ -1,181 +0,0 @@ -/* src/libsecp256k1-config.h. Generated from libsecp256k1-config.h.in by configure. */ -/* src/libsecp256k1-config.h.in. Generated from configure.ac by autoheader. */ - -#ifndef LIBSECP256K1_CONFIG_H - -#define LIBSECP256K1_CONFIG_H - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Define this symbol to compile out all VERIFY code */ -/* #undef COVERAGE */ - -/* Define this symbol to enable the Pedersen / zero knowledge bulletproof - module */ -#define ENABLE_MODULE_BULLETPROOF 1 - -/* Define this symbol to enable the Pedersen commitment module */ -#define ENABLE_MODULE_COMMITMENT 1 - -/* Define this symbol to enable the ECDH module */ -/* #undef ENABLE_MODULE_ECDH */ - -/* Define this symbol to enable the NUMS generator module */ -#define ENABLE_MODULE_GENERATOR 1 - -/* Define this symbol to enable the zero knowledge range proof module */ -/* #undef ENABLE_MODULE_RANGEPROOF */ - -/* Define this symbol to enable the ECDSA pubkey recovery module */ -/* #undef ENABLE_MODULE_RECOVERY */ - -/* Define this symbol to enable the surjection proof module */ -/* #undef ENABLE_MODULE_SURJECTIONPROOF */ - -/* Define this symbol to enable the key whitelisting module */ -/* #undef ENABLE_MODULE_WHITELIST */ - -/* Define this symbol if OpenSSL EC functions are available */ -#define ENABLE_OPENSSL_TESTS 1 - -/* Define this symbol if __builtin_clzll is available */ -#define HAVE_BUILTIN_CLZLL 1 - -/* Define this symbol if __builtin_ctzl is available */ -#define HAVE_BUILTIN_CTZL 1 - -/* Define this symbol if __builtin_expect is available */ -#define HAVE_BUILTIN_EXPECT 1 - -/* Define this symbol if __builtin_popcount is available */ -#define HAVE_BUILTIN_POPCOUNT 1 - -/* Define this symbol if __builtin_popcountl is available */ -#define HAVE_BUILTIN_POPCOUNTL 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define this symbol if libcrypto is installed */ -#define HAVE_LIBCRYPTO 1 - -/* Define this symbol if libgmp is installed */ -#define HAVE_LIBGMP 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `__int128'. */ -#define HAVE___INT128 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "libsecp256k1" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libsecp256k1" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libsecp256k1 0.1" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libsecp256k1" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.1" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define this symbol to enable x86_64 assembly optimizations */ -#define USE_ASM_X86_64 1 - -/* Define this symbol to use a statically generated ecmult table */ -#define USE_ECMULT_STATIC_PRECOMPUTATION 1 - -/* Define this symbol to use endomorphism optimization */ -/* #undef USE_ENDOMORPHISM */ - -/* Define this symbol if an external (non-inline) assembly implementation is - used */ -/* #undef USE_EXTERNAL_ASM */ - -/* Define this symbol to use the FIELD_10X26 implementation */ -/* #undef USE_FIELD_10X26 */ - -/* Define this symbol to use the FIELD_5X52 implementation */ -#define USE_FIELD_5X52 1 - -/* Define this symbol to use the native field inverse implementation */ -/* #undef USE_FIELD_INV_BUILTIN */ - -/* Define this symbol to use the num-based field inverse implementation */ -#define USE_FIELD_INV_NUM 1 - -/* Define this symbol to use the gmp implementation for num */ -#define USE_NUM_GMP 1 - -/* Define this symbol to use no num implementation */ -/* #undef USE_NUM_NONE */ - -/* Define this symbol to use the 4x64 scalar implementation */ -#define USE_SCALAR_4X64 1 - -/* Define this symbol to use the 8x32 scalar implementation */ -/* #undef USE_SCALAR_8X32 */ - -/* Define this symbol to use the native scalar inverse implementation */ -/* #undef USE_SCALAR_INV_BUILTIN */ - -/* Define this symbol to use the num-based scalar inverse implementation */ -#define USE_SCALAR_INV_NUM 1 - -/* Version number of package */ -#define VERSION "0.1" - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -#endif /*LIBSECP256K1_CONFIG_H*/ From 2af95deb573d8a3182ad85c5635e6ccc3ebecf8e Mon Sep 17 00:00:00 2001 From: JD Date: Mon, 16 Dec 2019 19:11:15 -0500 Subject: [PATCH 0004/1888] [Move Only] Move files to match Upstream (#18) * [Refactoring] [Move Only] Move wallet files into their own folder * [Refactor] Rename ui_interface.h file * [MoveOnly] Move non-wallet RPC files to subdir --- contrib/dapscoin-qt.pro | 26 +- src/Makefile.am | 48 +- src/Makefile.test.include | 2 +- src/activemasternode.h | 2 +- src/alert.cpp | 2 +- src/dapscoin-cli.cpp | 4 +- src/dapscoin-tx.cpp | 2 +- src/dapscoind.cpp | 6 +- src/{ui_interface.h => guiinterface.h} | 6 +- src/httprpc.cpp | 6 +- src/httpserver.cpp | 4 +- src/init.cpp | 10 +- src/main.cpp | 2 +- src/masternodeconfig.cpp | 2 +- src/miner.cpp | 2 +- src/net.cpp | 2 +- src/noui.cpp | 2 +- src/obfuscation.cpp | 2 +- src/qt/addresstablemodel.cpp | 2 +- src/qt/bip38tooldialog.cpp | 2 +- src/qt/bitcoingui.cpp | 2 +- src/qt/blockexplorer.cpp | 2 +- src/qt/clientmodel.cpp | 2 +- src/qt/coincontroldialog.cpp | 2 +- src/qt/dapscoin.cpp | 6 +- src/qt/entermnemonics.cpp | 2 +- src/qt/masternodelist.cpp | 2 +- src/qt/multisigdialog.cpp | 2 +- src/qt/optionsdialog.cpp | 2 +- src/qt/optionsmodel.cpp | 4 +- src/qt/optionspage.h | 2 +- src/qt/paymentserver.cpp | 4 +- src/qt/rpcconsole.cpp | 4 +- src/qt/sendcoinsdialog.cpp | 4 +- src/qt/signverifymessagedialog.cpp | 2 +- src/qt/splashscreen.cpp | 4 +- src/qt/transactiondesc.cpp | 6 +- src/qt/transactionrecord.cpp | 2 +- src/qt/transactiontablemodel.cpp | 2 +- src/qt/transactionview.cpp | 2 +- src/qt/walletmodel.cpp | 8 +- src/qt/walletmodel.h | 2 +- src/qt/walletmodeltransaction.cpp | 2 +- src/qt/walletview.cpp | 2 +- src/rest.cpp | 2 +- src/{rpcblockchain.cpp => rpc/blockchain.cpp} | 2 +- .../budget.cpp} | 4 +- src/{rpcclient.cpp => rpc/client.cpp} | 6 +- src/{rpcclient.h => rpc/client.h} | 0 src/rpc/dump.cpp | 504 +++ src/{rpcmasternode.cpp => rpc/masternode.cpp} | 4 +- src/{rpcmining.cpp => rpc/mining.cpp} | 6 +- src/{rpcmisc.cpp => rpc/misc.cpp} | 6 +- src/{rpcnet.cpp => rpc/net.cpp} | 4 +- src/{rpcprotocol.cpp => rpc/protocol.cpp} | 2 +- src/{rpcprotocol.h => rpc/protocol.h} | 0 .../rawtransaction.cpp} | 6 +- src/{rpcserver.cpp => rpc/server.cpp} | 6 +- src/{rpcserver.h => rpc/server.h} | 4 +- src/rpc/wallet.cpp | 3015 +++++++++++++++++ src/stakeinput.cpp | 2 +- src/test/accounting_tests.cpp | 4 +- src/test/multisig_tests.cpp | 2 +- src/test/rpc_tests.cpp | 4 +- src/test/rpc_wallet_tests.cpp | 6 +- src/test/script_P2SH_tests.cpp | 2 +- src/test/test_dapscoin.cpp | 6 +- src/timedata.cpp | 2 +- src/wallet/db.cpp | 455 +++ src/wallet/db.h | 328 ++ src/{ => wallet}/rpcdump.cpp | 4 +- src/{ => wallet}/rpcwallet.cpp | 6 +- src/wallet/test/wallet_tests.cpp | 393 +++ src/{ => wallet}/wallet.cpp | 2 +- src/{ => wallet}/wallet.h | 2 +- src/{ => wallet}/wallet_ismine.cpp | 0 src/{ => wallet}/wallet_ismine.h | 0 src/{ => wallet}/walletdb.cpp | 2 +- src/{ => wallet}/walletdb.h | 2 +- 79 files changed, 4847 insertions(+), 152 deletions(-) rename src/{ui_interface.h => guiinterface.h} (97%) rename src/{rpcblockchain.cpp => rpc/blockchain.cpp} (99%) rename src/{rpcmasternode-budget.cpp => rpc/budget.cpp} (99%) rename src/{rpcclient.cpp => rpc/client.cpp} (98%) rename src/{rpcclient.h => rpc/client.h} (100%) create mode 100644 src/rpc/dump.cpp rename src/{rpcmasternode.cpp => rpc/masternode.cpp} (99%) rename src/{rpcmining.cpp => rpc/mining.cpp} (99%) rename src/{rpcmisc.cpp => rpc/misc.cpp} (99%) rename src/{rpcnet.cpp => rpc/net.cpp} (99%) rename src/{rpcprotocol.cpp => rpc/protocol.cpp} (99%) rename src/{rpcprotocol.h => rpc/protocol.h} (100%) rename src/{rpcrawtransaction.cpp => rpc/rawtransaction.cpp} (99%) rename src/{rpcserver.cpp => rpc/server.cpp} (99%) rename src/{rpcserver.h => rpc/server.h} (99%) create mode 100644 src/rpc/wallet.cpp create mode 100644 src/wallet/db.cpp create mode 100644 src/wallet/db.h rename src/{ => wallet}/rpcdump.cpp (99%) rename src/{ => wallet}/rpcwallet.cpp (99%) create mode 100644 src/wallet/test/wallet_tests.cpp rename src/{ => wallet}/wallet.cpp (99%) rename src/{ => wallet}/wallet.h (99%) rename src/{ => wallet}/wallet_ismine.cpp (100%) rename src/{ => wallet}/wallet_ismine.h (100%) rename src/{ => wallet}/walletdb.cpp (99%) rename src/{ => wallet}/walletdb.h (99%) diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index e58c0ce48c..e89aa0d726 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -118,7 +118,7 @@ HEADERS += src/activemasternode.h \ src/tinyformat.h \ src/txdb.h \ src/txmempool.h \ - src/ui_interface.h \ + src/guiinterface.h \ src/uint256.h \ src/undo.h \ src/util.h \ @@ -411,18 +411,18 @@ SOURCES += src/activemasternode.cpp \ src/pubkey.cpp \ src/random.cpp \ src/rest.cpp \ - src/rpcblockchain.cpp \ - src/rpcclient.cpp \ - src/rpcdump.cpp \ - src/rpcmasternode-budget.cpp \ - src/rpcmasternode.cpp \ - src/rpcmining.cpp \ - src/rpcmisc.cpp \ - src/rpcnet.cpp \ - src/rpcprotocol.cpp \ - src/rpcrawtransaction.cpp \ - src/rpcserver.cpp \ - src/rpcwallet.cpp \ + src/rpc/blockchain.cpp \ + src/rpc/client.cpp \ + src/rpc/dump.cpp \ + src/rpc/budget.cpp \ + src/rpc/masternode.cpp \ + src/rpc/mining.cpp \ + src/rpc/misc.cpp \ + src/rpc/net.cpp \ + src/rpc/protocol.cpp \ + src/rpc/rawtransaction.cpp \ + src/rpc/server.cpp \ + src/rpc/wallet.cpp \ src/spork.cpp \ src/sync.cpp \ src/timedata.cpp \ diff --git a/src/Makefile.am b/src/Makefile.am index 68750a2d6f..ea0642c52f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ DIST_SUBDIRS = secp256k1 secp256k1-mw univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) -AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) +AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) AM_LIBTOOLFLAGS = --preserve-dup-deps EXTRA_LIBRARIES = @@ -121,7 +121,7 @@ BITCOIN_CORE_H = \ crypter.h \ obfuscation.h \ obfuscation-relay.h \ - db.h \ + wallet/db.h \ eccryptoverify.h \ ecwrapper.h \ hash.h \ @@ -172,7 +172,7 @@ BITCOIN_CORE_H = \ torcontrol.h \ txdb.h \ txmempool.h \ - ui_interface.h \ + guiinterface.h \ uint256.h \ undo.h \ util.h \ @@ -181,9 +181,9 @@ BITCOIN_CORE_H = \ utiltime.h \ validationinterface.h \ version.h \ - wallet.h \ - wallet_ismine.h \ - walletdb.h \ + wallet/wallet.h \ + wallet/wallet_ismine.h \ + wallet/walletdb.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h \ zmq/zmqnotificationinterface.h \ @@ -215,14 +215,14 @@ libbitcoin_server_a_SOURCES = \ noui.cpp \ pow.cpp \ rest.cpp \ - rpcblockchain.cpp \ - rpcmasternode.cpp \ - rpcmasternode-budget.cpp \ - rpcmining.cpp \ - rpcmisc.cpp \ - rpcnet.cpp \ - rpcrawtransaction.cpp \ - rpcserver.cpp \ + rpc/blockchain.cpp \ + rpc/masternode.cpp \ + rpc/budget.cpp \ + rpc/mining.cpp \ + rpc/misc.cpp \ + rpc/net.cpp \ + rpc/rawtransaction.cpp \ + rpc/server.cpp \ script/sigcache.cpp \ timedata.cpp \ torcontrol.cpp \ @@ -268,7 +268,7 @@ libbitcoin_wallet_a_SOURCES = \ bip38.cpp \ obfuscation.cpp \ obfuscation-relay.cpp \ - db.cpp \ + wallet/db.cpp \ crypter.cpp \ swifttx.cpp \ masternode.cpp \ @@ -277,12 +277,12 @@ libbitcoin_wallet_a_SOURCES = \ masternode-sync.cpp \ masternodeconfig.cpp \ masternodeman.cpp \ - rpcdump.cpp \ - rpcwallet.cpp \ + wallet/rpcdump.cpp \ + wallet/rpcwallet.cpp \ kernel.cpp \ - wallet.cpp \ - wallet_ismine.cpp \ - walletdb.cpp \ + wallet/wallet.cpp \ + wallet/wallet_ismine.cpp \ + wallet/walletdb.cpp \ $(BITCOIN_CORE_H) # crypto primitives library @@ -365,7 +365,7 @@ libbitcoin_util_a_SOURCES = \ chainparamsbase.cpp \ clientversion.cpp \ random.cpp \ - rpcprotocol.cpp \ + rpc/protocol.cpp \ sync.cpp \ uint256.cpp \ util.cpp \ @@ -383,7 +383,7 @@ endif # cli: shared between dapscoin-cli and dapscoin-qt libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_cli_a_SOURCES = \ - rpcclient.cpp \ + rpc/client.cpp \ $(BITCOIN_CORE_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h @@ -399,7 +399,7 @@ dapscoind_LDADD = \ $(LIBLEVELDB) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ - $(LIBSECP256K1_2) + $(LIBSECP256K1_2) if ENABLE_ZMQ dapscoind_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) @@ -431,7 +431,7 @@ dapscoin_cli_LDADD = \ $(CRYPTO_LIBS) \ $(EVENT_LIBS) \ $(LIBSECP256K1) \ - $(LIBSECP256K1_2) + $(LIBSECP256K1_2) dapscoin_cli_SOURCES = \ dapscoin-cli.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 94de6c9a89..876a594be5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -76,7 +76,7 @@ BITCOIN_TESTS =\ if ENABLE_WALLET BITCOIN_TESTS += \ test/accounting_tests.cpp \ - test/wallet_tests.cpp \ + wallet/test/wallet_tests.cpp \ test/rpc_wallet_tests.cpp endif diff --git a/src/activemasternode.h b/src/activemasternode.h index dd69141345..85a11f84ff 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -13,7 +13,7 @@ #include "net.h" #include "obfuscation.h" #include "sync.h" -#include "wallet.h" +#include "wallet/wallet.h" #define ACTIVE_MASTERNODE_INITIAL 0 // initial state #define ACTIVE_MASTERNODE_SYNC_IN_PROCESS 1 diff --git a/src/alert.cpp b/src/alert.cpp index 7a90cf3f90..8024a640fb 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -10,7 +10,7 @@ #include "net.h" #include "pubkey.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/dapscoin-cli.cpp b/src/dapscoin-cli.cpp index aab40e1757..d3b7303047 100644 --- a/src/dapscoin-cli.cpp +++ b/src/dapscoin-cli.cpp @@ -8,8 +8,8 @@ #include "chainparamsbase.h" #include "clientversion.h" -#include "rpcclient.h" -#include "rpcprotocol.h" +#include "rpc/client.h" +#include "rpc/protocol.h" #include "util.h" #include "utilstrencodings.h" diff --git a/src/dapscoin-tx.cpp b/src/dapscoin-tx.cpp index c416efdf09..5fbabacee0 100644 --- a/src/dapscoin-tx.cpp +++ b/src/dapscoin-tx.cpp @@ -13,7 +13,7 @@ #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" -#include "ui_interface.h" // for _(...) +#include "guiinterface.h" // for _(...) #include #include "util.h" #include "utilmoneystr.h" diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 3ad5d6bdd5..3a926cf138 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -11,12 +11,12 @@ #include "main.h" #include "masternodeconfig.h" #include "noui.h" -#include "rpcserver.h" -#include "ui_interface.h" +#include "rpc/server.h" +#include "guiinterface.h" #include "util.h" #include "httpserver.h" #include "httprpc.h" -#include "rpcserver.h" +#include "rpc/server.h" #include #include diff --git a/src/ui_interface.h b/src/guiinterface.h similarity index 97% rename from src/ui_interface.h rename to src/guiinterface.h index da0db95785..e538e61ed8 100644 --- a/src/ui_interface.h +++ b/src/guiinterface.h @@ -3,8 +3,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_UI_INTERFACE_H -#define BITCOIN_UI_INTERFACE_H +#ifndef BITCOIN_GUIINTERFACE_H +#define BITCOIN_GUIINTERFACE_H #include #include @@ -121,4 +121,4 @@ inline std::string _(const char* psz) return rv ? (*rv) : psz; } -#endif // BITCOIN_UI_INTERFACE_H +#endif // BITCOIN_GUIINTERFACE_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index f699371d7e..0df8c344ce 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -9,13 +9,13 @@ #include "base58.h" #include "chainparams.h" #include "httpserver.h" -#include "rpcprotocol.h" -#include "rpcserver.h" +#include "rpc/protocol.h" +#include "rpc/server.h" #include "random.h" #include "sync.h" #include "util.h" #include "utilstrencodings.h" -#include "ui_interface.h" +#include "guiinterface.h" #include // boost::trim diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 15052bdb22..d6b4c77ed2 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -10,9 +10,9 @@ #include "compat.h" #include "util.h" #include "netbase.h" -#include "rpcprotocol.h" // For HTTP status codes +#include "rpc/protocol.h" // For HTTP status codes #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/init.cpp b/src/init.cpp index 774303a545..2067d6e76b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -27,19 +27,19 @@ #include "masternodeman.h" #include "miner.h" #include "net.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/standard.h" #include "scheduler.h" #include "txdb.h" #include "torcontrol.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET -#include "db.h" -#include "wallet.h" -#include "walletdb.h" +#include "wallet/db.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #endif diff --git a/src/main.cpp b/src/main.cpp index d85120a397..18462166e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,7 @@ #include "swifttx.h" #include "txdb.h" #include "txmempool.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index d2c7b64459..461da1d26a 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -7,7 +7,7 @@ #include "net.h" #include "masternodeconfig.h" #include "util.h" -#include "ui_interface.h" +#include "guiinterface.h" #include CMasternodeConfig masternodeConfig; diff --git a/src/miner.cpp b/src/miner.cpp index ba1935a548..2ba99a9e26 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -22,7 +22,7 @@ #include "util.h" #include "utilmoneystr.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" extern CWallet *pwalletMain; #endif #include "masternode-payments.h" diff --git a/src/net.cpp b/src/net.cpp index 905c4cbf48..6edf3c376a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -19,7 +19,7 @@ #include "obfuscation.h" #include "primitives/transaction.h" #include "scheduler.h" -#include "ui_interface.h" +#include "guiinterface.h" #ifdef WIN32 #include diff --git a/src/noui.cpp b/src/noui.cpp index 0253cb51cf..fb4bc7ce9a 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -8,7 +8,7 @@ #include "noui.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index aec4b1bf40..9992ec6d43 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -11,7 +11,7 @@ #include "masternodeman.h" #include "script/sign.h" #include "swifttx.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include #include diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index ac5329faea..44c77b56b8 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -11,7 +11,7 @@ #include "walletmodel.h" #include "base58.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index 0563441ae7..74ad5072b0 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -15,7 +15,7 @@ #include "base58.h" #include "bip38.h" #include "init.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 64ea4642a7..a69c35381c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -34,7 +34,7 @@ #include "init.h" #include "masternodelist.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index ab0ecea91b..10e93612cd 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -8,7 +8,7 @@ #include "net.h" #include "txdb.h" #include "ui_blockexplorer.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" #include diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 25a58e1d30..dd1e9bf95e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -19,7 +19,7 @@ #include "masternode-sync.h" #include "masternodeman.h" #include "net.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 38319c523d..d9ea8400f3 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -18,7 +18,7 @@ #include "coincontrol.h" #include "main.h" #include "obfuscation.h" -#include "wallet.h" +#include "wallet/wallet.h" #include "multisigdialog.h" #include // for 'map_list_of()' diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index d375573541..33f8eacbcd 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -32,12 +32,12 @@ #include "init.h" #include "main.h" -#include "rpcserver.h" -#include "ui_interface.h" +#include "rpc/server.h" +#include "guiinterface.h" #include "util.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include "encryptdialog.h" diff --git a/src/qt/entermnemonics.cpp b/src/qt/entermnemonics.cpp index 1e7d83bca0..c3d9896754 100644 --- a/src/qt/entermnemonics.cpp +++ b/src/qt/entermnemonics.cpp @@ -4,7 +4,7 @@ #include "allocators.h" #include "guiconstants.h" #include "walletmodel.h" -#include "walletdb.h" +#include "wallet/walletdb.h" #include #include diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index 88ebd72617..cafb36db71 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -9,7 +9,7 @@ #include "masternodeconfig.h" #include "masternodeman.h" #include "sync.h" -#include "wallet.h" +#include "wallet/wallet.h" #include "walletmodel.h" #include diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index 6294370f43..effd0dcd24 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -16,7 +16,7 @@ #include "coins.h" #include "keystore.h" #include "init.h" -#include "wallet.h" +#include "wallet/wallet.h" #include "script/sign.h" #include "script/interpreter.h" #include "utilmoneystr.h" diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 31a7a4ce96..dd20cb8126 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -19,7 +19,7 @@ #include "txdb.h" // for -dbcache defaults #ifdef ENABLE_WALLET -#include "wallet.h" // for CWallet::minTxFee +#include "wallet/wallet.h" // for CWallet::minTxFee #endif #include diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index ebbe51d62e..55486914c7 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -22,8 +22,8 @@ #ifdef ENABLE_WALLET #include "masternodeconfig.h" -#include "wallet.h" -#include "walletdb.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #endif #include diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 1e41db6d6a..527b435272 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -18,7 +18,7 @@ #include #include #include -#include "wallet.h" +#include "wallet/wallet.h" class OptionsModel; class WalletModel; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 1f00497061..8d5fb2060a 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -13,9 +13,9 @@ #include "base58.h" #include "chainparams.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index abee055cd9..567837e7b4 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -14,8 +14,8 @@ #include "chainparams.h" #include "main.h" -#include "rpcclient.h" -#include "rpcserver.h" +#include "rpc/client.h" +#include "rpc/server.h" #include "util.h" #include diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 1f0f9bf97c..ffbc98afca 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -19,9 +19,9 @@ #include "base58.h" #include "coincontrol.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "utilmoneystr.h" -#include "wallet.h" +#include "wallet/wallet.h" #include "2faconfirmdialog.h" #include "timedata.h" diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 9f2924f5c6..82f672dcc9 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -14,7 +14,7 @@ #include "base58.h" #include "init.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 002a904351..231f0afaca 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -10,12 +10,12 @@ #include "clientversion.h" #include "init.h" #include "networkstyle.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "version.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 30e5cea651..aeac075eb5 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -13,13 +13,13 @@ #include "transactionrecord.h" #include "base58.h" -#include "db.h" +#include "wallet/db.h" #include "main.h" #include "script/script.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 3d9eb08cb3..4a513211e3 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -11,7 +11,7 @@ #include "obfuscation.h" #include "swifttx.h" #include "timedata.h" -#include "wallet.h" +#include "wallet/wallet.h" #include diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index fb20cac468..eda16a20da 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -16,7 +16,7 @@ #include "sync.h" #include "uint256.h" #include "util.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 3e7b1fff5e..534567de8b 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -16,7 +16,7 @@ #include "transactiontablemodel.h" #include "walletmodel.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ef8a87bf84..0dab47577d 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -17,14 +17,14 @@ #include "base58.h" -#include "db.h" +#include "wallet/db.h" #include "keystore.h" #include "main.h" #include "miner.h" #include "sync.h" -#include "ui_interface.h" -#include "wallet.h" -#include "walletdb.h" // for BackupWallet +#include "guiinterface.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" // for BackupWallet #include #include #include diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 7a91654af3..0d44f88875 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -11,7 +11,7 @@ #include "allocators.h" /* for SecureString */ #include "guiutil.h" #include "swifttx.h" -#include "wallet.h" +#include "wallet/wallet.h" #include "init.h" #include diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index deced7ad5f..1a6d20aee7 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -4,7 +4,7 @@ #include "walletmodeltransaction.h" -#include "wallet.h" +#include "wallet/wallet.h" WalletModelTransaction::WalletModelTransaction(const QList& recipients) : recipients(recipients), walletTransaction(0), diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 23f901f8bd..7a7dbd937d 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -25,7 +25,7 @@ #include "transactionview.h" #include "walletmodel.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/rest.cpp b/src/rest.cpp index 8f983a355d..d310f73bb5 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -8,7 +8,7 @@ #include "primitives/transaction.h" #include "main.h" #include "httpserver.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "streams.h" #include "sync.h" #include "txmempool.h" diff --git a/src/rpcblockchain.cpp b/src/rpc/blockchain.cpp similarity index 99% rename from src/rpcblockchain.cpp rename to src/rpc/blockchain.cpp index 01a695c09f..6fc68b0cb1 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -8,7 +8,7 @@ #include "checkpoints.h" #include "main.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "sync.h" #include "util.h" #include "utilmoneystr.h" diff --git a/src/rpcmasternode-budget.cpp b/src/rpc/budget.cpp similarity index 99% rename from src/rpcmasternode-budget.cpp rename to src/rpc/budget.cpp index 1a7577f508..1071cdaa51 100644 --- a/src/rpcmasternode-budget.cpp +++ b/src/rpc/budget.cpp @@ -5,14 +5,14 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "activemasternode.h" -#include "db.h" +#include "wallet/db.h" #include "init.h" #include "main.h" #include "masternode-budget.h" #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "utilmoneystr.h" #include diff --git a/src/rpcclient.cpp b/src/rpc/client.cpp similarity index 98% rename from src/rpcclient.cpp rename to src/rpc/client.cpp index 9fef0cdaf7..2606714ded 100644 --- a/src/rpcclient.cpp +++ b/src/rpc/client.cpp @@ -6,10 +6,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcclient.h" +#include "rpc/client.h" -#include "rpcprotocol.h" -#include "ui_interface.h" +#include "rpc/protocol.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/rpcclient.h b/src/rpc/client.h similarity index 100% rename from src/rpcclient.h rename to src/rpc/client.h diff --git a/src/rpc/dump.cpp b/src/rpc/dump.cpp new file mode 100644 index 0000000000..ae69b246ab --- /dev/null +++ b/src/rpc/dump.cpp @@ -0,0 +1,504 @@ +// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2018 The PIVX developers +// Copyright (c) 2018-2019 The DAPS Project developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bip38.h" +#include "init.h" +#include "main.h" +#include "rpc/server.h" +#include "script/script.h" +#include "script/standard.h" +#include "sync.h" +#include "util.h" +#include "utilstrencodings.h" +#include "utiltime.h" +#include "wallet/wallet.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace std; + +void EnsureWalletIsUnlocked(); + +std::string static EncodeDumpTime(int64_t nTime) +{ + return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); +} + +int64_t static DecodeDumpTime(const std::string& str) +{ + static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0); + static const std::locale loc(std::locale::classic(), + new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ")); + std::istringstream iss(str); + iss.imbue(loc); + boost::posix_time::ptime ptime(boost::date_time::not_a_date_time); + iss >> ptime; + if (ptime.is_not_a_date_time()) + return 0; + return (ptime - epoch).total_seconds(); +} + +std::string static EncodeDumpString(const std::string& str) +{ + std::stringstream ret; + for (unsigned char c : str) { + if (c <= 32 || c >= 128 || c == '%') { + ret << '%' << HexStr(&c, &c + 1); + } else { + ret << c; + } + } + return ret.str(); +} + +std::string DecodeDumpString(const std::string& str) +{ + std::stringstream ret; + for (unsigned int pos = 0; pos < str.length(); pos++) { + unsigned char c = str[pos]; + if (c == '%' && pos + 2 < str.length()) { + c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) | + ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15)); + pos += 2; + } + ret << c; + } + return ret.str(); +} + +UniValue importprivkey(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 3) + throw runtime_error( + "importprivkey \"dapscoinprivkey\" ( \"label\" rescan )\n" + "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" + "\nArguments:\n" + "1. \"dapscoinprivkey\" (string, required) The private key (see dumpprivkey)\n" + "2. \"label\" (string, optional, default=\"\") An optional label\n" + "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" + "\nNote: This call can take minutes to complete if rescan is true.\n" + "\nExamples:\n" + "\nDump a private key\n" + + HelpExampleCli("dumpprivkey", "\"myaddress\"") + + "\nImport the private key with rescan\n" + HelpExampleCli("importprivkey", "\"mykey\"") + + "\nImport using a label and without rescan\n" + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")); + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strSecret = params[0].get_str(); + string strLabel = ""; + if (params.size() > 1) + strLabel = params[1].get_str(); + + // Whether to perform rescan after import + bool fRescan = true; + if (params.size() > 2) + fRescan = params[2].get_bool(); + + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(strSecret); + + if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); + + CKey key = vchSecret.GetKey(); + if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); + + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + CKeyID vchAddress = pubkey.GetID(); + { + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); + + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(vchAddress)) + return NullUniValue; + + pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + + if (!pwalletMain->AddKeyPubKey(key, pubkey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + + // whenever a key is imported, we need to scan the whole chain + pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' + + if (fRescan) { + pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + } + } + + return NullUniValue; +} + +UniValue importaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 3) + throw runtime_error( + "importaddress \"address\" ( \"label\" rescan )\n" + "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n" + "\nArguments:\n" + "1. \"address\" (string, required) The address\n" + "2. \"label\" (string, optional, default=\"\") An optional label\n" + "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" + "\nNote: This call can take minutes to complete if rescan is true.\n" + "\nExamples:\n" + "\nImport an address with rescan\n" + + HelpExampleCli("importaddress", "\"myaddress\"") + + "\nImport using a label without rescan\n" + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CScript script; + + CBitcoinAddress address(params[0].get_str()); + if (address.IsValid()) { + script = GetScriptForDestination(address.Get()); + } else if (IsHex(params[0].get_str())) { + std::vector data(ParseHex(params[0].get_str())); + script = CScript(data.begin(), data.end()); + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address or script"); + } + + string strLabel = ""; + if (params.size() > 1) + strLabel = params[1].get_str(); + + // Whether to perform rescan after import + bool fRescan = true; + if (params.size() > 2) + fRescan = params[2].get_bool(); + + { + if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); + + // add to address book or update label + if (address.IsValid()) + pwalletMain->SetAddressBook(address.Get(), strLabel, "receive"); + + // Don't throw error in case an address is already there + if (pwalletMain->HaveWatchOnly(script)) + return NullUniValue; + + pwalletMain->MarkDirty(); + + if (!pwalletMain->AddWatchOnly(script)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + + if (fRescan) { + pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + pwalletMain->ReacceptWalletTransactions(); + } + } + + return NullUniValue; +} + +UniValue importwallet(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "importwallet \"filename\"\n" + "\nImports keys from a wallet dump file (see dumpwallet).\n" + "\nArguments:\n" + "1. \"filename\" (string, required) The wallet file\n" + "\nExamples:\n" + "\nDump the wallet\n" + + HelpExampleCli("dumpwallet", "\"test\"") + + "\nImport the wallet\n" + HelpExampleCli("importwallet", "\"test\"") + + "\nImport using the json rpc call\n" + HelpExampleRpc("importwallet", "\"test\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + ifstream file; + file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); + + bool fGood = true; + + int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); + file.seekg(0, file.beg); + + pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI + while (file.good()) { + pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100)))); + std::string line; + std::getline(file, line); + if (line.empty() || line[0] == '#') + continue; + + std::vector vstr; + boost::split(vstr, line, boost::is_any_of(" ")); + if (vstr.size() < 2) + continue; + CBitcoinSecret vchSecret; + if (!vchSecret.SetString(vstr[0])) + continue; + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + CKeyID keyid = pubkey.GetID(); + if (pwalletMain->HaveKey(keyid)) { + LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + continue; + } + int64_t nTime = DecodeDumpTime(vstr[1]); + std::string strLabel; + bool fLabel = true; + for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { + if (boost::algorithm::starts_with(vstr[nStr], "#")) + break; + if (vstr[nStr] == "change=1") + fLabel = false; + if (vstr[nStr] == "reserve=1") + fLabel = false; + if (boost::algorithm::starts_with(vstr[nStr], "label=")) { + strLabel = DecodeDumpString(vstr[nStr].substr(6)); + fLabel = true; + } + } + LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; + if (fLabel) + pwalletMain->SetAddressBook(keyid, strLabel, "receive"); + nTimeBegin = std::min(nTimeBegin, nTime); + } + file.close(); + pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI + + CBlockIndex* pindex = chainActive.Tip(); + while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) + pindex = pindex->pprev; + + if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey) + pwalletMain->nTimeFirstKey = nTimeBegin; + + LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); + pwalletMain->ScanForWalletTransactions(pindex); + pwalletMain->MarkDirty(); + + if (!fGood) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + + return NullUniValue; +} + +UniValue dumpprivkey(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpprivkey \"dapscoinaddress\"\n" + "\nReveals the private key corresponding to 'dapscoinaddress'.\n" + "Then the importprivkey can be used with this output\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address for the private key\n" + "\nResult:\n" + "\"key\" (string) The private key\n" + "\nExamples:\n" + + HelpExampleCli("dumpprivkey", "\"myaddress\"") + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + CKey vchSecret; + if (!pwalletMain->GetKey(keyID, vchSecret)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + return CBitcoinSecret(vchSecret).ToString(); +} + + +UniValue dumpwallet(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpwallet \"filename\"\n" + "\nDumps all wallet keys in a human-readable format.\n" + "\nArguments:\n" + "1. \"filename\" (string, required) The filename\n" + "\nExamples:\n" + + HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + ofstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + std::map mapKeyBirth; + std::set setKeyPool; + pwalletMain->GetKeyBirthTimes(mapKeyBirth); + pwalletMain->GetAllReserveKeys(setKeyPool); + + // sort time/key pairs + std::vector > vKeyBirth; + for (std::map::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { + vKeyBirth.push_back(std::make_pair(it->second, it->first)); + } + mapKeyBirth.clear(); + std::sort(vKeyBirth.begin(), vKeyBirth.end()); + + // produce output + file << strprintf("# Wallet dump created by DAPS %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); + file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); + file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); + file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); + file << "\n"; + for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { + const CKeyID& keyid = it->second; + std::string strTime = EncodeDumpTime(it->first); + std::string strAddr = CBitcoinAddress(keyid).ToString(); + CKey key; + if (pwalletMain->GetKey(keyid, key)) { + if (pwalletMain->mapAddressBook.count(keyid)) { + file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); + } else if (setKeyPool.count(keyid)) { + file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + } else { + file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + } + } + } + file << "\n"; + file << "# End of dump\n"; + file.close(); + return NullUniValue; +} + +UniValue bip38encrypt(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "bip38encrypt \"dapscoinaddress\"\n" + "\nEncrypts a private key corresponding to 'dapscoinaddress'.\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address for the private key (you must hold the key already)\n" + "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with - Valid special chars: !#$%&'()*+,-./:;<=>?`{|}~ \n" + "\nResult:\n" + "\"key\" (string) The encrypted private key\n" + "\nExamples:\n"); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + string strPassphrase = params[1].get_str(); + + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + CKey vchSecret; + if (!pwalletMain->GetKey(keyID, vchSecret)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + + uint256 privKey = vchSecret.GetPrivKey_256(); + string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed()); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("Addess", strAddress)); + result.push_back(Pair("Encrypted Key", encryptedOut)); + + return result; +} + +UniValue bip38decrypt(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "bip38decrypt \"dapscoinaddress\"\n" + "\nDecrypts and then imports password protected private key.\n" + "\nArguments:\n" + "1. \"encryptedkey\" (string, required) The encrypted private key\n" + "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with\n" + + "\nResult:\n" + "\"key\" (string) The decrypted private key\n" + "\nExamples:\n"); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + /** Collect private key and passphrase **/ + string strKey = params[0].get_str(); + string strPassphrase = params[1].get_str(); + + uint256 privKey; + bool fCompressed; + if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) + throw JSONRPCError(RPC_WALLET_ERROR, "Failed To Decrypt"); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("privatekey", HexStr(privKey))); + + CKey key; + key.Set(privKey.begin(), privKey.end(), fCompressed); + + if (!key.IsValid()) + throw JSONRPCError(RPC_WALLET_ERROR, "Private Key Not Valid"); + + CPubKey pubkey = key.GetPubKey(); + pubkey.IsCompressed(); + assert(key.VerifyPubKey(pubkey)); + result.push_back(Pair("Address", CBitcoinAddress(pubkey.GetID()).ToString())); + CKeyID vchAddress = pubkey.GetID(); + { + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBook(vchAddress, "", "receive"); + + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(vchAddress)) + throw JSONRPCError(RPC_WALLET_ERROR, "Key already held by wallet"); + + pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + + if (!pwalletMain->AddKeyPubKey(key, pubkey)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + + // whenever a key is imported, we need to scan the whole chain + pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' + pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + } + + return result; +} diff --git a/src/rpcmasternode.cpp b/src/rpc/masternode.cpp similarity index 99% rename from src/rpcmasternode.cpp rename to src/rpc/masternode.cpp index 47a498ea11..7606febca2 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpc/masternode.cpp @@ -5,14 +5,14 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "activemasternode.h" -#include "db.h" +#include "wallet/db.h" #include "init.h" #include "main.h" #include "masternode-budget.h" #include "masternode-payments.h" #include "masternodeconfig.h" #include "masternodeman.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "utilmoneystr.h" #include diff --git a/src/rpcmining.cpp b/src/rpc/mining.cpp similarity index 99% rename from src/rpcmining.cpp rename to src/rpc/mining.cpp index babce3ee28..82b3468ff8 100644 --- a/src/rpcmining.cpp +++ b/src/rpc/mining.cpp @@ -15,11 +15,11 @@ #include "miner.h" #include "net.h" #include "pow.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "util.h" #ifdef ENABLE_WALLET -#include "db.h" -#include "wallet.h" +#include "wallet/db.h" +#include "wallet/wallet.h" #endif #include diff --git a/src/rpcmisc.cpp b/src/rpc/misc.cpp similarity index 99% rename from src/rpcmisc.cpp rename to src/rpc/misc.cpp index 88ed9cc12a..b9e05244e0 100644 --- a/src/rpcmisc.cpp +++ b/src/rpc/misc.cpp @@ -13,13 +13,13 @@ #include "masternode-sync.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "timedata.h" #include "util.h" #ifdef ENABLE_WALLET -#include "wallet.h" -#include "walletdb.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #endif #include diff --git a/src/rpcnet.cpp b/src/rpc/net.cpp similarity index 99% rename from src/rpcnet.cpp rename to src/rpc/net.cpp index 4783ce240e..509b333149 100644 --- a/src/rpcnet.cpp +++ b/src/rpc/net.cpp @@ -5,7 +5,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "rpc/server.h" #include "clientversion.h" #include "main.h" @@ -14,7 +14,7 @@ #include "protocol.h" #include "sync.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "version.h" diff --git a/src/rpcprotocol.cpp b/src/rpc/protocol.cpp similarity index 99% rename from src/rpcprotocol.cpp rename to src/rpc/protocol.cpp index e592b4f69e..b500fa4298 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpc/protocol.cpp @@ -6,7 +6,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "random.h" #include "tinyformat.h" diff --git a/src/rpcprotocol.h b/src/rpc/protocol.h similarity index 100% rename from src/rpcprotocol.h rename to src/rpc/protocol.h diff --git a/src/rpcrawtransaction.cpp b/src/rpc/rawtransaction.cpp similarity index 99% rename from src/rpcrawtransaction.cpp rename to src/rpc/rawtransaction.cpp index 8e07835be6..88ca93e78b 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -13,15 +13,15 @@ #include "main.h" #include "net.h" #include "primitives/transaction.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/script.h" #include "script/sign.h" #include "script/standard.h" #include "uint256.h" #include "utilmoneystr.h" -#include "wallet.h" +#include "wallet/wallet.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include diff --git a/src/rpcserver.cpp b/src/rpc/server.cpp similarity index 99% rename from src/rpcserver.cpp rename to src/rpc/server.cpp index 8819719c67..c3a08b37c0 100644 --- a/src/rpcserver.cpp +++ b/src/rpc/server.cpp @@ -6,19 +6,19 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "rpc/server.h" #include "base58.h" #include "init.h" #include "main.h" #include "random.h" #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" #ifdef ENABLE_WALLET -#include "wallet.h" +#include "wallet/wallet.h" #endif #include diff --git a/src/rpcserver.h b/src/rpc/server.h similarity index 99% rename from src/rpcserver.h rename to src/rpc/server.h index 56a8054865..c5aca92be3 100644 --- a/src/rpcserver.h +++ b/src/rpc/server.h @@ -9,7 +9,7 @@ #define BITCOIN_RPCSERVER_H #include "amount.h" -#include "rpcprotocol.h" +#include "rpc/protocol.h" #include "uint256.h" #include @@ -279,7 +279,7 @@ extern UniValue decodescript(const UniValue& params, bool fHelp); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); -extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp +extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); extern UniValue settxfee(const UniValue& params, bool fHelp); diff --git a/src/rpc/wallet.cpp b/src/rpc/wallet.cpp new file mode 100644 index 0000000000..f99bf4906a --- /dev/null +++ b/src/rpc/wallet.cpp @@ -0,0 +1,3015 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2018 The PIVX developers +// Copyright (c) 2018-2019 The DAPS Project developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "amount.h" +#include "base58.h" +#include "core_io.h" +#include "init.h" +#include "net.h" +#include "netbase.h" +#include "rpc/server.h" +#include "timedata.h" +#include "util.h" +#include "utilmoneystr.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::assign; + +int64_t nWalletUnlockTime; +static CCriticalSection cs_nWalletUnlockTime; + +std::string HelpRequiringPassphrase() +{ + return pwalletMain && pwalletMain->IsCrypted() ? "\nRequires wallet passphrase to be set with walletpassphrase call." : ""; +} + +void EnsureWalletIsUnlocked() +{ + if (pwalletMain->IsLocked() || pwalletMain->fWalletUnlockAnonymizeOnly) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with unlockwallet first."); +} + +void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) +{ + int confirms = wtx.GetDepthInMainChain(false); + int confirmsTotal = GetIXConfirmations(wtx.GetHash()) + confirms; + entry.push_back(Pair("confirmations", confirmsTotal)); + entry.push_back(Pair("bcconfirmations", confirms)); + if (wtx.IsCoinBase() || wtx.IsCoinStake()) + entry.push_back(Pair("generated", true)); + if (confirms > 0) { + entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); + entry.push_back(Pair("blockindex", wtx.nIndex)); + entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + } + uint256 hash = wtx.GetHash(); + entry.push_back(Pair("txid", hash.GetHex())); + UniValue conflicts(UniValue::VARR); + for (const uint256& conflict : wtx.GetConflicts()) + conflicts.push_back(conflict.GetHex()); + entry.push_back(Pair("walletconflicts", conflicts)); + entry.push_back(Pair("time", wtx.GetTxTime())); + entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); + for (const PAIRTYPE(string, string) & item : wtx.mapValue) + entry.push_back(Pair(item.first, item.second)); +} + +string AccountFromValue(const UniValue& value) +{ + string strAccount = value.get_str(); + if (strAccount == "*") + throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); + return strAccount; +} + +UniValue getnewaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnewaddress ( \"account\" )\n" + "\nReturns a new DAPS address for receiving payments.\n" + "If 'account' is specified (recommended), it is added to the address book \n" + "so payments received with the address will be credited to 'account'.\n" + "\nArguments:\n" + "1. \"account\" (string, optional) The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" + "\nResult:\n" + "\"dapscoinaddress\" (string) The new dapscoin address\n" + "\nExamples:\n" + + HelpExampleCli("getnewaddress", "") + HelpExampleCli("getnewaddress", "\"\"") + HelpExampleCli("getnewaddress", "\"myaccount\"") + HelpExampleRpc("getnewaddress", "\"myaccount\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + // Parse the account first so we don't generate a key if there's an error + string strAccount; + if (params.size() > 0) + strAccount = AccountFromValue(params[0]); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + // Generate a new key that is added to wallet + CPubKey newKey; + if (!pwalletMain->GetKeyFromPool(newKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + CKeyID keyID = newKey.GetID(); + + pwalletMain->SetAddressBook(keyID, strAccount, "receive"); + + return CBitcoinAddress(keyID).ToString(); +} + + +CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + + CAccount account; + walletdb.ReadAccount(strAccount, account); + + bool bKeyUsed = false; + + // Check if the current key has been used + if (account.vchPubKey.IsValid()) { + CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); + ++it) { + const CWalletTx& wtx = (*it).second; + for (const CTxOut& txout : wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + bKeyUsed = true; + } + } + + // Generate a new key + if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { + EnsureWalletIsUnlocked(); + if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); + walletdb.WriteAccount(strAccount, account); + } + + return CBitcoinAddress(account.vchPubKey.GetID()); +} + +CBitcoinAddress GetHDAccountAddress(string strAccount, uint32_t nAccountIndex, bool bForceNew = false) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + + CAccount account; + walletdb.ReadAccount(strAccount, account); + + bool bKeyUsed = false; + + // Check if the current key has been used + if (account.vchPubKey.IsValid()) { + CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); + ++it) { + const CWalletTx& wtx = (*it).second; + for (const CTxOut& txout : wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + bKeyUsed = true; + } + } + + // Generate a new key + if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { + EnsureWalletIsUnlocked(); + // if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) + // throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + CKey newKey; + pwalletMain->DeriveNewChildKey(nAccountIndex, newKey); + account.vchPubKey = newKey.GetPubKey(); + account.nAccountIndex = nAccountIndex; + + pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); + walletdb.WriteAccount(strAccount, account); + } + + return CBitcoinAddress(account.vchPubKey.GetID()); +} + +UniValue getaccountaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccountaddress \"account\"\n" + "\nReturns the current DAPS address for receiving payments to this account.\n" + "\nArguments:\n" + "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n" + "\nResult:\n" + "\"dapscoinaddress\" (string) The account dapscoin address\n" + "\nExamples:\n" + + HelpExampleCli("getaccountaddress", "") + HelpExampleCli("getaccountaddress", "\"\"") + HelpExampleCli("getaccountaddress", "\"myaccount\"") + HelpExampleRpc("getaccountaddress", "\"myaccount\"")); + LOCK2(cs_main, pwalletMain->cs_wallet); + + // Parse the account first so we don't generate a key if there's an error + string strAccount = AccountFromValue(params[0]); + + UniValue ret(UniValue::VSTR); + + ret = GetAccountAddress(strAccount).ToString(); + return ret; +} + +UniValue getrawchangeaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getrawchangeaddress\n" + "\nReturns a new DAPS address, for receiving change.\n" + "This is for use with raw transactions, NOT normal use.\n" + "\nResult:\n" + "\"address\" (string) The address\n" + "\nExamples:\n" + + HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "")); + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + CReserveKey reservekey(pwalletMain); + CPubKey vchPubKey; + if (!reservekey.GetReservedKey(vchPubKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + reservekey.KeepKey(); + + CKeyID keyID = vchPubKey.GetID(); + + return CBitcoinAddress(keyID).ToString(); +} + +UniValue setaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setaccount \"dapscoinaddress\" \"account\"\n" + "\nSets the account associated with the given address.\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address to be associated with an account.\n" + "2. \"account\" (string, required) The account to assign the address to.\n" + "\nExamples:\n" + + HelpExampleCli("setaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"tabby\"") + HelpExampleRpc("setaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", \"tabby\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + + string strAccount; + if (params.size() > 1) + strAccount = AccountFromValue(params[1]); + + // Only add the account if the address is yours. + if (IsMine(*pwalletMain, address.Get())) { + // Detect when changing the account of an address that is the 'unused current key' of another account: + if (pwalletMain->mapAddressBook.count(address.Get())) { + string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; + if (address == GetAccountAddress(strOldAccount)) + GetAccountAddress(strOldAccount, true); + } + pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); + } else + throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); + return NullUniValue; +} + + +UniValue getaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccount \"dapscoinaddress\"\n" + "\nReturns the account associated with the given address.\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address for account lookup.\n" + "\nResult:\n" + "\"accountname\" (string) the account address\n" + "\nExamples:\n" + + HelpExampleCli("getaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"") + HelpExampleRpc("getaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + + string strAccount; + map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) + strAccount = (*mi).second.name; + + return strAccount; +} + +UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressesbyaccount \"account\"\n" + "\nReturns the list of addresses for the given account.\n" + "\nArguments:\n" + "1. \"account\" (string, required) The account name.\n" + "\nResult:\n" + "[ (json array of string)\n" + " \"dapscoinaddress\" (string) a dapscoin address associated with the given account\n" + " ,...\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getaddressesbyaccount", "\"tabby\"") + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount = AccountFromValue(params[0]); + + // Find all addresses that have the given account + UniValue ret(UniValue::VARR); + for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { + const CBitcoinAddress& address = item.first; + const string& strName = item.second.name; + if (strName == strAccount) + ret.push_back(address.ToString()); + } + return ret; +} + +void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, bool fUseIX = false) +{ + // Check amount + if (nValue <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); + + string strError; + if (pwalletMain->IsLocked()) { + strError = "Error: Wallet locked, unable to create transaction!"; + LogPrintf("SendMoney() : %s", strError); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + + // Parse DAPS address + CScript scriptPubKey = GetScriptForDestination(address); + + // Create and send the transaction + CReserveKey reservekey(pwalletMain); + CAmount nFeeRequired; + if (!pwalletMain->CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError, NULL, ALL_COINS, fUseIX, (CAmount)0)) { + if (nValue + nFeeRequired > pwalletMain->GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); + LogPrintf("SendMoney() : %s\n", strError); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + if (!pwalletMain->CommitTransaction(wtxNew, reservekey, (!fUseIX ? "tx" : "ix"))) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); +} + +UniValue sendtoaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "sendtoaddress \"dapscoinaddress\" amount \n" + "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address to send to.\n" + "2. \"amount\" (numeric, required) The amount in DAPS to send. eg 0.1\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + + HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1") + HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.1, \"donation\", \"seans outpost\"")); + + std::string stealthAddr = params[0].get_str(); + + // Amount + CAmount nAmount = AmountFromValue(params[1]); + + // Wallet comments + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { + throw JSONRPCError(RPC_WALLET_ERROR, + "Failed to create transaction."); + } + return wtx.GetHash().GetHex(); +} + +UniValue sendtoaddressix(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendtoaddressix \"dapscoinaddress\" amount\n" + "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address to send to.\n" + "2. \"amount\" (numeric, required) The amount in DAPS to send. eg 0.1\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + + HelpExampleCli("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1") + HelpExampleCli("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.1, \"donation\", \"seans outpost\"")); + + std::string stealthAddr = params[0].get_str(); + + // Amount + CAmount nAmount = AmountFromValue(params[1]); + + // Wallet comments + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { + throw JSONRPCError(RPC_WALLET_ERROR, + "Failed to create transaction."); + } + return wtx.GetHash().GetHex(); +} + +UniValue listaddressgroupings(const UniValue& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listaddressgroupings\n" + "\nLists groups of addresses which have had their common ownership\n" + "made public by common use as inputs or as the resulting change\n" + "in past transactions\n" + "\nResult:\n" + "[\n" + " [\n" + " [\n" + " \"dapscoinaddress\", (string) The dapscoin address\n" + " amount, (numeric) The amount in DAPS\n" + " \"account\" (string, optional) The account\n" + " ]\n" + " ,...\n" + " ]\n" + " ,...\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue jsonGroupings(UniValue::VARR); + map balances = pwalletMain->GetAddressBalances(); + for (set grouping : pwalletMain->GetAddressGroupings()) { + UniValue jsonGrouping(UniValue::VARR); + for (CTxDestination address : grouping) { + UniValue addressInfo(UniValue::VARR); + addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(ValueFromAmount(balances[address])); + { + if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) + addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); + } + jsonGrouping.push_back(addressInfo); + } + jsonGroupings.push_back(jsonGrouping); + } + return jsonGroupings; +} + +UniValue signmessage(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "signmessage \"dapscoinaddress\" \"message\"\n" + "\nSign a message with the private key of an address" + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address to use for the private key.\n" + "2. \"message\" (string, required) The message to create a signature of.\n" + "\nResult:\n" + "\"signature\" (string) The signature of the message encoded in base 64\n" + "\nExamples:\n" + "\nUnlock the wallet for 30 seconds\n" + + HelpExampleCli("unlockwallet", "\"mypassphrase\" 30") + + "\nCreate the signature\n" + HelpExampleCli("signmessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"my message\"") + + "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"signature\" \"my message\"") + + "\nAs json rpc\n" + HelpExampleRpc("signmessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", \"my message\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + string strMessage = params[1].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); + + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; + + vector vchSig; + if (!key.SignCompact(ss.GetHash(), vchSig)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); + + return EncodeBase64(&vchSig[0], vchSig.size()); +} + +UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaddress \"dapscoinaddress\" ( minconf )\n" + "\nReturns the total amount received by the given dapscoinaddress in transactions with at least minconf confirmations.\n" + "\nArguments:\n" + "1. \"dapscoinaddress\" (string, required) The dapscoin address for transactions.\n" + "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" + "\nResult:\n" + "amount (numeric) The total amount in DAPS received at this address.\n" + "\nExamples:\n" + "\nThe amount from transactions with at least 1 confirmation\n" + + HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"") + + "\nThe amount including unconfirmed transactions, zero confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0") + + "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 6") + + "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 6")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + // dapscoin address + CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + CScript scriptPubKey = GetScriptForDestination(address.Get()); + if (!IsMine(*pwalletMain, scriptPubKey)) + return (double)0.0; + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Tally + CAmount nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || !IsFinalTx(wtx)) + continue; + + for (const CTxOut& txout : wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + + return ValueFromAmount(nAmount); +} + + +UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaccount \"account\" ( minconf )\n" + "\nReturns the total amount received by addresses with in transactions with at least [minconf] confirmations.\n" + "\nArguments:\n" + "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n" + "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" + "\nResult:\n" + "amount (numeric) The total amount in DAPS received for this account.\n" + "\nExamples:\n" + "\nAmount received by the default account with at least 1 confirmation\n" + + HelpExampleCli("getreceivedbyaccount", "\"\"") + + "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n" + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") + + "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") + + "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Get the set of pub keys assigned to accountValue getreceivedbyaccount(const Array& params, bool fHelp) + string strAccount = AccountFromValue(params[0]); + set setAddress = pwalletMain->GetAccountAddresses(strAccount); + + // Tally + CAmount nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || !IsFinalTx(wtx)) + continue; + + for (const CTxOut& txout : wtx.vout) { + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + } + + return (double)nAmount / (double)COIN; +} + + +CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) +{ + CAmount nBalance = 0; + + // Tally wallet transactions + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) + continue; + + CAmount nReceived, nSent, nFee; + wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); + + if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) + nBalance += nReceived; + nBalance -= nSent + nFee; + } + + // Tally internal accounting entries + nBalance += walletdb.GetAccountCreditDebit(strAccount); + + return nBalance; +} + +CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); +} + +UniValue getbalance(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "getbalance ( \"account\" minconf includeWatchonly )\n" + "\nIf account is not specified, returns the server's total available balance.\n" + "If account is specified, returns the balance in the account.\n" + "Note that the account \"\" is not the same as leaving the parameter out.\n" + "The server total may be different to the balance in the default \"\" account.\n" + "\nArguments:\n" + "1. \"account\" (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n" + "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" + "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n" + "\nResult:\n" + "amount (numeric) The total amount in DAPS received for this account.\n" + "\nExamples:\n" + "\nThe total amount in the server across all accounts\n" + + HelpExampleCli("getbalance", "") + + "\nThe total amount in the server across all accounts, with at least 5 confirmations\n" + HelpExampleCli("getbalance", "\"*\" 6") + + "\nThe total amount in the default account with at least 1 confirmation\n" + HelpExampleCli("getbalance", "\"\"") + + "\nThe total amount in the account named tabby with at least 6 confirmations\n" + HelpExampleCli("getbalance", "\"tabby\" 6") + + "\nAs a json rpc call\n" + HelpExampleRpc("getbalance", "\"tabby\", 6")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (params.size() == 0) + return ValueFromAmount(pwalletMain->GetBalance()); + + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + isminefilter filter = ISMINE_SPENDABLE; + if (params.size() > 2) + if (params[2].get_bool()) + filter = filter | ISMINE_WATCH_ONLY; + + if (params[0].get_str() == "*") { + // Calculate total balance a different way from GetBalance() + // (GetBalance() sums up all unspent TxOuts) + // getbalance and "getbalance * 1 true" should return the same number + CAmount nBalance = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) + continue; + + CAmount allFee; + string strSentAccount; + list listReceived; + list listSent; + wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); + if (wtx.GetDepthInMainChain() >= nMinDepth) { + for (const COutputEntry& r : listReceived) + nBalance += r.amount; + } + for (const COutputEntry& s : listSent) + nBalance -= s.amount; + nBalance -= allFee; + } + return ValueFromAmount(nBalance); + } + + string strAccount = AccountFromValue(params[0]); + + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter); + + return ValueFromAmount(nBalance); +} + +UniValue getbalances(const UniValue& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "getbalances" + "\nArguments:\n" + "\nResult:\n" + "total (numeric) The total amount in DAPS received for this wallet.\n" + "spendable (numeric) The total amount in DAPS spendable for this wallet.\n" + "pending (numeric) The total amount in DAPS pending for this wallet." + "\nExamples:\n" + "\nThe total amount in the server across all accounts\n" + + HelpExampleCli("getbalances", "")); + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("total", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("spendable", ValueFromAmount(pwalletMain->GetSpendableBalance()))); + obj.push_back(Pair("pending", ValueFromAmount(pwalletMain->GetUnconfirmedBalance()))); + + return obj; +} + +UniValue getunconfirmedbalance(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "getunconfirmedbalance\n" + "Returns the server's total unconfirmed balance\n"); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + return ValueFromAmount(pwalletMain->GetUnconfirmedBalance()); +} + +UniValue movecmd(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 5) + throw runtime_error( + "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" + "\nMove a specified amount from one account in your wallet to another.\n" + "\nArguments:\n" + "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" + "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" + "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" + "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" + "\nResult:\n" + "true|false (boolean) true if successfull.\n" + "\nExamples:\n" + "\nMove 0.01 DAPS from the default account to the account named tabby\n" + + HelpExampleCli("move", "\"\" \"tabby\" 0.01") + + "\nMove 0.01 DAPS timotei to akiko with a comment and funds have 6 confirmations\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strFrom = AccountFromValue(params[0]); + string strTo = AccountFromValue(params[1]); + CAmount nAmount = AmountFromValue(params[2]); + if (params.size() > 3) + // unused parameter, used to be nMinDepth, keep type-checking it though + (void)params[3].get_int(); + string strComment; + if (params.size() > 4) + strComment = params[4].get_str(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.TxnBegin()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + int64_t nNow = GetAdjustedTime(); + + // Debit + CAccountingEntry debit; + debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + debit.strAccount = strFrom; + debit.nCreditDebit = -nAmount; + debit.nTime = nNow; + debit.strOtherAccount = strTo; + debit.strComment = strComment; + pwalletMain->AddAccountingEntry(debit, walletdb); + + // Credit + CAccountingEntry credit; + credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + credit.strAccount = strTo; + credit.nCreditDebit = nAmount; + credit.nTime = nNow; + credit.strOtherAccount = strFrom; + credit.strComment = strComment; + pwalletMain->AddAccountingEntry(credit, walletdb); + + if (!walletdb.TxnCommit()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + return true; +} + +UniValue sendfrom(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 6) + throw runtime_error( + "sendfrom \"fromaccount\" \"todapscoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" + "\nSent an amount from an account to a dapscoin address.\n" + "The amount is a real and is rounded to the nearest 0.00000001." + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n" + "2. \"todapscoinaddress\" (string, required) The dapscoin address to send funds to.\n" + "3. amount (numeric, required) The amount in DAPS. (transaction fee is added on top).\n" + "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" + "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" + " This is not part of the transaction, just kept in your wallet.\n" + "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n" + " to which you're sending the transaction. This is not part of the transaction, \n" + " it is just kept in your wallet.\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + "\nSend 0.01 DAPS from the default account to the address, must have at least 1 confirmation\n" + + HelpExampleCli("sendfrom", "\"\" \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.01") + + "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n" + HelpExampleCli("sendfrom", "\"tabby\" \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.01 6 \"donation\" \"seans outpost\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("sendfrom", "\"tabby\", \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.01, 6, \"donation\", \"seans outpost\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount = AccountFromValue(params[0]); + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + CAmount nAmount = AmountFromValue(params[2]); + int nMinDepth = 1; + if (params.size() > 3) + nMinDepth = params[3].get_int(); + + CWalletTx wtx; + wtx.strFromAccount = strAccount; + if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty()) + wtx.mapValue["comment"] = params[4].get_str(); + if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty()) + wtx.mapValue["to"] = params[5].get_str(); + + EnsureWalletIsUnlocked(); + + // Check funds + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + if (nAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + SendMoney(address.Get(), nAmount, wtx); + + return wtx.GetHash().GetHex(); +} + +UniValue sendmany(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n" + "\nSend multiple times. Amounts are double-precision floating point numbers." + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. \"fromaccount\" (string, required) The account to send the funds from, can be \"\" for the default account\n" + "2. \"amounts\" (string, required) A json object with addresses and amounts\n" + " {\n" + " \"address\":amount (numeric) The dapscoin address is the key, the numeric amount in DAPS is the value\n" + " ,...\n" + " }\n" + "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n" + "4. \"comment\" (string, optional) A comment\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" + " the number of addresses.\n" + "\nExamples:\n" + "\nSend two amounts to two different addresses:\n" + + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\"") + + "\nSend two amounts to two different addresses setting the confirmation and comment:\n" + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\" 6 \"testing\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\", 6, \"testing\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount = AccountFromValue(params[0]); + UniValue sendTo = params[1].get_obj(); + int nMinDepth = 1; + if (params.size() > 2) + nMinDepth = params[2].get_int(); + + CWalletTx wtx; + wtx.strFromAccount = strAccount; + if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) + wtx.mapValue["comment"] = params[3].get_str(); + + set setAddress; + vector > vecSend; + + CAmount totalAmount = 0; + vector keys = sendTo.getKeys(); + for (const string& name_ : keys) { + CBitcoinAddress address(name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid PIVX address: ")+name_); + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + setAddress.insert(address); + + CScript scriptPubKey = GetScriptForDestination(address.Get()); + CAmount nAmount = AmountFromValue(sendTo[name_]); + totalAmount += nAmount; + + vecSend.push_back(make_pair(scriptPubKey, nAmount)); + } + + EnsureWalletIsUnlocked(); + + // Check funds + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + if (totalAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + // Send + CReserveKey keyChange(pwalletMain); + CAmount nFeeRequired = 0; + string strFailReason; + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); + if (!fCreated) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); + if (!pwalletMain->CommitTransaction(wtx, keyChange)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + return wtx.GetHash().GetHex(); +} + +// Defined in rpcmisc.cpp +extern CScript _createmultisig_redeemScript(const UniValue& params); + +UniValue addmultisigaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) { + string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" + "\nAdd a nrequired-to-sign multisignature address to the wallet.\n" + "Each key is a DAPS address or hex-encoded public key.\n" + "If 'account' is specified, assign address to that account.\n" + + "\nArguments:\n" + "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" + "2. \"keysobject\" (string, required) A json array of dapscoin addresses or hex-encoded public keys\n" + " [\n" + " \"address\" (string) dapscoin address or hex-encoded public key\n" + " ...,\n" + " ]\n" + "3. \"account\" (string, optional) An account to assign the addresses to.\n" + + "\nResult:\n" + "\"dapscoinaddress\" (string) A dapscoin address associated with the keys.\n" + + "\nExamples:\n" + "\nAdd a multisig address from 2 addresses\n" + + HelpExampleCli("addmultisigaddress", "2 \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\"") + + "\nAs json rpc call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\""); + throw runtime_error(msg); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount; + if (params.size() > 2) + strAccount = AccountFromValue(params[2]); + + // Construct using pay-to-script-hash: + CScript inner = _createmultisig_redeemScript(params); + CScriptID innerID(inner); + pwalletMain->AddCScript(inner); + + pwalletMain->SetAddressBook(innerID, strAccount, "send"); + return CBitcoinAddress(innerID).ToString(); +} + + +struct tallyitem { + CAmount nAmount; + int nConf; + int nBCConf; + vector txids; + bool fIsWatchonly; + tallyitem() + { + nAmount = 0; + nConf = std::numeric_limits::max(); + nBCConf = std::numeric_limits::max(); + fIsWatchonly = false; + } +}; + +UniValue ListReceived(const UniValue& params, bool fByAccounts) +{ + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + // Whether to include empty accounts + bool fIncludeEmpty = false; + if (params.size() > 1) + fIncludeEmpty = params[1].get_bool(); + + isminefilter filter = ISMINE_SPENDABLE; + if (params.size() > 2) + if (params[2].get_bool()) + filter = filter | ISMINE_WATCH_ONLY; + + // Tally + map mapTally; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + + if (wtx.IsCoinBase() || !IsFinalTx(wtx)) + continue; + + int nDepth = wtx.GetDepthInMainChain(); + int nBCDepth = wtx.GetDepthInMainChain(false); + if (nDepth < nMinDepth) + continue; + + for (const CTxOut& txout : wtx.vout) { + CTxDestination address; + if (!ExtractDestination(txout.scriptPubKey, address)) + continue; + + isminefilter mine = IsMine(*pwalletMain, address); + if (!(mine & filter)) + continue; + + tallyitem& item = mapTally[address]; + item.nAmount += txout.nValue; + item.nConf = min(item.nConf, nDepth); + item.nBCConf = min(item.nBCConf, nBCDepth); + item.txids.push_back(wtx.GetHash()); + if (mine & ISMINE_WATCH_ONLY) + item.fIsWatchonly = true; + } + } + + // Reply + UniValue ret(UniValue::VARR); + map mapAccountTally; + for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { + const CBitcoinAddress& address = item.first; + const string& strAccount = item.second.name; + map::iterator it = mapTally.find(address); + if (it == mapTally.end() && !fIncludeEmpty) + continue; + + CAmount nAmount = 0; + int nConf = std::numeric_limits::max(); + int nBCConf = std::numeric_limits::max(); + bool fIsWatchonly = false; + if (it != mapTally.end()) { + nAmount = (*it).second.nAmount; + nConf = (*it).second.nConf; + nBCConf = (*it).second.nBCConf; + fIsWatchonly = (*it).second.fIsWatchonly; + } + + if (fByAccounts) { + tallyitem& item = mapAccountTally[strAccount]; + item.nAmount += nAmount; + item.nConf = min(item.nConf, nConf); + item.nBCConf = min(item.nBCConf, nBCConf); + item.fIsWatchonly = fIsWatchonly; + } else { + UniValue obj(UniValue::VOBJ); + if (fIsWatchonly) + obj.push_back(Pair("involvesWatchonly", true)); + obj.push_back(Pair("address", address.ToString())); + obj.push_back(Pair("account", strAccount)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); + UniValue transactions(UniValue::VARR); + if (it != mapTally.end()) { + for (const uint256& item : (*it).second.txids) { + transactions.push_back(item.GetHex()); + } + } + obj.push_back(Pair("txids", transactions)); + ret.push_back(obj); + } + } + + if (fByAccounts) { + for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { + CAmount nAmount = (*it).second.nAmount; + int nConf = (*it).second.nConf; + int nBCConf = (*it).second.nBCConf; + UniValue obj(UniValue::VOBJ); + if ((*it).second.fIsWatchonly) + obj.push_back(Pair("involvesWatchonly", true)); + obj.push_back(Pair("account", (*it).first)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); + ret.push_back(obj); + } + } + + return ret; +} + +UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n" + "\nList balances by receiving address.\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" + "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n" + "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" + + "\nResult:\n" + "[\n" + " {\n" + " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" + " \"address\" : \"receivingaddress\", (string) The receiving address\n" + " \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n" + " \"amount\" : x.xxx, (numeric) The total amount in DAPS received by the address\n" + " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" + " \"bcconfirmations\" : n (numeric) The number of blockchain confirmations of the most recent transaction included\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples:\n" + + HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + return ListReceived(params, false); +} + +UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" + "\nList balances by account.\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" + "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n" + "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" + + "\nResult:\n" + "[\n" + " {\n" + " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" + " \"account\" : \"accountname\", (string) The account name of the receiving account\n" + " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n" + " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" + " \"bcconfirmations\" : n (numeric) The number of blockchain confirmations of the most recent transaction included\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples:\n" + + HelpExampleCli("listreceivedbyaccount", "") + HelpExampleCli("listreceivedbyaccount", "6 true") + HelpExampleRpc("listreceivedbyaccount", "6, true, true")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + return ListReceived(params, true); +} + +static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) +{ + CBitcoinAddress addr; + if (addr.Set(dest)) + entry.push_back(Pair("address", addr.ToString())); +} + +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) +{ + CAmount nFee; + string strSentAccount; + list listReceived; + list listSent; + + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); + + bool fAllAccounts = (strAccount == string("*")); + bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); + + // Sent + if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { + for (const COutputEntry& s : listSent) { + UniValue entry(UniValue::VOBJ); + if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); + entry.push_back(Pair("account", strSentAccount)); + MaybePushAddress(entry, s.destination); + std::map::const_iterator it = wtx.mapValue.find("DS"); + entry.push_back(Pair("category", (it != wtx.mapValue.end() && it->second == "1") ? "darksent" : "send")); + entry.push_back(Pair("amount", ValueFromAmount(-s.amount))); + entry.push_back(Pair("vout", s.vout)); + entry.push_back(Pair("fee", ValueFromAmount(-nFee))); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + + // Received + if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { + for (const COutputEntry& r : listReceived) { + string account; + if (pwalletMain->mapAddressBook.count(r.destination)) + account = pwalletMain->mapAddressBook[r.destination].name; + if (fAllAccounts || (account == strAccount)) { + UniValue entry(UniValue::VOBJ); + if (involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); + entry.push_back(Pair("account", account)); + MaybePushAddress(entry, r.destination); + if (wtx.IsCoinBase()) { + if (wtx.GetDepthInMainChain() < 1) + entry.push_back(Pair("category", "orphan")); + else if (wtx.GetBlocksToMaturity() > 0) + entry.push_back(Pair("category", "immature")); + else + entry.push_back(Pair("category", "generate")); + } else { + entry.push_back(Pair("category", "receive")); + } + entry.push_back(Pair("amount", ValueFromAmount(r.amount))); + entry.push_back(Pair("vout", r.vout)); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + } +} + +void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) +{ + bool fAllAccounts = (strAccount == string("*")); + + if (fAllAccounts || acentry.strAccount == strAccount) { + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("account", acentry.strAccount)); + entry.push_back(Pair("category", "move")); + entry.push_back(Pair("time", acentry.nTime)); + entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); + entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); + entry.push_back(Pair("comment", acentry.strComment)); + ret.push_back(entry); + } +} + +UniValue listtransactions(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 4) + throw runtime_error( + "listtransactions ( \"account\" count from includeWatchonly)\n" + "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" + "\nArguments:\n" + "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n" + " If \"\" is set, it will list transactions for the default account.\n" + "2. count (numeric, optional, default=10) The number of transactions to return\n" + "3. from (numeric, optional, default=0) The number of transactions to skip\n" + "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n" + "\nResult:\n" + "[\n" + " {\n" + " \"account\":\"accountname\", (string) The account name associated with the transaction. \n" + " It will be \"\" for the default account.\n" + " \"address\":\"dapscoinaddress\", (string) The dapscoin address of the transaction. Not present for \n" + " move transactions (category = move).\n" + " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" + " transaction between accounts, and not associated with an address,\n" + " transaction id or block. 'send' and 'receive' transactions are \n" + " associated with an address, transaction id and block details\n" + " \"amount\": x.xxx, (numeric) The amount in DAPS. This is negative for the 'send' category, and for the\n" + " 'move' category for moves outbound. It is positive for the 'receive' category,\n" + " and for the 'move' category for inbound funds.\n" + " \"vout\" : n, (numeric) the vout value\n" + " \"fee\": x.xxx, (numeric) The amount of the fee in DAPS. This is negative and only available for the \n" + " 'send' category of transactions.\n" + " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" + " 'receive' category of transactions.\n" + " \"bcconfirmations\": n, (numeric) The number of blockchain confirmations for the transaction. Available for 'send'\n" + " and 'receive' category of transactions.\n" + " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" + " category of transactions.\n" + " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" + " category of transactions.\n" + " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" + " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" + " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" + " for 'send' and 'receive' category of transactions.\n" + " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" + " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" + " from (for receiving funds, positive amounts), or went to (for sending funds,\n" + " negative amounts).\n" + " }\n" + "]\n" + + "\nExamples:\n" + "\nList the most recent 10 transactions in the systems\n" + + HelpExampleCli("listtransactions", "") + + "\nList the most recent 10 transactions for the tabby account\n" + HelpExampleCli("listtransactions", "\"tabby\"") + + "\nList transactions 100 to 120 from the tabby account\n" + HelpExampleCli("listtransactions", "\"tabby\" 20 100") + + "\nAs a json rpc call\n" + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount = "*"; + if (params.size() > 0) + strAccount = params[0].get_str(); + int nCount = 10; + if (params.size() > 1) + nCount = params[1].get_int(); + int nFrom = 0; + if (params.size() > 2) + nFrom = params[2].get_int(); + isminefilter filter = ISMINE_SPENDABLE; + if (params.size() > 3) + if (params[3].get_bool()) + filter = filter | ISMINE_WATCH_ONLY; + + if (nCount < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); + if (nFrom < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); + + UniValue ret(UniValue::VARR); + + const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; + + // iterate backwards until we have nCount items to return: + for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { + CWalletTx* const pwtx = (*it).second.first; + if (pwtx != 0) + ListTransactions(*pwtx, strAccount, 0, true, ret, filter); + CAccountingEntry* const pacentry = (*it).second.second; + if (pacentry != 0) + AcentryToJSON(*pacentry, strAccount, ret); + + if ((int)ret.size() >= (nCount + nFrom)) break; + } + // ret is newest to oldest + + if (nFrom > (int)ret.size()) + nFrom = ret.size(); + if ((nFrom + nCount) > (int)ret.size()) + nCount = ret.size() - nFrom; + + vector arrTmp = ret.getValues(); + + vector::iterator first = arrTmp.begin(); + std::advance(first, nFrom); + + vector::iterator last = arrTmp.begin(); + std::advance(last, nFrom + nCount); + + if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); + if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); + + std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest + + ret.clear(); + ret.setArray(); + ret.push_backV(arrTmp); + + return ret; +} + +UniValue listaccounts(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "listaccounts ( minconf includeWatchonly)\n" + "\nReturns Object that has account names as keys, account balances as values.\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n" + "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n" + "\nResult:\n" + "{ (json object where keys are account names, and values are numeric balances\n" + " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n" + " ...\n" + "}\n" + "\nExamples:\n" + "\nList account balances where there at least 1 confirmation\n" + + HelpExampleCli("listaccounts", "") + + "\nList account balances including zero confirmation transactions\n" + HelpExampleCli("listaccounts", "0") + + "\nList account balances for 6 or more confirmations\n" + HelpExampleCli("listaccounts", "6") + + "\nAs json rpc call\n" + HelpExampleRpc("listaccounts", "6")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + isminefilter includeWatchonly = ISMINE_SPENDABLE; + if (params.size() > 1) + if (params[1].get_bool()) + includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; + + map mapAccountBalances; + for (const PAIRTYPE(CTxDestination, CAddressBookData) & entry : pwalletMain->mapAddressBook) { + if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me + mapAccountBalances[entry.second.name] = 0; + } + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + CAmount nFee; + string strSentAccount; + list listReceived; + list listSent; + int nDepth = wtx.GetDepthInMainChain(); + if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) + continue; + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); + mapAccountBalances[strSentAccount] -= nFee; + for (const COutputEntry& s : listSent) + mapAccountBalances[strSentAccount] -= s.amount; + if (nDepth >= nMinDepth) { + for (const COutputEntry& r : listReceived) + if (pwalletMain->mapAddressBook.count(r.destination)) + mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; + else + mapAccountBalances[""] += r.amount; + } + } + + const list & acentries = pwalletMain->laccentries; + for (const CAccountingEntry& entry : acentries) + mapAccountBalances[entry.strAccount] += entry.nCreditDebit; + + UniValue ret(UniValue::VOBJ); + for (const PAIRTYPE(string, CAmount) & accountBalance : mapAccountBalances) { + ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); + } + return ret; +} + +UniValue listsinceblock(const UniValue& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n" + "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n" + "\nArguments:\n" + "1. \"blockhash\" (string, optional) The block hash to list transactions since\n" + "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n" + "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')" + "\nResult:\n" + "{\n" + " \"transactions\": [\n" + " \"account\":\"accountname\", (string) The account name associated with the transaction. Will be \"\" for the default account.\n" + " \"address\":\"dapscoinaddress\", (string) The dapscoin address of the transaction. Not present for move transactions (category = move).\n" + " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n" + " \"amount\": x.xxx, (numeric) The amount in DAPS. This is negative for the 'send' category, and for the 'move' category for moves \n" + " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n" + " \"vout\" : n, (numeric) the vout value\n" + " \"fee\": x.xxx, (numeric) The amount of the fee in DAPS. This is negative and only available for the 'send' category of transactions.\n" + " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n" + " \"bcconfirmations\" : n, (numeric) The number of blockchain confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n" + " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n" + " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n" + " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" + " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" + " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n" + " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n" + " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" + " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n" + " ],\n" + " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("listsinceblock", "") + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6") + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBlockIndex* pindex = NULL; + int target_confirms = 1; + isminefilter filter = ISMINE_SPENDABLE; + + if (params.size() > 0) { + uint256 blockId = 0; + + blockId.SetHex(params[0].get_str()); + BlockMap::iterator it = mapBlockIndex.find(blockId); + if (it != mapBlockIndex.end()) + pindex = it->second; + } + + if (params.size() > 1) { + target_confirms = params[1].get_int(); + + if (target_confirms < 1) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + } + + if (params.size() > 2) + if (params[2].get_bool()) + filter = filter | ISMINE_WATCH_ONLY; + + int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; + + UniValue transactions(UniValue::VARR); + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { + CWalletTx tx = (*it).second; + + if (depth == -1 || tx.GetDepthInMainChain(false) < depth) + ListTransactions(tx, "*", 0, true, transactions, filter); + } + + CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; + uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("transactions", transactions)); + ret.push_back(Pair("lastblock", lastblock.GetHex())); + + return ret; +} + +UniValue gettransaction(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "gettransaction \"txid\" ( includeWatchonly )\n" + "\nGet detailed information about in-wallet transaction \n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id\n" + "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n" + "\nResult:\n" + "{\n" + " \"amount\" : x.xxx, (numeric) The transaction amount in DAPS\n" + " \"confirmations\" : n, (numeric) The number of confirmations\n" + " \"bcconfirmations\" : n, (numeric) The number of blockchain confirmations\n" + " \"blockhash\" : \"hash\", (string) The block hash\n" + " \"blockindex\" : xx, (numeric) The block index\n" + " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n" + " \"txid\" : \"transactionid\", (string) The transaction id.\n" + " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n" + " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n" + " \"details\" : [\n" + " {\n" + " \"account\" : \"accountname\", (string) The account name involved in the transaction, can be \"\" for the default account.\n" + " \"address\" : \"dapscoinaddress\", (string) The dapscoin address involved in the transaction\n" + " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" + " \"amount\" : x.xxx (numeric) The amount in DAPS\n" + " \"vout\" : n, (numeric) the vout value\n" + " }\n" + " ,...\n" + " ],\n" + " \"hex\" : \"data\" (string) Raw data for transaction\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true") + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + isminefilter filter = ISMINE_SPENDABLE; + if (params.size() > 1) + if (params[1].get_bool()) + filter = filter | ISMINE_WATCH_ONLY; + + UniValue entry(UniValue::VOBJ); + if (!pwalletMain->mapWallet.count(hash)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + + CAmount nCredit = wtx.GetCredit(filter); + CAmount nDebit = wtx.GetDebit(filter); + CAmount nNet = (nCredit > nDebit)? (nCredit - nDebit):(nDebit - nCredit); + CAmount nFee = wtx.nTxFee; + entry.push_back(Pair("amount", ValueFromAmount(nNet))); + if (wtx.IsFromMe(filter)) + entry.push_back(Pair("fee", ValueFromAmount(nFee))); + + WalletTxToJSON(wtx, entry); + + UniValue details(UniValue::VARR); + ListTransactions(wtx, "*", 0, false, details, filter); + entry.push_back(Pair("details", details)); + + string strHex = EncodeHexTx(static_cast(wtx)); + entry.push_back(Pair("hex", strHex)); + + return entry; +} + + +UniValue backupwallet(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "backupwallet \"destination\"\n" + "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n" + "\nArguments:\n" + "1. \"destination\" (string) The destination directory or file\n" + "\nExamples:\n" + + HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strDest = params[0].get_str(); + if (!BackupWallet(*pwalletMain, strDest)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); + + return "Done"; +} + + +UniValue keypoolrefill(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "keypoolrefill ( newsize )\n" + "\nFills the keypool." + + HelpRequiringPassphrase() + "\n" + "\nArguments\n" + "1. newsize (numeric, optional, default=100) The new keypool size\n" + "\nExamples:\n" + + HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool + unsigned int kpSize = 0; + if (params.size() > 0) { + if (params[0].get_int() < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size."); + kpSize = (unsigned int)params[0].get_int(); + } + + EnsureWalletIsUnlocked(); + pwalletMain->TopUpKeyPool(kpSize); + + if (pwalletMain->GetKeyPoolSize() < kpSize) + throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); + + return NullUniValue; +} + + +static void LockWallet(CWallet* pWallet) +{ + LOCK(cs_nWalletUnlockTime); + nWalletUnlockTime = 0; + pWallet->fWalletUnlockAnonymizeOnly = false; + pWallet->Lock(); +} + +UniValue unlockwallet(const UniValue& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) + throw runtime_error( + "unlockwallet \"passphrase\" timeout ( anonymizeonly )\n" + "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" + "This is needed prior to performing transactions related to private keys such as sending DAPSs\n" + "\nArguments:\n" + "1. \"passphrase\" (string, required) The wallet passphrase\n" + "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n" + "3. anonymizeonly (boolean, optional, default=false) If is true sending functions are disabled." + "\nNote:\n" + "Issuing the unlockwallet command while the wallet is already unlocked will set a new unlock\n" + "time that overrides the old one. A timeout of \"0\" unlocks until the wallet is closed.\n" + "\nExamples:\n" + "\nUnlock the wallet for 60 seconds\n" + + HelpExampleCli("unlockwallet", "\"my pass phrase\" 60") + + "\nUnlock the wallet for 60 seconds but allow Obfuscation only\n" + HelpExampleCli("unlockwallet", "\"my pass phrase\" 60 true") + + "\nLock the wallet again (before 60 seconds)\n" + HelpExampleCli("walletlock", "") + + "\nAs json rpc call\n" + HelpExampleRpc("unlockwallet", "\"my pass phrase\", 60")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but unlockwallet was called."); + + // Note that the walletpassphrase is stored in params[0] which is not mlock()ed + SecureString strWalletPass; + strWalletPass.reserve(100); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + strWalletPass = params[0].get_str().c_str(); + + bool anonymizeOnly = false; + if (params.size() == 3) + anonymizeOnly = params[2].get_bool(); + + if (!pwalletMain->IsLocked() && pwalletMain->fWalletUnlockAnonymizeOnly && anonymizeOnly) + throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); + + // Get the timeout + int64_t nSleepTime = params[1].get_int64(); + // Timeout cannot be negative, otherwise it will relock immediately + if (nSleepTime < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); + } + // Clamp timeout + constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug? + if (nSleepTime > MAX_SLEEP_TIME) { + nSleepTime = MAX_SLEEP_TIME; + } + + if (!pwalletMain->Unlock(strWalletPass, anonymizeOnly)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + + pwalletMain->TopUpKeyPool(); + + + if (nSleepTime > 0) { + nWalletUnlockTime = GetTime () + nSleepTime; + RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); + } + return NullUniValue; +} + + +UniValue walletpassphrasechange(const UniValue& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" + "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" + "\nArguments:\n" + "1. \"oldpassphrase\" (string) The current passphrase\n" + "2. \"newpassphrase\" (string) The new passphrase\n" + "\nExamples:\n" + + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); + + // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strOldWalletPass; + strOldWalletPass.reserve(100); + strOldWalletPass = params[0].get_str().c_str(); + + SecureString strNewWalletPass; + strNewWalletPass.reserve(100); + strNewWalletPass = params[1].get_str().c_str(); + + if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + + if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + + return NullUniValue; +} + + +UniValue walletlock(const UniValue& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) + throw runtime_error( + "walletlock\n" + "\nRemoves the wallet encryption key from memory, locking the wallet.\n" + "After calling this method, you will need to call unlockwallet again\n" + "before being able to call any methods which require the wallet to be unlocked.\n" + "\nExamples:\n" + "\nSet the passphrase for 2 minutes to perform a transaction\n" + + HelpExampleCli("unlockwallet", "\"my pass phrase\" 120") + + "\nPerform a send (requires passphrase set)\n" + HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 1.0") + + "\nClear the passphrase since we are done before 2 minutes is up\n" + HelpExampleCli("walletlock", "") + + "\nAs json rpc call\n" + HelpExampleRpc("walletlock", "")); + + /*if (fHelp) + LOCK2(cs_main, pwalletMain->cs_wallet); + + return Value::null;*/ + return "This feature is currently not available."; +} + + +UniValue encryptwallet(const UniValue& params, bool fHelp) +{ + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) + throw runtime_error( + "encryptwallet \"passphrase\"\n" + "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" + "After this, any calls that interact with private keys such as sending or signing \n" + "will require the passphrase to be set prior the making these calls.\n" + "Use the unlockwallet call for this, and then walletlock call.\n" + "If the wallet is already encrypted, use the walletpassphrasechange call.\n" + "Note that this will shutdown the server.\n" + "\nArguments:\n" + "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n" + "\nExamples:\n" + "\nEncrypt you wallet\n" + + HelpExampleCli("encryptwallet", "\"my pass phrase\"") + + "\nNow set the passphrase to use the wallet, such as for signing or sending DAPSs\n" + HelpExampleCli("unlockwallet", "\"my pass phrase\"") + + "\nNow we can so something like sign\n" + HelpExampleCli("signmessage", "\"dapscoinaddress\" \"test message\"") + + "\nNow lock the wallet again by removing the passphrase\n" + HelpExampleCli("walletlock", "") + + "\nAs a json rpc call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + if (fHelp) + return true; + if (pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called."); + + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strWalletPass; + strWalletPass.reserve(100); + strWalletPass = params[0].get_str().c_str(); + + if (strWalletPass.length() < 1) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + + + if (!pwalletMain->EncryptWallet(strWalletPass)) + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); + + // BDB seems to have a bad habit of writing old data into + // slack space in .dat files; that is bad if the old data is + // unencrypted private keys. So: + StartShutdown(); + return "wallet encrypted; dapscoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; +} + +UniValue lockunspent(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" + "\nUpdates list of temporarily unspendable outputs.\n" + "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" + "A locked transaction output will not be chosen by automatic coin selection, when spending DAPSs.\n" + "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" + "is always cleared (by virtue of process exit) when a node stops or fails.\n" + "Also see the listunspent call\n" + "\nArguments:\n" + "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n" + "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n" + " [ (json array of json objects)\n" + " {\n" + " \"txid\":\"id\", (string) The transaction id\n" + " \"vout\": n (numeric) The output number\n" + " }\n" + " ,...\n" + " ]\n" + + "\nResult:\n" + "true|false (boolean) Whether the command was successful or not\n" + + "\nExamples:\n" + "\nList the unspent transactions\n" + + HelpExampleCli("listunspent", "") + + "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + + "\nList the locked transactions\n" + HelpExampleCli("listlockunspent", "") + + "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (params.size() == 1) + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)); + else + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR)); + + bool fUnlock = params[0].get_bool(); + + if (params.size() == 1) { + if (fUnlock) + pwalletMain->UnlockAllCoins(); + return true; + } + + UniValue outputs = params[1].get_array(); + for (unsigned int idx = 0; idx < outputs.size(); idx++) { + const UniValue& output = outputs[idx]; + if (!output.isObject()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); + const UniValue& o = output.get_obj(); + RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); + + string txid = find_value(o, "txid").get_str(); + if (!IsHex(txid)) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); + + int nOutput = find_value(o, "vout").get_int(); + if (nOutput < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + + COutPoint outpt(uint256(txid), nOutput); + + if (fUnlock) + pwalletMain->UnlockCoin(outpt); + else + pwalletMain->LockCoin(outpt); + } + + return true; +} + +UniValue listlockunspent(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "listlockunspent\n" + "\nReturns list of temporarily unspendable outputs.\n" + "See the lockunspent call to lock and unlock transactions for spending.\n" + "\nResult:\n" + "[\n" + " {\n" + " \"txid\" : \"transactionid\", (string) The transaction id locked\n" + " \"vout\" : n (numeric) The vout value\n" + " }\n" + " ,...\n" + "]\n" + "\nExamples:\n" + "\nList the unspent transactions\n" + + HelpExampleCli("listunspent", "") + + "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + + "\nList the locked transactions\n" + HelpExampleCli("listlockunspent", "") + + "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("listlockunspent", "")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + vector vOutpts; + pwalletMain->ListLockedCoins(vOutpts); + + UniValue ret(UniValue::VARR); + + for (COutPoint& outpt : vOutpts) { + UniValue o(UniValue::VOBJ); + + o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("vout", (int)outpt.n)); + ret.push_back(o); + } + + return ret; +} + +UniValue settxfee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "settxfee amount\n" + "\nSet the transaction fee per kB.\n" + "\nArguments:\n" + "1. amount (numeric, required) The transaction fee in DAPS/kB rounded to the nearest 0.00000001\n" + "\nResult\n" + "true|false (boolean) Returns true if successful\n" + "\nExamples:\n" + + HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + // Amount + CAmount nAmount = 0; + if (params[0].get_real() != 0.0) + nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + + payTxFee = CFeeRate(nAmount, 1000); + return true; +} + +UniValue getwalletinfo(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getwalletinfo\n" + "Returns an object containing various wallet state info.\n" + "\nResult:\n" + "{\n" + " \"walletversion\": xxxxx, (numeric) the wallet version\n" + " \"balance\": xxxxxxx, (numeric) the total DAPS balance of the wallet\n" + " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" + " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); + obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); + if (pwalletMain->IsCrypted()) + obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + return obj; +} + +// ppcoin: reserve balance from being staked for network protection +UniValue reservebalance(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "reservebalance ( reserve amount )\n" + "\nShow or set the reserve amount not participating in network protection\n" + "If no parameters provided current setting is printed.\n" + + "\nArguments:\n" + "1. reserve (boolean, optional) is true or false to turn balance reserve on or off.\n" + "2. amount (numeric, optional) is a real and rounded to cent.\n" + + "\nResult:\n" + "{\n" + " \"reserve\": true|false, (boolean) Status of the reserve balance\n" + " \"amount\": x.xxxx (numeric) Amount reserved\n" + "\nExamples:\n" + + HelpExampleCli("reservebalance", "true 5000") + HelpExampleRpc("reservebalance", "true 5000")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + if (params.size() > 0) { + bool fReserve = params[0].get_bool(); + if (fReserve) { + if (params.size() == 1) + throw runtime_error("must provide amount to reserve balance.\n"); + CAmount nAmount = AmountFromValue(params[1]); + nAmount = (nAmount / CENT) * CENT; // round to cent + if (nAmount < 0) + throw runtime_error("amount cannot be negative.\n"); + nReserveBalance = nAmount; + + CWalletDB walletdb(pwalletMain->strWalletFile); + walletdb.WriteReserveAmount(nReserveBalance / COIN); + + } else { + if (params.size() > 1) + throw runtime_error("cannot specify amount to turn off reserve.\n"); + nReserveBalance = 0; + } + } + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("reserve", (nReserveBalance > 0))); + result.push_back(Pair("amount", ValueFromAmount(nReserveBalance))); + return result; +} + +// presstab HyperStake +UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "setstakesplitthreshold value\n" + "\nThis will set the output size of your stakes to never be below this number\n" + + "\nArguments:\n" + "1. value (numeric, required) Threshold value between 1 and 999999\n" + "\nResult:\n" + "{\n" + " \"threshold\": n, (numeric) Threshold value set\n" + " \"saved\": true|false (boolean) 'true' if successfully saved to the wallet file\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("setstakesplitthreshold", "5000") + HelpExampleRpc("setstakesplitthreshold", "5000")); + + uint64_t nStakeSplitThreshold = params[0].get_int(); + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Unlock wallet to use this feature"); + if (nStakeSplitThreshold > 999999) + throw runtime_error("Value out of range, max allowed is 999999"); + + CWalletDB walletdb(pwalletMain->strWalletFile); + LOCK(pwalletMain->cs_wallet); + { + bool fFileBacked = pwalletMain->fFileBacked; + + UniValue result(UniValue::VOBJ); + pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; + result.push_back(Pair("threshold", int(pwalletMain->nStakeSplitThreshold))); + if (fFileBacked) { + walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold); + result.push_back(Pair("saved", "true")); + } else + result.push_back(Pair("saved", "false")); + + return result; + } +} + +// presstab HyperStake +UniValue getstakesplitthreshold(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getstakesplitthreshold\n" + "Returns the threshold for stake splitting\n" + "\nResult:\n" + "n (numeric) Threshold value\n" + "\nExamples:\n" + + HelpExampleCli("getstakesplitthreshold", "") + HelpExampleRpc("getstakesplitthreshold", "")); + + return int(pwalletMain->nStakeSplitThreshold); +} + +UniValue autocombinedust(const UniValue& params, bool fHelp) +{ + bool fEnable; + if (params.size() >= 1) + fEnable = params[0].get_bool(); + + if (fHelp || params.size() < 1 || (fEnable && params.size() != 2) || params.size() > 2) + throw runtime_error( + "autocombinedust true|false ( threshold )\n" + "\nWallet will automatically monitor for any coins with value below the threshold amount, and combine them if they reside with the same DAPS address\n" + "When autocombinedust runs it will create a transaction, and therefore will be subject to transaction fees. Minimum of 25 dust transactions before activation.\n" + + "\nArguments:\n" + "1. true|false (boolean, required) Enable auto combine (true) or disable (false)\n" + "2. threshold (numeric, optional) Threshold amount (default: 0)\n" + "\nExamples:\n" + + HelpExampleCli("autocombinedust", "true 540") + HelpExampleRpc("autocombinedust", "true 540")); + + CWalletDB walletdb(pwalletMain->strWalletFile); + CAmount nThreshold = 0; + + if (fEnable) { + nThreshold = params[1].get_int(); + } else { + nThreshold = 0; + } + + pwalletMain->fCombineDust = fEnable; + pwalletMain->nAutoCombineThreshold = nThreshold; + + if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) + throw runtime_error("Changed settings in wallet but failed to save to database\n"); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("autocombinedust", params[0].get_bool())); + result.push_back(Pair("amount", int(pwalletMain->nAutoCombineThreshold))); + return result; +} + +UniValue printMultiSend() +{ + UniValue ret(UniValue::VARR); + UniValue act(UniValue::VARR); + act.push_back(Pair("MultiSendStake Activated?", pwalletMain->fMultiSendStake)); + act.push_back(Pair("MultiSendMasternode Activated?", pwalletMain->fMultiSendMasternodeReward)); + ret.push_back(act); + + if (pwalletMain->vDisabledAddresses.size() >= 1) { + UniValue disAdd(UniValue::VOBJ); + for (unsigned int i = 0; i < pwalletMain->vDisabledAddresses.size(); i++) { + disAdd.push_back(Pair("Disabled From Sending", pwalletMain->vDisabledAddresses[i])); + } + ret.push_back(disAdd); + } + + ret.push_back("MultiSend Addresses to Send To:"); + + UniValue vMS(UniValue::VOBJ); + for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { + vMS.push_back(Pair("Address " + std::to_string(i), pwalletMain->vMultiSend[i].first)); + vMS.push_back(Pair("Percent", pwalletMain->vMultiSend[i].second)); + } + + ret.push_back(vMS); + return ret; +} + +UniValue printAddresses() +{ + std::vector vCoins; + pwalletMain->AvailableCoins(vCoins); + std::map mapAddresses; + for (const COutput& out : vCoins) { + CTxDestination utxoAddress; + ExtractDestination(out.tx->vout[out.i].scriptPubKey, utxoAddress); + std::string strAdd = CBitcoinAddress(utxoAddress).ToString(); + + if (mapAddresses.find(strAdd) == mapAddresses.end()) //if strAdd is not already part of the map + mapAddresses[strAdd] = (double)out.tx->vout[out.i].nValue / (double)COIN; + else + mapAddresses[strAdd] += (double)out.tx->vout[out.i].nValue / (double)COIN; + } + + UniValue ret(UniValue::VARR); + for (map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { + UniValue obj(UniValue::VOBJ); + const std::string* strAdd = &(*it).first; + const double* nBalance = &(*it).second; + obj.push_back(Pair("Address ", *strAdd)); + obj.push_back(Pair("Balance ", *nBalance)); + ret.push_back(obj); + } + + return ret; +} + +unsigned int sumMultiSend() +{ + unsigned int sum = 0; + for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) + sum += pwalletMain->vMultiSend[i].second; + return sum; +} + +UniValue multisend(const UniValue& params, bool fHelp) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + bool fFileBacked; + //MultiSend Commands + if (params.size() == 1) { + string strCommand = params[0].get_str(); + UniValue ret(UniValue::VOBJ); + if (strCommand == "print") { + return printMultiSend(); + } else if (strCommand == "printaddress" || strCommand == "printaddresses") { + return printAddresses(); + } else if (strCommand == "clear") { + LOCK(pwalletMain->cs_wallet); + { + bool erased = false; + if (pwalletMain->fFileBacked) { + if (walletdb.EraseMultiSend(pwalletMain->vMultiSend)) + erased = true; + } + + pwalletMain->vMultiSend.clear(); + pwalletMain->setMultiSendDisabled(); + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("Erased from database", erased)); + obj.push_back(Pair("Erased from RAM", true)); + + return obj; + } + } else if (strCommand == "enablestake" || strCommand == "activatestake") { + if (pwalletMain->vMultiSend.size() < 1) + throw JSONRPCError(RPC_INVALID_REQUEST, "Unable to activate MultiSend, check MultiSend vector"); + + if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { + pwalletMain->fMultiSendStake = true; + if (!walletdb.WriteMSettings(true, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); + UniValue arr(UniValue::VARR); + arr.push_back(obj); + arr.push_back(printMultiSend()); + return arr; + } else + return printMultiSend(); + } + + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to activate MultiSend, check MultiSend vector"); + } else if (strCommand == "enablemasternode" || strCommand == "activatemasternode") { + if (pwalletMain->vMultiSend.size() < 1) + throw JSONRPCError(RPC_INVALID_REQUEST, "Unable to activate MultiSend, check MultiSend vector"); + + if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { + pwalletMain->fMultiSendMasternodeReward = true; + + if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, true, pwalletMain->nLastMultiSendHeight)) { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); + UniValue arr(UniValue::VARR); + arr.push_back(obj); + arr.push_back(printMultiSend()); + return arr; + } else + return printMultiSend(); + } + + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to activate MultiSend, check MultiSend vector"); + } else if (strCommand == "disable" || strCommand == "deactivate") { + pwalletMain->setMultiSendDisabled(); + if (!walletdb.WriteMSettings(false, false, pwalletMain->nLastMultiSendHeight)) + throw JSONRPCError(RPC_DATABASE_ERROR, "MultiSend deactivated but writing settings to DB failed"); + + return printMultiSend(); + } else if (strCommand == "enableall") { + if (!walletdb.EraseMSDisabledAddresses(pwalletMain->vDisabledAddresses)) + return "failed to clear old vector from walletDB"; + else { + pwalletMain->vDisabledAddresses.clear(); + return printMultiSend(); + } + } + } + if (params.size() == 2 && params[0].get_str() == "delete") { + int del = std::stoi(params[1].get_str().c_str()); + if (!walletdb.EraseMultiSend(pwalletMain->vMultiSend)) + throw JSONRPCError(RPC_DATABASE_ERROR, "failed to delete old MultiSend vector from database"); + + pwalletMain->vMultiSend.erase(pwalletMain->vMultiSend.begin() + del); + if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) + throw JSONRPCError(RPC_DATABASE_ERROR, "walletdb WriteMultiSend failed!"); + + return printMultiSend(); + } + if (params.size() == 2 && params[0].get_str() == "disable") { + std::string disAddress = params[1].get_str(); + if (!CBitcoinAddress(disAddress).IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "address you want to disable is not valid"); + else { + pwalletMain->vDisabledAddresses.push_back(disAddress); + if (!walletdb.EraseMSDisabledAddresses(pwalletMain->vDisabledAddresses)) + throw JSONRPCError(RPC_DATABASE_ERROR, "disabled address from sending, but failed to clear old vector from walletDB"); + + if (!walletdb.WriteMSDisabledAddresses(pwalletMain->vDisabledAddresses)) + throw JSONRPCError(RPC_DATABASE_ERROR, "disabled address from sending, but failed to store it to walletDB"); + else + return printMultiSend(); + } + } + + //if no commands are used + if (fHelp || params.size() != 2) + throw runtime_error( + "multisend \n" + "****************************************************************\n" + "WHAT IS MULTISEND?\n" + "MultiSend allows a user to automatically send a percent of their stake reward to as many addresses as you would like\n" + "The MultiSend transaction is sent when the staked coins mature (100 confirmations)\n" + "****************************************************************\n" + "TO CREATE OR ADD TO THE MULTISEND VECTOR:\n" + "multisend \n" + "This will add a new address to the MultiSend vector\n" + "Percent is a whole number 1 to 100.\n" + "****************************************************************\n" + "MULTISEND COMMANDS (usage: multisend )\n" + " print - displays the current MultiSend vector \n" + " clear - deletes the current MultiSend vector \n" + " enablestake/activatestake - activates the current MultiSend vector to be activated on stake rewards\n" + " enablemasternode/activatemasternode - activates the current MultiSend vector to be activated on masternode rewards\n" + " disable/deactivate - disables the current MultiSend vector \n" + " delete
- deletes an address from the MultiSend vector \n" + " disable
- prevents a specific address from sending MultiSend transactions\n" + " enableall - enables all addresses to be eligible to send MultiSend transactions\n" + "****************************************************************\n"); + + //if the user is entering a new MultiSend item + string strAddress = params[0].get_str(); + CBitcoinAddress address(strAddress); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); + if (std::stoi(params[1].get_str().c_str()) < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid percentage"); + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with unlockwallet first."); + unsigned int nPercent = (unsigned int) std::stoul(params[1].get_str().c_str()); + + LOCK(pwalletMain->cs_wallet); + { + fFileBacked = pwalletMain->fFileBacked; + //Error if 0 is entered + if (nPercent == 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Sending 0% of stake is not valid"); + } + + //MultiSend can only send 100% of your stake + if (nPercent + sumMultiSend() > 100) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, the sum of your MultiSend is greater than 100%"); + + for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { + if (pwalletMain->vMultiSend[i].first == strAddress) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, cannot use the same address twice"); + } + + if (fFileBacked) + walletdb.EraseMultiSend(pwalletMain->vMultiSend); + + std::pair newMultiSend; + newMultiSend.first = strAddress; + newMultiSend.second = nPercent; + pwalletMain->vMultiSend.push_back(newMultiSend); + if (fFileBacked) { + if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) + throw JSONRPCError(RPC_DATABASE_ERROR, "walletdb WriteMultiSend failed!"); + } + } + return printMultiSend(); +} + +UniValue createprivacywallet(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() >2 || params.size() < 1) + throw runtime_error( + "createprivacywallet \"password\" (\"language\") \n" + "\nCreate a new wallet for privacy with dual-key stealth address.\n" + "If 'language' is specified, it is used, otherwise english \n" + "\nArguments:\n" + "1. \"account\" (string, required) password for the wallet \n" + "2. \"language\" (string, optional) language for the wallet's mnemmonics \n" + "\nResult:\n" + "\"privacy wallet created\" (string) the base address of the wallet\n" + "\nExamples:\n" + + HelpExampleCli("createprivacywallet", "") + HelpExampleCli("createprivacywallet", "\"\"") + HelpExampleCli("createprivacywallet", "\"1234567890\"") + HelpExampleRpc("createprivacywallet", "\"1234567890\"")); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: RPC unimplemented."); +} + +UniValue createprivacyaccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "createprivacyaccount \n" + "\nCreate a new wallet account for privacy.\n" + "\nArguments:\n" + "\nResult:\n" + "\"account address\" (string) the address of the created account\n" + "\nExamples:\n" + + HelpExampleCli("createprivacyaccount", "") + HelpExampleCli("createprivacyaccount", "\"\"") + HelpExampleCli("createprivacyaccount", "") + HelpExampleRpc("createprivacyaccount", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + CWalletDB walletdb(pwalletMain->strWalletFile); + UniValue ret(UniValue::VOBJ); + int i = 0; + while (i < 10) { + std::string viewAccountLabel = "viewaccount"; + std::string spendAccountLabel = "spendaccount"; + + CAccount viewAccount; + walletdb.ReadAccount(viewAccountLabel, viewAccount); + if (!viewAccount.vchPubKey.IsValid()) { + std::string viewAccountAddress = GetHDAccountAddress(viewAccountLabel, 0).ToString(); + } + + CAccount spendAccount; + walletdb.ReadAccount(spendAccountLabel, spendAccount); + if (!spendAccount.vchPubKey.IsValid()) { + std::string spendAccountAddress = GetHDAccountAddress(spendAccountLabel, 1).ToString(); + } + if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { + i++; + continue; + } + ret.push_back(Pair("viewpublickey", viewAccount.vchPubKey.GetHex())); + + ret.push_back(Pair("spendpublickey", spendAccount.vchPubKey.GetHex())); + + std::string stealthAddr; + if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { + ret.push_back(Pair("stealthaddress", stealthAddr)); + } + break; + } + return ret; +} + +UniValue showstealthaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "showstealthaddress \n" + "\nShow stealth address.\n" + "\nArguments:\n" + "\nResult:\n" + "\"account address\" (string) the address of the created account\n" + "\nExamples:\n" + + HelpExampleCli("showstealthaddress", "") + HelpExampleCli("showstealthaddress", "\"\"") + HelpExampleCli("showstealthaddress", "") + HelpExampleRpc("showstealthaddress", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + CWalletDB walletdb(pwalletMain->strWalletFile); + UniValue ret(UniValue::VOBJ); + int i = 0; + while (i < 10) { + std::string viewAccountLabel = "viewaccount"; + std::string spendAccountLabel = "spendaccount"; + + CAccount viewAccount; + walletdb.ReadAccount(viewAccountLabel, viewAccount); + if (!viewAccount.vchPubKey.IsValid()) { + std::string viewAccountAddress = GetHDAccountAddress(viewAccountLabel, 0).ToString(); + } + + CAccount spendAccount; + walletdb.ReadAccount(spendAccountLabel, spendAccount); + if (!spendAccount.vchPubKey.IsValid()) { + std::string spendAccountAddress = GetHDAccountAddress(spendAccountLabel, 1).ToString(); + } + if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { + i++; + continue; + } + std::string stealthAddr; + if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { + ret.push_back(Pair("stealthaddress", stealthAddr)); + } + break; + } + return ret; +} + +UniValue generateintegratedaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "generateintegratedaddress \n" + "\nGenerate integrated addresses for this wallet with a random payment ID.\n" + "\nArguments:\n" + "optional: paymentID" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("generateintegratedaddress", "1234") + HelpExampleCli("generateintegratedaddress", "\"\"") + HelpExampleCli("generateintegratedaddress", "") + HelpExampleRpc("generateintegratedaddress", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + UniValue ret(UniValue::VOBJ); + uint64_t paymentID = 0; + std::string address; + if (params.size() == 1) { + paymentID = params[0].get_int64(); + address = pwalletMain->GenerateIntegratedAddressWithProvidedPaymentID("masteraccount", paymentID); + } else { + address = pwalletMain->GenerateIntegratedAddressWithRandomPaymentID("masteraccount", paymentID); + } + ret.push_back(Pair("integratedaddress", address)); + ret.push_back(Pair("paymentid", paymentID)); + return ret; +} + +UniValue importkeys(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "importkeys \n" + "\nCreate a new wallet account for privacy.\n" + "\nArguments:\n" + "\nResult:\n" + "\"account address\" (string) the address of the created account\n" + "\nExamples:\n" + + HelpExampleCli("importkeys", "") + HelpExampleCli("importkeys", "\"\"") + HelpExampleCli("importkeys", "") + HelpExampleRpc("importkeys", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + CWalletDB walletdb(pwalletMain->strWalletFile); + + std::string viewStr = params[0].get_str(); + std::string spendStr = params[1].get_str(); + + CAccount viewAc, spendAc; + + std::vector view, spend; + DecodeBase58(viewStr, view); + DecodeBase58(spendStr, spend); + std::string viewAccountLabel = "viewaccount"; + std::string spendAccountLabel = "spendaccount"; + + CKey viewPk, spendPk; + viewPk.Set(view.begin(), view.end(), true); + spendPk.Set(spend.begin(), spend.end(), true); + + pwalletMain->AddKey(viewPk); + pwalletMain->AddKey(spendPk); + viewAc.vchPubKey = viewPk.GetPubKey(); + spendAc.vchPubKey = spendPk.GetPubKey(); + + pwalletMain->SetAddressBook(viewAc.vchPubKey.GetID(), viewAccountLabel, "receive"); + walletdb.WriteAccount(viewAccountLabel, viewAc); + + pwalletMain->SetAddressBook(spendAc.vchPubKey.GetID(), spendAccountLabel, "receive"); + walletdb.WriteAccount(spendAccountLabel, spendAc); + + return true; +} + +UniValue createprivacysubaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "createprivacysubaddress \"label\" \n" + "\nCreate a new wallet account subaddress for privacy transaction.\n" + "\nArguments:\n" + "1. \"label\" (string, required) label for the wallet account address\n" + "\nResult:\n" + "\"account address\" (string) the created address for the corresponding account\n" + "\"address index\" (string) the index of the created address for the account\n" + "\nExamples:\n" + + HelpExampleCli("createprivacysubaddress", "") + HelpExampleCli("createprivacysubaddress", "\"\"") + HelpExampleCli("createprivacysubaddress", "\"address1\"") + HelpExampleRpc("createprivacysubaddress", "\"address1\"")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + std::string label = params[0].get_str(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + std::string viewAccountLabel = label + "view"; + std::string spendAccountLabel = label + "spend"; + CStealthAccount account; + if (!walletdb.ReadStealthAccount(label, account)) { + int i = 0; + while (i < 10) { + CAccount viewAccount; + walletdb.ReadAccount(label + "view", viewAccount); + if (!viewAccount.vchPubKey.IsValid()) { + GetAccountAddress(viewAccountLabel).ToString(); + } + + CAccount spendAccount; + walletdb.ReadAccount(spendAccountLabel, spendAccount); + if (!spendAccount.vchPubKey.IsValid()) { + GetAccountAddress(spendAccountLabel).ToString(); + } + if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { + i++; + continue; + } + account.viewAccount = viewAccount; + account.spendAccount = spendAccount; + walletdb.AppendStealthAccountList(label); + break; + } + } + + UniValue ret(UniValue::VOBJ); + + ret.push_back(Pair("viewpublickey", account.viewAccount.vchPubKey.GetHex())); + + ret.push_back(Pair("spendpublickey", account.spendAccount.vchPubKey.GetHex())); + + std::string stealthAddr; + if (pwalletMain->EncodeStealthPublicAddress(account.viewAccount.vchPubKey, account.spendAccount.vchPubKey, stealthAddr)) { + ret.push_back(Pair("stealthaddress", stealthAddr)); + } + return ret; +} + +UniValue readmasteraccount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "readmasteraccount \n" + "\nRead stealth master account address.\n" + "\nArguments:\n" + "\nResult:\n" + "\"public address\" (string) the public address" + "\nExamples:\n" + + HelpExampleCli("readmasteraccount", "") + HelpExampleCli("readmasteraccount", "\"\"") + HelpExampleCli("readmasteraccount", "") + HelpExampleRpc("readmasteraccount", "")); + + if (!pwalletMain) { + //privacy wallet is not yet created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + std::string address; + pwalletMain->ComputeStealthPublicAddress("masteraccount", address); + return address; +} + +UniValue decodestealthaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "decodestealthaddress \n" + "\nDecode a stealth address into spend and view public keys.\n" + "\nArguments:\n" + "1. \"stealth_address\" (string, required) The Base58 stealth address\n" + "\nResult:\n" + "\"public view key\" (string) the view public key\n" + "\"public spend key\" (string) the spend public key" + "\nExamples:\n" + + HelpExampleCli("decodestealthaddress", "") + HelpExampleCli("decodestealthaddress", "\"\"") + HelpExampleCli("decodestealthaddress", "") + HelpExampleRpc("decodestealthaddress", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + std::string addr = params[0].get_str(); + + UniValue ret(UniValue::VOBJ); + CPubKey viewKey, spendKey; + bool hasPaymentID; + uint64_t paymentID; + + if (!CWallet::DecodeStealthAddress(addr, viewKey, spendKey, hasPaymentID, paymentID)) { + throw JSONRPCError(RPC_WALLET_ERROR, + "Error: Stealth address is not correctly formatted."); + } + ret.push_back(Pair("spendpublickey", spendKey.GetHex())); + ret.push_back(Pair("viewpublickey", viewKey.GetHex())); + if (hasPaymentID) { + ret.push_back(Pair("paymentid", paymentID)); + } + + return ret; +} + +UniValue sendtostealthaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "sendtostealthaddress \"dapsstealthaddress\" amount\n" + "\nSend an amount to a given daps stealth address address. The amount is a real and is rounded to the nearest 0.00000001\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"dapsstealthaddress\" (string, required) The dapscoin stealth address to send to.\n" + "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + + HelpExampleCli("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\" 0.1") + HelpExampleCli("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\", 0.1, \"donation\", \"seans outpost\"")); + + std::string stealthAddr = params[0].get_str(); + + // Amount + CAmount nAmount = AmountFromValue(params[1]); + + // Wallet comments + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { + throw JSONRPCError(RPC_WALLET_ERROR, + "Cannot create transaction."); + } + return wtx.GetHash().GetHex(); +} + +UniValue setdecoyconfirmation(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "setdecoyconfirmation\n" + "\nSend the minimum confirmation for decoys in RingCT\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "2. \"confirm\" (numeric, required) The required minim confirmation for decoys\n" + "\nResult:\n" + "\"decoy_confirmation\" (numeric) The minimum decoy confirmation.\n" + "\nExamples:\n" + + HelpExampleCli("setdecoyconfirmation", "\"20\"") + HelpExampleCli("setdecoyconfirmation", "\"20\"") + HelpExampleRpc("setdecoyconfirmation", "\"20\"")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + int confirmation = params[0].get_int(); + + if (confirmation <= 0) { + throw JSONRPCError(RPC_PRIVACY_DECOY_MIN, + "Error: Min decoy confirmation must be positive."); + } + pwalletMain->DecoyConfirmationMinimum = confirmation; + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("decoy_confirmation", confirmation)); + return ret; +} + +UniValue getdecoyconfirmation(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getdecoyconfirmation\n" + "\nShow the current decoy confirmation\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "\nResult:\n" + "\"decoy_confirmation\" (numeric) The minimum decoy confirmation.\n" + "\nExamples:\n" + + HelpExampleCli("getdecoyconfirmation", "") + HelpExampleCli("getdecoyconfirmation", "") + HelpExampleRpc("getdecoyconfirmation", "")); + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("decoy_confirmation", pwalletMain->DecoyConfirmationMinimum)); + return ret; +} + +std::string GetHex(const unsigned char* vch, int sz) { + char psz[sz * 2 + 1]; + for (int i = 0; i < sz; i++) + sprintf(psz + i * 2, "%02x", vch[sz - i - 1]); + return std::string(psz, psz + sz * 2); +} + +UniValue revealviewprivatekey(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 0) + throw runtime_error( + "revealviewprivatekey \n" + "\nReveal view private key.\n" + "\nArguments:\n" + "\nResult:\n" + "\"Private view key\" (string) the private view key\n" + "\nExamples:\n" + + HelpExampleCli("revealviewprivatekey", "") + HelpExampleCli("revealviewprivatekey", "\"\"") + + HelpExampleCli("revealviewprivatekey", "") + HelpExampleRpc("revealviewprivatekey", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + CKey view; + pwalletMain->myViewPrivateKey(view); + return CBitcoinSecret(view).ToString(); +} + +UniValue revealspendprivatekey(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 0) + throw runtime_error( + "revealspendprivatekey \n" + "\nReveal view private key.\n" + "\nArguments:\n" + "\nResult:\n" + "\"Private spend key\" (string) the private spend key\n" + "\nExamples:\n" + + HelpExampleCli("revealspendprivatekey", "") + HelpExampleCli("revealspendprivatekey", "\"\"") + + HelpExampleCli("revealspendprivatekey", "") + HelpExampleRpc("revealspendprivatekey", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + CKey spend; + pwalletMain->mySpendPrivateKey(spend); + return CBitcoinSecret(spend).ToString(); +} + +UniValue showtxprivatekeys(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 1) + throw runtime_error( + "showtxprivatekeys \n" + "\nShow transaction private keys for each UTXO of a transaction.\n" + "\nArguments:\n" + "\nResult:\n" + "\"Private spend key\" (string) the private spend key\n" + "\nExamples:\n" + + HelpExampleCli("showtxprivatekeys", "") + HelpExampleCli("showtxprivatekeys", "\"\"") + + HelpExampleCli("showtxprivatekeys", "") + HelpExampleRpc("showtxprivatekeys", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + UniValue ret(UniValue::VOBJ); + CWalletDB db(pwalletMain->strWalletFile); + for(int i = 0; i < 10; i++) { + std::string key = params[0].get_str() + std::to_string(i); + std::string secret; + if (db.ReadTxPrivateKey(key, secret)) { + ret.push_back(Pair(std::to_string(i), secret)); + } else break; + } + return ret; +} + +UniValue rescan(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 0) + throw runtime_error( + "rescan\n" + "\nRescan wallet transactions from the first block.\n" + "\nArguments:\n" + "\nResult:\n" + "\"scanned wallet transactions\" \n" + "\nExamples:\n" + + HelpExampleCli("rescan", "") + HelpExampleCli("rescan", "\"\"") + + HelpExampleRpc("rescan", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + int nHeight = 1; + if (!pwalletMain->RescanAfterUnlock(nHeight)) { + return "Failed to rescan"; + } + return "Done"; +} + +UniValue rescanwallettransactions(const UniValue& params, bool fHelp) { + if (fHelp || params.size() != 1) + throw runtime_error( + "rescanwallettransactions \"block height\"\n" + "\nRescan wallet transactions from a certain block height.\n" + "\nArguments:\n" + "\nblock height: block height from which the chain will be rescanned\n" + "\nResult:\n" + "\"scanned wallet transactions\" \n" + "\nExamples:\n" + + HelpExampleCli("rescanwallettransactions", "") + HelpExampleCli("rescanwallettransactions", "\"\"") + + HelpExampleRpc("rescanwallettransactions", "")); + + if (!pwalletMain) { + //privacy wallet is already created + throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, + "Error: There is no privacy wallet, please use createprivacyaccount to create one."); + } + + EnsureWalletIsUnlocked(); + + int nHeight = 0; + if (params.size() == 1) { + nHeight = params[0].get_int(); + } + if (!pwalletMain->RescanAfterUnlock(nHeight)) { + return "Failed to rescan"; + } + return "Done"; +} + +UniValue revealmnemonicphrase(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "revealmnemonicphrase \n" + "\nReveal Mnemonic Phrase.\n" + "\nArguments:\n" + "\nResult:\n" + "\"Mnemonic Phrase\" (string) mnemonic phrase\n" + "\nExamples:\n" + + HelpExampleCli("revealmnemonicphrase", "") + HelpExampleCli("revealmnemonicphrase", "\"\"") + + HelpExampleCli("revealmnemonicphrase", "") + HelpExampleRpc("revealmnemonicphrase", "")); + + EnsureWalletIsUnlocked(); + + CHDChain hdChainCurrent; + if (!pwalletMain->GetDecryptedHDChain(hdChainCurrent)) + throw JSONRPCError(RPC_WALLET_ERROR, + "Error: There was a problem while getting mnemonic phrase."); + + SecureString mnemonic; + SecureString mnemonicPass; + if (!hdChainCurrent.GetMnemonic(mnemonic, mnemonicPass)) + throw JSONRPCError(RPC_WALLET_ERROR, + "Error: There was a problem while getting mnemonic phrase."); + + string mPhrase = std::string(mnemonic.begin(), mnemonic.end()).c_str(); + + return mPhrase; +} diff --git a/src/stakeinput.cpp b/src/stakeinput.cpp index 86a2200ec8..4518aac83e 100644 --- a/src/stakeinput.cpp +++ b/src/stakeinput.cpp @@ -7,7 +7,7 @@ #include "primitives/deterministicmint.h" #include "main.h" #include "stakeinput.h" -#include "wallet.h" +#include "wallet/wallet.h" //!DAPS Stake bool CDapsStake::SetInput(CTransaction txPrev, unsigned int n) diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 992861b17b..33104868d3 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -2,8 +2,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "wallet.h" -#include "walletdb.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #include diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 92509a4135..a1e8c3030c 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -12,7 +12,7 @@ #include "uint256.h" #ifdef ENABLE_WALLET -#include "wallet_ismine.h" +#include "wallet/wallet_ismine.h" #endif #include diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 75e31e1a6a..71cae631eb 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -2,8 +2,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "base58.h" #include "netbase.h" diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 077d5e202e..86594ab27b 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -2,11 +2,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" -#include "rpcclient.h" +#include "rpc/server.h" +#include "rpc/client.h" #include "base58.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 8c7cebec87..10d6be9598 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -10,7 +10,7 @@ #include "script/sign.h" #ifdef ENABLE_WALLET -#include "wallet_ismine.h" +#include "wallet/wallet_ismine.h" #endif #include diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index cc6f64678a..4d3f809bef 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -7,11 +7,11 @@ #include "main.h" #include "random.h" #include "txdb.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #ifdef ENABLE_WALLET -#include "db.h" -#include "wallet.h" +#include "wallet/db.h" +#include "wallet/wallet.h" #endif #include diff --git a/src/timedata.cpp b/src/timedata.cpp index f415849d39..813b119d5b 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -6,7 +6,7 @@ #include "netbase.h" #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp new file mode 100644 index 0000000000..cb5dcc56a8 --- /dev/null +++ b/src/wallet/db.cpp @@ -0,0 +1,455 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "wallet/db.h" + +#include "addrman.h" +#include "hash.h" +#include "protocol.h" +#include "util.h" +#include "utilstrencodings.h" + +#include + +#ifndef WIN32 +#include +#endif + +#include +#include +#include + +#include + +using namespace std; +using namespace boost; + + +unsigned int nWalletDBUpdated; + + +// +// CDB +// + +CDBEnv bitdb; + +void CDBEnv::EnvShutdown() +{ + if (!fDbEnvInit) + return; + + fDbEnvInit = false; + int ret = dbenv.close(0); + if (ret != 0) + LogPrintf("CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); + if (!fMockDb) + DbEnv(0).remove(strPath.c_str(), 0); +} + +CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) +{ + fDbEnvInit = false; + fMockDb = false; +} + +CDBEnv::~CDBEnv() +{ + EnvShutdown(); +} + +void CDBEnv::Close() +{ + EnvShutdown(); +} + +bool CDBEnv::Open(const boost::filesystem::path& pathIn) +{ + if (fDbEnvInit) + return true; + + boost::this_thread::interruption_point(); + + strPath = pathIn.string(); + boost::filesystem::path pathLogDir = pathIn / "database"; + TryCreateDirectory(pathLogDir); + boost::filesystem::path pathErrorFile = pathIn / "db.log"; + LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); + + unsigned int nEnvFlags = 0; + if (GetBoolArg("-privdb", true)) + nEnvFlags |= DB_PRIVATE; + + dbenv.set_lg_dir(pathLogDir.string().c_str()); + dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + dbenv.set_lg_bsize(0x10000); + dbenv.set_lg_max(1048576); + dbenv.set_lk_max_locks(40000); + dbenv.set_lk_max_objects(40000); + dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv.set_flags(DB_AUTO_COMMIT, 1); + dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); + dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); + int ret = dbenv.open(strPath.c_str(), + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_RECOVER | + nEnvFlags, + S_IRUSR | S_IWUSR); + if (ret != 0) + return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); + + fDbEnvInit = true; + fMockDb = false; + return true; +} + +void CDBEnv::MakeMock() +{ + if (fDbEnvInit) + throw runtime_error("CDBEnv::MakeMock : Already initialized"); + + boost::this_thread::interruption_point(); + + LogPrint("db", "CDBEnv::MakeMock\n"); + + dbenv.set_cachesize(1, 0, 1); + dbenv.set_lg_bsize(10485760 * 4); + dbenv.set_lg_max(10485760); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_flags(DB_AUTO_COMMIT, 1); + dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); + int ret = dbenv.open(NULL, + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_PRIVATE, + S_IRUSR | S_IWUSR); + if (ret > 0) + throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); + + fDbEnvInit = true; + fMockDb = true; +} + +CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, NULL, 0); + if (result == 0) + return VERIFY_OK; + else if (recoverFunc == NULL) + return RECOVER_FAIL; + + // Try to recover: + bool fRecovered = (*recoverFunc)(*this, strFile); + return (fRecovered ? RECOVER_OK : RECOVER_FAIL); +} + +bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector& vResult) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + u_int32_t flags = DB_SALVAGE; + if (fAggressive) + flags |= DB_AGGRESSIVE; + + stringstream strDump; + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, &strDump, flags); + if (result == DB_VERIFY_BAD) { + LogPrintf("CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n"); + if (!fAggressive) { + LogPrintf("CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n"); + return false; + } + } + if (result != 0 && result != DB_VERIFY_BAD) { + LogPrintf("CDBEnv::Salvage : Database salvage failed with result %d.\n", result); + return false; + } + + // Format of bdb dump is ascii lines: + // header lines... + // HEADER=END + // hexadecimal key + // hexadecimal value + // ... repeated + // DATA=END + + string strLine; + while (!strDump.eof() && strLine != "HEADER=END") + getline(strDump, strLine); // Skip past header + + std::string keyHex, valueHex; + while (!strDump.eof() && keyHex != "DATA=END") { + getline(strDump, keyHex); + if (keyHex != "DATA=END") { + getline(strDump, valueHex); + vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); + } + } + + return (result == 0); +} + + +void CDBEnv::CheckpointLSN(const std::string& strFile) +{ + dbenv.txn_checkpoint(0, 0, 0); + if (fMockDb) + return; + dbenv.lsn_reset(strFile.c_str(), 0); +} + + +CDB::CDB(const std::string& strFilename, const char* pszMode) : pdb(NULL), activeTxn(NULL) +{ + int ret; + fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); + if (strFilename.empty()) + return; + + bool fCreate = strchr(pszMode, 'c') != NULL; + unsigned int nFlags = DB_THREAD; + if (fCreate) + nFlags |= DB_CREATE; + + { + LOCK(bitdb.cs_db); + if (!bitdb.Open(GetDataDir())) + throw runtime_error("CDB : Failed to open database environment."); + + strFile = strFilename; + ++bitdb.mapFileUseCount[strFile]; + pdb = bitdb.mapDb[strFile]; + if (pdb == NULL) { + pdb = new Db(&bitdb.dbenv, 0); + + bool fMockDb = bitdb.IsMock(); + if (fMockDb) { + DbMpoolFile* mpf = pdb->get_mpf(); + ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); + if (ret != 0) + throw runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile)); + } + + ret = pdb->open(NULL, // Txn pointer + fMockDb ? NULL : strFile.c_str(), // Filename + fMockDb ? strFile.c_str() : "main", // Logical db name + DB_BTREE, // Database type + nFlags, // Flags + 0); + + if (ret != 0) { + delete pdb; + pdb = NULL; + --bitdb.mapFileUseCount[strFile]; + std::string tempCopy(strFile); + strFile = ""; + throw std::runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, tempCopy)); + } + + if (fCreate && !Exists(string("version"))) { + bool fTmp = fReadOnly; + fReadOnly = false; + WriteVersion(CLIENT_VERSION); + fReadOnly = fTmp; + } + + bitdb.mapDb[strFile] = pdb; + } + } +} + +void CDB::Flush() +{ + if (activeTxn) + return; + + // Flush database activity from memory pool to disk log + unsigned int nMinutes = 0; + if (fReadOnly) + nMinutes = 1; + + bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); +} + +void CDB::Close() +{ + if (!pdb) + return; + if (activeTxn) + activeTxn->abort(); + activeTxn = NULL; + pdb = NULL; + + Flush(); + + { + LOCK(bitdb.cs_db); + --bitdb.mapFileUseCount[strFile]; + } +} + +void CDBEnv::CloseDb(const string& strFile) +{ + { + LOCK(cs_db); + if (mapDb[strFile] != NULL) { + // Close the database handle + Db* pdb = mapDb[strFile]; + pdb->close(0); + delete pdb; + mapDb[strFile] = NULL; + } + } +} + +bool CDBEnv::RemoveDb(const string& strFile) +{ + this->CloseDb(strFile); + + LOCK(cs_db); + int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); + return (rc == 0); +} + +bool CDB::Rewrite(const string& strFile, const char* pszSkip) +{ + while (true) { + { + LOCK(bitdb.cs_db); + if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { + // Flush log data to the dat file + bitdb.CloseDb(strFile); + bitdb.CheckpointLSN(strFile); + bitdb.mapFileUseCount.erase(strFile); + + bool fSuccess = true; + LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); + string strFileRes = strFile + ".rewrite"; + { // surround usage of db with extra {} + CDB db(strFile.c_str(), "r"); + Db* pdbCopy = new Db(&bitdb.dbenv, 0); + + int ret = pdbCopy->open(NULL, // Txn pointer + strFileRes.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags + 0); + if (ret > 0) { + LogPrintf("CDB::Rewrite : Can't create database file %s\n", strFileRes); + fSuccess = false; + } + + Dbc* pcursor = db.GetCursor(); + if (pcursor) + while (fSuccess) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); + if (ret == DB_NOTFOUND) { + pcursor->close(); + break; + } else if (ret != 0) { + pcursor->close(); + fSuccess = false; + break; + } + if (pszSkip && + strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) + continue; + if (strncmp(&ssKey[0], "\x07version", 8) == 0) { + // Update version: + ssValue.clear(); + ssValue << CLIENT_VERSION; + } + Dbt datKey(&ssKey[0], ssKey.size()); + Dbt datValue(&ssValue[0], ssValue.size()); + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); + if (ret2 > 0) + fSuccess = false; + } + if (fSuccess) { + db.Close(); + bitdb.CloseDb(strFile); + if (pdbCopy->close(0)) + fSuccess = false; + delete pdbCopy; + } + } + if (fSuccess) { + Db dbA(&bitdb.dbenv, 0); + if (dbA.remove(strFile.c_str(), NULL, 0)) + fSuccess = false; + Db dbB(&bitdb.dbenv, 0); + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + fSuccess = false; + } + if (!fSuccess) + LogPrintf("CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes); + return fSuccess; + } + } + MilliSleep(100); + } + return false; +} + + +void CDBEnv::Flush(bool fShutdown) +{ + int64_t nStart = GetTimeMillis(); + // Flush log data to the actual data file on all files that are not in use + LogPrint("db", "CDBEnv::Flush : Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); + if (!fDbEnvInit) + return; + { + LOCK(cs_db); + map::iterator mi = mapFileUseCount.begin(); + while (mi != mapFileUseCount.end()) { + string strFile = (*mi).first; + int nRefCount = (*mi).second; + LogPrint("db", "CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount); + if (nRefCount == 0) { + // Move log data to the dat file + CloseDb(strFile); + LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile); + dbenv.txn_checkpoint(0, 0, 0); + LogPrint("db", "CDBEnv::Flush : %s detach\n", strFile); + if (!fMockDb) + dbenv.lsn_reset(strFile.c_str(), 0); + LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile); + mapFileUseCount.erase(mi++); + } else + mi++; + } + LogPrint("db", "CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); + if (fShutdown) { + char** listp; + if (mapFileUseCount.empty()) { + dbenv.log_archive(&listp, DB_ARCH_REMOVE); + Close(); + if (!fMockDb) + boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); + } + } + } +} diff --git a/src/wallet/db.h b/src/wallet/db.h new file mode 100644 index 0000000000..d380c2a307 --- /dev/null +++ b/src/wallet/db.h @@ -0,0 +1,328 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_DB_H +#define BITCOIN_DB_H + +#include "clientversion.h" +#include "serialize.h" +#include "streams.h" +#include "sync.h" +#include "version.h" + +#include +#include +#include + +#include + +#include + +class CDiskBlockIndex; +class COutPoint; + +struct CBlockLocator; + +extern unsigned int nWalletDBUpdated; + +void ThreadFlushWalletDB(const std::string& strWalletFile); + + +class CDBEnv +{ +private: + bool fDbEnvInit; + bool fMockDb; + // Don't change into boost::filesystem::path, as that can result in + // shutdown problems/crashes caused by a static initialized internal pointer. + std::string strPath; + + void EnvShutdown(); + +public: + mutable CCriticalSection cs_db; + DbEnv dbenv; + std::map mapFileUseCount; + std::map mapDb; + + CDBEnv(); + ~CDBEnv(); + void MakeMock(); + bool IsMock() { return fMockDb; } + + /** + * Verify that database file strFile is OK. If it is not, + * call the callback to try to recover. + * This must be called BEFORE strFile is opened. + * Returns true if strFile is OK. + */ + enum VerifyResult { VERIFY_OK, + RECOVER_OK, + RECOVER_FAIL }; + VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)); + /** + * Salvage data from a file that Verify says is bad. + * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation). + * Appends binary key/value pairs to vResult, returns true if successful. + * NOTE: reads the entire database into memory, so cannot be used + * for huge databases. + */ + typedef std::pair, std::vector > KeyValPair; + bool Salvage(std::string strFile, bool fAggressive, std::vector& vResult); + + bool Open(const boost::filesystem::path& path); + void Close(); + void Flush(bool fShutdown); + void CheckpointLSN(const std::string& strFile); + + void CloseDb(const std::string& strFile); + bool RemoveDb(const std::string& strFile); + + DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) + { + DbTxn* ptxn = NULL; + int ret = dbenv.txn_begin(NULL, &ptxn, flags); + if (!ptxn || ret != 0) + return NULL; + return ptxn; + } +}; + +extern CDBEnv bitdb; + + +/** RAII class that provides access to a Berkeley database */ +class CDB +{ +protected: + Db* pdb; + std::string strFile; + DbTxn* activeTxn; + bool fReadOnly; + + explicit CDB(const std::string& strFilename, const char* pszMode = "r+"); + ~CDB() { Close(); } + +public: + void Flush(); + void Close(); + +private: + CDB(const CDB&); + void operator=(const CDB&); + +protected: + template + bool Read(const K& key, T& value) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Read + Dbt datValue; + datValue.set_flags(DB_DBT_MALLOC); + int ret = pdb->get(activeTxn, &datKey, &datValue, 0); + memset(datKey.get_data(), 0, datKey.get_size()); + if (datValue.get_data() == NULL) + return false; + + // Unserialize value + try { + CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + } catch (const std::exception&) { + return false; + } + + // Clear and free memory + memset(datValue.get_data(), 0, datValue.get_size()); + free(datValue.get_data()); + return (ret == 0); + } + + template + bool Write(const K& key, const T& value, bool fOverwrite = true) + { + if (!pdb) + return false; + if (fReadOnly) + assert(!"Write called on database in read-only mode"); + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Value + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + ssValue.reserve(10000); + ssValue << value; + Dbt datValue(&ssValue[0], ssValue.size()); + + // Write + int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); + + // Clear memory in case it was a private key + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + return (ret == 0); + } + + template + bool Erase(const K& key) + { + if (!pdb) + return false; + if (fReadOnly) + assert(!"Erase called on database in read-only mode"); + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Erase + int ret = pdb->del(activeTxn, &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0 || ret == DB_NOTFOUND); + } + + template + bool Exists(const K& key) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Exists + int ret = pdb->exists(activeTxn, &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0); + } + + Dbc* GetCursor() + { + if (!pdb) + return NULL; + Dbc* pcursor = NULL; + int ret = pdb->cursor(NULL, &pcursor, 0); + if (ret != 0) + return NULL; + return pcursor; + } + + int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT) + { + // Read at cursor + Dbt datKey; + datKey.set_data(NULL); + if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { + datKey.set_data(&ssKey[0]); + datKey.set_size(ssKey.size()); + } + Dbt datValue; + datValue.set_data(NULL); + if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { + datValue.set_data(&ssValue[0]); + datValue.set_size(ssValue.size()); + } + datKey.set_flags(DB_DBT_MALLOC); + datValue.set_flags(DB_DBT_MALLOC); + int ret = pcursor->get(&datKey, &datValue, fFlags); + if (ret != 0) { + if (datKey.get_data() != NULL) + free(datKey.get_data()); + if (datValue.get_data() != NULL) + free(datValue.get_data()); + + return ret; + } + else if (datKey.get_data() == NULL || datValue.get_data() == NULL) { + if (datKey.get_data() != NULL) + free(datKey.get_data()); + if (datValue.get_data() != NULL) + free(datValue.get_data()); + + return 99999; + } + + // Convert to streams + ssKey.SetType(SER_DISK); + ssKey.clear(); + ssKey.write((char*)datKey.get_data(), datKey.get_size()); + ssValue.SetType(SER_DISK); + ssValue.clear(); + ssValue.write((char*)datValue.get_data(), datValue.get_size()); + + // Clear and free memory + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + free(datKey.get_data()); + free(datValue.get_data()); + return 0; + } + +public: + bool TxnBegin() + { + if (!pdb || activeTxn) + return false; + DbTxn* ptxn = bitdb.TxnBegin(); + if (!ptxn) + return false; + activeTxn = ptxn; + return true; + } + + bool TxnCommit() + { + if (!pdb || !activeTxn) + return false; + int ret = activeTxn->commit(0); + activeTxn = NULL; + return (ret == 0); + } + + bool TxnAbort() + { + if (!pdb || !activeTxn) + return false; + int ret = activeTxn->abort(); + activeTxn = NULL; + return (ret == 0); + } + + bool ReadVersion(int& nVersion) + { + nVersion = 0; + return Read(std::string("version"), nVersion); + } + + bool WriteVersion(int nVersion) + { + return Write(std::string("version"), nVersion); + } + + bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); +}; + +#endif // BITCOIN_DB_H diff --git a/src/rpcdump.cpp b/src/wallet/rpcdump.cpp similarity index 99% rename from src/rpcdump.cpp rename to src/wallet/rpcdump.cpp index 5ddf2e48e8..ae69b246ab 100644 --- a/src/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -8,14 +8,14 @@ #include "bip38.h" #include "init.h" #include "main.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "script/script.h" #include "script/standard.h" #include "sync.h" #include "util.h" #include "utilstrencodings.h" #include "utiltime.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/rpcwallet.cpp b/src/wallet/rpcwallet.cpp similarity index 99% rename from src/rpcwallet.cpp rename to src/wallet/rpcwallet.cpp index a7c01c0ba2..f99bf4906a 100644 --- a/src/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -12,12 +12,12 @@ #include "init.h" #include "net.h" #include "netbase.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" -#include "wallet.h" -#include "walletdb.h" +#include "wallet/wallet.h" +#include "wallet/walletdb.h" #include #include diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp new file mode 100644 index 0000000000..5a8f80a76a --- /dev/null +++ b/src/wallet/test/wallet_tests.cpp @@ -0,0 +1,393 @@ +// Copyright (c) 2012-2014 The Bitcoin Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "wallet/wallet.h" +#include "miner.h" + +#include +#include +#include +#include + +#include + +// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles +#define RUN_TESTS 100 + +// some tests fail 1% of the time due to bad luck. +// we repeat those tests this many times and only complain if all iterations of the test fail +#define RANDOM_REPEATS 5 + +using namespace std; + +typedef set > CoinSet; +extern CWallet* pwalletMain; +extern int64_t nReserveBalance; + +BOOST_AUTO_TEST_SUITE(wallet_tests) + +static void generate_block(int count) { + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = count; + CReserveKey reservekey(pwalletMain); + + { // Don't keep cs_main locked + // LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart + nGenerate; + } + unsigned int nExtraNonce = 0; + while (nHeight < nHeightEnd) { + bool createPoSBlock = false; + if (nHeight > Params().LAST_POW_BLOCK()) + createPoSBlock = true; + + unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, createPoSBlock)); + BOOST_CHECK(pblocktemplate.get()); + + CBlock* pblock = &pblocktemplate->block; + { + // LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^32). That ain't gonna happen. + ++pblock->nNonce; + } + CValidationState state; + BOOST_CHECK(ProcessNewBlock(state, NULL, pblock)); + ++nHeight; + } +} + +#ifdef DISABLE_FAILED_TEST +static CWallet wallet; +static vector vCoins; + +static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) +{ + static int nextLockTime = 0; + CMutableTransaction tx; + tx.nLockTime = nextLockTime++; // so all transactions get different hashes + tx.vout.resize(nInput+1); + tx.vout[nInput].nValue = nValue; + if (fIsFromMe) { + // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(), + // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe() + tx.vin.resize(1); + } + CWalletTx* wtx = new CWalletTx(&wallet, tx); + if (fIsFromMe) + { + wtx->fDebitCached = true; + wtx->nDebitCached = 1; + } + COutput output(wtx, nInput, nAge, true); + vCoins.push_back(output); +} + +static void empty_wallet(void) +{ + for (COutput output : vCoins) + delete output.tx; + vCoins.clear(); +} + +static bool equal_sets(CoinSet a, CoinSet b) +{ + pair ret = mismatch(a.begin(), a.end(), b.begin()); + return ret.first == a.end() && ret.second == b.end(); +} + +BOOST_AUTO_TEST_CASE(coin_selection_tests) +{ + CoinSet setCoinsRet, setCoinsRet2; + CAmount nValueRet; + + LOCK(pwalletMain->cs_wallet); + + // test multiple times to allow for differences in the shuffle order + for (int i = 0; i < RUN_TESTS; i++) + { + empty_wallet(); + + // with an empty wallet we can't even pay one cent + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + add_coin(1*CENT, 4); // add a new 1 cent coin + + // with a new 1 cent coin, we still can't find a mature 1 cent + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + // but we can find a new 1 cent + BOOST_CHECK( pwalletMain->SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); + + add_coin(2*CENT); // add a mature 2 cent coin + + // we can't make 3 cents of mature coins + BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + // we can make 3 cents of new coins + BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); + + add_coin(5*CENT); // add a mature 5 cent coin, + add_coin(10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses + add_coin(20*CENT); // and a mature 20 cent coin + + // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38 + + // we can't make 38 cents only if we disallow new coins: + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + // we can't even make 37 cents if we don't allow new coins even if they're from us + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet)); + // but we can make 37 cents if we accept new coins from ourself + BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); + // and we can make 38 cents if we accept all new coins + BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); + + // try making 34 cents from 1,2,5,10,20 - we can't do it exactly + BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) + + // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 + BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + + // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough. + BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(nValueRet == 8 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); + + // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10) + BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + + // now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin + empty_wallet(); + + add_coin( 6*CENT); + add_coin( 7*CENT); + add_coin( 8*CENT); + add_coin(20*CENT); + add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total + + // check that we have 71 and not 72 + BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + + // now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + + add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total + + // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); + + add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30 + + // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins + + // now try making 11 cents. we should get 5+6 + BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + + // check that the smallest bigger coin is used + add_coin( 1*COIN); + add_coin( 2*COIN); + add_coin( 3*COIN); + add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + + BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + + // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance + empty_wallet(); + add_coin(0.1*CENT); + add_coin(0.2*CENT); + add_coin(0.3*CENT); + add_coin(0.4*CENT); + add_coin(0.5*CENT); + + // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents + // we'll get sub-cent change whatever happens, so can expect 1.0 exactly + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); + + // but if we add a bigger coin, making it possible to avoid sub-cent change, things change: + add_coin(1111*CENT); + + // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + + // if we add more sub-cent coins: + add_coin(0.6*CENT); + add_coin(0.7*CENT); + + // and try again to make 1.0 cents, we can still make 1.0 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + + // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) + // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change + empty_wallet(); + for (int i = 0; i < 20; i++) + add_coin(50000 * COIN); + + BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount + BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins + + // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0), + // we need to try finding an exact subset anyway + + // sometimes it will fail, and so we use the next biggest coin: + empty_wallet(); + add_coin(0.5 * CENT); + add_coin(0.6 * CENT); + add_coin(0.7 * CENT); + add_coin(1111 * CENT); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); + + // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0) + empty_wallet(); + add_coin(0.4 * CENT); + add_coin(0.6 * CENT); + add_coin(0.8 * CENT); + add_coin(1111 * CENT); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 + + // test avoiding sub-cent change + empty_wallet(); + add_coin(0.0005 * COIN); + add_coin(0.01 * COIN); + add_coin(1 * COIN); + + // trying to make 1.0001 from these three coins + BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); + + // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change + BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01 + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); + + // test randomness + { + empty_wallet(); + for (int i2 = 0; i2 < 100; i2++) + add_coin(COIN); + + // picking 50 from 100 coins doesn't depend on the shuffle, + // but does depend on randomness in the stochastic approximation code + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); + + int fails = 0; + for (int i = 0; i < RANDOM_REPEATS; i++) + { + // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time + // run the test RANDOM_REPEATS times and only complain if all of them fail + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + if (equal_sets(setCoinsRet, setCoinsRet2)) + fails++; + } + BOOST_CHECK_NE(fails, RANDOM_REPEATS); + + // add 75 cents in small change. not enough to make 90 cents, + // then try making 90 cents. there are multiple competing "smallest bigger" coins, + // one of which should be picked at random + add_coin( 5*CENT); add_coin(10*CENT); add_coin(15*CENT); add_coin(20*CENT); add_coin(25*CENT); + + fails = 0; + for (int i = 0; i < RANDOM_REPEATS; i++) + { + // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time + // run the test RANDOM_REPEATS times and only complain if all of them fail + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet)); + if (equal_sets(setCoinsRet, setCoinsRet2)) + fails++; + } + BOOST_CHECK_NE(fails, RANDOM_REPEATS); + } + } + empty_wallet(); +} +#endif + +BOOST_AUTO_TEST_CASE(test_StealthSend) +{ + SelectParams(CBaseChainParams::REGTEST); + std::string stealthAddr = "41iK3WWry6hR9QBMrYRXcybkXk8TCuvcBSeBov1PBehUR8bYVsiGecoEuq9pcLBHkVAJ5CNr3nAoqEjtRJywPUKX19URn9t22yF"; + CAmount nAmount = 100 * COIN; + CWalletTx wtx; + bool ret; + + // check stealth sending on 0 balance wallet + printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); + try { + ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); + } catch (std::exception& e) { + ret = false; + } + BOOST_CHECK_MESSAGE(!ret, "Sending to stealth address have to be failed on 0 balance wallet"); + + // check stealth sending on not enough balance and reservebalance wallet + generate_block(101); + nReserveBalance = pwalletMain->GetBalance() - 90 * COIN; + printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); + try { + ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); + } catch (std::exception& e) { + ret = false; + } + BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success with reservebalance wallet"); + + // check stealth sending on enough balance wallet + nReserveBalance = 0; + printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); + try { + ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); + } catch (std::exception& e) { + ret = false; + } + BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success on enough balance wallet"); + + printf("%llu/%llu/%llu/%llu\n", pwalletMain->GetSpendableBalance(), pwalletMain->GetBalance(), pwalletMain->GetUnlockedCoins(), pwalletMain->GetLockedCoins()); + + // check stealth sending on not enough balance wallet + SelectParams(CBaseChainParams::UNITTEST); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet.cpp b/src/wallet/wallet.cpp similarity index 99% rename from src/wallet.cpp rename to src/wallet/wallet.cpp index 16737d0510..8633d4a26e 100644 --- a/src/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6,7 +6,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "wallet.h" +#include "wallet/wallet.h" #include "base58.h" #include "checkpoints.h" diff --git a/src/wallet.h b/src/wallet/wallet.h similarity index 99% rename from src/wallet.h rename to src/wallet/wallet.h index d3086edb47..f734fb3700 100644 --- a/src/wallet.h +++ b/src/wallet/wallet.h @@ -18,7 +18,7 @@ #include "main.h" #include "primitives/block.h" #include "primitives/transaction.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "validationinterface.h" #include "wallet_ismine.h" diff --git a/src/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp similarity index 100% rename from src/wallet_ismine.cpp rename to src/wallet/wallet_ismine.cpp diff --git a/src/wallet_ismine.h b/src/wallet/wallet_ismine.h similarity index 100% rename from src/wallet_ismine.h rename to src/wallet/wallet_ismine.h diff --git a/src/walletdb.cpp b/src/wallet/walletdb.cpp similarity index 99% rename from src/walletdb.cpp rename to src/wallet/walletdb.cpp index 5e3124b5a1..a5d8b04b14 100644 --- a/src/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -14,7 +14,7 @@ #include "sync.h" #include "util.h" #include "utiltime.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/walletdb.h b/src/wallet/walletdb.h similarity index 99% rename from src/walletdb.h rename to src/wallet/walletdb.h index 7242a58278..4840287c1c 100644 --- a/src/walletdb.h +++ b/src/wallet/walletdb.h @@ -9,7 +9,7 @@ #define BITCOIN_WALLETDB_H #include "amount.h" -#include "db.h" +#include "wallet/db.h" #include "key.h" #include "keystore.h" From 9a14d7e759cd248e7c900b12b25ae481601f1414 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Dec 2019 19:20:59 -0500 Subject: [PATCH 0005/1888] [UI] Fix improperly parented walletView and segmentation fault on QT 5.10 The walletView element should be parented to walletStack instead of the WalletFrame. --- src/qt/walletframe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 165da02446..75d13a390c 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -41,7 +41,7 @@ bool WalletFrame::addWallet(const QString& name, WalletModel* walletModel) if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) return false; LogPrint("wallet", "initializing walletview"); - WalletView* walletView = new WalletView(this); + WalletView* walletView = new WalletView(walletStack); LogPrint("wallet", "setting bitcoin GUI"); walletView->setBitcoinGUI(gui); LogPrint("wallet", "setting client model"); From 507014985157eeb7ee68e6f753b5dea16c91250c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Dec 2019 19:33:31 -0500 Subject: [PATCH 0006/1888] [Log] Handle errors during log message formatting --- src/util.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/util.h b/src/util.h index 6ddbf7b863..63267fb5b5 100644 --- a/src/util.h +++ b/src/util.h @@ -64,6 +64,9 @@ int LogPrintStr(const std::string& str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) +/** Get format string from VA_ARGS for error reporting */ +template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } + /** * When we switch to C++11, this can be switched to variadic templates instead * of this macro-based construction (see tinyformat.h). @@ -74,13 +77,25 @@ int LogPrintStr(const std::string& str); static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ { \ if (!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + return LogPrintStr(_log_msg_); \ } \ /** Log error and return false */ \ template \ static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ { \ - LogPrintStr(std::string("ERROR: ") + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + LogPrintStr(std::string("ERROR: ") + _log_msg_ + "\n"); \ return false; \ } From 15e1fd1bbe34eb3bfb3e15cc15bee769dfc3234d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Dec 2019 19:34:54 -0500 Subject: [PATCH 0007/1888] [UI] Fix AA_EnableHighDpiScaling warning --- src/qt/dapscoin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 33f8eacbcd..395116ce68 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -609,7 +609,6 @@ int main(int argc, char* argv[]) Q_INIT_RESOURCE(dapscoin_locale); Q_INIT_RESOURCE(dapscoin); - BitcoinApplication app(argc, argv); #if QT_VERSION > 0x050100 // Generate high-dpi pixmaps QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); @@ -620,6 +619,7 @@ int main(int argc, char* argv[]) #ifdef Q_OS_MAC QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); #endif + BitcoinApplication app(argc, argv); // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType(); From 5d831fd744f2e2a1922fde15f79953ebc60f934c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Dec 2019 20:18:11 -0500 Subject: [PATCH 0008/1888] [Refactor] Remove unused setStakeSeen variable --- src/main.cpp | 9 --------- src/main.h | 1 - src/txdb.cpp | 3 --- 3 files changed, 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 18462166e0..9652c797c0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,7 +57,6 @@ CCriticalSection cs_main; BlockMap mapBlockIndex; map mapProofOfStake; -set > setStakeSeen; map mapHashedBlocks; CChain chainActive; CBlockIndex* pindexBestHeader = NULL; @@ -3851,10 +3850,6 @@ CBlockIndex* AddToBlockIndex(const CBlock& block) pindexNew->nSequenceId = 0; BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - pindexNew->phashBlock = &((*mi).first); BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { @@ -4830,10 +4825,6 @@ CBlockIndex* InsertBlockIndex(uint256 hash) throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - pindexNew->phashBlock = &((*mi).first); return pindexNew; diff --git a/src/main.h b/src/main.h index 56226b0a8c..37ee0e7331 100644 --- a/src/main.h +++ b/src/main.h @@ -172,7 +172,6 @@ extern std::map mapRejectedBlocks; extern std::map mapHashedBlocks; extern std::map mapInvalidOutPoints; extern std::map mapInvalidSerials; -extern std::set > setStakeSeen; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex* pindexBestHeader; diff --git a/src/txdb.cpp b/src/txdb.cpp index c76541736b..05ca4773e1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -300,9 +300,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); } - // ppcoin: build setStakeSeen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); //populate accumulator checksum map in memory if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { From 380745f2d16c6f5d2e960244036f311536326a14 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Dec 2019 18:42:57 -0500 Subject: [PATCH 0009/1888] build: Deduplicate version numbers Reduce the number of instances where the version number needs to be updated: - Doxygen client version is now generated by the build system - clientversion.h now either pulls from dapscoin-config.h or not at all Also update to newer Doxygen version --- configure.ac | 1 + doc/.gitignore | 1 + doc/Doxyfile | 1752 ------------------------------------------- src/Makefile.am | 12 +- src/clientversion.h | 28 +- 5 files changed, 18 insertions(+), 1776 deletions(-) create mode 100644 doc/.gitignore delete mode 100644 doc/Doxyfile diff --git a/configure.ac b/configure.ac index b65afa1fa8..a089dea3ca 100644 --- a/configure.ac +++ b/configure.ac @@ -1047,6 +1047,7 @@ AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/t AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) +AC_CONFIG_FILES([doc/Doxyfile]) dnl boost's m4 checks do something really nasty: they export these vars. As a dnl result, they leak into secp256k1's configure and crazy things happen. diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000000..cef6e7b6bc --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +Doxyfile \ No newline at end of file diff --git a/doc/Doxyfile b/doc/Doxyfile deleted file mode 100644 index 3f527e858a..0000000000 --- a/doc/Doxyfile +++ /dev/null @@ -1,1752 +0,0 @@ -# Doxyfile 1.7.4 - -# !!! Invoke doxygen from project root using: -# doxygen doc/Doxyfile - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = DAPScoin - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 2.3.99 - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = "P2P Digital Currency" - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = doc/bitcoin_logo_doxygen.png - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = doc/doxygen - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = src - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.d \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.idl \ - *.odl \ - *.cs \ - *.php \ - *.php3 \ - *.inc \ - *.m \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.for \ - *.vhd \ - *.vhdl - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = src/leveldb src/json src/test /src/qt/test - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = boost google - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is adviced to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the -# mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will write a font called Helvetica to the output -# directory and reference it in all dot files that doxygen generates. -# When you want a differently looking font you can specify the font name -# using DOT_FONTNAME. You need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. - -DOT_IMAGE_FORMAT = svg - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/src/Makefile.am b/src/Makefile.am index ea0642c52f..1ba22a02e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,7 @@ $(LIBLEVELDB) $(LIBMEMENV): endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config -BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BITCOIN_CONFIG_INCLUDES) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += -I$(srcdir)/secp256k1-mw/include @@ -508,6 +508,13 @@ DISTCLEANFILES = obj/build.h EXTRA_DIST = leveldb +config/dapscoin-config.h: config/stamp-h1 + @$(MAKE) -C $(top_builddir) $(subdir)/$(@) +config/stamp-h1: $(top_srcdir)/$(subdir)/config/dapscoin-config.h.in $(top_builddir)/config.status + $(AM_V_at)$(MAKE) -C $(top_builddir) $(subdir)/$(@) +$(top_srcdir)/$(subdir)/config/dapscoin-config.h.in: $(am__configure_deps) + $(AM_V_at)$(MAKE) -C $(top_srcdir) $(subdir)/config/dapscoin-config.h.in + clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean @@ -518,7 +525,8 @@ clean-local: .rc.o: @test -f $(WINDRES) - $(AM_V_GEN) $(WINDRES) -DWINDRES_PREPROC -i $< -o $@ + ## 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) \ diff --git a/src/clientversion.h b/src/clientversion.h index 7b947c87f7..8b7d28c221 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,29 +7,13 @@ #if defined(HAVE_CONFIG_H) #include "config/dapscoin-config.h" -#else - -/** - * client versioning and copyright year - */ - -//! These need to be macros, as clientversion.cpp's and dapscoin*-res.rc's voodoo requires it -#define CLIENT_VERSION_MAJOR 1 -#define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 5 -#define CLIENT_VERSION_BUILD 3 - -//! Set to true for release, false for prerelease or test build -#define CLIENT_VERSION_IS_RELEASE true - -/** - * Copyright year (2009-this) - * Todo: update this when changing our copyright comments in the source - */ -#define COPYRIGHT_YEAR 2019 - #endif //HAVE_CONFIG_H +// Check that required client information is defined +#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_REVISION) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR) +#error Client version information missing: version is not defined by dapscoin-config.h or in any other way +#endif + /** * Converts the parameter X to a string after macro replacement on X has been performed. * Don't merge these into one macro! From 2a4ea7fd763eab82c8a2ba81658a365b53542765 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Dec 2019 19:17:47 -0500 Subject: [PATCH 0010/1888] [Net] Pull uacomment in from upstream Used primarialy (for now) in node identification for upcoming regtest scripting. --- src/init.cpp | 18 +++++++++++++++++- src/main.cpp | 2 +- src/net.cpp | 4 ++-- src/net.h | 5 +++++ src/rpc/net.cpp | 3 +-- src/utilstrencodings.cpp | 23 ++++++++++++++--------- src/utilstrencodings.h | 17 ++++++++++++++++- 7 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2067d6e76b..888f2ff2cd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -466,6 +466,7 @@ std::string HelpMessage(HelpMessageMode mode) #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); + strUsage += HelpMessageOpt("-uacomment=", _("Append comment to the user agent string")); if (GetBoolArg("-help-debug", false)) { strUsage += HelpMessageOpt("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. Also sets -checkmempool (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); strUsage += HelpMessageOpt("-checkmempool=", strprintf("Run checks every transactions (default: %u)", Params(CBaseChainParams::MAIN).DefaultConsistencyChecks())); @@ -1177,7 +1178,22 @@ bool AppInit2(bool isDaemon) //run daemon only if (isDaemon) RegisterNodeSignals(GetNodeSignals()); // block first after unlock/lock retry register - + + // sanitize comments per BIP-0014, format user agent and check total size + std::vector uacomments; + for (const std::string& cmt : mapMultiArgs["-uacomment"]) { + if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); + uacomments.push_back(cmt); + } + + // format user agent, check total size + strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); + if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), + strSubVersion.size(), MAX_SUBVERSION_LENGTH)); + } + if (mapArgs.count("-onlynet")) { std::set nets; for (std::string snet : mapMultiArgs["-onlynet"]) { diff --git a/src/main.cpp b/src/main.cpp index 9652c797c0..fa95d42a94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5818,7 +5818,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; if (!vRecv.empty()) { - vRecv >> LIMITED_STRING(pfrom->strSubVer, 256); + vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/") { diff --git a/src/net.cpp b/src/net.cpp index 6edf3c376a..b2e0306619 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -87,6 +87,7 @@ static std::vector vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; bool fAddressesInitialized = false; +std::string strSubVersion; vector vNodes; CCriticalSection cs_vNodes; @@ -464,8 +465,7 @@ void CNode::PushVersion() { LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight, - true); + nLocalHostNonce, strSubVersion, nBestHeight, true); } diff --git a/src/net.h b/src/net.h index 7e3888697a..7db07c8d28 100644 --- a/src/net.h +++ b/src/net.h @@ -51,6 +51,8 @@ static const unsigned int MAX_INV_SZ = 50000; static const unsigned int MAX_ADDR_TO_SEND = 1000; /** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */ static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024; +/** Maximum length of strSubVer in `version` message */ +static const unsigned int MAX_SUBVERSION_LENGTH = 256; /** -listen default */ static const bool DEFAULT_LISTEN = true; /** -upnp default */ @@ -142,6 +144,9 @@ extern CCriticalSection cs_vAddedNodes; extern NodeId nLastNodeId; extern CCriticalSection cs_nLastNodeId; +/** Subversion as sent to the P2P network in `version` messages */ +extern std::string strSubVersion; + struct LocalServiceInfo { int nScore; int nPort; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 509b333149..670ded1cd7 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -407,8 +407,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); - obj.push_back(Pair("subversion", - FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()))); + obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("timeoffset", GetTimeOffset())); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 8427ece297..a94cbd98d8 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -22,16 +22,21 @@ using namespace std; -string SanitizeString(const string& str) +static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static const std::string SAFE_CHARS[] = { - /** - * safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything - * even possibly remotely dangerous like & or > - */ - static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_-/:?@()"); - string strResult; - for (std::string::size_type i = 0; i < str.size(); i++) { - if (safeChars.find(str[i]) != std::string::npos) + CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT + CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT + CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME +}; + +std::string SanitizeString(const std::string& str, int rule) +{ + std::string strResult; + for (std::string::size_type i = 0; i < str.size(); i++) + { + if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) strResult.push_back(str[i]); } return strResult; diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 00f53f5c05..8885939a84 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -23,7 +23,22 @@ /** This is needed because the foreach macro can't get over the comma in pair */ #define PAIRTYPE(t1, t2) std::pair -std::string SanitizeString(const std::string& str); +/** Used by SanitizeString() */ +enum SafeChars +{ + SAFE_CHARS_DEFAULT, //!< The full set of allowed chars + SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset + SAFE_CHARS_FILENAME, //!< Chars allowed in filenames +}; + +/** +* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email +* addresses, but avoid anything even possibly remotely dangerous like & or > +* @param[in] str The string to sanitize +* @param[in] rule The set of safe chars to choose (default: least restrictive) +* @return A new string without unsafe chars +*/ +std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT); std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); signed char HexDigit(char c); From d980df791bd54a8d93cf857fc6b85a4e99377351 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 00:02:54 -0500 Subject: [PATCH 0011/1888] [Build] Add info about '--with-unsupported-ssl' --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index a089dea3ca..7f11150eb7 100644 --- a/configure.ac +++ b/configure.ac @@ -802,10 +802,10 @@ else fi AC_CHECK_LIB([crypto],[RAND_egd],[],[ - AC_ARG_WITH([libressl], - [AS_HELP_STRING([--with-libressl],[Build with system LibreSSL (default is no; DANGEROUS; NOT SUPPORTED)])], - [AC_MSG_WARN([Detected LibreSSL: This is NOT supported, and may break consensus compatibility!])], - [AC_MSG_ERROR([Detected LibreSSL: This is NOT supported, and may break consensus compatibility!])] + AC_ARG_WITH([unsupported-ssl], + [AS_HELP_STRING([--with-unsupported-ssl],[Build with system SSL (default is no; DANGEROUS; NOT SUPPORTED; You should use OpenSSL 1.0)])], + [AC_MSG_WARN([Detected unsupported SSL version: This is NOT supported, and may break consensus compatibility! Use '--with-unsupported-ssl' if you don't care])], + [AC_MSG_ERROR([Detected unsupported SSL version: This is NOT supported, and may break consensus compatibility! Use '--with-unsupported-ssl' if you don't care])] ) ]) From 9fd2912d5d338e4b74522c677446d06ff5d5682e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 00:27:21 -0500 Subject: [PATCH 0012/1888] [Qt] Prevent double deletion of progress dialog --- src/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fa95d42a94..f33935a992 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2849,10 +2849,13 @@ bool RecalculateDAPSSupply(int nHeightStart) CBlockIndex* pindex = chainActive[nHeightStart]; CAmount nSupplyPrev = pindex->pprev->nMoneySupply; + uiInterface.ShowProgress(_("Recalculating DAPS supply..."), 0); while (true) { - if (pindex->nHeight % 1000 == 0) + if (pindex->nHeight % 1000 == 0) { LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); - + int percent = std::max(1, std::min(99, (int)((double)((pindex->nHeight - nHeightStart) * 100) / (chainActive.Height() - nHeightStart)))); + uiInterface.ShowProgress(_("Recalculating DAPS supply..."), percent); + } CBlock block; assert(ReadBlockFromDisk(block, pindex)); From 1676d03da04ed7ca56f92d50808e075658373fc9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 00:30:44 -0500 Subject: [PATCH 0013/1888] [RPC] Remove deprecated masternode/budget RPC commands --- src/rpc/budget.cpp | 108 +------------------------------ src/rpc/client.cpp | 4 -- src/rpc/masternode.cpp | 140 ----------------------------------------- src/rpc/server.cpp | 1 - src/rpc/server.h | 4 +- 5 files changed, 4 insertions(+), 253 deletions(-) diff --git a/src/rpc/budget.cpp b/src/rpc/budget.cpp index 1071cdaa51..14fc25dbc5 100644 --- a/src/rpc/budget.cpp +++ b/src/rpc/budget.cpp @@ -50,108 +50,6 @@ void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj) bObj.push_back(Pair("fValid", pbudgetProposal->fValid)); } -// This command is retained for backwards compatibility, but is depreciated. -// Future removal of this command is planned to keep things clean. -UniValue mnbudget(const UniValue& params, bool fHelp) -{ - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); - - if (fHelp || - (strCommand != "vote-alias" && strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check" && strCommand != "nextblock")) - throw runtime_error( - "mnbudget \"command\"... ( \"passphrase\" )\n" - "\nVote or show current budgets\n" - "This command is depreciated, please see individual command documentation for future reference\n\n" - - "\nAvailable commands:\n" - " prepare - Prepare proposal for network by signing and creating tx\n" - " submit - Submit proposal for network\n" - " vote-many - Vote on a Dapscoin initiative\n" - " vote-alias - Vote on a Dapscoin initiative\n" - " vote - Vote on a Dapscoin initiative/budget\n" - " getvotes - Show current masternode budgets\n" - " getinfo - Show current masternode budgets\n" - " show - Show all budgets\n" - " projection - Show the projection of which proposals will be paid the next cycle\n" - " check - Scan proposals and remove invalid\n" - " nextblock - Get next superblock for budget system\n"); - - if (strCommand == "nextblock") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getnextsuperblock(newParams, fHelp); - } - - if (strCommand == "prepare") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return preparebudget(newParams, fHelp); - } - - if (strCommand == "submit") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return submitbudget(newParams, fHelp); - } - - if (strCommand == "vote" || strCommand == "vote-many" || strCommand == "vote-alias") { - if (strCommand == "vote-alias") - throw runtime_error( - "vote-alias is not supported with this command\n" - "Please use mnbudgetvote instead.\n" - ); - return mnbudgetvote(params, fHelp); - } - - if (strCommand == "projection") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - } - - if (strCommand == "show" || strCommand == "getinfo") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetinfo(newParams, fHelp); - } - - if (strCommand == "getvotes") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetvotes(newParams, fHelp); - } - - if (strCommand == "check") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return checkbudgets(newParams, fHelp); - } - - return NullUniValue; -} - UniValue preparebudget(const UniValue& params, bool fHelp) { int nBlockMin = 0; @@ -159,7 +57,7 @@ UniValue preparebudget(const UniValue& params, bool fHelp) if (fHelp || params.size() != 6) throw runtime_error( - "preparebudget \"proposal-name\" \"url\" payment-count block-start \"dapscoin-address\" monthy-payment\n" + "preparebudget \"proposal-name\" \"url\" payment-count block-start \"dapscoin-address\" monthly-payment\n" "\nPrepare proposal for network by signing and creating tx\n" "\nArguments:\n" @@ -249,7 +147,7 @@ UniValue submitbudget(const UniValue& params, bool fHelp) if (fHelp || params.size() != 7) throw runtime_error( - "submitbudget \"proposal-name\" \"url\" payment-count block-start \"dapscoin-address\" monthy-payment \"fee-tx\"\n" + "submitbudget \"proposal-name\" \"url\" payment-count block-start \"dapscoin-address\" monthly-payment \"fee-tx\"\n" "\nSubmit proposal to the network\n" "\nArguments:\n" @@ -1028,7 +926,7 @@ UniValue checkbudgets(const UniValue& params, bool fHelp) if (fHelp || params.size() != 0) throw runtime_error( "checkbudgets\n" - "\nInitiates a buddget check cycle manually\n" + "\nInitiates a budget check cycle manually\n" "\nExamples:\n" + HelpExampleCli("checkbudgets", "") + HelpExampleRpc("checkbudgets", "")); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 2606714ded..d73cbd0565 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -113,10 +113,6 @@ static const CRPCConvertParam vRPCConvertParams[] = {"prioritisetransaction", 2}, {"setban", 2}, {"setban", 3}, - {"mnbudget", 3}, - {"mnbudget", 4}, - {"mnbudget", 6}, - {"mnbudget", 8}, {"preparebudget", 2}, {"preparebudget", 3}, {"preparebudget", 5}, diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 7606febca2..8ffae2ad85 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -50,146 +50,6 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp) return obj; } -// This command is retained for backwards compatibility, but is depreciated. -// Future removal of this command is planned to keep things clean. -UniValue masternode(const UniValue& params, bool fHelp) -{ - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); - - if (fHelp || - (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "start-all" && strCommand != "start-missing" && - strCommand != "start-disabled" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" && - strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" && - strCommand != "outputs" && strCommand != "status" && strCommand != "calcscore")) - throw runtime_error( - "masternode \"command\"...\n" - "\nSet of commands to execute masternode related actions\n" - "This command is depreciated, please see individual command documentation for future reference\n\n" - - "\nArguments:\n" - "1. \"command\" (string or set of strings, required) The command to execute\n" - - "\nAvailable commands:\n" - " count - Print count information of all known masternodes\n" - " current - Print info on current masternode winner\n" - " debug - Print masternode status\n" - " genkey - Generate new masternodeprivkey\n" - " outputs - Print masternode compatible outputs\n" - " start - Start masternode configured in dapscoin.conf\n" - " start-alias - Start single masternode by assigned alias configured in masternode.conf\n" - " start- - Start masternodes configured in masternode.conf (: 'all', 'missing', 'disabled')\n" - " status - Print masternode status information\n" - " list - Print list of all known masternodes (see masternodelist for more info)\n" - " list-conf - Print masternode.conf in JSON format\n" - " winners - Print list of masternode winners\n"); - - if (strCommand == "list") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodes(newParams, fHelp); - } - - if (strCommand == "connect") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - } - - if (strCommand == "count") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodecount(newParams, fHelp); - } - - if (strCommand == "current") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodecurrent(newParams, fHelp); - } - - if (strCommand == "debug") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodedebug(newParams, fHelp); - } - - if (strCommand == "start" || strCommand == "start-alias" || strCommand == "start-many" || strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") { - return startmasternode(params, fHelp); - } - - if (strCommand == "genkey") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return createmasternodekey(newParams, fHelp); - } - - if (strCommand == "list-conf") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodeconf(newParams, fHelp); - } - - if (strCommand == "outputs") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodeoutputs(newParams, fHelp); - } - - if (strCommand == "status") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodestatus(newParams, fHelp); - } - - if (strCommand == "winners") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodewinners(newParams, fHelp); - } - - if (strCommand == "calcscore") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodescores(newParams, fHelp); - } - - return NullUniValue; -} - UniValue listmasternodes(const UniValue& params, bool fHelp) { std::string strFilter = ""; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index c3a08b37c0..74858ac73f 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -343,7 +343,6 @@ static const CRPCCommand vRPCCommands[] = // {"hidden", "setmocktime", &setmocktime, true, false, false}, /* Dapscoin features */ - {"dapscoin", "masternode", &masternode, true, true, false}, {"dapscoin", "listmasternodes", &listmasternodes, true, true, false}, {"dapscoin", "getmasternodecount", &getmasternodecount, true, true, false}, {"dapscoin", "getcurrentseesawreward", &getcurrentseesawreward, true, true, false}, diff --git a/src/rpc/server.h b/src/rpc/server.h index c5aca92be3..24be590ad5 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -300,7 +300,6 @@ extern UniValue reconsiderblock(const UniValue& params, bool fHelp); extern UniValue getinvalid(const UniValue& params, bool fHelp); extern UniValue getpoolinfo(const UniValue& params, bool fHelp); -extern UniValue masternode(const UniValue& params, bool fHelp); extern UniValue listmasternodes(const UniValue& params, bool fHelp); extern UniValue getmasternodecount(const UniValue& params, bool fHelp); extern UniValue createmasternodebroadcast(const UniValue& params, bool fHelp); @@ -320,8 +319,7 @@ extern UniValue getmasternodestatus(const UniValue& params, bool fHelp); extern UniValue getmasternodewinners(const UniValue& params, bool fHelp); extern UniValue getmasternodescores(const UniValue& params, bool fHelp); -extern UniValue mnbudget(const UniValue& params, bool fHelp); // in rpcmasternode-budget.cpp -extern UniValue preparebudget(const UniValue& params, bool fHelp); +extern UniValue preparebudget(const UniValue& params, bool fHelp); // in rpc/budget.cpp extern UniValue submitbudget(const UniValue& params, bool fHelp); extern UniValue mnbudgetvote(const UniValue& params, bool fHelp); extern UniValue getbudgetvotes(const UniValue& params, bool fHelp); From 901d3a593e1c5741a365ab0b77d353683369f7ef Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 00:36:28 -0500 Subject: [PATCH 0014/1888] [Staking] Prevent potential negative out values during stake splitting --- src/masternode-payments.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 4553513bc6..7eac1c1fab 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -330,7 +330,20 @@ bool CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe std::copy(mnPaymentPrivTx.begin(), mnPaymentPrivTx.end(), std::back_inserter(txNew.vout[i].txPriv)); std::copy(mnPaymentPubTx.begin(), mnPaymentPubTx.end(), std::back_inserter(txNew.vout[i].txPub)); //subtract mn payment from the stake reward - txNew.vout[i - 1].nValue -= masternodePayment; + if (i == 2) { + // Majority of cases; do it quick and move on + txNew.vout[i - 1].nValue -= masternodePayment; + } else if (i > 2) { + // special case, stake is split between (i-1) outputs + unsigned int outputs = i-1; + CAmount mnPaymentSplit = masternodePayment / outputs; + CAmount mnPaymentRemainder = masternodePayment - (mnPaymentSplit * outputs); + for (unsigned int j=1; j<=outputs; j++) { + txNew.vout[j].nValue -= mnPaymentSplit; + } + // in case it's not an even division, take the last bit of dust from the last one + txNew.vout[outputs].nValue -= mnPaymentRemainder; + } } else { txNew.vout.resize(2); txNew.vout[1].scriptPubKey = payee; From b932ab0190914a69dccb96c19592caecbb6c32c4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 01:45:04 -0500 Subject: [PATCH 0015/1888] [Trivial] AdvertizeLocal -> AdvertiseLocal --- src/main.cpp | 6 +++--- src/net.cpp | 5 +++-- src/net.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f33935a992..a4ae2f9191 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -924,7 +924,7 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex* pindex mapBlocksInFlight[hash] = std::make_pair(nodeid, it); } -/** Check whether the last unknown block a peer advertized is not yet known. */ +/** Check whether the last unknown block a peer advertiszed is not yet known. */ void ProcessBlockAvailability(NodeId nodeid) { CNodeState* state = State(nodeid); @@ -6754,7 +6754,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pnode->setAddrKnown.clear(); // Rebroadcast our address - AdvertizeLocal(pnode); + AdvertiseLocal(pnode); } if (!vNodes.empty()) nLastRebroadcast = GetTime(); @@ -6880,7 +6880,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link - // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes + // being saturated. We only count validated in-flight blocks so peers can't advertise nonexisting block hashes // to unreasonably increase our timeout. if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", diff --git a/src/net.cpp b/src/net.cpp index b2e0306619..b254602a4c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -216,7 +216,8 @@ bool IsPeerAddrLocalGood(CNode *pnode) { } // pushes our own address to a peer -void AdvertizeLocal(CNode *pnode) { +void AdvertiseLocal(CNode* pnode) +{ if (fListen && pnode->fSuccessfullyConnected) { CAddress addrLocal = GetLocalAddress(&pnode->addr); // If discovery is enabled, sometimes give our peer the address it @@ -227,7 +228,7 @@ void AdvertizeLocal(CNode *pnode) { addrLocal.SetIP(pnode->addrLocal); } if (addrLocal.IsRoutable()) { - LogPrintf("AdvertizeLocal: advertizing address %s\n", addrLocal.ToString()); + LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } diff --git a/src/net.h b/src/net.h index 7db07c8d28..417cf52bf7 100644 --- a/src/net.h +++ b/src/net.h @@ -109,7 +109,7 @@ enum { }; bool IsPeerAddrLocalGood(CNode* pnode); -void AdvertizeLocal(CNode* pnode); +void AdvertiseLocal(CNode* pnode); void SetLimited(enum Network net, bool fLimited = true); bool IsLimited(enum Network net); bool IsLimited(const CNetAddr& addr); From 8108b4bb34b62932c186767ccb7936a879c61915 Mon Sep 17 00:00:00 2001 From: JD Date: Wed, 18 Dec 2019 01:47:01 -0500 Subject: [PATCH 0016/1888] Minor Build Fixes (#20) * Minor fixes - Fix incorrect paths - Remove non-existent file references - Remove incorrectly moved files * Update missing line break in Miner logs --- contrib/dapscoin-qt.pro | 45 +- src/Makefile.am | 6 +- src/miner.cpp | 8 +- src/qt/forms/obfuscationconfig.ui | 188 -- src/rpc/dump.cpp | 504 ----- src/rpc/wallet.cpp | 3015 ----------------------------- 6 files changed, 21 insertions(+), 3745 deletions(-) delete mode 100644 src/qt/forms/obfuscationconfig.ui delete mode 100644 src/rpc/dump.cpp delete mode 100644 src/rpc/wallet.cpp diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index e89aa0d726..2aafcd8531 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -77,14 +77,13 @@ HEADERS += src/activemasternode.h \ src/crypter.h \ src/obfuscation-relay.h \ src/obfuscation.h \ - src/dapscoin-config.h \ - src/db.h \ + src/config/dapscoin-config.h \ + src/wallet/db.h \ src/eccryptoverify.h \ src/ecwrapper.h \ src/hash.h \ src/init.h \ src/swifttx.h \ - src/keepass.h \ src/key.h \ src/keystore.h \ src/leveldbwrapper.h \ @@ -106,11 +105,10 @@ HEADERS += src/activemasternode.h \ src/protocol.h \ src/pubkey.h \ src/random.h \ - src/rpcclient.h \ - src/rpcprotocol.h \ - src/rpcserver.h \ + src/rpc/client.h \ + src/rpc/protocol.h \ + src/rpc/server.h \ src/serialize.h \ - src/spork.h \ src/streams.h \ src/sync.h \ src/threadsafety.h \ @@ -126,9 +124,9 @@ HEADERS += src/activemasternode.h \ src/utilstrencodings.h \ src/utiltime.h \ src/version.h \ - src/wallet.h \ - src/wallet_ismine.h \ - src/walletdb.h \ + src/wallet/wallet.h \ + src/wallet/wallet_ismine.h \ + src/wallet/walletdb.h \ src/compat/sanity.h \ src/config/dapscoin-config.h \ src/crypto/common.h \ @@ -151,15 +149,6 @@ HEADERS += src/activemasternode.h \ src/crypto/sph_simd.h \ src/crypto/sph_skein.h \ src/crypto/sph_types.h \ - src/json/json_spirit.h \ - src/json/json_spirit_error_position.h \ - src/json/json_spirit_reader.h \ - src/json/json_spirit_reader_template.h \ - src/json/json_spirit_stream_reader.h \ - src/json/json_spirit_utils.h \ - src/json/json_spirit_value.h \ - src/json/json_spirit_writer.h \ - src/json/json_spirit_writer_template.h \ src/obj/build.h \ src/primitives/block.h \ src/primitives/transaction.h \ @@ -174,7 +163,6 @@ HEADERS += src/activemasternode.h \ src/qt/coincontroldialog.h \ src/qt/coincontroltreewidget.h \ src/qt/csvmodelwriter.h \ - src/qt/obfuscationconfig.h \ src/qt/editaddressdialog.h \ src/qt/guiconstants.h \ src/qt/guiutil.h \ @@ -266,7 +254,6 @@ HEADERS += src/activemasternode.h \ src/leveldb/util/random.h \ src/leveldb/util/testharness.h \ src/leveldb/util/testutil.h \ - src/qt/forms/ui_aboutdialog.h \ src/qt/test/paymentrequestdata.h \ src/qt/test/paymentservertests.h \ src/qt/test/uritests.h \ @@ -343,7 +330,6 @@ HEADERS += src/activemasternode.h \ FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/askpassphrasedialog.ui \ src/qt/forms/coincontroldialog.ui \ - src/qt/forms/obfuscationconfig.ui \ src/qt/forms/editaddressdialog.ui \ src/qt/forms/helpmessagedialog.ui \ src/qt/forms/historypage.ui \ @@ -383,14 +369,13 @@ SOURCES += src/activemasternode.cpp \ src/dapscoin-cli.cpp \ src/dapscoin-tx.cpp \ src/dapscoin.cpp \ - src/db.cpp \ + src/wallet/db.cpp \ src/eccryptoverify.cpp \ src/ecwrapper.cpp \ src/editaddressdialog.cpp \ src/hash.cpp \ src/init.cpp \ src/swifttx.cpp \ - src/keepass.cpp \ src/key.cpp \ src/keystore.cpp \ src/leveldbwrapper.cpp \ @@ -413,7 +398,7 @@ SOURCES += src/activemasternode.cpp \ src/rest.cpp \ src/rpc/blockchain.cpp \ src/rpc/client.cpp \ - src/rpc/dump.cpp \ + src/wallet/rpcdump.cpp \ src/rpc/budget.cpp \ src/rpc/masternode.cpp \ src/rpc/mining.cpp \ @@ -422,8 +407,7 @@ SOURCES += src/activemasternode.cpp \ src/rpc/protocol.cpp \ src/rpc/rawtransaction.cpp \ src/rpc/server.cpp \ - src/rpc/wallet.cpp \ - src/spork.cpp \ + src/wallet/rpcwallet.cpp \ src/sync.cpp \ src/timedata.cpp \ src/txdb.cpp \ @@ -433,9 +417,9 @@ SOURCES += src/activemasternode.cpp \ src/utilmoneystr.cpp \ src/utilstrencodings.cpp \ src/utiltime.cpp \ - src/wallet.cpp \ - src/wallet_ismine.cpp \ - src/walletdb.cpp \ + src/wallet/wallet.cpp \ + src/wallet/wallet_ismine.cpp \ + src/wallet/walletdb.cpp \ src/compat/glibc_compat.cpp \ src/compat/glibc_sanity.cpp \ src/compat/glibcxx_compat.cpp \ @@ -476,7 +460,6 @@ SOURCES += src/activemasternode.cpp \ src/qt/coincontroldialog.cpp \ src/qt/coincontroltreewidget.cpp \ src/qt/csvmodelwriter.cpp \ - src/qt/obfuscationconfig.cpp \ src/qt/dapscoin.cpp \ src/qt/dapscoinstrings.cpp \ src/qt/editaddressdialog.cpp \ diff --git a/src/Makefile.am b/src/Makefile.am index ea0642c52f..c1c70e77df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,9 +153,9 @@ BITCOIN_CORE_H = \ random.h \ reverselock.h \ reverse_iterate.h \ - rpcclient.h \ - rpcprotocol.h \ - rpcserver.h \ + rpc/client.h \ + rpc/protocol.h \ + rpc/server.h \ scheduler.h \ script/interpreter.h \ script/script.h \ diff --git a/src/miner.cpp b/src/miner.cpp index 2ba99a9e26..8375722982 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -835,9 +835,9 @@ void static ThreadBitcoinMiner(void* parg) } boost::this_thread::interruption_point(); } catch (std::exception& e) { - LogPrintf("ThreadBitcoinMiner() exception"); + LogPrintf("ThreadBitcoinMiner() exception\n"); } catch (...) { - LogPrintf("ThreadBitcoinMiner() exception"); + LogPrintf("ThreadBitcoinMiner() exception\n"); } LogPrintf("ThreadBitcoinMiner exiting\n"); @@ -854,9 +854,9 @@ void static ThreadDapscoinMiner(void* parg) } boost::this_thread::interruption_point(); } catch (std::exception& e) { - LogPrintf("ThreadBitcoinMiner() exception"); + LogPrintf("ThreadBitcoinMiner() exception\n"); } catch (...) { - LogPrintf("ThreadBitcoinMiner() exception"); + LogPrintf("ThreadBitcoinMiner() exception\n"); } LogPrintf("ThreadBitcoinMiner exiting\n"); diff --git a/src/qt/forms/obfuscationconfig.ui b/src/qt/forms/obfuscationconfig.ui deleted file mode 100644 index e03ce0f89c..0000000000 --- a/src/qt/forms/obfuscationconfig.ui +++ /dev/null @@ -1,188 +0,0 @@ - - - ObfuscationConfig - - - - 0 - 0 - 630 - 307 - - - - Configure Obfuscation - - - - - 20 - 70 - 151 - 27 - - - - Basic Privacy - - - - - - 20 - 140 - 151 - 27 - - - - High Privacy - - - - - - 20 - 210 - 151 - 27 - - - - Maximum Privacy - - - - - - 30 - 20 - 571 - 31 - - - - Please select a privacy level. - - - - - - 190 - 70 - 421 - 21 - - - - Use 2 separate masternodes to mix funds up to 1000000 DAPS - - - - - - 190 - 140 - 411 - 21 - - - - Use 8 separate masternodes to mix funds up to 1000000 DAPS - - - - - - 190 - 210 - 421 - 21 - - - - Use 16 separate masternodes - - - - - - 40 - 100 - 561 - 21 - - - - This option is the quickest and will cost about ~0.025 DAPS to anonymize 10000 DAPS - - - - - - 40 - 170 - 561 - 21 - - - - This option is moderately fast and will cost about 0.05 DAPS to anonymize 10000 DAPS - - - - - - 40 - 240 - 561 - 21 - - - - This is the slowest and most secure option. Using maximum anonymity will cost - - - - - - 40 - 260 - 561 - 21 - - - - 0.1 DAPS per 10000 DAPS you anonymize. - - - - - - 10 - 120 - 601 - 16 - - - - Qt::Horizontal - - - - - - 10 - 190 - 601 - 16 - - - - Qt::Horizontal - - - - - - diff --git a/src/rpc/dump.cpp b/src/rpc/dump.cpp deleted file mode 100644 index ae69b246ab..0000000000 --- a/src/rpc/dump.cpp +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright (c) 2009-2014 The Bitcoin developers -// Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "bip38.h" -#include "init.h" -#include "main.h" -#include "rpc/server.h" -#include "script/script.h" -#include "script/standard.h" -#include "sync.h" -#include "util.h" -#include "utilstrencodings.h" -#include "utiltime.h" -#include "wallet/wallet.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include - -using namespace std; - -void EnsureWalletIsUnlocked(); - -std::string static EncodeDumpTime(int64_t nTime) -{ - return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); -} - -int64_t static DecodeDumpTime(const std::string& str) -{ - static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0); - static const std::locale loc(std::locale::classic(), - new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ")); - std::istringstream iss(str); - iss.imbue(loc); - boost::posix_time::ptime ptime(boost::date_time::not_a_date_time); - iss >> ptime; - if (ptime.is_not_a_date_time()) - return 0; - return (ptime - epoch).total_seconds(); -} - -std::string static EncodeDumpString(const std::string& str) -{ - std::stringstream ret; - for (unsigned char c : str) { - if (c <= 32 || c >= 128 || c == '%') { - ret << '%' << HexStr(&c, &c + 1); - } else { - ret << c; - } - } - return ret.str(); -} - -std::string DecodeDumpString(const std::string& str) -{ - std::stringstream ret; - for (unsigned int pos = 0; pos < str.length(); pos++) { - unsigned char c = str[pos]; - if (c == '%' && pos + 2 < str.length()) { - c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) | - ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15)); - pos += 2; - } - ret << c; - } - return ret.str(); -} - -UniValue importprivkey(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 3) - throw runtime_error( - "importprivkey \"dapscoinprivkey\" ( \"label\" rescan )\n" - "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" - "\nArguments:\n" - "1. \"dapscoinprivkey\" (string, required) The private key (see dumpprivkey)\n" - "2. \"label\" (string, optional, default=\"\") An optional label\n" - "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" - "\nNote: This call can take minutes to complete if rescan is true.\n" - "\nExamples:\n" - "\nDump a private key\n" + - HelpExampleCli("dumpprivkey", "\"myaddress\"") + - "\nImport the private key with rescan\n" + HelpExampleCli("importprivkey", "\"mykey\"") + - "\nImport using a label and without rescan\n" + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + - "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")); - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - string strSecret = params[0].get_str(); - string strLabel = ""; - if (params.size() > 1) - strLabel = params[1].get_str(); - - // Whether to perform rescan after import - bool fRescan = true; - if (params.size() > 2) - fRescan = params[2].get_bool(); - - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); - - CKey key = vchSecret.GetKey(); - if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); - - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); - CKeyID vchAddress = pubkey.GetID(); - { - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); - - // Don't throw error in case a key is already there - if (pwalletMain->HaveKey(vchAddress)) - return NullUniValue; - - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; - - if (!pwalletMain->AddKeyPubKey(key, pubkey)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - - // whenever a key is imported, we need to scan the whole chain - pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' - - if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - } - } - - return NullUniValue; -} - -UniValue importaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 3) - throw runtime_error( - "importaddress \"address\" ( \"label\" rescan )\n" - "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n" - "\nArguments:\n" - "1. \"address\" (string, required) The address\n" - "2. \"label\" (string, optional, default=\"\") An optional label\n" - "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" - "\nNote: This call can take minutes to complete if rescan is true.\n" - "\nExamples:\n" - "\nImport an address with rescan\n" + - HelpExampleCli("importaddress", "\"myaddress\"") + - "\nImport using a label without rescan\n" + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + - "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - CScript script; - - CBitcoinAddress address(params[0].get_str()); - if (address.IsValid()) { - script = GetScriptForDestination(address.Get()); - } else if (IsHex(params[0].get_str())) { - std::vector data(ParseHex(params[0].get_str())); - script = CScript(data.begin(), data.end()); - } else { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address or script"); - } - - string strLabel = ""; - if (params.size() > 1) - strLabel = params[1].get_str(); - - // Whether to perform rescan after import - bool fRescan = true; - if (params.size() > 2) - fRescan = params[2].get_bool(); - - { - if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) - throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); - - // add to address book or update label - if (address.IsValid()) - pwalletMain->SetAddressBook(address.Get(), strLabel, "receive"); - - // Don't throw error in case an address is already there - if (pwalletMain->HaveWatchOnly(script)) - return NullUniValue; - - pwalletMain->MarkDirty(); - - if (!pwalletMain->AddWatchOnly(script)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); - - if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - pwalletMain->ReacceptWalletTransactions(); - } - } - - return NullUniValue; -} - -UniValue importwallet(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "importwallet \"filename\"\n" - "\nImports keys from a wallet dump file (see dumpwallet).\n" - "\nArguments:\n" - "1. \"filename\" (string, required) The wallet file\n" - "\nExamples:\n" - "\nDump the wallet\n" + - HelpExampleCli("dumpwallet", "\"test\"") + - "\nImport the wallet\n" + HelpExampleCli("importwallet", "\"test\"") + - "\nImport using the json rpc call\n" + HelpExampleRpc("importwallet", "\"test\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - ifstream file; - file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - - int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); - - bool fGood = true; - - int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); - file.seekg(0, file.beg); - - pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI - while (file.good()) { - pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100)))); - std::string line; - std::getline(file, line); - if (line.empty() || line[0] == '#') - continue; - - std::vector vstr; - boost::split(vstr, line, boost::is_any_of(" ")); - if (vstr.size() < 2) - continue; - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) - continue; - CKey key = vchSecret.GetKey(); - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); - CKeyID keyid = pubkey.GetID(); - if (pwalletMain->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); - continue; - } - int64_t nTime = DecodeDumpTime(vstr[1]); - std::string strLabel; - bool fLabel = true; - for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { - if (boost::algorithm::starts_with(vstr[nStr], "#")) - break; - if (vstr[nStr] == "change=1") - fLabel = false; - if (vstr[nStr] == "reserve=1") - fLabel = false; - if (boost::algorithm::starts_with(vstr[nStr], "label=")) { - strLabel = DecodeDumpString(vstr[nStr].substr(6)); - fLabel = true; - } - } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { - fGood = false; - continue; - } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwalletMain->SetAddressBook(keyid, strLabel, "receive"); - nTimeBegin = std::min(nTimeBegin, nTime); - } - file.close(); - pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI - - CBlockIndex* pindex = chainActive.Tip(); - while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) - pindex = pindex->pprev; - - if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey) - pwalletMain->nTimeFirstKey = nTimeBegin; - - LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); - pwalletMain->ScanForWalletTransactions(pindex); - pwalletMain->MarkDirty(); - - if (!fGood) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); - - return NullUniValue; -} - -UniValue dumpprivkey(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "dumpprivkey \"dapscoinaddress\"\n" - "\nReveals the private key corresponding to 'dapscoinaddress'.\n" - "Then the importprivkey can be used with this output\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address for the private key\n" - "\nResult:\n" - "\"key\" (string) The private key\n" - "\nExamples:\n" + - HelpExampleCli("dumpprivkey", "\"myaddress\"") + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - string strAddress = params[0].get_str(); - CBitcoinAddress address; - if (!address.SetString(strAddress)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - CKeyID keyID; - if (!address.GetKeyID(keyID)) - throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); - CKey vchSecret; - if (!pwalletMain->GetKey(keyID, vchSecret)) - throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); - return CBitcoinSecret(vchSecret).ToString(); -} - - -UniValue dumpwallet(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "dumpwallet \"filename\"\n" - "\nDumps all wallet keys in a human-readable format.\n" - "\nArguments:\n" - "1. \"filename\" (string, required) The filename\n" - "\nExamples:\n" + - HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - ofstream file; - file.open(params[0].get_str().c_str()); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - - std::map mapKeyBirth; - std::set setKeyPool; - pwalletMain->GetKeyBirthTimes(mapKeyBirth); - pwalletMain->GetAllReserveKeys(setKeyPool); - - // sort time/key pairs - std::vector > vKeyBirth; - for (std::map::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { - vKeyBirth.push_back(std::make_pair(it->second, it->first)); - } - mapKeyBirth.clear(); - std::sort(vKeyBirth.begin(), vKeyBirth.end()); - - // produce output - file << strprintf("# Wallet dump created by DAPS %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); - file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); - file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); - file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); - file << "\n"; - for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { - const CKeyID& keyid = it->second; - std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); - CKey key; - if (pwalletMain->GetKey(keyid, key)) { - if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); - } else if (setKeyPool.count(keyid)) { - file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); - } else { - file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); - } - } - } - file << "\n"; - file << "# End of dump\n"; - file.close(); - return NullUniValue; -} - -UniValue bip38encrypt(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "bip38encrypt \"dapscoinaddress\"\n" - "\nEncrypts a private key corresponding to 'dapscoinaddress'.\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address for the private key (you must hold the key already)\n" - "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with - Valid special chars: !#$%&'()*+,-./:;<=>?`{|}~ \n" - "\nResult:\n" - "\"key\" (string) The encrypted private key\n" - "\nExamples:\n"); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - string strAddress = params[0].get_str(); - string strPassphrase = params[1].get_str(); - - CBitcoinAddress address; - if (!address.SetString(strAddress)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - CKeyID keyID; - if (!address.GetKeyID(keyID)) - throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); - CKey vchSecret; - if (!pwalletMain->GetKey(keyID, vchSecret)) - throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); - - uint256 privKey = vchSecret.GetPrivKey_256(); - string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed()); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("Addess", strAddress)); - result.push_back(Pair("Encrypted Key", encryptedOut)); - - return result; -} - -UniValue bip38decrypt(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "bip38decrypt \"dapscoinaddress\"\n" - "\nDecrypts and then imports password protected private key.\n" - "\nArguments:\n" - "1. \"encryptedkey\" (string, required) The encrypted private key\n" - "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with\n" - - "\nResult:\n" - "\"key\" (string) The decrypted private key\n" - "\nExamples:\n"); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - /** Collect private key and passphrase **/ - string strKey = params[0].get_str(); - string strPassphrase = params[1].get_str(); - - uint256 privKey; - bool fCompressed; - if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) - throw JSONRPCError(RPC_WALLET_ERROR, "Failed To Decrypt"); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("privatekey", HexStr(privKey))); - - CKey key; - key.Set(privKey.begin(), privKey.end(), fCompressed); - - if (!key.IsValid()) - throw JSONRPCError(RPC_WALLET_ERROR, "Private Key Not Valid"); - - CPubKey pubkey = key.GetPubKey(); - pubkey.IsCompressed(); - assert(key.VerifyPubKey(pubkey)); - result.push_back(Pair("Address", CBitcoinAddress(pubkey.GetID()).ToString())); - CKeyID vchAddress = pubkey.GetID(); - { - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, "", "receive"); - - // Don't throw error in case a key is already there - if (pwalletMain->HaveKey(vchAddress)) - throw JSONRPCError(RPC_WALLET_ERROR, "Key already held by wallet"); - - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; - - if (!pwalletMain->AddKeyPubKey(key, pubkey)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); - - // whenever a key is imported, we need to scan the whole chain - pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - } - - return result; -} diff --git a/src/rpc/wallet.cpp b/src/rpc/wallet.cpp deleted file mode 100644 index f99bf4906a..0000000000 --- a/src/rpc/wallet.cpp +++ /dev/null @@ -1,3015 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "amount.h" -#include "base58.h" -#include "core_io.h" -#include "init.h" -#include "net.h" -#include "netbase.h" -#include "rpc/server.h" -#include "timedata.h" -#include "util.h" -#include "utilmoneystr.h" -#include "wallet/wallet.h" -#include "wallet/walletdb.h" - -#include -#include -#include - -#include -#include - -using namespace std; -using namespace boost; -using namespace boost::assign; - -int64_t nWalletUnlockTime; -static CCriticalSection cs_nWalletUnlockTime; - -std::string HelpRequiringPassphrase() -{ - return pwalletMain && pwalletMain->IsCrypted() ? "\nRequires wallet passphrase to be set with walletpassphrase call." : ""; -} - -void EnsureWalletIsUnlocked() -{ - if (pwalletMain->IsLocked() || pwalletMain->fWalletUnlockAnonymizeOnly) - throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with unlockwallet first."); -} - -void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) -{ - int confirms = wtx.GetDepthInMainChain(false); - int confirmsTotal = GetIXConfirmations(wtx.GetHash()) + confirms; - entry.push_back(Pair("confirmations", confirmsTotal)); - entry.push_back(Pair("bcconfirmations", confirms)); - if (wtx.IsCoinBase() || wtx.IsCoinStake()) - entry.push_back(Pair("generated", true)); - if (confirms > 0) { - entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); - entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); - } - uint256 hash = wtx.GetHash(); - entry.push_back(Pair("txid", hash.GetHex())); - UniValue conflicts(UniValue::VARR); - for (const uint256& conflict : wtx.GetConflicts()) - conflicts.push_back(conflict.GetHex()); - entry.push_back(Pair("walletconflicts", conflicts)); - entry.push_back(Pair("time", wtx.GetTxTime())); - entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); - for (const PAIRTYPE(string, string) & item : wtx.mapValue) - entry.push_back(Pair(item.first, item.second)); -} - -string AccountFromValue(const UniValue& value) -{ - string strAccount = value.get_str(); - if (strAccount == "*") - throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); - return strAccount; -} - -UniValue getnewaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getnewaddress ( \"account\" )\n" - "\nReturns a new DAPS address for receiving payments.\n" - "If 'account' is specified (recommended), it is added to the address book \n" - "so payments received with the address will be credited to 'account'.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" - "\nResult:\n" - "\"dapscoinaddress\" (string) The new dapscoin address\n" - "\nExamples:\n" + - HelpExampleCli("getnewaddress", "") + HelpExampleCli("getnewaddress", "\"\"") + HelpExampleCli("getnewaddress", "\"myaccount\"") + HelpExampleRpc("getnewaddress", "\"myaccount\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Parse the account first so we don't generate a key if there's an error - string strAccount; - if (params.size() > 0) - strAccount = AccountFromValue(params[0]); - - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - // Generate a new key that is added to wallet - CPubKey newKey; - if (!pwalletMain->GetKeyFromPool(newKey)) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - CKeyID keyID = newKey.GetID(); - - pwalletMain->SetAddressBook(keyID, strAccount, "receive"); - - return CBitcoinAddress(keyID).ToString(); -} - - -CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - - CAccount account; - walletdb.ReadAccount(strAccount, account); - - bool bKeyUsed = false; - - // Check if the current key has been used - if (account.vchPubKey.IsValid()) { - CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); - ++it) { - const CWalletTx& wtx = (*it).second; - for (const CTxOut& txout : wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - bKeyUsed = true; - } - } - - // Generate a new key - if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { - EnsureWalletIsUnlocked(); - if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); - walletdb.WriteAccount(strAccount, account); - } - - return CBitcoinAddress(account.vchPubKey.GetID()); -} - -CBitcoinAddress GetHDAccountAddress(string strAccount, uint32_t nAccountIndex, bool bForceNew = false) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - - CAccount account; - walletdb.ReadAccount(strAccount, account); - - bool bKeyUsed = false; - - // Check if the current key has been used - if (account.vchPubKey.IsValid()) { - CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map::iterator it = pwalletMain->mapWallet.begin(); - it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); - ++it) { - const CWalletTx& wtx = (*it).second; - for (const CTxOut& txout : wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - bKeyUsed = true; - } - } - - // Generate a new key - if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { - EnsureWalletIsUnlocked(); - // if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) - // throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - CKey newKey; - pwalletMain->DeriveNewChildKey(nAccountIndex, newKey); - account.vchPubKey = newKey.GetPubKey(); - account.nAccountIndex = nAccountIndex; - - pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); - walletdb.WriteAccount(strAccount, account); - } - - return CBitcoinAddress(account.vchPubKey.GetID()); -} - -UniValue getaccountaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaccountaddress \"account\"\n" - "\nReturns the current DAPS address for receiving payments to this account.\n" - "\nArguments:\n" - "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n" - "\nResult:\n" - "\"dapscoinaddress\" (string) The account dapscoin address\n" - "\nExamples:\n" + - HelpExampleCli("getaccountaddress", "") + HelpExampleCli("getaccountaddress", "\"\"") + HelpExampleCli("getaccountaddress", "\"myaccount\"") + HelpExampleRpc("getaccountaddress", "\"myaccount\"")); - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Parse the account first so we don't generate a key if there's an error - string strAccount = AccountFromValue(params[0]); - - UniValue ret(UniValue::VSTR); - - ret = GetAccountAddress(strAccount).ToString(); - return ret; -} - -UniValue getrawchangeaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getrawchangeaddress\n" - "\nReturns a new DAPS address, for receiving change.\n" - "This is for use with raw transactions, NOT normal use.\n" - "\nResult:\n" - "\"address\" (string) The address\n" - "\nExamples:\n" + - HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "")); - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - CReserveKey reservekey(pwalletMain); - CPubKey vchPubKey; - if (!reservekey.GetReservedKey(vchPubKey)) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - reservekey.KeepKey(); - - CKeyID keyID = vchPubKey.GetID(); - - return CBitcoinAddress(keyID).ToString(); -} - -UniValue setaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "setaccount \"dapscoinaddress\" \"account\"\n" - "\nSets the account associated with the given address.\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address to be associated with an account.\n" - "2. \"account\" (string, required) The account to assign the address to.\n" - "\nExamples:\n" + - HelpExampleCli("setaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"tabby\"") + HelpExampleRpc("setaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", \"tabby\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - - string strAccount; - if (params.size() > 1) - strAccount = AccountFromValue(params[1]); - - // Only add the account if the address is yours. - if (IsMine(*pwalletMain, address.Get())) { - // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwalletMain->mapAddressBook.count(address.Get())) { - string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(strOldAccount)) - GetAccountAddress(strOldAccount, true); - } - pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); - } else - throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); - return NullUniValue; -} - - -UniValue getaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaccount \"dapscoinaddress\"\n" - "\nReturns the account associated with the given address.\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address for account lookup.\n" - "\nResult:\n" - "\"accountname\" (string) the account address\n" - "\nExamples:\n" + - HelpExampleCli("getaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"") + HelpExampleRpc("getaccount", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - - string strAccount; - map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); - if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) - strAccount = (*mi).second.name; - - return strAccount; -} - -UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getaddressesbyaccount \"account\"\n" - "\nReturns the list of addresses for the given account.\n" - "\nArguments:\n" - "1. \"account\" (string, required) The account name.\n" - "\nResult:\n" - "[ (json array of string)\n" - " \"dapscoinaddress\" (string) a dapscoin address associated with the given account\n" - " ,...\n" - "]\n" - "\nExamples:\n" + - HelpExampleCli("getaddressesbyaccount", "\"tabby\"") + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount = AccountFromValue(params[0]); - - // Find all addresses that have the given account - UniValue ret(UniValue::VARR); - for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; - if (strName == strAccount) - ret.push_back(address.ToString()); - } - return ret; -} - -void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, bool fUseIX = false) -{ - // Check amount - if (nValue <= 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount"); - - string strError; - if (pwalletMain->IsLocked()) { - strError = "Error: Wallet locked, unable to create transaction!"; - LogPrintf("SendMoney() : %s", strError); - throw JSONRPCError(RPC_WALLET_ERROR, strError); - } - - // Parse DAPS address - CScript scriptPubKey = GetScriptForDestination(address); - - // Create and send the transaction - CReserveKey reservekey(pwalletMain); - CAmount nFeeRequired; - if (!pwalletMain->CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError, NULL, ALL_COINS, fUseIX, (CAmount)0)) { - if (nValue + nFeeRequired > pwalletMain->GetBalance()) - strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); - LogPrintf("SendMoney() : %s\n", strError); - throw JSONRPCError(RPC_WALLET_ERROR, strError); - } - if (!pwalletMain->CommitTransaction(wtxNew, reservekey, (!fUseIX ? "tx" : "ix"))) - throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); -} - -UniValue sendtoaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "sendtoaddress \"dapscoinaddress\" amount \n" - "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + - HelpRequiringPassphrase() + - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address to send to.\n" - "2. \"amount\" (numeric, required) The amount in DAPS to send. eg 0.1\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id.\n" - "\nExamples:\n" + - HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1") + HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.1, \"donation\", \"seans outpost\"")); - - std::string stealthAddr = params[0].get_str(); - - // Amount - CAmount nAmount = AmountFromValue(params[1]); - - // Wallet comments - CWalletTx wtx; - - EnsureWalletIsUnlocked(); - - if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Failed to create transaction."); - } - return wtx.GetHash().GetHex(); -} - -UniValue sendtoaddressix(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( - "sendtoaddressix \"dapscoinaddress\" amount\n" - "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n" + - HelpRequiringPassphrase() + - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address to send to.\n" - "2. \"amount\" (numeric, required) The amount in DAPS to send. eg 0.1\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id.\n" - "\nExamples:\n" + - HelpExampleCli("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1") + HelpExampleCli("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtoaddressix", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.1, \"donation\", \"seans outpost\"")); - - std::string stealthAddr = params[0].get_str(); - - // Amount - CAmount nAmount = AmountFromValue(params[1]); - - // Wallet comments - CWalletTx wtx; - - EnsureWalletIsUnlocked(); - - if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Failed to create transaction."); - } - return wtx.GetHash().GetHex(); -} - -UniValue listaddressgroupings(const UniValue& params, bool fHelp) -{ - if (fHelp) - throw runtime_error( - "listaddressgroupings\n" - "\nLists groups of addresses which have had their common ownership\n" - "made public by common use as inputs or as the resulting change\n" - "in past transactions\n" - "\nResult:\n" - "[\n" - " [\n" - " [\n" - " \"dapscoinaddress\", (string) The dapscoin address\n" - " amount, (numeric) The amount in DAPS\n" - " \"account\" (string, optional) The account\n" - " ]\n" - " ,...\n" - " ]\n" - " ,...\n" - "]\n" - "\nExamples:\n" + - HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - UniValue jsonGroupings(UniValue::VARR); - map balances = pwalletMain->GetAddressBalances(); - for (set grouping : pwalletMain->GetAddressGroupings()) { - UniValue jsonGrouping(UniValue::VARR); - for (CTxDestination address : grouping) { - UniValue addressInfo(UniValue::VARR); - addressInfo.push_back(CBitcoinAddress(address).ToString()); - addressInfo.push_back(ValueFromAmount(balances[address])); - { - if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) - addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name); - } - jsonGrouping.push_back(addressInfo); - } - jsonGroupings.push_back(jsonGrouping); - } - return jsonGroupings; -} - -UniValue signmessage(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "signmessage \"dapscoinaddress\" \"message\"\n" - "\nSign a message with the private key of an address" + - HelpRequiringPassphrase() + "\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address to use for the private key.\n" - "2. \"message\" (string, required) The message to create a signature of.\n" - "\nResult:\n" - "\"signature\" (string) The signature of the message encoded in base 64\n" - "\nExamples:\n" - "\nUnlock the wallet for 30 seconds\n" + - HelpExampleCli("unlockwallet", "\"mypassphrase\" 30") + - "\nCreate the signature\n" + HelpExampleCli("signmessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"my message\"") + - "\nVerify the signature\n" + HelpExampleCli("verifymessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" \"signature\" \"my message\"") + - "\nAs json rpc\n" + HelpExampleRpc("signmessage", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", \"my message\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - string strAddress = params[0].get_str(); - string strMessage = params[1].get_str(); - - CBitcoinAddress addr(strAddress); - if (!addr.IsValid()) - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); - - CKeyID keyID; - if (!addr.GetKeyID(keyID)) - throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); - - CKey key; - if (!pwalletMain->GetKey(keyID, key)) - throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); - - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - vector vchSig; - if (!key.SignCompact(ss.GetHash(), vchSig)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); - - return EncodeBase64(&vchSig[0], vchSig.size()); -} - -UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getreceivedbyaddress \"dapscoinaddress\" ( minconf )\n" - "\nReturns the total amount received by the given dapscoinaddress in transactions with at least minconf confirmations.\n" - "\nArguments:\n" - "1. \"dapscoinaddress\" (string, required) The dapscoin address for transactions.\n" - "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" - "\nResult:\n" - "amount (numeric) The total amount in DAPS received at this address.\n" - "\nExamples:\n" - "\nThe amount from transactions with at least 1 confirmation\n" + - HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\"") + - "\nThe amount including unconfirmed transactions, zero confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0") + - "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 6") + - "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 6")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // dapscoin address - CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); - if (!IsMine(*pwalletMain, scriptPubKey)) - return (double)0.0; - - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - - // Tally - CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !IsFinalTx(wtx)) - continue; - - for (const CTxOut& txout : wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - if (wtx.GetDepthInMainChain() >= nMinDepth) - nAmount += txout.nValue; - } - - return ValueFromAmount(nAmount); -} - - -UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getreceivedbyaccount \"account\" ( minconf )\n" - "\nReturns the total amount received by addresses with in transactions with at least [minconf] confirmations.\n" - "\nArguments:\n" - "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n" - "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" - "\nResult:\n" - "amount (numeric) The total amount in DAPS received for this account.\n" - "\nExamples:\n" - "\nAmount received by the default account with at least 1 confirmation\n" + - HelpExampleCli("getreceivedbyaccount", "\"\"") + - "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n" + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") + - "\nThe amount with at least 6 confirmation, very safe\n" + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") + - "\nAs a json rpc call\n" + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - - // Get the set of pub keys assigned to accountValue getreceivedbyaccount(const Array& params, bool fHelp) - string strAccount = AccountFromValue(params[0]); - set setAddress = pwalletMain->GetAccountAddresses(strAccount); - - // Tally - CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - if (wtx.IsCoinBase() || !IsFinalTx(wtx)) - continue; - - for (const CTxOut& txout : wtx.vout) { - CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) - if (wtx.GetDepthInMainChain() >= nMinDepth) - nAmount += txout.nValue; - } - } - - return (double)nAmount / (double)COIN; -} - - -CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) -{ - CAmount nBalance = 0; - - // Tally wallet transactions - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) - continue; - - CAmount nReceived, nSent, nFee; - wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); - - if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) - nBalance += nReceived; - nBalance -= nSent + nFee; - } - - // Tally internal accounting entries - nBalance += walletdb.GetAccountCreditDebit(strAccount); - - return nBalance; -} - -CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); -} - -UniValue getbalance(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 3) - throw runtime_error( - "getbalance ( \"account\" minconf includeWatchonly )\n" - "\nIf account is not specified, returns the server's total available balance.\n" - "If account is specified, returns the balance in the account.\n" - "Note that the account \"\" is not the same as leaving the parameter out.\n" - "The server total may be different to the balance in the default \"\" account.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n" - "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" - "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n" - "\nResult:\n" - "amount (numeric) The total amount in DAPS received for this account.\n" - "\nExamples:\n" - "\nThe total amount in the server across all accounts\n" + - HelpExampleCli("getbalance", "") + - "\nThe total amount in the server across all accounts, with at least 5 confirmations\n" + HelpExampleCli("getbalance", "\"*\" 6") + - "\nThe total amount in the default account with at least 1 confirmation\n" + HelpExampleCli("getbalance", "\"\"") + - "\nThe total amount in the account named tabby with at least 6 confirmations\n" + HelpExampleCli("getbalance", "\"tabby\" 6") + - "\nAs a json rpc call\n" + HelpExampleRpc("getbalance", "\"tabby\", 6")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (params.size() == 0) - return ValueFromAmount(pwalletMain->GetBalance()); - - int nMinDepth = 1; - if (params.size() > 1) - nMinDepth = params[1].get_int(); - isminefilter filter = ISMINE_SPENDABLE; - if (params.size() > 2) - if (params[2].get_bool()) - filter = filter | ISMINE_WATCH_ONLY; - - if (params[0].get_str() == "*") { - // Calculate total balance a different way from GetBalance() - // (GetBalance() sums up all unspent TxOuts) - // getbalance and "getbalance * 1 true" should return the same number - CAmount nBalance = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) - continue; - - CAmount allFee; - string strSentAccount; - list listReceived; - list listSent; - wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); - if (wtx.GetDepthInMainChain() >= nMinDepth) { - for (const COutputEntry& r : listReceived) - nBalance += r.amount; - } - for (const COutputEntry& s : listSent) - nBalance -= s.amount; - nBalance -= allFee; - } - return ValueFromAmount(nBalance); - } - - string strAccount = AccountFromValue(params[0]); - - CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter); - - return ValueFromAmount(nBalance); -} - -UniValue getbalances(const UniValue& params, bool fHelp) -{ - if (fHelp) - throw runtime_error( - "getbalances" - "\nArguments:\n" - "\nResult:\n" - "total (numeric) The total amount in DAPS received for this wallet.\n" - "spendable (numeric) The total amount in DAPS spendable for this wallet.\n" - "pending (numeric) The total amount in DAPS pending for this wallet." - "\nExamples:\n" - "\nThe total amount in the server across all accounts\n" + - HelpExampleCli("getbalances", "")); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("total", ValueFromAmount(pwalletMain->GetBalance()))); - obj.push_back(Pair("spendable", ValueFromAmount(pwalletMain->GetSpendableBalance()))); - obj.push_back(Pair("pending", ValueFromAmount(pwalletMain->GetUnconfirmedBalance()))); - - return obj; -} - -UniValue getunconfirmedbalance(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 0) - throw runtime_error( - "getunconfirmedbalance\n" - "Returns the server's total unconfirmed balance\n"); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - return ValueFromAmount(pwalletMain->GetUnconfirmedBalance()); -} - -UniValue movecmd(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 3 || params.size() > 5) - throw runtime_error( - "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" - "\nMove a specified amount from one account in your wallet to another.\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" - "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" - "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" - "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" - "\nResult:\n" - "true|false (boolean) true if successfull.\n" - "\nExamples:\n" - "\nMove 0.01 DAPS from the default account to the account named tabby\n" + - HelpExampleCli("move", "\"\" \"tabby\" 0.01") + - "\nMove 0.01 DAPS timotei to akiko with a comment and funds have 6 confirmations\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strFrom = AccountFromValue(params[0]); - string strTo = AccountFromValue(params[1]); - CAmount nAmount = AmountFromValue(params[2]); - if (params.size() > 3) - // unused parameter, used to be nMinDepth, keep type-checking it though - (void)params[3].get_int(); - string strComment; - if (params.size() > 4) - strComment = params[4].get_str(); - - CWalletDB walletdb(pwalletMain->strWalletFile); - if (!walletdb.TxnBegin()) - throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); - - int64_t nNow = GetAdjustedTime(); - - // Debit - CAccountingEntry debit; - debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); - debit.strAccount = strFrom; - debit.nCreditDebit = -nAmount; - debit.nTime = nNow; - debit.strOtherAccount = strTo; - debit.strComment = strComment; - pwalletMain->AddAccountingEntry(debit, walletdb); - - // Credit - CAccountingEntry credit; - credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); - credit.strAccount = strTo; - credit.nCreditDebit = nAmount; - credit.nTime = nNow; - credit.strOtherAccount = strFrom; - credit.strComment = strComment; - pwalletMain->AddAccountingEntry(credit, walletdb); - - if (!walletdb.TxnCommit()) - throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); - - return true; -} - -UniValue sendfrom(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 3 || params.size() > 6) - throw runtime_error( - "sendfrom \"fromaccount\" \"todapscoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" - "\nSent an amount from an account to a dapscoin address.\n" - "The amount is a real and is rounded to the nearest 0.00000001." + - HelpRequiringPassphrase() + "\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n" - "2. \"todapscoinaddress\" (string, required) The dapscoin address to send funds to.\n" - "3. amount (numeric, required) The amount in DAPS. (transaction fee is added on top).\n" - "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" - "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" - " This is not part of the transaction, just kept in your wallet.\n" - "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n" - " to which you're sending the transaction. This is not part of the transaction, \n" - " it is just kept in your wallet.\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id.\n" - "\nExamples:\n" - "\nSend 0.01 DAPS from the default account to the address, must have at least 1 confirmation\n" + - HelpExampleCli("sendfrom", "\"\" \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.01") + - "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n" + HelpExampleCli("sendfrom", "\"tabby\" \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 0.01 6 \"donation\" \"seans outpost\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("sendfrom", "\"tabby\", \"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\", 0.01, 6, \"donation\", \"seans outpost\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount = AccountFromValue(params[0]); - CBitcoinAddress address(params[1].get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - CAmount nAmount = AmountFromValue(params[2]); - int nMinDepth = 1; - if (params.size() > 3) - nMinDepth = params[3].get_int(); - - CWalletTx wtx; - wtx.strFromAccount = strAccount; - if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty()) - wtx.mapValue["comment"] = params[4].get_str(); - if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty()) - wtx.mapValue["to"] = params[5].get_str(); - - EnsureWalletIsUnlocked(); - - // Check funds - CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); - if (nAmount > nBalance) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); - - SendMoney(address.Get(), nAmount, wtx); - - return wtx.GetHash().GetHex(); -} - -UniValue sendmany(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 4) - throw runtime_error( - "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n" - "\nSend multiple times. Amounts are double-precision floating point numbers." + - HelpRequiringPassphrase() + "\n" - "\nArguments:\n" - "1. \"fromaccount\" (string, required) The account to send the funds from, can be \"\" for the default account\n" - "2. \"amounts\" (string, required) A json object with addresses and amounts\n" - " {\n" - " \"address\":amount (numeric) The dapscoin address is the key, the numeric amount in DAPS is the value\n" - " ,...\n" - " }\n" - "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n" - "4. \"comment\" (string, optional) A comment\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" - " the number of addresses.\n" - "\nExamples:\n" - "\nSend two amounts to two different addresses:\n" + - HelpExampleCli("sendmany", "\"tabby\" \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\"") + - "\nSend two amounts to two different addresses setting the confirmation and comment:\n" + HelpExampleCli("sendmany", "\"tabby\" \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\" 6 \"testing\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.01,\\\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\\\":0.02}\", 6, \"testing\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount = AccountFromValue(params[0]); - UniValue sendTo = params[1].get_obj(); - int nMinDepth = 1; - if (params.size() > 2) - nMinDepth = params[2].get_int(); - - CWalletTx wtx; - wtx.strFromAccount = strAccount; - if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) - wtx.mapValue["comment"] = params[3].get_str(); - - set setAddress; - vector > vecSend; - - CAmount totalAmount = 0; - vector keys = sendTo.getKeys(); - for (const string& name_ : keys) { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid PIVX address: ")+name_); - - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); - - CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(sendTo[name_]); - totalAmount += nAmount; - - vecSend.push_back(make_pair(scriptPubKey, nAmount)); - } - - EnsureWalletIsUnlocked(); - - // Check funds - CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); - if (totalAmount > nBalance) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); - - // Send - CReserveKey keyChange(pwalletMain); - CAmount nFeeRequired = 0; - string strFailReason; - bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); - if (!fCreated) - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); - if (!pwalletMain->CommitTransaction(wtx, keyChange)) - throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); - - return wtx.GetHash().GetHex(); -} - -// Defined in rpcmisc.cpp -extern CScript _createmultisig_redeemScript(const UniValue& params); - -UniValue addmultisigaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 3) { - string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" - "\nAdd a nrequired-to-sign multisignature address to the wallet.\n" - "Each key is a DAPS address or hex-encoded public key.\n" - "If 'account' is specified, assign address to that account.\n" - - "\nArguments:\n" - "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keysobject\" (string, required) A json array of dapscoin addresses or hex-encoded public keys\n" - " [\n" - " \"address\" (string) dapscoin address or hex-encoded public key\n" - " ...,\n" - " ]\n" - "3. \"account\" (string, optional) An account to assign the addresses to.\n" - - "\nResult:\n" - "\"dapscoinaddress\" (string) A dapscoin address associated with the keys.\n" - - "\nExamples:\n" - "\nAdd a multisig address from 2 addresses\n" + - HelpExampleCli("addmultisigaddress", "2 \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\"") + - "\nAs json rpc call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"Xt4qk9uKvQYAonVGSZNXqxeDmtjaEWgfrs\\\",\\\"XoSoWQkpgLpppPoyyzbUFh1fq2RBvW6UK1\\\"]\""); - throw runtime_error(msg); - } - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount; - if (params.size() > 2) - strAccount = AccountFromValue(params[2]); - - // Construct using pay-to-script-hash: - CScript inner = _createmultisig_redeemScript(params); - CScriptID innerID(inner); - pwalletMain->AddCScript(inner); - - pwalletMain->SetAddressBook(innerID, strAccount, "send"); - return CBitcoinAddress(innerID).ToString(); -} - - -struct tallyitem { - CAmount nAmount; - int nConf; - int nBCConf; - vector txids; - bool fIsWatchonly; - tallyitem() - { - nAmount = 0; - nConf = std::numeric_limits::max(); - nBCConf = std::numeric_limits::max(); - fIsWatchonly = false; - } -}; - -UniValue ListReceived(const UniValue& params, bool fByAccounts) -{ - // Minimum confirmations - int nMinDepth = 1; - if (params.size() > 0) - nMinDepth = params[0].get_int(); - - // Whether to include empty accounts - bool fIncludeEmpty = false; - if (params.size() > 1) - fIncludeEmpty = params[1].get_bool(); - - isminefilter filter = ISMINE_SPENDABLE; - if (params.size() > 2) - if (params[2].get_bool()) - filter = filter | ISMINE_WATCH_ONLY; - - // Tally - map mapTally; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - - if (wtx.IsCoinBase() || !IsFinalTx(wtx)) - continue; - - int nDepth = wtx.GetDepthInMainChain(); - int nBCDepth = wtx.GetDepthInMainChain(false); - if (nDepth < nMinDepth) - continue; - - for (const CTxOut& txout : wtx.vout) { - CTxDestination address; - if (!ExtractDestination(txout.scriptPubKey, address)) - continue; - - isminefilter mine = IsMine(*pwalletMain, address); - if (!(mine & filter)) - continue; - - tallyitem& item = mapTally[address]; - item.nAmount += txout.nValue; - item.nConf = min(item.nConf, nDepth); - item.nBCConf = min(item.nBCConf, nBCDepth); - item.txids.push_back(wtx.GetHash()); - if (mine & ISMINE_WATCH_ONLY) - item.fIsWatchonly = true; - } - } - - // Reply - UniValue ret(UniValue::VARR); - map mapAccountTally; - for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { - const CBitcoinAddress& address = item.first; - const string& strAccount = item.second.name; - map::iterator it = mapTally.find(address); - if (it == mapTally.end() && !fIncludeEmpty) - continue; - - CAmount nAmount = 0; - int nConf = std::numeric_limits::max(); - int nBCConf = std::numeric_limits::max(); - bool fIsWatchonly = false; - if (it != mapTally.end()) { - nAmount = (*it).second.nAmount; - nConf = (*it).second.nConf; - nBCConf = (*it).second.nBCConf; - fIsWatchonly = (*it).second.fIsWatchonly; - } - - if (fByAccounts) { - tallyitem& item = mapAccountTally[strAccount]; - item.nAmount += nAmount; - item.nConf = min(item.nConf, nConf); - item.nBCConf = min(item.nBCConf, nBCConf); - item.fIsWatchonly = fIsWatchonly; - } else { - UniValue obj(UniValue::VOBJ); - if (fIsWatchonly) - obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("address", address.ToString())); - obj.push_back(Pair("account", strAccount)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); - obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); - UniValue transactions(UniValue::VARR); - if (it != mapTally.end()) { - for (const uint256& item : (*it).second.txids) { - transactions.push_back(item.GetHex()); - } - } - obj.push_back(Pair("txids", transactions)); - ret.push_back(obj); - } - } - - if (fByAccounts) { - for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { - CAmount nAmount = (*it).second.nAmount; - int nConf = (*it).second.nConf; - int nBCConf = (*it).second.nBCConf; - UniValue obj(UniValue::VOBJ); - if ((*it).second.fIsWatchonly) - obj.push_back(Pair("involvesWatchonly", true)); - obj.push_back(Pair("account", (*it).first)); - obj.push_back(Pair("amount", ValueFromAmount(nAmount))); - obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); - obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); - ret.push_back(obj); - } - } - - return ret; -} - -UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 3) - throw runtime_error( - "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n" - "\nList balances by receiving address.\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n" - "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" - - "\nResult:\n" - "[\n" - " {\n" - " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" - " \"address\" : \"receivingaddress\", (string) The receiving address\n" - " \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n" - " \"amount\" : x.xxx, (numeric) The total amount in DAPS received by the address\n" - " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" - " \"bcconfirmations\" : n (numeric) The number of blockchain confirmations of the most recent transaction included\n" - " }\n" - " ,...\n" - "]\n" - - "\nExamples:\n" + - HelpExampleCli("listreceivedbyaddress", "") + HelpExampleCli("listreceivedbyaddress", "6 true") + HelpExampleRpc("listreceivedbyaddress", "6, true, true")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - return ListReceived(params, false); -} - -UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 3) - throw runtime_error( - "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" - "\nList balances by account.\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" - "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n" - "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n" - - "\nResult:\n" - "[\n" - " {\n" - " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" - " \"account\" : \"accountname\", (string) The account name of the receiving account\n" - " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n" - " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" - " \"bcconfirmations\" : n (numeric) The number of blockchain confirmations of the most recent transaction included\n" - " }\n" - " ,...\n" - "]\n" - - "\nExamples:\n" + - HelpExampleCli("listreceivedbyaccount", "") + HelpExampleCli("listreceivedbyaccount", "6 true") + HelpExampleRpc("listreceivedbyaccount", "6, true, true")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - return ListReceived(params, true); -} - -static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) -{ - CBitcoinAddress addr; - if (addr.Set(dest)) - entry.push_back(Pair("address", addr.ToString())); -} - -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) -{ - CAmount nFee; - string strSentAccount; - list listReceived; - list listSent; - - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); - - bool fAllAccounts = (strAccount == string("*")); - bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); - - // Sent - if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { - for (const COutputEntry& s : listSent) { - UniValue entry(UniValue::VOBJ); - if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) - entry.push_back(Pair("involvesWatchonly", true)); - entry.push_back(Pair("account", strSentAccount)); - MaybePushAddress(entry, s.destination); - std::map::const_iterator it = wtx.mapValue.find("DS"); - entry.push_back(Pair("category", (it != wtx.mapValue.end() && it->second == "1") ? "darksent" : "send")); - entry.push_back(Pair("amount", ValueFromAmount(-s.amount))); - entry.push_back(Pair("vout", s.vout)); - entry.push_back(Pair("fee", ValueFromAmount(-nFee))); - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - } - - // Received - if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { - for (const COutputEntry& r : listReceived) { - string account; - if (pwalletMain->mapAddressBook.count(r.destination)) - account = pwalletMain->mapAddressBook[r.destination].name; - if (fAllAccounts || (account == strAccount)) { - UniValue entry(UniValue::VOBJ); - if (involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) - entry.push_back(Pair("involvesWatchonly", true)); - entry.push_back(Pair("account", account)); - MaybePushAddress(entry, r.destination); - if (wtx.IsCoinBase()) { - if (wtx.GetDepthInMainChain() < 1) - entry.push_back(Pair("category", "orphan")); - else if (wtx.GetBlocksToMaturity() > 0) - entry.push_back(Pair("category", "immature")); - else - entry.push_back(Pair("category", "generate")); - } else { - entry.push_back(Pair("category", "receive")); - } - entry.push_back(Pair("amount", ValueFromAmount(r.amount))); - entry.push_back(Pair("vout", r.vout)); - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - } - } -} - -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) -{ - bool fAllAccounts = (strAccount == string("*")); - - if (fAllAccounts || acentry.strAccount == strAccount) { - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("account", acentry.strAccount)); - entry.push_back(Pair("category", "move")); - entry.push_back(Pair("time", acentry.nTime)); - entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); - entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); - entry.push_back(Pair("comment", acentry.strComment)); - ret.push_back(entry); - } -} - -UniValue listtransactions(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 4) - throw runtime_error( - "listtransactions ( \"account\" count from includeWatchonly)\n" - "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n" - " If \"\" is set, it will list transactions for the default account.\n" - "2. count (numeric, optional, default=10) The number of transactions to return\n" - "3. from (numeric, optional, default=0) The number of transactions to skip\n" - "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n" - "\nResult:\n" - "[\n" - " {\n" - " \"account\":\"accountname\", (string) The account name associated with the transaction. \n" - " It will be \"\" for the default account.\n" - " \"address\":\"dapscoinaddress\", (string) The dapscoin address of the transaction. Not present for \n" - " move transactions (category = move).\n" - " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" - " transaction between accounts, and not associated with an address,\n" - " transaction id or block. 'send' and 'receive' transactions are \n" - " associated with an address, transaction id and block details\n" - " \"amount\": x.xxx, (numeric) The amount in DAPS. This is negative for the 'send' category, and for the\n" - " 'move' category for moves outbound. It is positive for the 'receive' category,\n" - " and for the 'move' category for inbound funds.\n" - " \"vout\" : n, (numeric) the vout value\n" - " \"fee\": x.xxx, (numeric) The amount of the fee in DAPS. This is negative and only available for the \n" - " 'send' category of transactions.\n" - " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" - " 'receive' category of transactions.\n" - " \"bcconfirmations\": n, (numeric) The number of blockchain confirmations for the transaction. Available for 'send'\n" - " and 'receive' category of transactions.\n" - " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" - " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" - " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" - " for 'send' and 'receive' category of transactions.\n" - " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" - " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" - " from (for receiving funds, positive amounts), or went to (for sending funds,\n" - " negative amounts).\n" - " }\n" - "]\n" - - "\nExamples:\n" - "\nList the most recent 10 transactions in the systems\n" + - HelpExampleCli("listtransactions", "") + - "\nList the most recent 10 transactions for the tabby account\n" + HelpExampleCli("listtransactions", "\"tabby\"") + - "\nList transactions 100 to 120 from the tabby account\n" + HelpExampleCli("listtransactions", "\"tabby\" 20 100") + - "\nAs a json rpc call\n" + HelpExampleRpc("listtransactions", "\"tabby\", 20, 100")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strAccount = "*"; - if (params.size() > 0) - strAccount = params[0].get_str(); - int nCount = 10; - if (params.size() > 1) - nCount = params[1].get_int(); - int nFrom = 0; - if (params.size() > 2) - nFrom = params[2].get_int(); - isminefilter filter = ISMINE_SPENDABLE; - if (params.size() > 3) - if (params[3].get_bool()) - filter = filter | ISMINE_WATCH_ONLY; - - if (nCount < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); - if (nFrom < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - - UniValue ret(UniValue::VARR); - - const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered; - - // iterate backwards until we have nCount items to return: - for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { - CWalletTx* const pwtx = (*it).second.first; - if (pwtx != 0) - ListTransactions(*pwtx, strAccount, 0, true, ret, filter); - CAccountingEntry* const pacentry = (*it).second.second; - if (pacentry != 0) - AcentryToJSON(*pacentry, strAccount, ret); - - if ((int)ret.size() >= (nCount + nFrom)) break; - } - // ret is newest to oldest - - if (nFrom > (int)ret.size()) - nFrom = ret.size(); - if ((nFrom + nCount) > (int)ret.size()) - nCount = ret.size() - nFrom; - - vector arrTmp = ret.getValues(); - - vector::iterator first = arrTmp.begin(); - std::advance(first, nFrom); - - vector::iterator last = arrTmp.begin(); - std::advance(last, nFrom + nCount); - - if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); - if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); - - std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest - - ret.clear(); - ret.setArray(); - ret.push_backV(arrTmp); - - return ret; -} - -UniValue listaccounts(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "listaccounts ( minconf includeWatchonly)\n" - "\nReturns Object that has account names as keys, account balances as values.\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n" - "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n" - "\nResult:\n" - "{ (json object where keys are account names, and values are numeric balances\n" - " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n" - " ...\n" - "}\n" - "\nExamples:\n" - "\nList account balances where there at least 1 confirmation\n" + - HelpExampleCli("listaccounts", "") + - "\nList account balances including zero confirmation transactions\n" + HelpExampleCli("listaccounts", "0") + - "\nList account balances for 6 or more confirmations\n" + HelpExampleCli("listaccounts", "6") + - "\nAs json rpc call\n" + HelpExampleRpc("listaccounts", "6")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - int nMinDepth = 1; - if (params.size() > 0) - nMinDepth = params[0].get_int(); - isminefilter includeWatchonly = ISMINE_SPENDABLE; - if (params.size() > 1) - if (params[1].get_bool()) - includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; - - map mapAccountBalances; - for (const PAIRTYPE(CTxDestination, CAddressBookData) & entry : pwalletMain->mapAddressBook) { - if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me - mapAccountBalances[entry.second.name] = 0; - } - - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - CAmount nFee; - string strSentAccount; - list listReceived; - list listSent; - int nDepth = wtx.GetDepthInMainChain(); - if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) - continue; - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); - mapAccountBalances[strSentAccount] -= nFee; - for (const COutputEntry& s : listSent) - mapAccountBalances[strSentAccount] -= s.amount; - if (nDepth >= nMinDepth) { - for (const COutputEntry& r : listReceived) - if (pwalletMain->mapAddressBook.count(r.destination)) - mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; - else - mapAccountBalances[""] += r.amount; - } - } - - const list & acentries = pwalletMain->laccentries; - for (const CAccountingEntry& entry : acentries) - mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - - UniValue ret(UniValue::VOBJ); - for (const PAIRTYPE(string, CAmount) & accountBalance : mapAccountBalances) { - ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); - } - return ret; -} - -UniValue listsinceblock(const UniValue& params, bool fHelp) -{ - if (fHelp) - throw runtime_error( - "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n" - "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n" - "\nArguments:\n" - "1. \"blockhash\" (string, optional) The block hash to list transactions since\n" - "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n" - "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')" - "\nResult:\n" - "{\n" - " \"transactions\": [\n" - " \"account\":\"accountname\", (string) The account name associated with the transaction. Will be \"\" for the default account.\n" - " \"address\":\"dapscoinaddress\", (string) The dapscoin address of the transaction. Not present for move transactions (category = move).\n" - " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n" - " \"amount\": x.xxx, (numeric) The amount in DAPS. This is negative for the 'send' category, and for the 'move' category for moves \n" - " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n" - " \"vout\" : n, (numeric) the vout value\n" - " \"fee\": x.xxx, (numeric) The amount of the fee in DAPS. This is negative and only available for the 'send' category of transactions.\n" - " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n" - " \"bcconfirmations\" : n, (numeric) The number of blockchain confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n" - " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n" - " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n" - " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n" - " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" - " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n" - " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n" - " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" - " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n" - " ],\n" - " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n" - "}\n" - "\nExamples:\n" + - HelpExampleCli("listsinceblock", "") + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6") + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - CBlockIndex* pindex = NULL; - int target_confirms = 1; - isminefilter filter = ISMINE_SPENDABLE; - - if (params.size() > 0) { - uint256 blockId = 0; - - blockId.SetHex(params[0].get_str()); - BlockMap::iterator it = mapBlockIndex.find(blockId); - if (it != mapBlockIndex.end()) - pindex = it->second; - } - - if (params.size() > 1) { - target_confirms = params[1].get_int(); - - if (target_confirms < 1) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); - } - - if (params.size() > 2) - if (params[2].get_bool()) - filter = filter | ISMINE_WATCH_ONLY; - - int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; - - UniValue transactions(UniValue::VARR); - - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { - CWalletTx tx = (*it).second; - - if (depth == -1 || tx.GetDepthInMainChain(false) < depth) - ListTransactions(tx, "*", 0, true, transactions, filter); - } - - CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; - uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; - - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("transactions", transactions)); - ret.push_back(Pair("lastblock", lastblock.GetHex())); - - return ret; -} - -UniValue gettransaction(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "gettransaction \"txid\" ( includeWatchonly )\n" - "\nGet detailed information about in-wallet transaction \n" - "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" - "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n" - "\nResult:\n" - "{\n" - " \"amount\" : x.xxx, (numeric) The transaction amount in DAPS\n" - " \"confirmations\" : n, (numeric) The number of confirmations\n" - " \"bcconfirmations\" : n, (numeric) The number of blockchain confirmations\n" - " \"blockhash\" : \"hash\", (string) The block hash\n" - " \"blockindex\" : xx, (numeric) The block index\n" - " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n" - " \"txid\" : \"transactionid\", (string) The transaction id.\n" - " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n" - " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n" - " \"details\" : [\n" - " {\n" - " \"account\" : \"accountname\", (string) The account name involved in the transaction, can be \"\" for the default account.\n" - " \"address\" : \"dapscoinaddress\", (string) The dapscoin address involved in the transaction\n" - " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n" - " \"amount\" : x.xxx (numeric) The amount in DAPS\n" - " \"vout\" : n, (numeric) the vout value\n" - " }\n" - " ,...\n" - " ],\n" - " \"hex\" : \"data\" (string) Raw data for transaction\n" - "}\n" - - "\nExamples:\n" + - HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"") + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true") + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - uint256 hash; - hash.SetHex(params[0].get_str()); - - isminefilter filter = ISMINE_SPENDABLE; - if (params.size() > 1) - if (params[1].get_bool()) - filter = filter | ISMINE_WATCH_ONLY; - - UniValue entry(UniValue::VOBJ); - if (!pwalletMain->mapWallet.count(hash)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - - CAmount nCredit = wtx.GetCredit(filter); - CAmount nDebit = wtx.GetDebit(filter); - CAmount nNet = (nCredit > nDebit)? (nCredit - nDebit):(nDebit - nCredit); - CAmount nFee = wtx.nTxFee; - entry.push_back(Pair("amount", ValueFromAmount(nNet))); - if (wtx.IsFromMe(filter)) - entry.push_back(Pair("fee", ValueFromAmount(nFee))); - - WalletTxToJSON(wtx, entry); - - UniValue details(UniValue::VARR); - ListTransactions(wtx, "*", 0, false, details, filter); - entry.push_back(Pair("details", details)); - - string strHex = EncodeHexTx(static_cast(wtx)); - entry.push_back(Pair("hex", strHex)); - - return entry; -} - - -UniValue backupwallet(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "backupwallet \"destination\"\n" - "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n" - "\nArguments:\n" - "1. \"destination\" (string) The destination directory or file\n" - "\nExamples:\n" + - HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backup.dat\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - string strDest = params[0].get_str(); - if (!BackupWallet(*pwalletMain, strDest)) - throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); - - return "Done"; -} - - -UniValue keypoolrefill(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "keypoolrefill ( newsize )\n" - "\nFills the keypool." + - HelpRequiringPassphrase() + "\n" - "\nArguments\n" - "1. newsize (numeric, optional, default=100) The new keypool size\n" - "\nExamples:\n" + - HelpExampleCli("keypoolrefill", "") + HelpExampleRpc("keypoolrefill", "")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool - unsigned int kpSize = 0; - if (params.size() > 0) { - if (params[0].get_int() < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size."); - kpSize = (unsigned int)params[0].get_int(); - } - - EnsureWalletIsUnlocked(); - pwalletMain->TopUpKeyPool(kpSize); - - if (pwalletMain->GetKeyPoolSize() < kpSize) - throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); - - return NullUniValue; -} - - -static void LockWallet(CWallet* pWallet) -{ - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = 0; - pWallet->fWalletUnlockAnonymizeOnly = false; - pWallet->Lock(); -} - -UniValue unlockwallet(const UniValue& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) - throw runtime_error( - "unlockwallet \"passphrase\" timeout ( anonymizeonly )\n" - "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" - "This is needed prior to performing transactions related to private keys such as sending DAPSs\n" - "\nArguments:\n" - "1. \"passphrase\" (string, required) The wallet passphrase\n" - "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n" - "3. anonymizeonly (boolean, optional, default=false) If is true sending functions are disabled." - "\nNote:\n" - "Issuing the unlockwallet command while the wallet is already unlocked will set a new unlock\n" - "time that overrides the old one. A timeout of \"0\" unlocks until the wallet is closed.\n" - "\nExamples:\n" - "\nUnlock the wallet for 60 seconds\n" + - HelpExampleCli("unlockwallet", "\"my pass phrase\" 60") + - "\nUnlock the wallet for 60 seconds but allow Obfuscation only\n" + HelpExampleCli("unlockwallet", "\"my pass phrase\" 60 true") + - "\nLock the wallet again (before 60 seconds)\n" + HelpExampleCli("walletlock", "") + - "\nAs json rpc call\n" + HelpExampleRpc("unlockwallet", "\"my pass phrase\", 60")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (fHelp) - return true; - if (!pwalletMain->IsCrypted()) - throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but unlockwallet was called."); - - // Note that the walletpassphrase is stored in params[0] which is not mlock()ed - SecureString strWalletPass; - strWalletPass.reserve(100); - // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) - // Alternately, find a way to make params[0] mlock()'d to begin with. - strWalletPass = params[0].get_str().c_str(); - - bool anonymizeOnly = false; - if (params.size() == 3) - anonymizeOnly = params[2].get_bool(); - - if (!pwalletMain->IsLocked() && pwalletMain->fWalletUnlockAnonymizeOnly && anonymizeOnly) - throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked."); - - // Get the timeout - int64_t nSleepTime = params[1].get_int64(); - // Timeout cannot be negative, otherwise it will relock immediately - if (nSleepTime < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative."); - } - // Clamp timeout - constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug? - if (nSleepTime > MAX_SLEEP_TIME) { - nSleepTime = MAX_SLEEP_TIME; - } - - if (!pwalletMain->Unlock(strWalletPass, anonymizeOnly)) - throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); - - pwalletMain->TopUpKeyPool(); - - - if (nSleepTime > 0) { - nWalletUnlockTime = GetTime () + nSleepTime; - RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); - } - return NullUniValue; -} - - -UniValue walletpassphrasechange(const UniValue& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) - throw runtime_error( - "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" - "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" - "\nArguments:\n" - "1. \"oldpassphrase\" (string) The current passphrase\n" - "2. \"newpassphrase\" (string) The new passphrase\n" - "\nExamples:\n" + - HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"") + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (fHelp) - return true; - if (!pwalletMain->IsCrypted()) - throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); - - // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) - // Alternately, find a way to make params[0] mlock()'d to begin with. - SecureString strOldWalletPass; - strOldWalletPass.reserve(100); - strOldWalletPass = params[0].get_str().c_str(); - - SecureString strNewWalletPass; - strNewWalletPass.reserve(100); - strNewWalletPass = params[1].get_str().c_str(); - - if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) - throw runtime_error( - "walletpassphrasechange \n" - "Changes the wallet passphrase from to ."); - - if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) - throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); - - return NullUniValue; -} - - -UniValue walletlock(const UniValue& params, bool fHelp) -{ - if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) - throw runtime_error( - "walletlock\n" - "\nRemoves the wallet encryption key from memory, locking the wallet.\n" - "After calling this method, you will need to call unlockwallet again\n" - "before being able to call any methods which require the wallet to be unlocked.\n" - "\nExamples:\n" - "\nSet the passphrase for 2 minutes to perform a transaction\n" + - HelpExampleCli("unlockwallet", "\"my pass phrase\" 120") + - "\nPerform a send (requires passphrase set)\n" + HelpExampleCli("sendtoaddress", "\"DEQsu2RRB5iphm9tKXiP4iWSRMC17gseW5\" 1.0") + - "\nClear the passphrase since we are done before 2 minutes is up\n" + HelpExampleCli("walletlock", "") + - "\nAs json rpc call\n" + HelpExampleRpc("walletlock", "")); - - /*if (fHelp) - LOCK2(cs_main, pwalletMain->cs_wallet); - - return Value::null;*/ - return "This feature is currently not available."; -} - - -UniValue encryptwallet(const UniValue& params, bool fHelp) -{ - if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) - throw runtime_error( - "encryptwallet \"passphrase\"\n" - "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" - "After this, any calls that interact with private keys such as sending or signing \n" - "will require the passphrase to be set prior the making these calls.\n" - "Use the unlockwallet call for this, and then walletlock call.\n" - "If the wallet is already encrypted, use the walletpassphrasechange call.\n" - "Note that this will shutdown the server.\n" - "\nArguments:\n" - "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n" - "\nExamples:\n" - "\nEncrypt you wallet\n" + - HelpExampleCli("encryptwallet", "\"my pass phrase\"") + - "\nNow set the passphrase to use the wallet, such as for signing or sending DAPSs\n" + HelpExampleCli("unlockwallet", "\"my pass phrase\"") + - "\nNow we can so something like sign\n" + HelpExampleCli("signmessage", "\"dapscoinaddress\" \"test message\"") + - "\nNow lock the wallet again by removing the passphrase\n" + HelpExampleCli("walletlock", "") + - "\nAs a json rpc call\n" + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - if (fHelp) - return true; - if (pwalletMain->IsCrypted()) - throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called."); - - // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) - // Alternately, find a way to make params[0] mlock()'d to begin with. - SecureString strWalletPass; - strWalletPass.reserve(100); - strWalletPass = params[0].get_str().c_str(); - - if (strWalletPass.length() < 1) - throw runtime_error( - "encryptwallet \n" - "Encrypts the wallet with ."); - - - if (!pwalletMain->EncryptWallet(strWalletPass)) - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); - - // BDB seems to have a bad habit of writing old data into - // slack space in .dat files; that is bad if the old data is - // unencrypted private keys. So: - StartShutdown(); - return "wallet encrypted; dapscoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; -} - -UniValue lockunspent(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" - "\nUpdates list of temporarily unspendable outputs.\n" - "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" - "A locked transaction output will not be chosen by automatic coin selection, when spending DAPSs.\n" - "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" - "is always cleared (by virtue of process exit) when a node stops or fails.\n" - "Also see the listunspent call\n" - "\nArguments:\n" - "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n" - "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n" - " [ (json array of json objects)\n" - " {\n" - " \"txid\":\"id\", (string) The transaction id\n" - " \"vout\": n (numeric) The output number\n" - " }\n" - " ,...\n" - " ]\n" - - "\nResult:\n" - "true|false (boolean) Whether the command was successful or not\n" - - "\nExamples:\n" - "\nList the unspent transactions\n" + - HelpExampleCli("listunspent", "") + - "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + - "\nList the locked transactions\n" + HelpExampleCli("listlockunspent", "") + - "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (params.size() == 1) - RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)); - else - RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR)); - - bool fUnlock = params[0].get_bool(); - - if (params.size() == 1) { - if (fUnlock) - pwalletMain->UnlockAllCoins(); - return true; - } - - UniValue outputs = params[1].get_array(); - for (unsigned int idx = 0; idx < outputs.size(); idx++) { - const UniValue& output = outputs[idx]; - if (!output.isObject()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); - const UniValue& o = output.get_obj(); - RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); - - string txid = find_value(o, "txid").get_str(); - if (!IsHex(txid)) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); - - int nOutput = find_value(o, "vout").get_int(); - if (nOutput < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - - COutPoint outpt(uint256(txid), nOutput); - - if (fUnlock) - pwalletMain->UnlockCoin(outpt); - else - pwalletMain->LockCoin(outpt); - } - - return true; -} - -UniValue listlockunspent(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 0) - throw runtime_error( - "listlockunspent\n" - "\nReturns list of temporarily unspendable outputs.\n" - "See the lockunspent call to lock and unlock transactions for spending.\n" - "\nResult:\n" - "[\n" - " {\n" - " \"txid\" : \"transactionid\", (string) The transaction id locked\n" - " \"vout\" : n (numeric) The vout value\n" - " }\n" - " ,...\n" - "]\n" - "\nExamples:\n" - "\nList the unspent transactions\n" + - HelpExampleCli("listunspent", "") + - "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + - "\nList the locked transactions\n" + HelpExampleCli("listlockunspent", "") + - "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"afbf98345239a27c35db94c03c33d87104ee9ce5c9790f3f756620e6f23d3816\\\",\\\"vout\\\":1}]\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("listlockunspent", "")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - vector vOutpts; - pwalletMain->ListLockedCoins(vOutpts); - - UniValue ret(UniValue::VARR); - - for (COutPoint& outpt : vOutpts) { - UniValue o(UniValue::VOBJ); - - o.push_back(Pair("txid", outpt.hash.GetHex())); - o.push_back(Pair("vout", (int)outpt.n)); - ret.push_back(o); - } - - return ret; -} - -UniValue settxfee(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "settxfee amount\n" - "\nSet the transaction fee per kB.\n" - "\nArguments:\n" - "1. amount (numeric, required) The transaction fee in DAPS/kB rounded to the nearest 0.00000001\n" - "\nResult\n" - "true|false (boolean) Returns true if successful\n" - "\nExamples:\n" + - HelpExampleCli("settxfee", "0.00001") + HelpExampleRpc("settxfee", "0.00001")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Amount - CAmount nAmount = 0; - if (params[0].get_real() != 0.0) - nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts - - payTxFee = CFeeRate(nAmount, 1000); - return true; -} - -UniValue getwalletinfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getwalletinfo\n" - "Returns an object containing various wallet state info.\n" - "\nResult:\n" - "{\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total DAPS balance of the wallet\n" - " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" - " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - "}\n" - "\nExamples:\n" + - HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); - obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); - if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); - return obj; -} - -// ppcoin: reserve balance from being staked for network protection -UniValue reservebalance(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "reservebalance ( reserve amount )\n" - "\nShow or set the reserve amount not participating in network protection\n" - "If no parameters provided current setting is printed.\n" - - "\nArguments:\n" - "1. reserve (boolean, optional) is true or false to turn balance reserve on or off.\n" - "2. amount (numeric, optional) is a real and rounded to cent.\n" - - "\nResult:\n" - "{\n" - " \"reserve\": true|false, (boolean) Status of the reserve balance\n" - " \"amount\": x.xxxx (numeric) Amount reserved\n" - "\nExamples:\n" + - HelpExampleCli("reservebalance", "true 5000") + HelpExampleRpc("reservebalance", "true 5000")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - if (params.size() > 0) { - bool fReserve = params[0].get_bool(); - if (fReserve) { - if (params.size() == 1) - throw runtime_error("must provide amount to reserve balance.\n"); - CAmount nAmount = AmountFromValue(params[1]); - nAmount = (nAmount / CENT) * CENT; // round to cent - if (nAmount < 0) - throw runtime_error("amount cannot be negative.\n"); - nReserveBalance = nAmount; - - CWalletDB walletdb(pwalletMain->strWalletFile); - walletdb.WriteReserveAmount(nReserveBalance / COIN); - - } else { - if (params.size() > 1) - throw runtime_error("cannot specify amount to turn off reserve.\n"); - nReserveBalance = 0; - } - } - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("reserve", (nReserveBalance > 0))); - result.push_back(Pair("amount", ValueFromAmount(nReserveBalance))); - return result; -} - -// presstab HyperStake -UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "setstakesplitthreshold value\n" - "\nThis will set the output size of your stakes to never be below this number\n" - - "\nArguments:\n" - "1. value (numeric, required) Threshold value between 1 and 999999\n" - "\nResult:\n" - "{\n" - " \"threshold\": n, (numeric) Threshold value set\n" - " \"saved\": true|false (boolean) 'true' if successfully saved to the wallet file\n" - "}\n" - "\nExamples:\n" + - HelpExampleCli("setstakesplitthreshold", "5000") + HelpExampleRpc("setstakesplitthreshold", "5000")); - - uint64_t nStakeSplitThreshold = params[0].get_int(); - if (pwalletMain->IsLocked()) - throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Unlock wallet to use this feature"); - if (nStakeSplitThreshold > 999999) - throw runtime_error("Value out of range, max allowed is 999999"); - - CWalletDB walletdb(pwalletMain->strWalletFile); - LOCK(pwalletMain->cs_wallet); - { - bool fFileBacked = pwalletMain->fFileBacked; - - UniValue result(UniValue::VOBJ); - pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; - result.push_back(Pair("threshold", int(pwalletMain->nStakeSplitThreshold))); - if (fFileBacked) { - walletdb.WriteStakeSplitThreshold(nStakeSplitThreshold); - result.push_back(Pair("saved", "true")); - } else - result.push_back(Pair("saved", "false")); - - return result; - } -} - -// presstab HyperStake -UniValue getstakesplitthreshold(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getstakesplitthreshold\n" - "Returns the threshold for stake splitting\n" - "\nResult:\n" - "n (numeric) Threshold value\n" - "\nExamples:\n" + - HelpExampleCli("getstakesplitthreshold", "") + HelpExampleRpc("getstakesplitthreshold", "")); - - return int(pwalletMain->nStakeSplitThreshold); -} - -UniValue autocombinedust(const UniValue& params, bool fHelp) -{ - bool fEnable; - if (params.size() >= 1) - fEnable = params[0].get_bool(); - - if (fHelp || params.size() < 1 || (fEnable && params.size() != 2) || params.size() > 2) - throw runtime_error( - "autocombinedust true|false ( threshold )\n" - "\nWallet will automatically monitor for any coins with value below the threshold amount, and combine them if they reside with the same DAPS address\n" - "When autocombinedust runs it will create a transaction, and therefore will be subject to transaction fees. Minimum of 25 dust transactions before activation.\n" - - "\nArguments:\n" - "1. true|false (boolean, required) Enable auto combine (true) or disable (false)\n" - "2. threshold (numeric, optional) Threshold amount (default: 0)\n" - "\nExamples:\n" + - HelpExampleCli("autocombinedust", "true 540") + HelpExampleRpc("autocombinedust", "true 540")); - - CWalletDB walletdb(pwalletMain->strWalletFile); - CAmount nThreshold = 0; - - if (fEnable) { - nThreshold = params[1].get_int(); - } else { - nThreshold = 0; - } - - pwalletMain->fCombineDust = fEnable; - pwalletMain->nAutoCombineThreshold = nThreshold; - - if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) - throw runtime_error("Changed settings in wallet but failed to save to database\n"); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("autocombinedust", params[0].get_bool())); - result.push_back(Pair("amount", int(pwalletMain->nAutoCombineThreshold))); - return result; -} - -UniValue printMultiSend() -{ - UniValue ret(UniValue::VARR); - UniValue act(UniValue::VARR); - act.push_back(Pair("MultiSendStake Activated?", pwalletMain->fMultiSendStake)); - act.push_back(Pair("MultiSendMasternode Activated?", pwalletMain->fMultiSendMasternodeReward)); - ret.push_back(act); - - if (pwalletMain->vDisabledAddresses.size() >= 1) { - UniValue disAdd(UniValue::VOBJ); - for (unsigned int i = 0; i < pwalletMain->vDisabledAddresses.size(); i++) { - disAdd.push_back(Pair("Disabled From Sending", pwalletMain->vDisabledAddresses[i])); - } - ret.push_back(disAdd); - } - - ret.push_back("MultiSend Addresses to Send To:"); - - UniValue vMS(UniValue::VOBJ); - for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { - vMS.push_back(Pair("Address " + std::to_string(i), pwalletMain->vMultiSend[i].first)); - vMS.push_back(Pair("Percent", pwalletMain->vMultiSend[i].second)); - } - - ret.push_back(vMS); - return ret; -} - -UniValue printAddresses() -{ - std::vector vCoins; - pwalletMain->AvailableCoins(vCoins); - std::map mapAddresses; - for (const COutput& out : vCoins) { - CTxDestination utxoAddress; - ExtractDestination(out.tx->vout[out.i].scriptPubKey, utxoAddress); - std::string strAdd = CBitcoinAddress(utxoAddress).ToString(); - - if (mapAddresses.find(strAdd) == mapAddresses.end()) //if strAdd is not already part of the map - mapAddresses[strAdd] = (double)out.tx->vout[out.i].nValue / (double)COIN; - else - mapAddresses[strAdd] += (double)out.tx->vout[out.i].nValue / (double)COIN; - } - - UniValue ret(UniValue::VARR); - for (map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { - UniValue obj(UniValue::VOBJ); - const std::string* strAdd = &(*it).first; - const double* nBalance = &(*it).second; - obj.push_back(Pair("Address ", *strAdd)); - obj.push_back(Pair("Balance ", *nBalance)); - ret.push_back(obj); - } - - return ret; -} - -unsigned int sumMultiSend() -{ - unsigned int sum = 0; - for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) - sum += pwalletMain->vMultiSend[i].second; - return sum; -} - -UniValue multisend(const UniValue& params, bool fHelp) -{ - CWalletDB walletdb(pwalletMain->strWalletFile); - bool fFileBacked; - //MultiSend Commands - if (params.size() == 1) { - string strCommand = params[0].get_str(); - UniValue ret(UniValue::VOBJ); - if (strCommand == "print") { - return printMultiSend(); - } else if (strCommand == "printaddress" || strCommand == "printaddresses") { - return printAddresses(); - } else if (strCommand == "clear") { - LOCK(pwalletMain->cs_wallet); - { - bool erased = false; - if (pwalletMain->fFileBacked) { - if (walletdb.EraseMultiSend(pwalletMain->vMultiSend)) - erased = true; - } - - pwalletMain->vMultiSend.clear(); - pwalletMain->setMultiSendDisabled(); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("Erased from database", erased)); - obj.push_back(Pair("Erased from RAM", true)); - - return obj; - } - } else if (strCommand == "enablestake" || strCommand == "activatestake") { - if (pwalletMain->vMultiSend.size() < 1) - throw JSONRPCError(RPC_INVALID_REQUEST, "Unable to activate MultiSend, check MultiSend vector"); - - if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { - pwalletMain->fMultiSendStake = true; - if (!walletdb.WriteMSettings(true, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - UniValue arr(UniValue::VARR); - arr.push_back(obj); - arr.push_back(printMultiSend()); - return arr; - } else - return printMultiSend(); - } - - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to activate MultiSend, check MultiSend vector"); - } else if (strCommand == "enablemasternode" || strCommand == "activatemasternode") { - if (pwalletMain->vMultiSend.size() < 1) - throw JSONRPCError(RPC_INVALID_REQUEST, "Unable to activate MultiSend, check MultiSend vector"); - - if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { - pwalletMain->fMultiSendMasternodeReward = true; - - if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, true, pwalletMain->nLastMultiSendHeight)) { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - UniValue arr(UniValue::VARR); - arr.push_back(obj); - arr.push_back(printMultiSend()); - return arr; - } else - return printMultiSend(); - } - - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to activate MultiSend, check MultiSend vector"); - } else if (strCommand == "disable" || strCommand == "deactivate") { - pwalletMain->setMultiSendDisabled(); - if (!walletdb.WriteMSettings(false, false, pwalletMain->nLastMultiSendHeight)) - throw JSONRPCError(RPC_DATABASE_ERROR, "MultiSend deactivated but writing settings to DB failed"); - - return printMultiSend(); - } else if (strCommand == "enableall") { - if (!walletdb.EraseMSDisabledAddresses(pwalletMain->vDisabledAddresses)) - return "failed to clear old vector from walletDB"; - else { - pwalletMain->vDisabledAddresses.clear(); - return printMultiSend(); - } - } - } - if (params.size() == 2 && params[0].get_str() == "delete") { - int del = std::stoi(params[1].get_str().c_str()); - if (!walletdb.EraseMultiSend(pwalletMain->vMultiSend)) - throw JSONRPCError(RPC_DATABASE_ERROR, "failed to delete old MultiSend vector from database"); - - pwalletMain->vMultiSend.erase(pwalletMain->vMultiSend.begin() + del); - if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) - throw JSONRPCError(RPC_DATABASE_ERROR, "walletdb WriteMultiSend failed!"); - - return printMultiSend(); - } - if (params.size() == 2 && params[0].get_str() == "disable") { - std::string disAddress = params[1].get_str(); - if (!CBitcoinAddress(disAddress).IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "address you want to disable is not valid"); - else { - pwalletMain->vDisabledAddresses.push_back(disAddress); - if (!walletdb.EraseMSDisabledAddresses(pwalletMain->vDisabledAddresses)) - throw JSONRPCError(RPC_DATABASE_ERROR, "disabled address from sending, but failed to clear old vector from walletDB"); - - if (!walletdb.WriteMSDisabledAddresses(pwalletMain->vDisabledAddresses)) - throw JSONRPCError(RPC_DATABASE_ERROR, "disabled address from sending, but failed to store it to walletDB"); - else - return printMultiSend(); - } - } - - //if no commands are used - if (fHelp || params.size() != 2) - throw runtime_error( - "multisend \n" - "****************************************************************\n" - "WHAT IS MULTISEND?\n" - "MultiSend allows a user to automatically send a percent of their stake reward to as many addresses as you would like\n" - "The MultiSend transaction is sent when the staked coins mature (100 confirmations)\n" - "****************************************************************\n" - "TO CREATE OR ADD TO THE MULTISEND VECTOR:\n" - "multisend \n" - "This will add a new address to the MultiSend vector\n" - "Percent is a whole number 1 to 100.\n" - "****************************************************************\n" - "MULTISEND COMMANDS (usage: multisend )\n" - " print - displays the current MultiSend vector \n" - " clear - deletes the current MultiSend vector \n" - " enablestake/activatestake - activates the current MultiSend vector to be activated on stake rewards\n" - " enablemasternode/activatemasternode - activates the current MultiSend vector to be activated on masternode rewards\n" - " disable/deactivate - disables the current MultiSend vector \n" - " delete
- deletes an address from the MultiSend vector \n" - " disable
- prevents a specific address from sending MultiSend transactions\n" - " enableall - enables all addresses to be eligible to send MultiSend transactions\n" - "****************************************************************\n"); - - //if the user is entering a new MultiSend item - string strAddress = params[0].get_str(); - CBitcoinAddress address(strAddress); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); - if (std::stoi(params[1].get_str().c_str()) < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid percentage"); - if (pwalletMain->IsLocked()) - throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with unlockwallet first."); - unsigned int nPercent = (unsigned int) std::stoul(params[1].get_str().c_str()); - - LOCK(pwalletMain->cs_wallet); - { - fFileBacked = pwalletMain->fFileBacked; - //Error if 0 is entered - if (nPercent == 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sending 0% of stake is not valid"); - } - - //MultiSend can only send 100% of your stake - if (nPercent + sumMultiSend() > 100) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, the sum of your MultiSend is greater than 100%"); - - for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { - if (pwalletMain->vMultiSend[i].first == strAddress) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, cannot use the same address twice"); - } - - if (fFileBacked) - walletdb.EraseMultiSend(pwalletMain->vMultiSend); - - std::pair newMultiSend; - newMultiSend.first = strAddress; - newMultiSend.second = nPercent; - pwalletMain->vMultiSend.push_back(newMultiSend); - if (fFileBacked) { - if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) - throw JSONRPCError(RPC_DATABASE_ERROR, "walletdb WriteMultiSend failed!"); - } - } - return printMultiSend(); -} - -UniValue createprivacywallet(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() >2 || params.size() < 1) - throw runtime_error( - "createprivacywallet \"password\" (\"language\") \n" - "\nCreate a new wallet for privacy with dual-key stealth address.\n" - "If 'language' is specified, it is used, otherwise english \n" - "\nArguments:\n" - "1. \"account\" (string, required) password for the wallet \n" - "2. \"language\" (string, optional) language for the wallet's mnemmonics \n" - "\nResult:\n" - "\"privacy wallet created\" (string) the base address of the wallet\n" - "\nExamples:\n" + - HelpExampleCli("createprivacywallet", "") + HelpExampleCli("createprivacywallet", "\"\"") + HelpExampleCli("createprivacywallet", "\"1234567890\"") + HelpExampleRpc("createprivacywallet", "\"1234567890\"")); - - LOCK2(cs_main, pwalletMain->cs_wallet); - - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: RPC unimplemented."); -} - -UniValue createprivacyaccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "createprivacyaccount \n" - "\nCreate a new wallet account for privacy.\n" - "\nArguments:\n" - "\nResult:\n" - "\"account address\" (string) the address of the created account\n" - "\nExamples:\n" + - HelpExampleCli("createprivacyaccount", "") + HelpExampleCli("createprivacyaccount", "\"\"") + HelpExampleCli("createprivacyaccount", "") + HelpExampleRpc("createprivacyaccount", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - CWalletDB walletdb(pwalletMain->strWalletFile); - UniValue ret(UniValue::VOBJ); - int i = 0; - while (i < 10) { - std::string viewAccountLabel = "viewaccount"; - std::string spendAccountLabel = "spendaccount"; - - CAccount viewAccount; - walletdb.ReadAccount(viewAccountLabel, viewAccount); - if (!viewAccount.vchPubKey.IsValid()) { - std::string viewAccountAddress = GetHDAccountAddress(viewAccountLabel, 0).ToString(); - } - - CAccount spendAccount; - walletdb.ReadAccount(spendAccountLabel, spendAccount); - if (!spendAccount.vchPubKey.IsValid()) { - std::string spendAccountAddress = GetHDAccountAddress(spendAccountLabel, 1).ToString(); - } - if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { - i++; - continue; - } - ret.push_back(Pair("viewpublickey", viewAccount.vchPubKey.GetHex())); - - ret.push_back(Pair("spendpublickey", spendAccount.vchPubKey.GetHex())); - - std::string stealthAddr; - if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); - } - break; - } - return ret; -} - -UniValue showstealthaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "showstealthaddress \n" - "\nShow stealth address.\n" - "\nArguments:\n" - "\nResult:\n" - "\"account address\" (string) the address of the created account\n" - "\nExamples:\n" + - HelpExampleCli("showstealthaddress", "") + HelpExampleCli("showstealthaddress", "\"\"") + HelpExampleCli("showstealthaddress", "") + HelpExampleRpc("showstealthaddress", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - CWalletDB walletdb(pwalletMain->strWalletFile); - UniValue ret(UniValue::VOBJ); - int i = 0; - while (i < 10) { - std::string viewAccountLabel = "viewaccount"; - std::string spendAccountLabel = "spendaccount"; - - CAccount viewAccount; - walletdb.ReadAccount(viewAccountLabel, viewAccount); - if (!viewAccount.vchPubKey.IsValid()) { - std::string viewAccountAddress = GetHDAccountAddress(viewAccountLabel, 0).ToString(); - } - - CAccount spendAccount; - walletdb.ReadAccount(spendAccountLabel, spendAccount); - if (!spendAccount.vchPubKey.IsValid()) { - std::string spendAccountAddress = GetHDAccountAddress(spendAccountLabel, 1).ToString(); - } - if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { - i++; - continue; - } - std::string stealthAddr; - if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); - } - break; - } - return ret; -} - -UniValue generateintegratedaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "generateintegratedaddress \n" - "\nGenerate integrated addresses for this wallet with a random payment ID.\n" - "\nArguments:\n" - "optional: paymentID" - "\nResult:\n" - "\nExamples:\n" + - HelpExampleCli("generateintegratedaddress", "1234") + HelpExampleCli("generateintegratedaddress", "\"\"") + HelpExampleCli("generateintegratedaddress", "") + HelpExampleRpc("generateintegratedaddress", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - UniValue ret(UniValue::VOBJ); - uint64_t paymentID = 0; - std::string address; - if (params.size() == 1) { - paymentID = params[0].get_int64(); - address = pwalletMain->GenerateIntegratedAddressWithProvidedPaymentID("masteraccount", paymentID); - } else { - address = pwalletMain->GenerateIntegratedAddressWithRandomPaymentID("masteraccount", paymentID); - } - ret.push_back(Pair("integratedaddress", address)); - ret.push_back(Pair("paymentid", paymentID)); - return ret; -} - -UniValue importkeys(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "importkeys \n" - "\nCreate a new wallet account for privacy.\n" - "\nArguments:\n" - "\nResult:\n" - "\"account address\" (string) the address of the created account\n" - "\nExamples:\n" + - HelpExampleCli("importkeys", "") + HelpExampleCli("importkeys", "\"\"") + HelpExampleCli("importkeys", "") + HelpExampleRpc("importkeys", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - CWalletDB walletdb(pwalletMain->strWalletFile); - - std::string viewStr = params[0].get_str(); - std::string spendStr = params[1].get_str(); - - CAccount viewAc, spendAc; - - std::vector view, spend; - DecodeBase58(viewStr, view); - DecodeBase58(spendStr, spend); - std::string viewAccountLabel = "viewaccount"; - std::string spendAccountLabel = "spendaccount"; - - CKey viewPk, spendPk; - viewPk.Set(view.begin(), view.end(), true); - spendPk.Set(spend.begin(), spend.end(), true); - - pwalletMain->AddKey(viewPk); - pwalletMain->AddKey(spendPk); - viewAc.vchPubKey = viewPk.GetPubKey(); - spendAc.vchPubKey = spendPk.GetPubKey(); - - pwalletMain->SetAddressBook(viewAc.vchPubKey.GetID(), viewAccountLabel, "receive"); - walletdb.WriteAccount(viewAccountLabel, viewAc); - - pwalletMain->SetAddressBook(spendAc.vchPubKey.GetID(), spendAccountLabel, "receive"); - walletdb.WriteAccount(spendAccountLabel, spendAc); - - return true; -} - -UniValue createprivacysubaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "createprivacysubaddress \"label\" \n" - "\nCreate a new wallet account subaddress for privacy transaction.\n" - "\nArguments:\n" - "1. \"label\" (string, required) label for the wallet account address\n" - "\nResult:\n" - "\"account address\" (string) the created address for the corresponding account\n" - "\"address index\" (string) the index of the created address for the account\n" - "\nExamples:\n" + - HelpExampleCli("createprivacysubaddress", "") + HelpExampleCli("createprivacysubaddress", "\"\"") + HelpExampleCli("createprivacysubaddress", "\"address1\"") + HelpExampleRpc("createprivacysubaddress", "\"address1\"")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - - std::string label = params[0].get_str(); - - CWalletDB walletdb(pwalletMain->strWalletFile); - std::string viewAccountLabel = label + "view"; - std::string spendAccountLabel = label + "spend"; - CStealthAccount account; - if (!walletdb.ReadStealthAccount(label, account)) { - int i = 0; - while (i < 10) { - CAccount viewAccount; - walletdb.ReadAccount(label + "view", viewAccount); - if (!viewAccount.vchPubKey.IsValid()) { - GetAccountAddress(viewAccountLabel).ToString(); - } - - CAccount spendAccount; - walletdb.ReadAccount(spendAccountLabel, spendAccount); - if (!spendAccount.vchPubKey.IsValid()) { - GetAccountAddress(spendAccountLabel).ToString(); - } - if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { - i++; - continue; - } - account.viewAccount = viewAccount; - account.spendAccount = spendAccount; - walletdb.AppendStealthAccountList(label); - break; - } - } - - UniValue ret(UniValue::VOBJ); - - ret.push_back(Pair("viewpublickey", account.viewAccount.vchPubKey.GetHex())); - - ret.push_back(Pair("spendpublickey", account.spendAccount.vchPubKey.GetHex())); - - std::string stealthAddr; - if (pwalletMain->EncodeStealthPublicAddress(account.viewAccount.vchPubKey, account.spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); - } - return ret; -} - -UniValue readmasteraccount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "readmasteraccount \n" - "\nRead stealth master account address.\n" - "\nArguments:\n" - "\nResult:\n" - "\"public address\" (string) the public address" - "\nExamples:\n" + - HelpExampleCli("readmasteraccount", "") + HelpExampleCli("readmasteraccount", "\"\"") + HelpExampleCli("readmasteraccount", "") + HelpExampleRpc("readmasteraccount", "")); - - if (!pwalletMain) { - //privacy wallet is not yet created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - std::string address; - pwalletMain->ComputeStealthPublicAddress("masteraccount", address); - return address; -} - -UniValue decodestealthaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "decodestealthaddress \n" - "\nDecode a stealth address into spend and view public keys.\n" - "\nArguments:\n" - "1. \"stealth_address\" (string, required) The Base58 stealth address\n" - "\nResult:\n" - "\"public view key\" (string) the view public key\n" - "\"public spend key\" (string) the spend public key" - "\nExamples:\n" + - HelpExampleCli("decodestealthaddress", "") + HelpExampleCli("decodestealthaddress", "\"\"") + HelpExampleCli("decodestealthaddress", "") + HelpExampleRpc("decodestealthaddress", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - std::string addr = params[0].get_str(); - - UniValue ret(UniValue::VOBJ); - CPubKey viewKey, spendKey; - bool hasPaymentID; - uint64_t paymentID; - - if (!CWallet::DecodeStealthAddress(addr, viewKey, spendKey, hasPaymentID, paymentID)) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Error: Stealth address is not correctly formatted."); - } - ret.push_back(Pair("spendpublickey", spendKey.GetHex())); - ret.push_back(Pair("viewpublickey", viewKey.GetHex())); - if (hasPaymentID) { - ret.push_back(Pair("paymentid", paymentID)); - } - - return ret; -} - -UniValue sendtostealthaddress(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "sendtostealthaddress \"dapsstealthaddress\" amount\n" - "\nSend an amount to a given daps stealth address address. The amount is a real and is rounded to the nearest 0.00000001\n" + - HelpRequiringPassphrase() + - "\nArguments:\n" - "1. \"dapsstealthaddress\" (string, required) The dapscoin stealth address to send to.\n" - "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n" - "\nResult:\n" - "\"transactionid\" (string) The transaction id.\n" - "\nExamples:\n" + - HelpExampleCli("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\" 0.1") + HelpExampleCli("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\" 0.1 \"donation\" \"seans outpost\"") + HelpExampleRpc("sendtostealthaddress", "\"41kYDmcd27f2ULWE6tfC19UnEHYpEhMBtfiYwVFUYbZhXrjLomZXSovQPGzwTCAgwQLpWiEQPA5uyNjmEVLPr4g71AUMNjaVD3n\", 0.1, \"donation\", \"seans outpost\"")); - - std::string stealthAddr = params[0].get_str(); - - // Amount - CAmount nAmount = AmountFromValue(params[1]); - - // Wallet comments - CWalletTx wtx; - - EnsureWalletIsUnlocked(); - - if (!pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx)) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Cannot create transaction."); - } - return wtx.GetHash().GetHex(); -} - -UniValue setdecoyconfirmation(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "setdecoyconfirmation\n" - "\nSend the minimum confirmation for decoys in RingCT\n" + - HelpRequiringPassphrase() + - "\nArguments:\n" - "2. \"confirm\" (numeric, required) The required minim confirmation for decoys\n" - "\nResult:\n" - "\"decoy_confirmation\" (numeric) The minimum decoy confirmation.\n" - "\nExamples:\n" + - HelpExampleCli("setdecoyconfirmation", "\"20\"") + HelpExampleCli("setdecoyconfirmation", "\"20\"") + HelpExampleRpc("setdecoyconfirmation", "\"20\"")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - int confirmation = params[0].get_int(); - - if (confirmation <= 0) { - throw JSONRPCError(RPC_PRIVACY_DECOY_MIN, - "Error: Min decoy confirmation must be positive."); - } - pwalletMain->DecoyConfirmationMinimum = confirmation; - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("decoy_confirmation", confirmation)); - return ret; -} - -UniValue getdecoyconfirmation(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getdecoyconfirmation\n" - "\nShow the current decoy confirmation\n" + - HelpRequiringPassphrase() + - "\nArguments:\n" - "\nResult:\n" - "\"decoy_confirmation\" (numeric) The minimum decoy confirmation.\n" - "\nExamples:\n" + - HelpExampleCli("getdecoyconfirmation", "") + HelpExampleCli("getdecoyconfirmation", "") + HelpExampleRpc("getdecoyconfirmation", "")); - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("decoy_confirmation", pwalletMain->DecoyConfirmationMinimum)); - return ret; -} - -std::string GetHex(const unsigned char* vch, int sz) { - char psz[sz * 2 + 1]; - for (int i = 0; i < sz; i++) - sprintf(psz + i * 2, "%02x", vch[sz - i - 1]); - return std::string(psz, psz + sz * 2); -} - -UniValue revealviewprivatekey(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) - throw runtime_error( - "revealviewprivatekey \n" - "\nReveal view private key.\n" - "\nArguments:\n" - "\nResult:\n" - "\"Private view key\" (string) the private view key\n" - "\nExamples:\n" + - HelpExampleCli("revealviewprivatekey", "") + HelpExampleCli("revealviewprivatekey", "\"\"") + - HelpExampleCli("revealviewprivatekey", "") + HelpExampleRpc("revealviewprivatekey", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - - CKey view; - pwalletMain->myViewPrivateKey(view); - return CBitcoinSecret(view).ToString(); -} - -UniValue revealspendprivatekey(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) - throw runtime_error( - "revealspendprivatekey \n" - "\nReveal view private key.\n" - "\nArguments:\n" - "\nResult:\n" - "\"Private spend key\" (string) the private spend key\n" - "\nExamples:\n" + - HelpExampleCli("revealspendprivatekey", "") + HelpExampleCli("revealspendprivatekey", "\"\"") + - HelpExampleCli("revealspendprivatekey", "") + HelpExampleRpc("revealspendprivatekey", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - - CKey spend; - pwalletMain->mySpendPrivateKey(spend); - return CBitcoinSecret(spend).ToString(); -} - -UniValue showtxprivatekeys(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 1) - throw runtime_error( - "showtxprivatekeys \n" - "\nShow transaction private keys for each UTXO of a transaction.\n" - "\nArguments:\n" - "\nResult:\n" - "\"Private spend key\" (string) the private spend key\n" - "\nExamples:\n" + - HelpExampleCli("showtxprivatekeys", "") + HelpExampleCli("showtxprivatekeys", "\"\"") + - HelpExampleCli("showtxprivatekeys", "") + HelpExampleRpc("showtxprivatekeys", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - UniValue ret(UniValue::VOBJ); - CWalletDB db(pwalletMain->strWalletFile); - for(int i = 0; i < 10; i++) { - std::string key = params[0].get_str() + std::to_string(i); - std::string secret; - if (db.ReadTxPrivateKey(key, secret)) { - ret.push_back(Pair(std::to_string(i), secret)); - } else break; - } - return ret; -} - -UniValue rescan(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) - throw runtime_error( - "rescan\n" - "\nRescan wallet transactions from the first block.\n" - "\nArguments:\n" - "\nResult:\n" - "\"scanned wallet transactions\" \n" - "\nExamples:\n" + - HelpExampleCli("rescan", "") + HelpExampleCli("rescan", "\"\"") + - HelpExampleRpc("rescan", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - - int nHeight = 1; - if (!pwalletMain->RescanAfterUnlock(nHeight)) { - return "Failed to rescan"; - } - return "Done"; -} - -UniValue rescanwallettransactions(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 1) - throw runtime_error( - "rescanwallettransactions \"block height\"\n" - "\nRescan wallet transactions from a certain block height.\n" - "\nArguments:\n" - "\nblock height: block height from which the chain will be rescanned\n" - "\nResult:\n" - "\"scanned wallet transactions\" \n" - "\nExamples:\n" + - HelpExampleCli("rescanwallettransactions", "") + HelpExampleCli("rescanwallettransactions", "\"\"") + - HelpExampleRpc("rescanwallettransactions", "")); - - if (!pwalletMain) { - //privacy wallet is already created - throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, - "Error: There is no privacy wallet, please use createprivacyaccount to create one."); - } - - EnsureWalletIsUnlocked(); - - int nHeight = 0; - if (params.size() == 1) { - nHeight = params[0].get_int(); - } - if (!pwalletMain->RescanAfterUnlock(nHeight)) { - return "Failed to rescan"; - } - return "Done"; -} - -UniValue revealmnemonicphrase(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "revealmnemonicphrase \n" - "\nReveal Mnemonic Phrase.\n" - "\nArguments:\n" - "\nResult:\n" - "\"Mnemonic Phrase\" (string) mnemonic phrase\n" - "\nExamples:\n" + - HelpExampleCli("revealmnemonicphrase", "") + HelpExampleCli("revealmnemonicphrase", "\"\"") + - HelpExampleCli("revealmnemonicphrase", "") + HelpExampleRpc("revealmnemonicphrase", "")); - - EnsureWalletIsUnlocked(); - - CHDChain hdChainCurrent; - if (!pwalletMain->GetDecryptedHDChain(hdChainCurrent)) - throw JSONRPCError(RPC_WALLET_ERROR, - "Error: There was a problem while getting mnemonic phrase."); - - SecureString mnemonic; - SecureString mnemonicPass; - if (!hdChainCurrent.GetMnemonic(mnemonic, mnemonicPass)) - throw JSONRPCError(RPC_WALLET_ERROR, - "Error: There was a problem while getting mnemonic phrase."); - - string mPhrase = std::string(mnemonic.begin(), mnemonic.end()).c_str(); - - return mPhrase; -} From 2372b8ba8bc80527e53fcb3d859891334583f129 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 01:53:49 -0500 Subject: [PATCH 0017/1888] [RPC] Fix movecmd's help description to include amount --- src/wallet/rpcwallet.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f99bf4906a..6be769d5be 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -755,31 +755,32 @@ UniValue getunconfirmedbalance(const UniValue& params, bool fHelp) UniValue movecmd(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 5) - throw runtime_error( + throw std::runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" "\nMove a specified amount from one account in your wallet to another.\n" "\nArguments:\n" "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n" "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n" - "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" - "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" + "3. amount (numeric, required) Quantity of PIV to move between accounts.\n" + "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n" + "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n" "\nResult:\n" - "true|false (boolean) true if successfull.\n" + "true|false (boolean) true if successful.\n" "\nExamples:\n" "\nMove 0.01 DAPS from the default account to the account named tabby\n" + HelpExampleCli("move", "\"\" \"tabby\" 0.01") + - "\nMove 0.01 DAPS timotei to akiko with a comment and funds have 6 confirmations\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") + - "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")); + "\nMove 0.01 DAPS timotei to akiko with a comment\n" + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 1 \"happy birthday!\"") + + "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 1, \"happy birthday!\"")); LOCK2(cs_main, pwalletMain->cs_wallet); - string strFrom = AccountFromValue(params[0]); - string strTo = AccountFromValue(params[1]); + std::string strFrom = AccountFromValue(params[0]); + std::string strTo = AccountFromValue(params[1]); CAmount nAmount = AmountFromValue(params[2]); if (params.size() > 3) // unused parameter, used to be nMinDepth, keep type-checking it though (void)params[3].get_int(); - string strComment; + std::string strComment; if (params.size() > 4) strComment = params[4].get_str(); From ca928ecdf9b9f9ed195232e905b4adbf5bbc2680 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 02:01:14 -0500 Subject: [PATCH 0018/1888] [Build] Remove stale m4 file --- pkg.m4 | 214 --------------------------------------------------------- 1 file changed, 214 deletions(-) delete mode 100644 pkg.m4 diff --git a/pkg.m4 b/pkg.m4 deleted file mode 100644 index c5b26b52e6..0000000000 --- a/pkg.m4 +++ /dev/null @@ -1,214 +0,0 @@ -# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -# serial 1 (pkg-config-0.24) -# -# Copyright © 2004 Scott James Remnant . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# PKG_PROG_PKG_CONFIG([MIN-VERSION]) -# ---------------------------------- -AC_DEFUN([PKG_PROG_PKG_CONFIG], -[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) -m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) -m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) -AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) -AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) -AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) - -if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then - AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) -fi -if test -n "$PKG_CONFIG"; then - _pkg_min_version=m4_default([$1], [0.9.0]) - AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) - if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - PKG_CONFIG="" - fi -fi[]dnl -])# PKG_PROG_PKG_CONFIG - -# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# -# Check to see whether a particular set of modules exists. Similar -# to PKG_CHECK_MODULES(), but does not set variables or print errors. -# -# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -# only at the first occurence in configure.ac, so if the first place -# it's called might be skipped (such as if it is within an "if", you -# have to call PKG_CHECK_EXISTS manually -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_EXISTS], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -if test -n "$PKG_CONFIG" && \ - AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then - m4_default([$2], [:]) -m4_ifvaln([$3], [else - $3])dnl -fi]) - -# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) -# --------------------------------------------- -m4_define([_PKG_CONFIG], -[if test -n "$$1"; then - pkg_cv_[]$1="$$1" - elif test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` - test "x$?" != "x0" && pkg_failed=yes ], - [pkg_failed=yes]) - else - pkg_failed=untried -fi[]dnl -])# _PKG_CONFIG - -# _PKG_SHORT_ERRORS_SUPPORTED -# ----------------------------- -AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) -if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then - _pkg_short_errors_supported=yes -else - _pkg_short_errors_supported=no -fi[]dnl -])# _PKG_SHORT_ERRORS_SUPPORTED - - -# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], -# [ACTION-IF-NOT-FOUND]) -# -# -# Note that if there is a possibility the first call to -# PKG_CHECK_MODULES might not happen, you should be sure to include an -# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac -# -# -# -------------------------------------------------------------- -AC_DEFUN([PKG_CHECK_MODULES], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl -AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl - -pkg_failed=no -AC_MSG_CHECKING([for $1]) - -_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) -_PKG_CONFIG([$1][_LIBS], [libs], [$2]) - -m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS -and $1[]_LIBS to avoid the need to call pkg-config. -See the pkg-config man page for more details.]) - -if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) - _PKG_SHORT_ERRORS_SUPPORTED - if test $_pkg_short_errors_supported = yes; then - $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else - $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` - fi - # Put the nasty error message in config.log where it belongs - echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD - - m4_default([$4], [AC_MSG_ERROR( -[Package requirements ($2) were not met: - -$$1_PKG_ERRORS - -Consider adjusting the PKG_CONFIG_PATH environment variable if you -installed software in a non-standard prefix. - -_PKG_TEXT])[]dnl - ]) -elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) - m4_default([$4], [AC_MSG_FAILURE( -[The pkg-config script could not be found or is too old. Make sure it -is in your PATH or set the PKG_CONFIG environment variable to the full -path to pkg-config. - -_PKG_TEXT - -To get pkg-config, see .])[]dnl - ]) -else - $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS - $1[]_LIBS=$pkg_cv_[]$1[]_LIBS - AC_MSG_RESULT([yes]) - $3 -fi[]dnl -])# PKG_CHECK_MODULES - - -# PKG_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable pkgconfigdir as the location where a module -# should install pkg-config .pc files. By default the directory is -# $libdir/pkgconfig, but the default can be changed by passing -# DIRECTORY. The user can override through the --with-pkgconfigdir -# parameter. -AC_DEFUN([PKG_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([pkgconfigdir], - [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, - [with_pkgconfigdir=]pkg_default) -AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_INSTALLDIR - - -# PKG_NOARCH_INSTALLDIR(DIRECTORY) -# ------------------------- -# Substitutes the variable noarch_pkgconfigdir as the location where a -# module should install arch-independent pkg-config .pc files. By -# default the directory is $datadir/pkgconfig, but the default can be -# changed by passing DIRECTORY. The user can override through the -# --with-noarch-pkgconfigdir parameter. -AC_DEFUN([PKG_NOARCH_INSTALLDIR], -[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) -m4_pushdef([pkg_description], - [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) -AC_ARG_WITH([noarch-pkgconfigdir], - [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, - [with_noarch_pkgconfigdir=]pkg_default) -AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) -m4_popdef([pkg_default]) -m4_popdef([pkg_description]) -]) dnl PKG_NOARCH_INSTALLDIR - - -# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, -# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -# ------------------------------------------- -# Retrieves the value of the pkg-config variable for the given module. -AC_DEFUN([PKG_CHECK_VAR], -[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl -AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl - -_PKG_CONFIG([$1], [variable="][$3]["], [$2]) -AS_VAR_COPY([$1], [pkg_cv_][$1]) - -AS_VAR_IF([$1], [""], [$5], [$4])dnl -])# PKG_CHECK_VAR From 23f4ab8204e34222b19e1ec06d9c4383809c0e98 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 02:35:19 -0500 Subject: [PATCH 0019/1888] [RPC] Add mediantime to getblock/getblockheader output --- src/rpc/blockchain.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6fc68b0cb1..9709c25124 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -66,6 +66,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("version", blockindex->nVersion)); result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -105,6 +106,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -322,6 +324,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " ,...\n" " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" @@ -376,8 +379,9 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash' header.\n" From 0813bd574e791b45fea0bf1fba593f651599bdc5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Dec 2019 03:01:20 -0500 Subject: [PATCH 0020/1888] Build: Show PIC/PIE flags in configure summary --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7f11150eb7..cd50716eda 100644 --- a/configure.ac +++ b/configure.ac @@ -1099,7 +1099,6 @@ echo "Options used to compile and link:" echo " with wallet = $enable_wallet" echo " with gui / qt = $bitcoin_enable_qt" if test x$bitcoin_enable_qt != xno; then - echo " qt version = $bitcoin_qt_got_major_vers" echo " with qr = $use_qr" fi echo " with zmq = $use_zmq" @@ -1117,4 +1116,6 @@ echo " CPPFLAGS = $CPPFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $CXXFLAGS" echo " LDFLAGS = $LDFLAGS" +echo " PIC_FLAGS = $PIC_FLAGS" +echo " QT_PIE_FLAGS = $QT_PIE_FLAGS" echo From 0526152d3a9c9d5b193a725b5f2d07a2d3ee2ec2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 19 Dec 2019 20:37:42 -0500 Subject: [PATCH 0021/1888] Bump version to v1.0.5.4 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cd50716eda..6c7544399f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_BUILD, 4) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) From 9487f06ed8d9fee1aadb124652342eaf9c7b56a8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 01:00:49 -0500 Subject: [PATCH 0022/1888] Add checkpoint for 188549 --- src/chainparams.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4aefdd0dcd..7b19032218 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -92,11 +92,12 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (147000, uint256("e60eb87bdbeaee7582826418c8c4504637e51684a3e631b5683390497a4e2535")) (147200, uint256("55fcf4abbd7a1b3aa91460378c3b833f9d1569780b0a1e7e6ee2d1b3a4256b24")) (147400, uint256("15d8ed0575995a4b3ab8337d87213943abb9e3fba5389c57cbd48a2751f78a5d")) + (188549, uint256("cfe3696e23e393fa9230f84dfa16a505ac3f40fd147a79adba8a54fa17d24e91")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1573659116, // * UNIX timestamp of last checkpoint block - 379717, // * total number of transactions between genesis and last checkpoint + 1576134192, // * UNIX timestamp of last checkpoint block + 479108, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From d755009077b546ceacedd1ab367359b593315278 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 17:16:14 -0500 Subject: [PATCH 0023/1888] Add History, Masternodes, Settings to Tray/Dock icon menu --- src/qt/bitcoingui.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a69c35381c..e6ee66a903 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -323,9 +323,9 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) masternodeAction->setToolTip(masternodeAction->statusTip()); masternodeAction->setCheckable(true); #ifdef Q_OS_MAC - masternodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_6)); + masternodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); #else - masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6)); + masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); #endif tabGroup->addAction(masternodeAction); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); @@ -712,7 +712,10 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addSeparator(); trayIconMenu->addAction(sendCoinsAction); trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addAction(historyAction); + trayIconMenu->addAction(masternodeAction); trayIconMenu->addSeparator(); + trayIconMenu->addAction(optionsAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(openInfoAction); trayIconMenu->addAction(openRPCConsoleAction); From 45c79d20c7ed8849bdd34caa0cec6d45f3e1793f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 17:18:59 -0500 Subject: [PATCH 0024/1888] Add "not responding" message to Unlock Dialog --- src/qt/forms/unlockdialog.ui | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/unlockdialog.ui b/src/qt/forms/unlockdialog.ui index a5fb1af48f..28df5ebc38 100644 --- a/src/qt/forms/unlockdialog.ui +++ b/src/qt/forms/unlockdialog.ui @@ -24,7 +24,7 @@ 30 - + @@ -35,10 +35,17 @@ + + + + (Wallet may appear not responding as it rescans for all transactions) + + + - + 30 @@ -91,7 +98,7 @@ - + 50 From aa2500d2eb1e542a5f8c6d0ba45bc32b242973f6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 18:23:05 -0500 Subject: [PATCH 0025/1888] [UI] Sort numbers correctly in coin control dialog --- src/qt/bitcoingui.h | 20 ++++++++++++++++++++ src/qt/coincontroldialog.cpp | 35 +++++++++++------------------------ src/qt/coincontroldialog.h | 1 - 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 88206164d4..afb1204027 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -19,6 +19,7 @@ #include #include #include +#include class ClientModel; class NetworkStyle; @@ -280,4 +281,23 @@ private slots: void onMenuSelection(QAction* action); }; +class TreeWidgetItem : public QTreeWidgetItem { +public: + TreeWidgetItem() : QTreeWidgetItem(){} + TreeWidgetItem(QTreeWidgetItem* item) : QTreeWidgetItem(item){} + TreeWidgetItem(QTreeWidget* parent) : QTreeWidgetItem(parent){} +private: + bool operator<(const QTreeWidgetItem &other)const { + int column = treeWidget()->sortColumn(); + bool isNumber; + double item1 = text(column).toDouble(&isNumber); + if (isNumber) { + double item2 = other.text(column).toDouble(&isNumber); + if (isNumber) + return item1 < item2; + } + return text(column) < other.text(column); + } +}; + #endif // BITCOIN_QT_BITCOINGUI_H diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d9ea8400f3..d8a538b4f4 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -9,6 +9,7 @@ #include "ui_coincontroldialog.h" #include "addresstablemodel.h" +#include "bitcoingui.h" //TreeWidgetItem #include "bitcoinunits.h" #include "guiutil.h" #include "init.h" @@ -32,7 +33,6 @@ #include #include #include -#include using namespace std; QList CoinControlDialog::payAmounts; @@ -178,19 +178,6 @@ void CoinControlDialog::setModel(WalletModel* model) } } -// helper function str_pad -QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding) -{ - QString padding = sPadding; - if (!sPadding.length()) - padding = " "; - - while (s.length() < nPadLength) - s = padding + s; - - return s; -} - // ok button void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) { @@ -756,7 +743,7 @@ void CoinControlDialog::updateView() model->listCoins(mapCoins); for (PAIRTYPE(QString, vector) coins : mapCoins) { - QTreeWidgetItem* itemWalletAddress = new QTreeWidgetItem(); + TreeWidgetItem* itemWalletAddress = new TreeWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); @@ -793,11 +780,11 @@ void CoinControlDialog::updateView() nSum += model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]); nChildren++; - QTreeWidgetItem* itemOutput; + TreeWidgetItem* itemOutput; if (treeMode) - itemOutput = new QTreeWidgetItem(itemWalletAddress); + itemOutput = new TreeWidgetItem(itemWalletAddress); else - itemOutput = new QTreeWidgetItem(ui->treeWidget); + itemOutput = new TreeWidgetItem(ui->treeWidget); itemOutput->setFlags(flgCheckbox); itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); @@ -849,20 +836,20 @@ void CoinControlDialog::updateView() // amount itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); itemOutput->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); - itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i])), 15, " ")); // padding so that sorting works correctly + itemOutput->setText(COLUMN_AMOUNT_INT64, QString::number(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); itemOutput->setToolTip(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " ")); + itemOutput->setText(COLUMN_DATE_INT64, QString::number(out.tx->GetTxTime())); // confirmations - itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); + itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth)); // priority double dPriority = ((double)(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i])) / (nInputSize + 78)) * (out.nDepth + 1); // 78 = 2 * 34 + 10 itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority)); - itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " ")); + itemOutput->setText(COLUMN_PRIORITY_INT64, QString::number((int64_t)dPriority)); dPrioritySum += (double)(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i])) * (out.nDepth + 1); nInputSum += nInputSize; @@ -892,9 +879,9 @@ void CoinControlDialog::updateView() itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); - itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " ")); + itemWalletAddress->setText(COLUMN_AMOUNT_INT64, QString::number(nSum)); itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority)); - itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " ")); + itemWalletAddress->setText(COLUMN_PRIORITY_INT64, QString::number((int64_t)dPrioritySum)); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 163aa8cf90..1e1fedf162 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -59,7 +59,6 @@ class CoinControlDialog : public QDialog QAction* lockAction; QAction* unlockAction; - QString strPad(QString, int, QString); void sortView(int, Qt::SortOrder); void updateView(); From 1b2f7d45b5bb24865f8c85fdab0459f1ac31fc59 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 18:56:48 -0500 Subject: [PATCH 0026/1888] [GUI] Sort by 'data' in coin control dialog --- src/qt/bitcoingui.h | 20 ---------------- src/qt/coincontroldialog.cpp | 38 ++++++++++++++++--------------- src/qt/coincontroldialog.h | 37 ++++++++++-------------------- src/qt/forms/coincontroldialog.ui | 17 +------------- 4 files changed, 33 insertions(+), 79 deletions(-) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index afb1204027..88206164d4 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -19,7 +19,6 @@ #include #include #include -#include class ClientModel; class NetworkStyle; @@ -281,23 +280,4 @@ private slots: void onMenuSelection(QAction* action); }; -class TreeWidgetItem : public QTreeWidgetItem { -public: - TreeWidgetItem() : QTreeWidgetItem(){} - TreeWidgetItem(QTreeWidgetItem* item) : QTreeWidgetItem(item){} - TreeWidgetItem(QTreeWidget* parent) : QTreeWidgetItem(parent){} -private: - bool operator<(const QTreeWidgetItem &other)const { - int column = treeWidget()->sortColumn(); - bool isNumber; - double item1 = text(column).toDouble(&isNumber); - if (isNumber) { - double item2 = other.text(column).toDouble(&isNumber); - if (isNumber) - return item1 < item2; - } - return text(column) < other.text(column); - } -}; - #endif // BITCOIN_QT_BITCOINGUI_H diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d8a538b4f4..3dd8c0fb67 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -9,7 +9,6 @@ #include "ui_coincontroldialog.h" #include "addresstablemodel.h" -#include "bitcoingui.h" //TreeWidgetItem #include "bitcoinunits.h" #include "guiutil.h" #include "init.h" @@ -39,6 +38,13 @@ QList CoinControlDialog::payAmounts; int CoinControlDialog::nSplitBlockDummy; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); +bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { + int column = treeWidget()->sortColumn(); + if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS) + return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong(); + return QTreeWidgetItem::operator<(other); +} + CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::CoinControlDialog), model(0) @@ -141,12 +147,9 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it - ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but dont show it // default view is sorted by amount desc - sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); + sortView(COLUMN_AMOUNT, Qt::DescendingOrder); // restore list mode and sortorder as a convenience feature QSettings settings; @@ -380,7 +383,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order) sortColumn = column; sortOrder = order; ui->treeWidget->sortItems(column, order); - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } // treeview: clicked on header @@ -388,10 +391,8 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex) { if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing { - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } else { - logicalIndex = getMappedColumn(logicalIndex, false); - if (sortColumn == logicalIndex) sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder); else { @@ -743,7 +744,7 @@ void CoinControlDialog::updateView() model->listCoins(mapCoins); for (PAIRTYPE(QString, vector) coins : mapCoins) { - TreeWidgetItem* itemWalletAddress = new TreeWidgetItem(); + CCoinControlWidgetItem* itemWalletAddress = new CCoinControlWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); @@ -780,11 +781,11 @@ void CoinControlDialog::updateView() nSum += model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]); nChildren++; - TreeWidgetItem* itemOutput; + CCoinControlWidgetItem* itemOutput; if (treeMode) - itemOutput = new TreeWidgetItem(itemWalletAddress); + itemOutput = new CCoinControlWidgetItem(itemWalletAddress); else - itemOutput = new TreeWidgetItem(ui->treeWidget); + itemOutput = new CCoinControlWidgetItem(ui->treeWidget); itemOutput->setFlags(flgCheckbox); itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); @@ -836,20 +837,21 @@ void CoinControlDialog::updateView() // amount itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); itemOutput->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); - itemOutput->setText(COLUMN_AMOUNT_INT64, QString::number(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); // padding so that sorting works correctly + itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong) model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]))); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); itemOutput->setToolTip(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setText(COLUMN_DATE_INT64, QString::number(out.tx->GetTxTime())); + itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong) out.tx->GetTxTime())); // confirmations itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth)); + itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong) out.nDepth)); // priority double dPriority = ((double)(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i])) / (nInputSize + 78)) * (out.nDepth + 1); // 78 = 2 * 34 + 10 itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority)); - itemOutput->setText(COLUMN_PRIORITY_INT64, QString::number((int64_t)dPriority)); + itemOutput->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong) dPriority)); dPrioritySum += (double)(model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i])) * (out.nDepth + 1); nInputSum += nInputSize; @@ -879,9 +881,9 @@ void CoinControlDialog::updateView() itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); - itemWalletAddress->setText(COLUMN_AMOUNT_INT64, QString::number(nSum)); + itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong) nSum)); itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority)); - itemWalletAddress->setText(COLUMN_PRIORITY_INT64, QString::number((int64_t)dPrioritySum)); + itemWalletAddress->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong) dPrioritySum)); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 1e1fedf162..ce3a040434 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -27,6 +27,16 @@ namespace Ui class CoinControlDialog; } +class CCoinControlWidgetItem : public QTreeWidgetItem +{ +public: + explicit CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + explicit CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {} + explicit CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + + bool operator<(const QTreeWidgetItem &other) const; +}; + class CoinControlDialog : public QDialog { Q_OBJECT @@ -37,6 +47,7 @@ class CoinControlDialog : public QDialog void setModel(WalletModel* model); void updateDialogLabels(); + void updateView(); // static because also called from sendcoinsdialog static void updateLabels(WalletModel*, QDialog*); @@ -60,7 +71,6 @@ class CoinControlDialog : public QDialog QAction* unlockAction; void sortView(int, Qt::SortOrder); - void updateView(); enum { COLUMN_CHECKBOX, @@ -73,32 +83,9 @@ class CoinControlDialog : public QDialog COLUMN_PRIORITY, COLUMN_TXHASH, COLUMN_VOUT_INDEX, - COLUMN_AMOUNT_INT64, - COLUMN_PRIORITY_INT64, - COLUMN_DATE_INT64 }; - // some columns have a hidden column containing the value used for sorting - int getMappedColumn(int column, bool fVisibleColumn = true) - { - if (fVisibleColumn) { - if (column == COLUMN_AMOUNT_INT64) - return COLUMN_AMOUNT; - else if (column == COLUMN_PRIORITY_INT64) - return COLUMN_PRIORITY; - else if (column == COLUMN_DATE_INT64) - return COLUMN_DATE; - } else { - if (column == COLUMN_AMOUNT) - return COLUMN_AMOUNT_INT64; - else if (column == COLUMN_PRIORITY) - return COLUMN_PRIORITY_INT64; - else if (column == COLUMN_DATE) - return COLUMN_DATE_INT64; - } - - return column; - } + friend class CCoinControlWidgetItem; private slots: void showMenu(const QPoint&); diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui index 8d99644dd2..7f6eed2fc5 100644 --- a/src/qt/forms/coincontroldialog.ui +++ b/src/qt/forms/coincontroldialog.ui @@ -447,7 +447,7 @@ false - 13 + 10 true @@ -508,21 +508,6 @@ - - - - - - - - - - - - - - - From 690917a14d3c530dfe88549b23a87ff6856b12dc Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Dec 2019 19:20:31 -0500 Subject: [PATCH 0027/1888] [GUI] Segfault for a bad cast of the parent in the escape key press event --- src/qt/coincontroltreewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp index 71e60f5a9c..d01c239b32 100644 --- a/src/qt/coincontroltreewidget.cpp +++ b/src/qt/coincontroltreewidget.cpp @@ -20,7 +20,7 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent* event) } else if (event->key() == Qt::Key_Escape) // press esc -> close dialog { event->ignore(); - CoinControlDialog* coinControlDialog = (CoinControlDialog*)this->parentWidget(); + auto* coinControlDialog = (CoinControlDialog*) this->parentWidget()->parentWidget(); coinControlDialog->done(QDialog::Accepted); } else { this->QTreeWidget::keyPressEvent(event); From 23e3abfea28097c3dd7e0344d13407b03ff96df9 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Thu, 26 Dec 2019 09:14:33 +0100 Subject: [PATCH 0028/1888] Add checkpoint for 190000 to 208000 --- src/chainparams.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7b19032218..4f7a1ba880 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -93,11 +93,24 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (147200, uint256("55fcf4abbd7a1b3aa91460378c3b833f9d1569780b0a1e7e6ee2d1b3a4256b24")) (147400, uint256("15d8ed0575995a4b3ab8337d87213943abb9e3fba5389c57cbd48a2751f78a5d")) (188549, uint256("cfe3696e23e393fa9230f84dfa16a505ac3f40fd147a79adba8a54fa17d24e91")) + (190000, uint256("733448a9b7429b4387610c0e6d7c62eddf6dea928dc1b53a6d3f64bfa753ff0f")) + (192500, uint256("d4279eaff8eda44f854d4eebadfd2b321541e998f3e884594f95d32bc301591d")) + (195000, uint256("d0b7aaa2f79c9dacd1583419fcd36534e42f304dc3ae411eb4cac9937860f2a5")) + (197500, uint256("d929090435e931bb160fd49905ef0ae6fad00e57e03b036a5b426a18fd712051")) + (200000, uint256("876a19d823513ad7c58dfd95d5d41e4f7f96450ddb0803001f9581a14f1eebf5")) + (201000, uint256("bcd41352ffff450691c0c8cfc83ac1d776f679691539baf1c4eadd9b666c820a")) + (202000, uint256("b1c5ad472a396dca3bd26bd0e607a5e93484315fd85af8ff71610743718a949b")) + (203000, uint256("ba981cf2bc14d172b7813b9b27022a127dc6d5c59b5febea187c8e751da79eeb")) + (204000, uint256("f66d3c726fd217908728ccd7405b108d7eb22cfff880bfcbe8995291d9a07fa5")) + (205000, uint256("31e73a522aca4a4513cd07c4888ffa061d396039ae00812dc673fb181068d880")) + (206000, uint256("03ef5e49e95d5b6caf6f5c9083a6505aecaaf110d352dfbd3e5ed226673c085f")) + (207000, uint256("173efe8f8cc450a83353c31c1d06d7b8c284eac46ed2d4c916cac29713a09abe")) + (208000, uint256("995328748210f12b77700e5589cb5bb4d5b84353682647d1771cbc77e77ffa35")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1576134192, // * UNIX timestamp of last checkpoint block - 479108, // * total number of transactions between genesis and last checkpoint + 1577304443, // * UNIX timestamp of last checkpoint block + 524535, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 39fb455df9fe478eb75160de1b654e46b5a549ff Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Fri, 27 Dec 2019 00:03:54 +0100 Subject: [PATCH 0029/1888] Update checkpoints 209577 --- src/chainparams.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4f7a1ba880..5c35632387 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -105,12 +105,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (205000, uint256("31e73a522aca4a4513cd07c4888ffa061d396039ae00812dc673fb181068d880")) (206000, uint256("03ef5e49e95d5b6caf6f5c9083a6505aecaaf110d352dfbd3e5ed226673c085f")) (207000, uint256("173efe8f8cc450a83353c31c1d06d7b8c284eac46ed2d4c916cac29713a09abe")) - (208000, uint256("995328748210f12b77700e5589cb5bb4d5b84353682647d1771cbc77e77ffa35")) + (208000, uint256("995328748210f12b77700e5589cb5bb4d5b84353682647d1771cbc77e77ffa35")) + (209577, uint256("5231320be89de8a0fdebbd45d4d0c58abb1ea7a134ba52a11a2036f32d90e66c")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1577304443, // * UNIX timestamp of last checkpoint block - 524535, // * total number of transactions between genesis and last checkpoint + 1577399767, // * UNIX timestamp of last checkpoint block + 528235, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 73e093b218acb1d6330890aa10ad1d06096a0a8b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 26 Dec 2019 23:51:33 -0500 Subject: [PATCH 0030/1888] Disable Coin Control button for now --- src/qt/forms/sendcoinsdialog.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index b3d32f4120..cd06258be7 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -153,6 +153,9 @@ + + false + From 9a7a626b2077d24c373dd77abf2f5c56e7402543 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 13:15:28 -0500 Subject: [PATCH 0031/1888] Fix Genesis in Block Explorer --- src/qt/blockexplorer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index 10e93612cd..eadbc4a683 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -172,7 +172,7 @@ const CBlockIndex* getexplorerBlockIndex(int64_t height) std::string getexplorerBlockHash(int64_t Height) { - std::string genesisblockhash = "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818"; + std::string genesisblockhash = "0000039a711dba61e12c29fb86542fa059e9616aafe9b4c61e065d393f31535e"; CBlockIndex* pindexBest = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; if ((Height < 0) || (Height > pindexBest->nHeight)) { return genesisblockhash; From fd3bdd563021cefcc8e5744f75ae47f4bbbe7c24 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 14:11:02 -0500 Subject: [PATCH 0032/1888] Restore appMenuBar --- src/qt/bitcoingui.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e6ee66a903..b45ee5498b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -471,28 +471,28 @@ void BitcoinGUI::createMenuBar() // Configure the menus QMenu* file = appMenuBar->addMenu(tr("&File")); if (walletFrame) { - file->addAction(openAction); + //file->addAction(openAction); file->addAction(backupWalletAction); file->addSeparator(); - file->addAction(usedSendingAddressesAction); - file->addAction(usedReceivingAddressesAction); - file->addSeparator(); - file->addAction(multisigCreateAction); - file->addAction(multisigSpendAction); - file->addAction(multisigSignAction); - file->addSeparator(); + //file->addAction(usedSendingAddressesAction); + //file->addAction(usedReceivingAddressesAction); + //file->addSeparator(); + //file->addAction(multisigCreateAction); + //file->addAction(multisigSpendAction); + //file->addAction(multisigSignAction); + //file->addSeparator(); } file->addAction(quitAction); - QMenu* settings = appMenuBar->addMenu(tr("&Settings")); - if (walletFrame) { - settings->addAction(encryptWalletAction); - settings->addAction(changePassphraseAction); - settings->addAction(unlockWalletAction); - settings->addAction(lockWalletAction); - settings->addAction(multiSendAction); - settings->addSeparator(); - } + //QMenu* settings = appMenuBar->addMenu(tr("&Settings")); + //if (walletFrame) { + //settings->addAction(encryptWalletAction); + //settings->addAction(changePassphraseAction); + //settings->addAction(unlockWalletAction); + //settings->addAction(lockWalletAction); + //settings->addAction(multiSendAction); + //settings->addSeparator(); + //} if (walletFrame) { walletFrame->addAction(openRPCConsoleAction); @@ -514,7 +514,7 @@ void BitcoinGUI::createMenuBar() help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); - appMenuBar->setVisible(false); + appMenuBar->setVisible(true); } void BitcoinGUI::createToolBars() From 472a0932ecd7f22c24751d9ef5c60b9462f2f214 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 16:24:12 -0500 Subject: [PATCH 0033/1888] Add function to "Show DAPScoin Folder" --- src/qt/bitcoingui.cpp | 5 +++++ src/qt/bitcoingui.h | 1 + src/qt/guiutil.cpp | 9 +++++++++ src/qt/guiutil.h | 3 +++ src/qt/rpcconsole.cpp | 5 +++++ src/qt/rpcconsole.h | 2 ++ 6 files changed, 25 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b45ee5498b..f29902fd96 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -218,6 +218,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai connect(openRepairAction, SIGNAL(triggered()), rpcConsole, SLOT(showRepair())); connect(openConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showConfEditor())); connect(openMNConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showMNConfEditor())); + connect(showDataDirAction, SIGNAL(triggered()), rpcConsole, SLOT(showDataDir())); connect(showBackupsAction, SIGNAL(triggered()), rpcConsole, SLOT(showBackups())); connect(labelConnectionsIcon, SIGNAL(clicked()), rpcConsole, SLOT(showPeers())); connect(labelEncryptionIcon, SIGNAL(clicked()), walletFrame, SLOT(toggleLockWallet())); @@ -410,6 +411,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openConfEditorAction->setStatusTip(tr("Open configuration file")); openMNConfEditorAction = new QAction(QIcon(":/icons/edit"), tr("Open &Masternode Configuration File"), this); openMNConfEditorAction->setStatusTip(tr("Open Masternode configuration file")); + showDataDirAction = new QAction(QIcon(":/icons/browse"), tr("Show &DAPScoin Folder"), this); + showDataDirAction->setStatusTip(tr("Show the DAPScoin folder")); showBackupsAction = new QAction(QIcon(":/icons/browse"), tr("Show Automatic &Backups"), this); showBackupsAction->setStatusTip(tr("Show automatically created wallet backups")); @@ -505,6 +508,7 @@ void BitcoinGUI::createMenuBar() tools->addSeparator(); tools->addAction(openConfEditorAction); tools->addAction(openMNConfEditorAction); + tools->addAction(showDataDirAction); tools->addAction(showBackupsAction); tools->addAction(openBlockExplorerAction); } @@ -725,6 +729,7 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addSeparator(); trayIconMenu->addAction(openConfEditorAction); trayIconMenu->addAction(openMNConfEditorAction); + trayIconMenu->addAction(showDataDirAction); trayIconMenu->addAction(showBackupsAction); trayIconMenu->addAction(openBlockExplorerAction); #ifndef Q_OS_MAC // This is built-in on Mac diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 88206164d4..2a8f9e23f0 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -118,6 +118,7 @@ class BitcoinGUI : public QMainWindow QAction* openRepairAction; QAction* openConfEditorAction; QAction* openMNConfEditorAction; + QAction* showDataDirAction; QAction* showBackupsAction; QAction* openAction; QAction* openBlockExplorerAction; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 6b56e2f913..37990949c8 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -392,6 +392,15 @@ void openMNConfigfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); } +void showDataDir() +{ + boost::filesystem::path pathBackups = GetDataDir(); + + /* Open folder with default browser */ + if (boost::filesystem::exists(pathBackups)) + QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathBackups))); +} + void showBackups() { boost::filesystem::path pathBackups = GetDataDir() / "backups"; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 386ab479df..0fadd11288 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -121,6 +121,9 @@ void openConfigfile(); // Open masternode.conf void openMNConfigfile(); +// Browse DataDir folder +void showDataDir(); + // Browse backup folder void showBackups(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 567837e7b4..e27382fe1d 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -968,6 +968,11 @@ void RPCConsole::hideEvent(QHideEvent* event) clientModel->getPeerTableModel()->stopAutoRefresh(); } +void RPCConsole::showDataDir() +{ + GUIUtil::showDataDir(); +} + void RPCConsole::showBackups() { GUIUtil::showBackups(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 31a60b545a..ea0cd3f228 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -117,6 +117,8 @@ public slots: void banSelectedNode(int bantime); /** Unban a selected node on the Bans tab */ void unbanSelectedNode(); + /** Show DataDir folder in default browser */ + void showDataDir(); /** Show folder with wallet backups in default browser */ void showBackups(); From 97e90d0ba07e063c7e30bf39ff21437f46debc28 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 17:12:10 -0500 Subject: [PATCH 0034/1888] Add Telegram/Discord Support links --- src/qt/bitcoingui.cpp | 32 ++++++++++++++++++++++++++++++++ src/qt/bitcoingui.h | 6 ++++++ src/qt/dapscoin.qrc | 2 ++ src/qt/res/icons/discord.png | Bin 0 -> 663 bytes src/qt/res/icons/telegram.png | Bin 0 -> 641 bytes 5 files changed, 40 insertions(+) create mode 100644 src/qt/res/icons/discord.png create mode 100644 src/qt/res/icons/telegram.png diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index f29902fd96..48d5fe81a5 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #if QT_VERSION < 0x050000 #include @@ -437,12 +438,23 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); + // Help Links + openTGTechSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Tech Support"), this); + openTGTechSupportAction->setStatusTip(tr("Telegram Tech Support")); + openTGMNSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Masternode Support"), this); + openTGMNSupportAction->setStatusTip(tr("Telegram Masternode Support")); + openDiscordSupportAction = new QAction(QIcon(":/icons/discord"), tr("&Discord Tech Support"), this); + openDiscordSupportAction->setStatusTip(tr("Discord Tech Support")); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(optionsAction, SIGNAL(triggered()), this, SLOT(gotoOptionsPage())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); + connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); + connect(openTGMNSupportAction, SIGNAL(triggered()), this, SLOT(openTGMNSupportClicked())); + connect(openDiscordSupportAction, SIGNAL(triggered()), this, SLOT(openDiscordSupportClicked())); #ifdef ENABLE_WALLET if (walletFrame) { connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); @@ -516,6 +528,11 @@ void BitcoinGUI::createMenuBar() QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); + help->addAction(openTGTechSupportAction); + help->addAction(openTGMNSupportAction); + help->addSeparator(); + help->addAction(openDiscordSupportAction); + help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); appMenuBar->setVisible(true); @@ -774,6 +791,21 @@ void BitcoinGUI::showHelpMessageClicked() help->show(); } +void BitcoinGUI::openTGTechSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPSTechSupport")); +} + +void BitcoinGUI::openTGMNSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPS_MN_Support")); +} + +void BitcoinGUI::openDiscordSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://discord.gg/8vbXJMf")); +} + #ifdef ENABLE_WALLET void BitcoinGUI::openClicked() { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 2a8f9e23f0..b4dc73563f 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -123,6 +123,9 @@ class BitcoinGUI : public QMainWindow QAction* openAction; QAction* openBlockExplorerAction; QAction* showHelpMessageAction; + QAction* openTGTechSupportAction; + QAction* openTGMNSupportAction; + QAction* openDiscordSupportAction; QAction* multiSendAction; QFrame* frameBlocks; QLabel *stakingState; @@ -235,6 +238,9 @@ private slots: void aboutClicked(); /** Show help message dialog */ void showHelpMessageClicked(); + void openTGTechSupportClicked(); + void openTGMNSupportClicked(); + void openDiscordSupportClicked(); #ifndef Q_OS_MAC /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 42fd66a0ea..1de95b9848 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -66,6 +66,8 @@ res/icons/staking_inactive.png res/icons/staking_disabled.png res/icons/staking_waiting.png + res/icons/discord.png + res/icons/telegram.png res/css/Light.css diff --git a/src/qt/res/icons/discord.png b/src/qt/res/icons/discord.png new file mode 100644 index 0000000000000000000000000000000000000000..d222940a79b34aba069baabc07c12112f319dde0 GIT binary patch literal 663 zcmV;I0%-k-P)a z-FlGRgP7lVj@*Wt;EJ8$k)z{@oZx|$-jSo?sJ7{+w&*=>c{ zYlGNvh}vm_*!}(g^!EJ0%kTL4{np*}Wq#M`?fRFfnX0NYaqb z<6Zr{faa?v>D3G-LF6gswTDIe`v{!W5V)7`7^iUqcZf=o6KMXN3O=Q_IAE zf93+$Gf)I>;og_-3()RD xl1}?FPfzRC0fl3{-!l}B@zK<^<9xno+8>4tWL{5Ao)iE8002ovPDHLkV1jNuUuggU literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/telegram.png b/src/qt/res/icons/telegram.png new file mode 100644 index 0000000000000000000000000000000000000000..4b65b515c506e3a4cb54a9646180191bb177aa93 GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy=L38~T!FOC(g*ZM|NsBjT=GD5 z(S7*^_mmdiS6h7l@4x>y-u(>U{%rB}4-+oDbKmgf$M3)AUj5kf=*#-sA4`wCO56Lw zck@$|6%U_&{(brN_v6pL&c5a-ZMf`zcZI{0mjy+ZADwCikr( z`;(>aJ})uoJoL9uEtKI!`lX-0eO6vInHkR#@S>yS*Pc0=Z=VVzE#md<`hRJ;d+C;r zjIE4ny!NGD&xE7CzUaF=HOctry(=y|9x&S}sf6kY*5_W2X_UAi;#;FXiA!<%ie~-z zhv|#Aq#p4u7l=6}TUF+KT<;J`88%4(*PmcSs&In?Tk@qoIQOyb3&TAbhO-(AJ<>jTxiodt``_pB74HP i>{VN?bZI)v8*!x@r4 Date: Fri, 27 Dec 2019 18:52:55 -0500 Subject: [PATCH 0035/1888] Add Social Menu --- src/qt/bitcoingui.cpp | 76 +++++++++++++++++++++++++++++++++ src/qt/bitcoingui.h | 19 +++++++++ src/qt/dapscoin.qrc | 6 +++ src/qt/res/icons/facebook.png | Bin 0 -> 429 bytes src/qt/res/icons/instagram.png | Bin 0 -> 3438 bytes src/qt/res/icons/medium.png | Bin 0 -> 639 bytes src/qt/res/icons/reddit.png | Bin 0 -> 2478 bytes src/qt/res/icons/steemit.png | Bin 0 -> 1489 bytes src/qt/res/icons/twitter.png | Bin 0 -> 1028 bytes 9 files changed, 101 insertions(+) create mode 100644 src/qt/res/icons/facebook.png create mode 100644 src/qt/res/icons/instagram.png create mode 100644 src/qt/res/icons/medium.png create mode 100644 src/qt/res/icons/reddit.png create mode 100644 src/qt/res/icons/steemit.png create mode 100644 src/qt/res/icons/twitter.png diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 48d5fe81a5..c88779a334 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -434,6 +434,25 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain explorer"), this); openBlockExplorerAction->setStatusTip(tr("Block explorer window")); + facebookAction = new QAction(QIcon(":/icons/facebook"), tr("Facebook"), this); + facebookAction->setStatusTip(tr("DAPS Facebook")); + twitterAction = new QAction(QIcon(":/icons/twitter"), tr("Twitter"), this); + twitterAction->setStatusTip(tr("DAPS Twitter")); + discordAction = new QAction(QIcon(":/icons/discord"), tr("Discord"), this); + discordAction->setStatusTip(tr("DAPS Discord")); + telegramOfficialAction = new QAction(QIcon(":/icons/telegram"), tr("Telegram - Main"), this); + telegramOfficialAction->setStatusTip(tr("DAPS Telegram - Main")); + telegramLoungeAction = new QAction(QIcon(":/icons/telegram"), tr("Telegram - Lounge"), this); + telegramLoungeAction->setStatusTip(tr("DAPS Telegram - Lounge")); + mediumAction = new QAction(QIcon(":/icons/medium"), tr("Medium"), this); + mediumAction->setStatusTip(tr("DAPS Medium")); + steemitAction = new QAction(QIcon(":/icons/steemit"), tr("Steemit"), this); + steemitAction->setStatusTip(tr("DAPS Steemit")); + instagramAction = new QAction(QIcon(":/icons/instagram"), tr("Instagram"), this); + instagramAction->setStatusTip(tr("DAPS Instagram")); + redditAction = new QAction(QIcon(":/icons/reddit"), tr("Reddit"), this); + redditAction->setStatusTip(tr("DAPS Reddit")); + showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); @@ -471,6 +490,15 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(multisigSignAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSign())); } #endif // ENABLE_WALLET + connect(facebookAction, SIGNAL(triggered()), this, SLOT(facebookActionClicked())); + connect(twitterAction, SIGNAL(triggered()), this, SLOT(twitterActionClicked())); + connect(discordAction, SIGNAL(triggered()), this, SLOT(discordActionClicked())); + connect(telegramOfficialAction, SIGNAL(triggered()), this, SLOT(telegramOfficialActionClicked())); + connect(telegramLoungeAction, SIGNAL(triggered()), this, SLOT(telegramLoungeActionClicked())); + connect(mediumAction, SIGNAL(triggered()), this, SLOT(mediumActionClicked())); + connect(steemitAction, SIGNAL(triggered()), this, SLOT(steemitActionClicked())); + connect(instagramAction, SIGNAL(triggered()), this, SLOT(instagramActionClicked())); + connect(redditAction, SIGNAL(triggered()), this, SLOT(redditActionClicked())); } void BitcoinGUI::createMenuBar() @@ -525,6 +553,17 @@ void BitcoinGUI::createMenuBar() tools->addAction(openBlockExplorerAction); } + QMenu* socials = appMenuBar->addMenu(tr("Social")); + socials->addAction(facebookAction); + socials->addAction(twitterAction); + socials->addAction(discordAction); + socials->addAction(telegramOfficialAction); + socials->addAction(telegramLoungeAction); + socials->addAction(mediumAction); + socials->addAction(steemitAction); + socials->addAction(instagramAction); + socials->addAction(redditAction); + QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); @@ -775,6 +814,43 @@ void BitcoinGUI::optionsClicked() dlg.exec(); } +void BitcoinGUI::facebookActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.facebook.com/officialdapscoin/")); +} +void BitcoinGUI::twitterActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://twitter.com/DAPScoin")); +} +void BitcoinGUI::discordActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://officialdapscoin.com/discord")); +} +void BitcoinGUI::telegramOfficialActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/dapscoin")); +} +void BitcoinGUI::telegramLoungeActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPS_LOUNGE")); +} +void BitcoinGUI::mediumActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://medium.com/DAPScoin")); +} +void BitcoinGUI::instagramActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.instagram.com/DAPSCoin/")); +} +void BitcoinGUI::redditActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.reddit.com/r/DAPSCoin/")); +} +void BitcoinGUI::steemitActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://steemit.com/@DAPSCoin/")); +} + void BitcoinGUI::aboutClicked() { if (!clientModel) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index b4dc73563f..d4c2f81655 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -122,6 +122,15 @@ class BitcoinGUI : public QMainWindow QAction* showBackupsAction; QAction* openAction; QAction* openBlockExplorerAction; + QAction* facebookAction; + QAction* twitterAction; + QAction* discordAction; + QAction* telegramOfficialAction; + QAction* telegramLoungeAction; + QAction* mediumAction; + QAction* steemitAction; + QAction* instagramAction; + QAction* redditAction; QAction* showHelpMessageAction; QAction* openTGTechSupportAction; QAction* openTGMNSupportAction; @@ -232,6 +241,16 @@ private slots: void openClicked(); #endif // ENABLE_WALLET + /** Social Networks */ + void facebookActionClicked(); + void twitterActionClicked(); + void discordActionClicked(); + void telegramOfficialActionClicked(); + void telegramLoungeActionClicked(); + void mediumActionClicked(); + void redditActionClicked(); + void instagramActionClicked(); + void steemitActionClicked(); /** Show configuration dialog */ void optionsClicked(); /** Show about dialog */ diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 1de95b9848..410a266d9a 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -67,7 +67,13 @@ res/icons/staking_disabled.png res/icons/staking_waiting.png res/icons/discord.png + res/icons/facebook.png + res/icons/instagram.png + res/icons/medium.png + res/icons/reddit.png + res/icons/steemit.png res/icons/telegram.png + res/icons/twitter.png res/css/Light.css diff --git a/src/qt/res/icons/facebook.png b/src/qt/res/icons/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c79c4527b6627c86b2cb50c22a295d298ed659 GIT binary patch literal 429 zcmV;e0aE^nP))0|NsCBO?RT09wz$z`!u@4q%}~vxG1=gP*-BgMpejgD^iQ z10y2?!|y-;7_QxW!_YeK7;PP3r6C@lczZ#jI2 zVdKHuL|cjs20R;%I$+cRL(~COY|0PO5EyU=pw*xM$#0JkUmep54ACf{sskvAKq>$L X9-?4pZcGm<00000NkvXXu0mjfu70-u literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/instagram.png b/src/qt/res/icons/instagram.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd7571e961b55e31ab78a93d7e03f4870d5870a GIT binary patch literal 3438 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 O12QwV#?~5n$NUT4TINmw literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/medium.png b/src/qt/res/icons/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..a02a1d69a1d03f22a8d8b96e676cb38a6b9782d6 GIT binary patch literal 639 zcmV-_0)YLAP)zQ@Pds$*kYF5nQv!yXMI2p z_{|no24q`90dGHl#(zs~Gx!c*2e1PG2zV_h7K@yoo?@D&YyRfuhDM_SfKrN5sl@T| zv1`r#{yw+2w-gG6?*oLxVRT(bDR;86*{lPQNF=ztyj%egZX?8z}eXuS65d6v|25mpPvbZ zLK^{izJiYmg+dGl13H}!>2w-h*Eu;k0iar~Vw&d4Yw^-XtKXeJJUjr)8Xq1WV%s*g zS`EM7zfthD0W8aM+4XweWj{VX((CnB(*Jqiw*exNh|6xb+q}HIICia81KhXX=kpPb zM%QuwbtAgJzjvCCh)Ac?5kSi2vNNY?nq)E=84ic?QM1`h^7;IijmYy7&gXNw-7c18 zp_Fo7z}?*)M@L7D$77zJo=7H>OePbC!yzI9EdPSff5^re`026r?|28W1K0s5;MX<* Z{sKnfT^_grsCxha002ovPDHLkV1f($7+(MY literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/reddit.png b/src/qt/res/icons/reddit.png new file mode 100644 index 0000000000000000000000000000000000000000..84b8c2947d326809976354ae6c3db8bf848c0d09 GIT binary patch literal 2478 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/steemit.png b/src/qt/res/icons/steemit.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e92a03352de9833df9c09d1d6b0105c4ccb09e GIT binary patch literal 1489 zcmV;?1upuDP)b98#MGYYW#*QF&fgQkS!GQnD|1!YqtIPt{0jq$F(7vW(bp##&p8^|#0e?rz z1~^`S50r*HlQ8L%zk~b&yb=ufuk~nv*H<|X*bkbgJrNr!65&mLL9PHZg8~2fq%s}P zkAdbTQj$FMc1=7kH5xHuaxmb(9%q1)^CN0kxKmaUBGUkU3_f-*0sm1EDZjRJMF)Uo z7`aZ-QkztrOq%P^%HH$lx|uhnC=QBXehM*FP>Gx z2yeD=3Zn5&THL@&0L!`I7TFjf*6ua0JoW9?Q&+38B5? z=Wg(8Z37}g#iT-t3OqD6xAEPf$d&GUVI=uEZm!(8OV!bfhzJv($zxK)1+Azwe`0-bn+^y z%8ZFa>6@8>DL=X#skeX{jR{ihdpFAVy|su4xt>fid!+-gIZzX(8a$v6$X0 zJv27A^UlVDbZfFXK^g?AEoXY&5mFU8D6wmoCA|9a9$N1|ioy>XkVSX5^4_MOxz}#v z^0Kp7_)!&CZ?+meF!FOu+IlVE?+^g5uW~4GPSM^8jSa^`V|IiSU%$@AZ;!L%$1`#G zWc*IVM+O7_Mi;=nvsHKcje5x?PG3me&*OVro+pco*YEJnp>uJxkK+ef6AbtdK=eek z!I@se-kG*X_jCJ5-E3)RcXeG9z9)W=g9w|VaSnKWl|z6dz)+qPoT0CW?}j>HYB1mr zw^TC%ICJ|<;7SVpJQ|;1o`{(V>wp=i@;Cz=BhCYpL5}v+&lBOzfP{X69CSR7`%H^7 zz%k;wh?EQRfgr8P`gwG}kDn(5xhu#@gjunk6Q=F~oauEXuoTEmVeSWL0JZ|3CsUlV r0fr$Nz;sghJQtz*+Rnruqp|QGLw#TBJ(Qu&00000NkvXXu0mjfrth`Z literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/twitter.png b/src/qt/res/icons/twitter.png new file mode 100644 index 0000000000000000000000000000000000000000..51f20d9c73151cb1c49043d007e4c2564924b521 GIT binary patch literal 1028 zcmV+f1pE7mP)~ z6l_#bQi&F%H-aDtYQx_6cM}M~QpB5BC~5J!2wIRrup!{Zx>6)I6^Usgh0ry$WOt1% zcCwRZvpeT_G1=H=c6Y{*)IOKDUKy+#sQt_$!28Oe7g0YFs7r(nJ$A+DMgX8*F??+y$Kr}kBpPRPb19OiD?oXOTa%<3|`sK}d*(hmrsB~r}$neeS2ihMS`%!=)i z)>TeiS@s?z$VulW;{zLBYYP$zc$Xn}TQNNC!+>I5f}ZhZK*Nh;COk(fDfV`>b{l3Vz*J@w)Y^^z*De_aDxLaS37!)#T;@xJWt+-=nfFm7Yp4<`O z)kKhH!(E2Szir;WP~_K~$I7pwv`Hb8c4qo=;S@r=-)Q_Jy8^tkH^ROh23;+ZCPR?5 z6hGgn@Xgf{>A5oaTb~YEpXS}xqxZ>i+}EB5F?3JF0T4sgYuUdW(dCKbpvJdeT#Y+g zt5)uc{jZl&a7s~GJ_P#umWY?^p7p(f`z$#6@Nblh$;~Z?8mC-LuI~wI8vrL0Q Date: Fri, 27 Dec 2019 18:53:26 -0500 Subject: [PATCH 0036/1888] Add BootStrap link --- src/qt/bitcoingui.cpp | 10 ++++++++++ src/qt/bitcoingui.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c88779a334..a4d80cd705 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -458,6 +458,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); // Help Links + openBootStrapAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&BootStrap"), this); + openBootStrapAction->setStatusTip(tr("BootStrap Link")); openTGTechSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Tech Support"), this); openTGTechSupportAction->setStatusTip(tr("Telegram Tech Support")); openTGMNSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Masternode Support"), this); @@ -471,6 +473,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(optionsAction, SIGNAL(triggered()), this, SLOT(gotoOptionsPage())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); + connect(openBootStrapAction, SIGNAL(triggered()), this, SLOT(openBootStrapClicked())); connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); connect(openTGMNSupportAction, SIGNAL(triggered()), this, SLOT(openTGMNSupportClicked())); connect(openDiscordSupportAction, SIGNAL(triggered()), this, SLOT(openDiscordSupportClicked())); @@ -567,6 +570,8 @@ void BitcoinGUI::createMenuBar() QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); + help->addAction(openBootStrapAction); + help->addSeparator(); help->addAction(openTGTechSupportAction); help->addAction(openTGMNSupportAction); help->addSeparator(); @@ -867,6 +872,11 @@ void BitcoinGUI::showHelpMessageClicked() help->show(); } +void BitcoinGUI::openBootStrapClicked() +{ + QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/BootStrap/releases/tag/latest")); +} + void BitcoinGUI::openTGTechSupportClicked() { QDesktopServices::openUrl(QUrl("https://t.me/DAPSTechSupport")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d4c2f81655..404c827b32 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -132,6 +132,7 @@ class BitcoinGUI : public QMainWindow QAction* instagramAction; QAction* redditAction; QAction* showHelpMessageAction; + QAction* openBootStrapAction; QAction* openTGTechSupportAction; QAction* openTGMNSupportAction; QAction* openDiscordSupportAction; @@ -257,6 +258,7 @@ private slots: void aboutClicked(); /** Show help message dialog */ void showHelpMessageClicked(); + void openBootStrapClicked(); void openTGTechSupportClicked(); void openTGMNSupportClicked(); void openDiscordSupportClicked(); From 1ab80c4df064d0bda5e03a8cb19550f2d649e846 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 19:01:26 -0500 Subject: [PATCH 0037/1888] [Trivial] Capitalization of Menu Items --- src/qt/bitcoingui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a4d80cd705..9993378f64 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -399,12 +399,12 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openInfoAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Information"), this); openInfoAction->setStatusTip(tr("Show diagnostic information")); - openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug console"), this); + openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug Console"), this); openRPCConsoleAction->setStatusTip(tr("Open debugging console")); openRPCConsoleAction->setShortcut(Qt::Key_F1); openNetworkAction = new QAction(QIcon(":/icons/connect_4"), tr("&Network Monitor"), this); openNetworkAction->setStatusTip(tr("Show network monitor")); - openPeersAction = new QAction(QIcon(":/icons/connect_4"), tr("&Peers list"), this); + openPeersAction = new QAction(QIcon(":/icons/connect_4"), tr("&Peers List"), this); openPeersAction->setStatusTip(tr("Show peers info")); openRepairAction = new QAction(QIcon(":/icons/options"), tr("Wallet &Repair"), this); openRepairAction->setStatusTip(tr("Show wallet repair options")); @@ -431,7 +431,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a DAPS: URI or payment request")); - openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain explorer"), this); + openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain Explorer"), this); openBlockExplorerAction->setStatusTip(tr("Block explorer window")); facebookAction = new QAction(QIcon(":/icons/facebook"), tr("Facebook"), this); @@ -453,7 +453,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) redditAction = new QAction(QIcon(":/icons/reddit"), tr("Reddit"), this); redditAction->setStatusTip(tr("DAPS Reddit")); - showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this); + showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line Options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); From dabd5a48df34fb9a193e16914e8f0844e767e730 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 19:06:28 -0500 Subject: [PATCH 0038/1888] Add Blockhain Explorer API link --- src/qt/bitcoingui.cpp | 9 +++++++++ src/qt/bitcoingui.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 9993378f64..46be2570e3 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -458,6 +458,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); // Help Links + openBlockExplorerAPIAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Blockhain Explorer API"), this); + openBlockExplorerAPIAction->setStatusTip(tr("Blockhain Explorer API")); openBootStrapAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&BootStrap"), this); openBootStrapAction->setStatusTip(tr("BootStrap Link")); openTGTechSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Tech Support"), this); @@ -473,6 +475,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(optionsAction, SIGNAL(triggered()), this, SLOT(gotoOptionsPage())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); + connect(openBlockExplorerAPIAction, SIGNAL(triggered()), this, SLOT(openBlockExplorerAPIClicked())); connect(openBootStrapAction, SIGNAL(triggered()), this, SLOT(openBootStrapClicked())); connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); connect(openTGMNSupportAction, SIGNAL(triggered()), this, SLOT(openTGMNSupportClicked())); @@ -570,6 +573,7 @@ void BitcoinGUI::createMenuBar() QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); + help->addAction(openBlockExplorerAPIAction); help->addAction(openBootStrapAction); help->addSeparator(); help->addAction(openTGTechSupportAction); @@ -872,6 +876,11 @@ void BitcoinGUI::showHelpMessageClicked() help->show(); } +void BitcoinGUI::openBlockExplorerAPIClicked() +{ + QDesktopServices::openUrl(QUrl("https://explorer.dapscoin.com/api/getblockcount")); +} + void BitcoinGUI::openBootStrapClicked() { QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/BootStrap/releases/tag/latest")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 404c827b32..40c1d2619d 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -132,6 +132,7 @@ class BitcoinGUI : public QMainWindow QAction* instagramAction; QAction* redditAction; QAction* showHelpMessageAction; + QAction* openBlockExplorerAPIAction; QAction* openBootStrapAction; QAction* openTGTechSupportAction; QAction* openTGMNSupportAction; @@ -258,6 +259,7 @@ private slots: void aboutClicked(); /** Show help message dialog */ void showHelpMessageClicked(); + void openBlockExplorerAPIClicked(); void openBootStrapClicked(); void openTGTechSupportClicked(); void openTGMNSupportClicked(); From 83246f1c9d30dba4618ee231be3fd5b88d35286f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 19:49:41 -0500 Subject: [PATCH 0039/1888] Remove file preventing make translate --- src/Makefile.qt.include | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 0a500733b0..ec6b015718 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -157,7 +157,6 @@ BITCOIN_QT_H = \ qt/2faqrdialog.h \ qt/encryptdialog.h \ qt/qgoogleauth.h \ - qt/qgoogleauth_global.h \ qt/addressbookpage.h \ qt/addresstablemodel.h \ qt/askpassphrasedialog.h \ From bbeaa29e2af8a628b50459823acfdadcd63869b8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 19:49:49 -0500 Subject: [PATCH 0040/1888] Update translation --- src/qt/locale/dapscoin_en.ts | 747 +++++++++++++++++++++++++++-------- 1 file changed, 574 insertions(+), 173 deletions(-) diff --git a/src/qt/locale/dapscoin_en.ts b/src/qt/locale/dapscoin_en.ts index e0cbe5060d..f990c5ed33 100644 --- a/src/qt/locale/dapscoin_en.ts +++ b/src/qt/locale/dapscoin_en.ts @@ -476,12 +476,12 @@ BitcoinGUI - + Node Node - + &Overview &Overview @@ -496,7 +496,7 @@ &Receive - + E&xit E&xit @@ -582,12 +582,7 @@ Show diagnostic information - - &Debug console - &Debug console - - - + Open debugging console Open debugging console @@ -602,12 +597,7 @@ Show network monitor - - &Peers list - &Peers list - - - + Show peers info Show peers info @@ -628,6 +618,16 @@ + Show &DAPScoin Folder + + + + + Show the DAPScoin folder + + + + Show Automatic &Backups Show Automatic &Backups @@ -691,13 +691,8 @@ Open &URI... Open &URI... - - - &Command-line options - &Command-line options - - + %n Active Connections @@ -728,12 +723,12 @@ Confirmations: %5 - + Staking Enabled - + Enabling Staking... @@ -744,18 +739,17 @@ Confirmations: %5 - + &File &File - - + &Settings &Settings - + DAPS Coin @@ -765,17 +759,17 @@ Confirmations: %5 - + &History - + Masternodes - + Modify settings @@ -795,27 +789,42 @@ Confirmations: %5 &Network - + + &Debug Console + + + + + &Peers List + + + + + &Blockchain Explorer + + + + &Tools &Tools - + &Help &Help - + DAPS - + &Masternodes - + &About DAPS @@ -850,32 +859,177 @@ Confirmations: %5 - + Open a DAPS: URI or payment request + + + Block explorer window + + + + + Facebook + + - &Blockchain explorer + DAPS Facebook - Block explorer window + Twitter - + + DAPS Twitter + + + + + Discord + + + + + DAPS Discord + + + + + Telegram - Main + + + + + DAPS Telegram - Main + + + + + Telegram - Lounge + + + + + DAPS Telegram - Lounge + + + + + Medium + + + + + DAPS Medium + + + + + Steemit + + + + + DAPS Steemit + + + + + Instagram + + + + + DAPS Instagram + + + + + Reddit + + + + + DAPS Reddit + + + + + &Command-line Options + + + + Show the DAPS help message to get a list with possible DAPS command-line options - + + &Blockhain Explorer API + + + + + Blockhain Explorer API + + + + + &BootStrap + + + + + BootStrap Link + + + + + &Telegram Tech Support + + + + + Telegram Tech Support + + + + + &Telegram Masternode Support + + + + + Telegram Masternode Support + + + + + &Discord Tech Support + + + + + Discord Tech Support + + + + + Social + + + + DAPS client - + Up to date Up to date @@ -963,7 +1117,17 @@ Confirmations: %5 - + + Syncing MN List... + + + + + Consolidating Transactions… + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Wallet is <b>encrypted</b> and currently <b>unlocked</b> @@ -1019,12 +1183,12 @@ Confirmations: %5 ClientModel - + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5) - + Network Alert Network Alert @@ -1142,7 +1306,7 @@ Confirmations: %5 Priority - + Copy address Copy address @@ -1208,12 +1372,12 @@ Confirmations: %5 Copy change - + Please switch to "List mode" to use this function. - + highest highest @@ -1574,7 +1738,7 @@ lowercase letters, numbers, symbols) - + All Types @@ -1820,7 +1984,7 @@ lowercase letters, numbers, symbols) - + Confirm masternode start @@ -1981,7 +2145,7 @@ MultiSend will not be activated unless you have clicked Activate - + The entered address: @@ -2521,7 +2685,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Cancel - + default default @@ -2531,7 +2695,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsnone - + Confirm options reset Confirm options reset @@ -2552,45 +2716,56 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsThis change would require a client restart. - + The supplied proxy address is invalid. The supplied proxy address is invalid. - - - OptionsPage - - Staking Status: + + The supplied proxy port is invalid. - + + The supplied proxy settings are invalid. + + + + + OptionsPage + + Turn staking on or off - + On - - + + Off - - Backup wallet to directory of choice + + Staking Mode: - + + Backup Wallet Backup Wallet + + + Show Seed Phrase + + Theme Selection: @@ -2612,7 +2787,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Change current passphrase @@ -2642,37 +2817,32 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Quantity of DAPS to keep as spendable (not staking) - - Save - - - - - Disable + + Enabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking. - - Mnemonic Recovery Phrase + + Automatically add any new deposits received to your staked balance - - We strongly recommend you only view your mnemonic phrase in a secure environment safe from video cameras or any wandering eyes. + + Save - - Show Phrase + + Disable - + Two Factor Authentication @@ -2701,6 +2871,11 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsCurrent Authentication Code + + + Wallet Data (*.dat) + Wallet Data (*.dat) + OverviewPage @@ -2920,7 +3095,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsAmount - + %1 d %1 d @@ -3007,7 +3182,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Information - + General General @@ -3022,7 +3197,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsClient name - + + @@ -3033,7 +3209,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + + @@ -3050,17 +3227,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + N/A N/A - + Number of connections Number of connections - + + Block chain + + + + &Open &Open @@ -3120,12 +3302,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsNumber of Masternodes - - Blockchain - - - - + &Console &Console @@ -3171,8 +3348,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - + + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3202,12 +3379,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsServices - - Rebuild blockchain index from current blk000??.dat files. - - - - + Ban Score Ban Score @@ -3262,67 +3434,92 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Wallet Repair - + + Rebuild block chain index from current blk000??.dat files. + + + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. + + + + Wallet In Use: - + Salvage wallet Salvage wallet - + Attempt to recover private keys from a corrupt wallet.dat. - + Rescan blockchain files Rescan blockchain files - + Recover transactions 1 Recover transactions 1 - + Recover transactions from blockchain (keep meta-data, e.g. account owner). - + + Data Directory + + + + + Last block hash + + + + Recover transactions 2 Recover transactions 2 - + + Rescan the block chain for missing wallet transactions. + + + + Recover transactions from blockchain (drop meta-data). - + Upgrade wallet format Upgrade wallet format - + -resync: - - Deletes all local blockchain folders so the wallet synchronizes from scratch. + + Delete local Blockchain Folders - - The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. - The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. + + Deletes all local blockchain folders so the wallet synchronizes from scratch. + - + Starting Block @@ -3337,32 +3534,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - Delete local blockchain Folders - - - - + Wallet repair options. Wallet repair options. - - Rescan the blockchain for missing wallet transactions. - - - - + Upgrade wallet to latest format on startup. (Note: this is NOT an update of the wallet itself!) - + Rebuild index Rebuild index - + In: In: @@ -3372,12 +3559,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsOut: - + Welcome to the DAPS RPC console. - + &Disconnect Node @@ -3415,7 +3602,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.<br /><br /> @@ -3440,9 +3627,9 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + Use up and down arrows to navigate history, and %1 to clear screen. + @@ -3450,7 +3637,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsType <b>help</b> for an overview of available commands. - + + WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. + + + + %1 B %1 B @@ -3578,7 +3770,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsAn optional amount to request. Leave this empty or zero to not request a specific amount. - + Copy label Copy label @@ -3664,7 +3856,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations RecentRequestsTableModel - + Date Date @@ -3755,13 +3947,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsSend Coins - - - Your current spendable balance - Your current spendable balance - - - + Confirm the send action Confirm the send action @@ -3775,21 +3961,201 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsSend to multiple recipients at once Send to multiple recipients at once + + + Coin Control Features + + + + + Open Coin Control... + + + + + Coins automatically selected + + + + + Insufficient funds! + + + + + Quantity: + Quantity: + + + + Bytes: + Bytes: + + + + Amount: + Amount: + + + + Priority: + Priority: + + + + medium + medium + + + + Fee: + Fee: + + + + Dust: + Dust: + + + + no + no + + + + After Fee: + After Fee: + + + + Change: + Change: + + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + + + + + Split UTXO + + + + + # of outputs + + + + + UTXO Size: + + + + + 0 DAPS + + + + Add &Recipient Add &Recipient - + Balance: Balance: - + + Copy quantity + Copy quantity + + + + Copy amount + Copy amount + + + + Copy fee + Copy fee + + + + Copy after fee + Copy after fee + + + + Copy bytes + Copy bytes + + + + Copy priority + Copy priority + + + + Copy dust + Copy dust + + + + Copy change + Copy change + + + + Destination + + + + + Are you sure you want to send? + + + + + Estimated Transaction fee + + + + + <span class='h3'>Total Amount = <b>%1</b><br/><hr /></center> + + + + + Confirm Send Coins + + + + Copy + + + Warning: Invalid PIVX address + + + + + Warning: Unknown change address + + + + + (no label) + (no label) + SendCoinsEntry @@ -4693,7 +5059,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsShow transaction details - + Export Transaction History Export Transaction History @@ -4879,13 +5245,13 @@ Please try again. TwoFAQRDialog - - Recovery Code + + Below are your 2FA QR Code & Recovery Key. - Keep your recovery code in a safe place. Use it to regain access to your account if you lose your phone. + Please store them safely. Use them to regain access if you lose your device. @@ -4894,27 +5260,27 @@ Please try again. QR Code - + Cancel - + Esc - + Next - + Return - + Resulting URI too long, try to reduce the text for label / message. Resulting URI too long, try to reduce the text for label / message. @@ -4973,7 +5339,12 @@ Please try again. - + + (Wallet may appear not responding as it rescans for all transactions) + + + + Unlock @@ -5027,7 +5398,7 @@ Please try again. Selected amount: - + Backup Wallet Backup Wallet @@ -5280,7 +5651,7 @@ Please try again. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. - + Unable to bind to %s on this computer. DAPS is probably already running. @@ -5425,7 +5796,7 @@ Please try again. Always query for peer addresses via DNS lookup (default: %u) - + Attempt to recover private keys from a corrupt wallet.dat Attempt to recover private keys from a corrupt wallet.dat @@ -5500,7 +5871,7 @@ Please try again. - + Corrupted block database detected Corrupted block database detected @@ -5749,11 +6120,6 @@ Please try again. Invalid -onion address or hostname: '%s' - - - Invalid -proxy address or hostname: '%s' - - Invalid amount for -maxtxfee=<amount>: '%s' @@ -5810,12 +6176,12 @@ Please try again. Invalid script detected. - + SwiftX options: - + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! @@ -5835,7 +6201,12 @@ Please try again. - + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + + + + <category> can be: @@ -5846,6 +6217,11 @@ Please try again. + Append comment to the user agent string + + + + Attempt to force blockchain corruption recovery @@ -5891,6 +6267,11 @@ Please try again. + Copyright (C) 2015-%i The PIVX Core Developers + + + + Copyright (C) 2018-%i The DAPS Project developers @@ -5970,7 +6351,7 @@ Please try again. - + Keep at most <n> unconnectable transactions in memory (default: %u) Keep at most <n> unconnectable transactions in memory (default: %u) @@ -6029,6 +6410,11 @@ Please try again. Lock masternodes from masternode configuration file (default: %u) Lock masternodes from masternode configuration file (default: %u) + + + Lookup(): Invalid -proxy address or hostname: '%s' + + Maintain at most <n> connections to peers (default: %u) @@ -6174,6 +6560,11 @@ Please try again. Rebuild block chain index from current blk000??.dat files Rebuild block chain index from current blk000??.dat files + + + Recalculating DAPS supply... + + Receive and display P2P network alerts (default: %u) @@ -6524,6 +6915,11 @@ Please try again. Use the test network Use the test network + + + User Agent comment (%s) contains unsafe characters. + + Username for JSON-RPC connections @@ -6614,6 +7010,11 @@ Please try again. ZeroMQ notification options: + + + isValid(): Invalid -proxy address or hostname: '%s' + + on startup From 411238b6f0ab6abec30056c8d48eeff74ded0d72 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 27 Dec 2019 19:50:05 -0500 Subject: [PATCH 0041/1888] Update makeseeds.py --- contrib/seeds/makeseeds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 58dcba329f..6fb51023e2 100644 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -26,7 +26,7 @@ PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(/DAPScoinCore:2.2.(0|1|99)/)$") +PATTERN_AGENT = re.compile(r"^(/DAPS:1.0.4.6)/)$") def parseline(line): sline = line.split() From d73b4644043254f3e4e8ae0ce1c35d7de2cc1037 Mon Sep 17 00:00:00 2001 From: JD Date: Fri, 27 Dec 2019 22:21:18 -0500 Subject: [PATCH 0042/1888] Develop -> Master for Beta Test (#32) * Fix Genesis in Block Explorer * Restore appMenuBar * Add function to "Show DAPScoin Folder" * Add Telegram/Discord Support links * Add Social Menu * Add BootStrap link * [Trivial] Capitalization of Menu Items * Add Blockhain Explorer API link * Remove file preventing make translate * Update translation * Update makeseeds.py --- contrib/seeds/makeseeds.py | 2 +- src/Makefile.qt.include | 1 - src/qt/bitcoingui.cpp | 176 +++++++- src/qt/bitcoingui.h | 30 ++ src/qt/blockexplorer.cpp | 2 +- src/qt/dapscoin.qrc | 8 + src/qt/guiutil.cpp | 9 + src/qt/guiutil.h | 3 + src/qt/locale/dapscoin_en.ts | 747 +++++++++++++++++++++++++-------- src/qt/res/icons/discord.png | Bin 0 -> 663 bytes src/qt/res/icons/facebook.png | Bin 0 -> 429 bytes src/qt/res/icons/instagram.png | Bin 0 -> 3438 bytes src/qt/res/icons/medium.png | Bin 0 -> 639 bytes src/qt/res/icons/reddit.png | Bin 0 -> 2478 bytes src/qt/res/icons/steemit.png | Bin 0 -> 1489 bytes src/qt/res/icons/telegram.png | Bin 0 -> 641 bytes src/qt/res/icons/twitter.png | Bin 0 -> 1028 bytes src/qt/rpcconsole.cpp | 5 + src/qt/rpcconsole.h | 2 + 19 files changed, 787 insertions(+), 198 deletions(-) create mode 100644 src/qt/res/icons/discord.png create mode 100644 src/qt/res/icons/facebook.png create mode 100644 src/qt/res/icons/instagram.png create mode 100644 src/qt/res/icons/medium.png create mode 100644 src/qt/res/icons/reddit.png create mode 100644 src/qt/res/icons/steemit.png create mode 100644 src/qt/res/icons/telegram.png create mode 100644 src/qt/res/icons/twitter.png diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 58dcba329f..6fb51023e2 100644 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -26,7 +26,7 @@ PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(/DAPScoinCore:2.2.(0|1|99)/)$") +PATTERN_AGENT = re.compile(r"^(/DAPS:1.0.4.6)/)$") def parseline(line): sline = line.split() diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 0a500733b0..ec6b015718 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -157,7 +157,6 @@ BITCOIN_QT_H = \ qt/2faqrdialog.h \ qt/encryptdialog.h \ qt/qgoogleauth.h \ - qt/qgoogleauth_global.h \ qt/addressbookpage.h \ qt/addresstablemodel.h \ qt/askpassphrasedialog.h \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e6ee66a903..46be2570e3 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #if QT_VERSION < 0x050000 #include @@ -218,6 +219,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai connect(openRepairAction, SIGNAL(triggered()), rpcConsole, SLOT(showRepair())); connect(openConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showConfEditor())); connect(openMNConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showMNConfEditor())); + connect(showDataDirAction, SIGNAL(triggered()), rpcConsole, SLOT(showDataDir())); connect(showBackupsAction, SIGNAL(triggered()), rpcConsole, SLOT(showBackups())); connect(labelConnectionsIcon, SIGNAL(clicked()), rpcConsole, SLOT(showPeers())); connect(labelEncryptionIcon, SIGNAL(clicked()), walletFrame, SLOT(toggleLockWallet())); @@ -397,12 +399,12 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openInfoAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Information"), this); openInfoAction->setStatusTip(tr("Show diagnostic information")); - openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug console"), this); + openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug Console"), this); openRPCConsoleAction->setStatusTip(tr("Open debugging console")); openRPCConsoleAction->setShortcut(Qt::Key_F1); openNetworkAction = new QAction(QIcon(":/icons/connect_4"), tr("&Network Monitor"), this); openNetworkAction->setStatusTip(tr("Show network monitor")); - openPeersAction = new QAction(QIcon(":/icons/connect_4"), tr("&Peers list"), this); + openPeersAction = new QAction(QIcon(":/icons/connect_4"), tr("&Peers List"), this); openPeersAction->setStatusTip(tr("Show peers info")); openRepairAction = new QAction(QIcon(":/icons/options"), tr("Wallet &Repair"), this); openRepairAction->setStatusTip(tr("Show wallet repair options")); @@ -410,6 +412,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openConfEditorAction->setStatusTip(tr("Open configuration file")); openMNConfEditorAction = new QAction(QIcon(":/icons/edit"), tr("Open &Masternode Configuration File"), this); openMNConfEditorAction->setStatusTip(tr("Open Masternode configuration file")); + showDataDirAction = new QAction(QIcon(":/icons/browse"), tr("Show &DAPScoin Folder"), this); + showDataDirAction->setStatusTip(tr("Show the DAPScoin folder")); showBackupsAction = new QAction(QIcon(":/icons/browse"), tr("Show Automatic &Backups"), this); showBackupsAction->setStatusTip(tr("Show automatically created wallet backups")); @@ -427,19 +431,55 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a DAPS: URI or payment request")); - openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain explorer"), this); + openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain Explorer"), this); openBlockExplorerAction->setStatusTip(tr("Block explorer window")); - showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this); + facebookAction = new QAction(QIcon(":/icons/facebook"), tr("Facebook"), this); + facebookAction->setStatusTip(tr("DAPS Facebook")); + twitterAction = new QAction(QIcon(":/icons/twitter"), tr("Twitter"), this); + twitterAction->setStatusTip(tr("DAPS Twitter")); + discordAction = new QAction(QIcon(":/icons/discord"), tr("Discord"), this); + discordAction->setStatusTip(tr("DAPS Discord")); + telegramOfficialAction = new QAction(QIcon(":/icons/telegram"), tr("Telegram - Main"), this); + telegramOfficialAction->setStatusTip(tr("DAPS Telegram - Main")); + telegramLoungeAction = new QAction(QIcon(":/icons/telegram"), tr("Telegram - Lounge"), this); + telegramLoungeAction->setStatusTip(tr("DAPS Telegram - Lounge")); + mediumAction = new QAction(QIcon(":/icons/medium"), tr("Medium"), this); + mediumAction->setStatusTip(tr("DAPS Medium")); + steemitAction = new QAction(QIcon(":/icons/steemit"), tr("Steemit"), this); + steemitAction->setStatusTip(tr("DAPS Steemit")); + instagramAction = new QAction(QIcon(":/icons/instagram"), tr("Instagram"), this); + instagramAction->setStatusTip(tr("DAPS Instagram")); + redditAction = new QAction(QIcon(":/icons/reddit"), tr("Reddit"), this); + redditAction->setStatusTip(tr("DAPS Reddit")); + + showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line Options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); + // Help Links + openBlockExplorerAPIAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Blockhain Explorer API"), this); + openBlockExplorerAPIAction->setStatusTip(tr("Blockhain Explorer API")); + openBootStrapAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&BootStrap"), this); + openBootStrapAction->setStatusTip(tr("BootStrap Link")); + openTGTechSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Tech Support"), this); + openTGTechSupportAction->setStatusTip(tr("Telegram Tech Support")); + openTGMNSupportAction = new QAction(QIcon(":/icons/telegram"), tr("&Telegram Masternode Support"), this); + openTGMNSupportAction->setStatusTip(tr("Telegram Masternode Support")); + openDiscordSupportAction = new QAction(QIcon(":/icons/discord"), tr("&Discord Tech Support"), this); + openDiscordSupportAction->setStatusTip(tr("Discord Tech Support")); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(optionsAction, SIGNAL(triggered()), this, SLOT(gotoOptionsPage())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); + connect(openBlockExplorerAPIAction, SIGNAL(triggered()), this, SLOT(openBlockExplorerAPIClicked())); + connect(openBootStrapAction, SIGNAL(triggered()), this, SLOT(openBootStrapClicked())); + connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); + connect(openTGMNSupportAction, SIGNAL(triggered()), this, SLOT(openTGMNSupportClicked())); + connect(openDiscordSupportAction, SIGNAL(triggered()), this, SLOT(openDiscordSupportClicked())); #ifdef ENABLE_WALLET if (walletFrame) { connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); @@ -456,6 +496,15 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(multisigSignAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSign())); } #endif // ENABLE_WALLET + connect(facebookAction, SIGNAL(triggered()), this, SLOT(facebookActionClicked())); + connect(twitterAction, SIGNAL(triggered()), this, SLOT(twitterActionClicked())); + connect(discordAction, SIGNAL(triggered()), this, SLOT(discordActionClicked())); + connect(telegramOfficialAction, SIGNAL(triggered()), this, SLOT(telegramOfficialActionClicked())); + connect(telegramLoungeAction, SIGNAL(triggered()), this, SLOT(telegramLoungeActionClicked())); + connect(mediumAction, SIGNAL(triggered()), this, SLOT(mediumActionClicked())); + connect(steemitAction, SIGNAL(triggered()), this, SLOT(steemitActionClicked())); + connect(instagramAction, SIGNAL(triggered()), this, SLOT(instagramActionClicked())); + connect(redditAction, SIGNAL(triggered()), this, SLOT(redditActionClicked())); } void BitcoinGUI::createMenuBar() @@ -471,28 +520,28 @@ void BitcoinGUI::createMenuBar() // Configure the menus QMenu* file = appMenuBar->addMenu(tr("&File")); if (walletFrame) { - file->addAction(openAction); + //file->addAction(openAction); file->addAction(backupWalletAction); file->addSeparator(); - file->addAction(usedSendingAddressesAction); - file->addAction(usedReceivingAddressesAction); - file->addSeparator(); - file->addAction(multisigCreateAction); - file->addAction(multisigSpendAction); - file->addAction(multisigSignAction); - file->addSeparator(); + //file->addAction(usedSendingAddressesAction); + //file->addAction(usedReceivingAddressesAction); + //file->addSeparator(); + //file->addAction(multisigCreateAction); + //file->addAction(multisigSpendAction); + //file->addAction(multisigSignAction); + //file->addSeparator(); } file->addAction(quitAction); - QMenu* settings = appMenuBar->addMenu(tr("&Settings")); - if (walletFrame) { - settings->addAction(encryptWalletAction); - settings->addAction(changePassphraseAction); - settings->addAction(unlockWalletAction); - settings->addAction(lockWalletAction); - settings->addAction(multiSendAction); - settings->addSeparator(); - } + //QMenu* settings = appMenuBar->addMenu(tr("&Settings")); + //if (walletFrame) { + //settings->addAction(encryptWalletAction); + //settings->addAction(changePassphraseAction); + //settings->addAction(unlockWalletAction); + //settings->addAction(lockWalletAction); + //settings->addAction(multiSendAction); + //settings->addSeparator(); + //} if (walletFrame) { walletFrame->addAction(openRPCConsoleAction); @@ -505,16 +554,36 @@ void BitcoinGUI::createMenuBar() tools->addSeparator(); tools->addAction(openConfEditorAction); tools->addAction(openMNConfEditorAction); + tools->addAction(showDataDirAction); tools->addAction(showBackupsAction); tools->addAction(openBlockExplorerAction); } + QMenu* socials = appMenuBar->addMenu(tr("Social")); + socials->addAction(facebookAction); + socials->addAction(twitterAction); + socials->addAction(discordAction); + socials->addAction(telegramOfficialAction); + socials->addAction(telegramLoungeAction); + socials->addAction(mediumAction); + socials->addAction(steemitAction); + socials->addAction(instagramAction); + socials->addAction(redditAction); + QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); + help->addAction(openBlockExplorerAPIAction); + help->addAction(openBootStrapAction); + help->addSeparator(); + help->addAction(openTGTechSupportAction); + help->addAction(openTGMNSupportAction); + help->addSeparator(); + help->addAction(openDiscordSupportAction); + help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); - appMenuBar->setVisible(false); + appMenuBar->setVisible(true); } void BitcoinGUI::createToolBars() @@ -725,6 +794,7 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addSeparator(); trayIconMenu->addAction(openConfEditorAction); trayIconMenu->addAction(openMNConfEditorAction); + trayIconMenu->addAction(showDataDirAction); trayIconMenu->addAction(showBackupsAction); trayIconMenu->addAction(openBlockExplorerAction); #ifndef Q_OS_MAC // This is built-in on Mac @@ -753,6 +823,43 @@ void BitcoinGUI::optionsClicked() dlg.exec(); } +void BitcoinGUI::facebookActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.facebook.com/officialdapscoin/")); +} +void BitcoinGUI::twitterActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://twitter.com/DAPScoin")); +} +void BitcoinGUI::discordActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://officialdapscoin.com/discord")); +} +void BitcoinGUI::telegramOfficialActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/dapscoin")); +} +void BitcoinGUI::telegramLoungeActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPS_LOUNGE")); +} +void BitcoinGUI::mediumActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://medium.com/DAPScoin")); +} +void BitcoinGUI::instagramActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.instagram.com/DAPSCoin/")); +} +void BitcoinGUI::redditActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://www.reddit.com/r/DAPSCoin/")); +} +void BitcoinGUI::steemitActionClicked() +{ + QDesktopServices::openUrl(QUrl("https://steemit.com/@DAPSCoin/")); +} + void BitcoinGUI::aboutClicked() { if (!clientModel) @@ -769,6 +876,31 @@ void BitcoinGUI::showHelpMessageClicked() help->show(); } +void BitcoinGUI::openBlockExplorerAPIClicked() +{ + QDesktopServices::openUrl(QUrl("https://explorer.dapscoin.com/api/getblockcount")); +} + +void BitcoinGUI::openBootStrapClicked() +{ + QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/BootStrap/releases/tag/latest")); +} + +void BitcoinGUI::openTGTechSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPSTechSupport")); +} + +void BitcoinGUI::openTGMNSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://t.me/DAPS_MN_Support")); +} + +void BitcoinGUI::openDiscordSupportClicked() +{ + QDesktopServices::openUrl(QUrl("https://discord.gg/8vbXJMf")); +} + #ifdef ENABLE_WALLET void BitcoinGUI::openClicked() { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 88206164d4..40c1d2619d 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -118,10 +118,25 @@ class BitcoinGUI : public QMainWindow QAction* openRepairAction; QAction* openConfEditorAction; QAction* openMNConfEditorAction; + QAction* showDataDirAction; QAction* showBackupsAction; QAction* openAction; QAction* openBlockExplorerAction; + QAction* facebookAction; + QAction* twitterAction; + QAction* discordAction; + QAction* telegramOfficialAction; + QAction* telegramLoungeAction; + QAction* mediumAction; + QAction* steemitAction; + QAction* instagramAction; + QAction* redditAction; QAction* showHelpMessageAction; + QAction* openBlockExplorerAPIAction; + QAction* openBootStrapAction; + QAction* openTGTechSupportAction; + QAction* openTGMNSupportAction; + QAction* openDiscordSupportAction; QAction* multiSendAction; QFrame* frameBlocks; QLabel *stakingState; @@ -228,12 +243,27 @@ private slots: void openClicked(); #endif // ENABLE_WALLET + /** Social Networks */ + void facebookActionClicked(); + void twitterActionClicked(); + void discordActionClicked(); + void telegramOfficialActionClicked(); + void telegramLoungeActionClicked(); + void mediumActionClicked(); + void redditActionClicked(); + void instagramActionClicked(); + void steemitActionClicked(); /** Show configuration dialog */ void optionsClicked(); /** Show about dialog */ void aboutClicked(); /** Show help message dialog */ void showHelpMessageClicked(); + void openBlockExplorerAPIClicked(); + void openBootStrapClicked(); + void openTGTechSupportClicked(); + void openTGMNSupportClicked(); + void openDiscordSupportClicked(); #ifndef Q_OS_MAC /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index 10e93612cd..eadbc4a683 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -172,7 +172,7 @@ const CBlockIndex* getexplorerBlockIndex(int64_t height) std::string getexplorerBlockHash(int64_t Height) { - std::string genesisblockhash = "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818"; + std::string genesisblockhash = "0000039a711dba61e12c29fb86542fa059e9616aafe9b4c61e065d393f31535e"; CBlockIndex* pindexBest = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; if ((Height < 0) || (Height > pindexBest->nHeight)) { return genesisblockhash; diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 42fd66a0ea..410a266d9a 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -66,6 +66,14 @@ res/icons/staking_inactive.png res/icons/staking_disabled.png res/icons/staking_waiting.png + res/icons/discord.png + res/icons/facebook.png + res/icons/instagram.png + res/icons/medium.png + res/icons/reddit.png + res/icons/steemit.png + res/icons/telegram.png + res/icons/twitter.png res/css/Light.css diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 6b56e2f913..37990949c8 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -392,6 +392,15 @@ void openMNConfigfile() QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); } +void showDataDir() +{ + boost::filesystem::path pathBackups = GetDataDir(); + + /* Open folder with default browser */ + if (boost::filesystem::exists(pathBackups)) + QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathBackups))); +} + void showBackups() { boost::filesystem::path pathBackups = GetDataDir() / "backups"; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 386ab479df..0fadd11288 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -121,6 +121,9 @@ void openConfigfile(); // Open masternode.conf void openMNConfigfile(); +// Browse DataDir folder +void showDataDir(); + // Browse backup folder void showBackups(); diff --git a/src/qt/locale/dapscoin_en.ts b/src/qt/locale/dapscoin_en.ts index e0cbe5060d..f990c5ed33 100644 --- a/src/qt/locale/dapscoin_en.ts +++ b/src/qt/locale/dapscoin_en.ts @@ -476,12 +476,12 @@ BitcoinGUI - + Node Node - + &Overview &Overview @@ -496,7 +496,7 @@ &Receive - + E&xit E&xit @@ -582,12 +582,7 @@ Show diagnostic information - - &Debug console - &Debug console - - - + Open debugging console Open debugging console @@ -602,12 +597,7 @@ Show network monitor - - &Peers list - &Peers list - - - + Show peers info Show peers info @@ -628,6 +618,16 @@ + Show &DAPScoin Folder + + + + + Show the DAPScoin folder + + + + Show Automatic &Backups Show Automatic &Backups @@ -691,13 +691,8 @@ Open &URI... Open &URI... - - - &Command-line options - &Command-line options - - + %n Active Connections @@ -728,12 +723,12 @@ Confirmations: %5 - + Staking Enabled - + Enabling Staking... @@ -744,18 +739,17 @@ Confirmations: %5 - + &File &File - - + &Settings &Settings - + DAPS Coin @@ -765,17 +759,17 @@ Confirmations: %5 - + &History - + Masternodes - + Modify settings @@ -795,27 +789,42 @@ Confirmations: %5 &Network - + + &Debug Console + + + + + &Peers List + + + + + &Blockchain Explorer + + + + &Tools &Tools - + &Help &Help - + DAPS - + &Masternodes - + &About DAPS @@ -850,32 +859,177 @@ Confirmations: %5 - + Open a DAPS: URI or payment request + + + Block explorer window + + + + + Facebook + + - &Blockchain explorer + DAPS Facebook - Block explorer window + Twitter - + + DAPS Twitter + + + + + Discord + + + + + DAPS Discord + + + + + Telegram - Main + + + + + DAPS Telegram - Main + + + + + Telegram - Lounge + + + + + DAPS Telegram - Lounge + + + + + Medium + + + + + DAPS Medium + + + + + Steemit + + + + + DAPS Steemit + + + + + Instagram + + + + + DAPS Instagram + + + + + Reddit + + + + + DAPS Reddit + + + + + &Command-line Options + + + + Show the DAPS help message to get a list with possible DAPS command-line options - + + &Blockhain Explorer API + + + + + Blockhain Explorer API + + + + + &BootStrap + + + + + BootStrap Link + + + + + &Telegram Tech Support + + + + + Telegram Tech Support + + + + + &Telegram Masternode Support + + + + + Telegram Masternode Support + + + + + &Discord Tech Support + + + + + Discord Tech Support + + + + + Social + + + + DAPS client - + Up to date Up to date @@ -963,7 +1117,17 @@ Confirmations: %5 - + + Syncing MN List... + + + + + Consolidating Transactions… + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Wallet is <b>encrypted</b> and currently <b>unlocked</b> @@ -1019,12 +1183,12 @@ Confirmations: %5 ClientModel - + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5) - + Network Alert Network Alert @@ -1142,7 +1306,7 @@ Confirmations: %5 Priority - + Copy address Copy address @@ -1208,12 +1372,12 @@ Confirmations: %5 Copy change - + Please switch to "List mode" to use this function. - + highest highest @@ -1574,7 +1738,7 @@ lowercase letters, numbers, symbols) - + All Types @@ -1820,7 +1984,7 @@ lowercase letters, numbers, symbols) - + Confirm masternode start @@ -1981,7 +2145,7 @@ MultiSend will not be activated unless you have clicked Activate - + The entered address: @@ -2521,7 +2685,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Cancel - + default default @@ -2531,7 +2695,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsnone - + Confirm options reset Confirm options reset @@ -2552,45 +2716,56 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsThis change would require a client restart. - + The supplied proxy address is invalid. The supplied proxy address is invalid. - - - OptionsPage - - Staking Status: + + The supplied proxy port is invalid. - + + The supplied proxy settings are invalid. + + + + + OptionsPage + + Turn staking on or off - + On - - + + Off - - Backup wallet to directory of choice + + Staking Mode: - + + Backup Wallet Backup Wallet + + + Show Seed Phrase + + Theme Selection: @@ -2612,7 +2787,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Change current passphrase @@ -2642,37 +2817,32 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Quantity of DAPS to keep as spendable (not staking) - - Save - - - - - Disable + + Enabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking. - - Mnemonic Recovery Phrase + + Automatically add any new deposits received to your staked balance - - We strongly recommend you only view your mnemonic phrase in a secure environment safe from video cameras or any wandering eyes. + + Save - - Show Phrase + + Disable - + Two Factor Authentication @@ -2701,6 +2871,11 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsCurrent Authentication Code + + + Wallet Data (*.dat) + Wallet Data (*.dat) + OverviewPage @@ -2920,7 +3095,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsAmount - + %1 d %1 d @@ -3007,7 +3182,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Information - + General General @@ -3022,7 +3197,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsClient name - + + @@ -3033,7 +3209,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + + @@ -3050,17 +3227,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + N/A N/A - + Number of connections Number of connections - + + Block chain + + + + &Open &Open @@ -3120,12 +3302,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsNumber of Masternodes - - Blockchain - - - - + &Console &Console @@ -3171,8 +3348,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - + + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3202,12 +3379,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsServices - - Rebuild blockchain index from current blk000??.dat files. - - - - + Ban Score Ban Score @@ -3262,67 +3434,92 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Wallet Repair - + + Rebuild block chain index from current blk000??.dat files. + + + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions. + + + + Wallet In Use: - + Salvage wallet Salvage wallet - + Attempt to recover private keys from a corrupt wallet.dat. - + Rescan blockchain files Rescan blockchain files - + Recover transactions 1 Recover transactions 1 - + Recover transactions from blockchain (keep meta-data, e.g. account owner). - + + Data Directory + + + + + Last block hash + + + + Recover transactions 2 Recover transactions 2 - + + Rescan the block chain for missing wallet transactions. + + + + Recover transactions from blockchain (drop meta-data). - + Upgrade wallet format Upgrade wallet format - + -resync: - - Deletes all local blockchain folders so the wallet synchronizes from scratch. + + Delete local Blockchain Folders - - The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. - The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. + + Deletes all local blockchain folders so the wallet synchronizes from scratch. + - + Starting Block @@ -3337,32 +3534,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - Delete local blockchain Folders - - - - + Wallet repair options. Wallet repair options. - - Rescan the blockchain for missing wallet transactions. - - - - + Upgrade wallet to latest format on startup. (Note: this is NOT an update of the wallet itself!) - + Rebuild index Rebuild index - + In: In: @@ -3372,12 +3559,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsOut: - + Welcome to the DAPS RPC console. - + &Disconnect Node @@ -3415,7 +3602,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.<br /><br /> @@ -3440,9 +3627,9 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. - Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + Use up and down arrows to navigate history, and %1 to clear screen. + @@ -3450,7 +3637,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsType <b>help</b> for an overview of available commands. - + + WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command. + + + + %1 B %1 B @@ -3578,7 +3770,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsAn optional amount to request. Leave this empty or zero to not request a specific amount. - + Copy label Copy label @@ -3664,7 +3856,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations RecentRequestsTableModel - + Date Date @@ -3755,13 +3947,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsSend Coins - - - Your current spendable balance - Your current spendable balance - - - + Confirm the send action Confirm the send action @@ -3775,21 +3961,201 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsSend to multiple recipients at once Send to multiple recipients at once + + + Coin Control Features + + + + + Open Coin Control... + + + + + Coins automatically selected + + + + + Insufficient funds! + + + + + Quantity: + Quantity: + + + + Bytes: + Bytes: + + + + Amount: + Amount: + + + + Priority: + Priority: + + + + medium + medium + + + + Fee: + Fee: + + + + Dust: + Dust: + + + + no + no + + + + After Fee: + After Fee: + + + + Change: + Change: + + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + + + + + Split UTXO + + + + + # of outputs + + + + + UTXO Size: + + + + + 0 DAPS + + + + Add &Recipient Add &Recipient - + Balance: Balance: - + + Copy quantity + Copy quantity + + + + Copy amount + Copy amount + + + + Copy fee + Copy fee + + + + Copy after fee + Copy after fee + + + + Copy bytes + Copy bytes + + + + Copy priority + Copy priority + + + + Copy dust + Copy dust + + + + Copy change + Copy change + + + + Destination + + + + + Are you sure you want to send? + + + + + Estimated Transaction fee + + + + + <span class='h3'>Total Amount = <b>%1</b><br/><hr /></center> + + + + + Confirm Send Coins + + + + Copy + + + Warning: Invalid PIVX address + + + + + Warning: Unknown change address + + + + + (no label) + (no label) + SendCoinsEntry @@ -4693,7 +5059,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsShow transaction details - + Export Transaction History Export Transaction History @@ -4879,13 +5245,13 @@ Please try again. TwoFAQRDialog - - Recovery Code + + Below are your 2FA QR Code & Recovery Key. - Keep your recovery code in a safe place. Use it to regain access to your account if you lose your phone. + Please store them safely. Use them to regain access if you lose your device. @@ -4894,27 +5260,27 @@ Please try again. QR Code - + Cancel - + Esc - + Next - + Return - + Resulting URI too long, try to reduce the text for label / message. Resulting URI too long, try to reduce the text for label / message. @@ -4973,7 +5339,12 @@ Please try again. - + + (Wallet may appear not responding as it rescans for all transactions) + + + + Unlock @@ -5027,7 +5398,7 @@ Please try again. Selected amount: - + Backup Wallet Backup Wallet @@ -5280,7 +5651,7 @@ Please try again. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. - + Unable to bind to %s on this computer. DAPS is probably already running. @@ -5425,7 +5796,7 @@ Please try again. Always query for peer addresses via DNS lookup (default: %u) - + Attempt to recover private keys from a corrupt wallet.dat Attempt to recover private keys from a corrupt wallet.dat @@ -5500,7 +5871,7 @@ Please try again. - + Corrupted block database detected Corrupted block database detected @@ -5749,11 +6120,6 @@ Please try again. Invalid -onion address or hostname: '%s' - - - Invalid -proxy address or hostname: '%s' - - Invalid amount for -maxtxfee=<amount>: '%s' @@ -5810,12 +6176,12 @@ Please try again. Invalid script detected. - + SwiftX options: - + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! @@ -5835,7 +6201,12 @@ Please try again. - + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + + + + <category> can be: @@ -5846,6 +6217,11 @@ Please try again. + Append comment to the user agent string + + + + Attempt to force blockchain corruption recovery @@ -5891,6 +6267,11 @@ Please try again. + Copyright (C) 2015-%i The PIVX Core Developers + + + + Copyright (C) 2018-%i The DAPS Project developers @@ -5970,7 +6351,7 @@ Please try again. - + Keep at most <n> unconnectable transactions in memory (default: %u) Keep at most <n> unconnectable transactions in memory (default: %u) @@ -6029,6 +6410,11 @@ Please try again. Lock masternodes from masternode configuration file (default: %u) Lock masternodes from masternode configuration file (default: %u) + + + Lookup(): Invalid -proxy address or hostname: '%s' + + Maintain at most <n> connections to peers (default: %u) @@ -6174,6 +6560,11 @@ Please try again. Rebuild block chain index from current blk000??.dat files Rebuild block chain index from current blk000??.dat files + + + Recalculating DAPS supply... + + Receive and display P2P network alerts (default: %u) @@ -6524,6 +6915,11 @@ Please try again. Use the test network Use the test network + + + User Agent comment (%s) contains unsafe characters. + + Username for JSON-RPC connections @@ -6614,6 +7010,11 @@ Please try again. ZeroMQ notification options: + + + isValid(): Invalid -proxy address or hostname: '%s' + + on startup diff --git a/src/qt/res/icons/discord.png b/src/qt/res/icons/discord.png new file mode 100644 index 0000000000000000000000000000000000000000..d222940a79b34aba069baabc07c12112f319dde0 GIT binary patch literal 663 zcmV;I0%-k-P)a z-FlGRgP7lVj@*Wt;EJ8$k)z{@oZx|$-jSo?sJ7{+w&*=>c{ zYlGNvh}vm_*!}(g^!EJ0%kTL4{np*}Wq#M`?fRFfnX0NYaqb z<6Zr{faa?v>D3G-LF6gswTDIe`v{!W5V)7`7^iUqcZf=o6KMXN3O=Q_IAE zf93+$Gf)I>;og_-3()RD xl1}?FPfzRC0fl3{-!l}B@zK<^<9xno+8>4tWL{5Ao)iE8002ovPDHLkV1jNuUuggU literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/facebook.png b/src/qt/res/icons/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c79c4527b6627c86b2cb50c22a295d298ed659 GIT binary patch literal 429 zcmV;e0aE^nP))0|NsCBO?RT09wz$z`!u@4q%}~vxG1=gP*-BgMpejgD^iQ z10y2?!|y-;7_QxW!_YeK7;PP3r6C@lczZ#jI2 zVdKHuL|cjs20R;%I$+cRL(~COY|0PO5EyU=pw*xM$#0JkUmep54ACf{sskvAKq>$L X9-?4pZcGm<00000NkvXXu0mjfu70-u literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/instagram.png b/src/qt/res/icons/instagram.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd7571e961b55e31ab78a93d7e03f4870d5870a GIT binary patch literal 3438 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 O12QwV#?~5n$NUT4TINmw literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/medium.png b/src/qt/res/icons/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..a02a1d69a1d03f22a8d8b96e676cb38a6b9782d6 GIT binary patch literal 639 zcmV-_0)YLAP)zQ@Pds$*kYF5nQv!yXMI2p z_{|no24q`90dGHl#(zs~Gx!c*2e1PG2zV_h7K@yoo?@D&YyRfuhDM_SfKrN5sl@T| zv1`r#{yw+2w-gG6?*oLxVRT(bDR;86*{lPQNF=ztyj%egZX?8z}eXuS65d6v|25mpPvbZ zLK^{izJiYmg+dGl13H}!>2w-h*Eu;k0iar~Vw&d4Yw^-XtKXeJJUjr)8Xq1WV%s*g zS`EM7zfthD0W8aM+4XweWj{VX((CnB(*Jqiw*exNh|6xb+q}HIICia81KhXX=kpPb zM%QuwbtAgJzjvCCh)Ac?5kSi2vNNY?nq)E=84ic?QM1`h^7;IijmYy7&gXNw-7c18 zp_Fo7z}?*)M@L7D$77zJo=7H>OePbC!yzI9EdPSff5^re`026r?|28W1K0s5;MX<* Z{sKnfT^_grsCxha002ovPDHLkV1f($7+(MY literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/reddit.png b/src/qt/res/icons/reddit.png new file mode 100644 index 0000000000000000000000000000000000000000..84b8c2947d326809976354ae6c3db8bf848c0d09 GIT binary patch literal 2478 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/steemit.png b/src/qt/res/icons/steemit.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e92a03352de9833df9c09d1d6b0105c4ccb09e GIT binary patch literal 1489 zcmV;?1upuDP)b98#MGYYW#*QF&fgQkS!GQnD|1!YqtIPt{0jq$F(7vW(bp##&p8^|#0e?rz z1~^`S50r*HlQ8L%zk~b&yb=ufuk~nv*H<|X*bkbgJrNr!65&mLL9PHZg8~2fq%s}P zkAdbTQj$FMc1=7kH5xHuaxmb(9%q1)^CN0kxKmaUBGUkU3_f-*0sm1EDZjRJMF)Uo z7`aZ-QkztrOq%P^%HH$lx|uhnC=QBXehM*FP>Gx z2yeD=3Zn5&THL@&0L!`I7TFjf*6ua0JoW9?Q&+38B5? z=Wg(8Z37}g#iT-t3OqD6xAEPf$d&GUVI=uEZm!(8OV!bfhzJv($zxK)1+Azwe`0-bn+^y z%8ZFa>6@8>DL=X#skeX{jR{ihdpFAVy|su4xt>fid!+-gIZzX(8a$v6$X0 zJv27A^UlVDbZfFXK^g?AEoXY&5mFU8D6wmoCA|9a9$N1|ioy>XkVSX5^4_MOxz}#v z^0Kp7_)!&CZ?+meF!FOu+IlVE?+^g5uW~4GPSM^8jSa^`V|IiSU%$@AZ;!L%$1`#G zWc*IVM+O7_Mi;=nvsHKcje5x?PG3me&*OVro+pco*YEJnp>uJxkK+ef6AbtdK=eek z!I@se-kG*X_jCJ5-E3)RcXeG9z9)W=g9w|VaSnKWl|z6dz)+qPoT0CW?}j>HYB1mr zw^TC%ICJ|<;7SVpJQ|;1o`{(V>wp=i@;Cz=BhCYpL5}v+&lBOzfP{X69CSR7`%H^7 zz%k;wh?EQRfgr8P`gwG}kDn(5xhu#@gjunk6Q=F~oauEXuoTEmVeSWL0JZ|3CsUlV r0fr$Nz;sghJQtz*+Rnruqp|QGLw#TBJ(Qu&00000NkvXXu0mjfrth`Z literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/telegram.png b/src/qt/res/icons/telegram.png new file mode 100644 index 0000000000000000000000000000000000000000..4b65b515c506e3a4cb54a9646180191bb177aa93 GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy=L38~T!FOC(g*ZM|NsBjT=GD5 z(S7*^_mmdiS6h7l@4x>y-u(>U{%rB}4-+oDbKmgf$M3)AUj5kf=*#-sA4`wCO56Lw zck@$|6%U_&{(brN_v6pL&c5a-ZMf`zcZI{0mjy+ZADwCikr( z`;(>aJ})uoJoL9uEtKI!`lX-0eO6vInHkR#@S>yS*Pc0=Z=VVzE#md<`hRJ;d+C;r zjIE4ny!NGD&xE7CzUaF=HOctry(=y|9x&S}sf6kY*5_W2X_UAi;#;FXiA!<%ie~-z zhv|#Aq#p4u7l=6}TUF+KT<;J`88%4(*PmcSs&In?Tk@qoIQOyb3&TAbhO-(AJ<>jTxiodt``_pB74HP i>{VN?bZI)v8*!x@r4~ z6l_#bQi&F%H-aDtYQx_6cM}M~QpB5BC~5J!2wIRrup!{Zx>6)I6^Usgh0ry$WOt1% zcCwRZvpeT_G1=H=c6Y{*)IOKDUKy+#sQt_$!28Oe7g0YFs7r(nJ$A+DMgX8*F??+y$Kr}kBpPRPb19OiD?oXOTa%<3|`sK}d*(hmrsB~r}$neeS2ihMS`%!=)i z)>TeiS@s?z$VulW;{zLBYYP$zc$Xn}TQNNC!+>I5f}ZhZK*Nh;COk(fDfV`>b{l3Vz*J@w)Y^^z*De_aDxLaS37!)#T;@xJWt+-=nfFm7Yp4<`O z)kKhH!(E2Szir;WP~_K~$I7pwv`Hb8c4qo=;S@r=-)Q_Jy8^tkH^ROh23;+ZCPR?5 z6hGgn@Xgf{>A5oaTb~YEpXS}xqxZ>i+}EB5F?3JF0T4sgYuUdW(dCKbpvJdeT#Y+g zt5)uc{jZl&a7s~GJ_P#umWY?^p7p(f`z$#6@Nblh$;~Z?8mC-LuI~wI8vrL0QgetPeerTableModel()->stopAutoRefresh(); } +void RPCConsole::showDataDir() +{ + GUIUtil::showDataDir(); +} + void RPCConsole::showBackups() { GUIUtil::showBackups(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 31a60b545a..ea0cd3f228 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -117,6 +117,8 @@ public slots: void banSelectedNode(int bantime); /** Unban a selected node on the Bans tab */ void unbanSelectedNode(); + /** Show DataDir folder in default browser */ + void showDataDir(); /** Show folder with wallet backups in default browser */ void showBackups(); From edf3616ad8924d146f9cab6cebfcc049b85922dd Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sat, 28 Dec 2019 18:32:02 +0100 Subject: [PATCH 0043/1888] Update Makefile.qt.include --- src/Makefile.qt.include | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index ec6b015718..6e7e47825f 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -11,13 +11,18 @@ QT_TS = \ qt/locale/dapscoin_de.ts \ qt/locale/dapscoin_en.ts \ qt/locale/dapscoin_en_US.ts \ + qt/locale/dapscoin_eo.ts \ qt/locale/dapscoin_es.ts \ + qt/locale/dapscoin_es_ES.ts \ qt/locale/dapscoin_fi.ts \ qt/locale/dapscoin_fr_FR.ts \ + qt/locale/dapscoin_hi_IN.ts \ qt/locale/dapscoin_hr.ts \ + qt/locale/dapscoin_hr_HR.ts \ qt/locale/dapscoin_it.ts \ qt/locale/dapscoin_ja.ts \ qt/locale/dapscoin_ko_KR.ts \ + qt/locale/dapscoin_lt_LT.ts \ qt/locale/dapscoin_nl.ts \ qt/locale/dapscoin_pl.ts \ qt/locale/dapscoin_pt.ts \ @@ -28,6 +33,7 @@ QT_TS = \ qt/locale/dapscoin_sv.ts \ qt/locale/dapscoin_tr.ts \ qt/locale/dapscoin_uk.ts \ + qt/locale/dapscoin_vi.ts \ qt/locale/dapscoin_zh_CN.ts \ qt/locale/dapscoin_zh_TW.ts From 9f6e3f044a3510013c41e54aef761650eb8141d5 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sat, 28 Dec 2019 18:34:28 +0100 Subject: [PATCH 0044/1888] Update dapscoin_locale.qrc Added: eo, es_ES, hi_IN, hr_HR, lt_LT and vi --- src/qt/dapscoin_locale.qrc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qt/dapscoin_locale.qrc b/src/qt/dapscoin_locale.qrc index 9d19df7051..266f74ffcf 100644 --- a/src/qt/dapscoin_locale.qrc +++ b/src/qt/dapscoin_locale.qrc @@ -7,23 +7,29 @@ locale/dapscoin_de.qm locale/dapscoin_en.qm locale/dapscoin_en_US.qm + locale/dapscoin_eo.qm locale/dapscoin_es.qm + locale/dapscoin_es_ES.qm locale/dapscoin_fi.qm locale/dapscoin_fr_FR.qm + locale/dapscoin_hi_IN.qm locale/dapscoin_hr.qm + locale/dapscoin_hr_HR.qm locale/dapscoin_it.qm locale/dapscoin_ja.qm locale/dapscoin_ko_KR.qm + locale/dapscoin_lt_LT.qm locale/dapscoin_nl.qm locale/dapscoin_pl.qm locale/dapscoin_pt.qm - locale/dapscoin_pt_BR.qm + locale/dapscoin_pt_BR.qm locale/dapscoin_ro_RO.qm locale/dapscoin_ru.qm locale/dapscoin_sk.qm locale/dapscoin_sv.qm locale/dapscoin_tr.qm locale/dapscoin_uk.qm + locale/dapscoin_vi.qm locale/dapscoin_zh_CN.qm locale/dapscoin_zh_TW.qm From e325364c149da67f2e0ca1b86926764d476c9967 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 15:24:08 -0500 Subject: [PATCH 0045/1888] Restore old masternodes command to avoid confusion --- src/rpc/masternode.cpp | 138 +++++++++++++++++++++++++++++++++++++++++ src/rpc/server.cpp | 5 +- src/rpc/server.h | 1 + 3 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 8ffae2ad85..01c6abfe20 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -50,6 +50,144 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp) return obj; } +UniValue masternode(const UniValue& params, bool fHelp) +{ + string strCommand; + if (params.size() >= 1) + strCommand = params[0].get_str(); + + if (fHelp || + (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "start-all" && strCommand != "start-missing" && + strCommand != "start-disabled" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" && + strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" && + strCommand != "outputs" && strCommand != "status" && strCommand != "calcscore")) + throw runtime_error( + "masternode \"command\"...\n" + "\nSet of commands to execute masternode related actions\n" + "This command is depreciated, please see individual command documentation for future reference\n\n" + + "\nArguments:\n" + "1. \"command\" (string or set of strings, required) The command to execute\n" + + "\nAvailable commands:\n" + " count - Print count information of all known masternodes\n" + " current - Print info on current masternode winner\n" + " debug - Print masternode status\n" + " genkey - Generate new masternodeprivkey\n" + " outputs - Print masternode compatible outputs\n" + " start - Start masternode configured in dapscoin.conf\n" + " start-alias - Start single masternode by assigned alias configured in masternode.conf\n" + " start- - Start masternodes configured in masternode.conf (: 'all', 'missing', 'disabled')\n" + " status - Print masternode status information\n" + " list - Print list of all known masternodes (see masternodelist for more info)\n" + " list-conf - Print masternode.conf in JSON format\n" + " winners - Print list of masternode winners\n"); + + if (strCommand == "list") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return listmasternodes(newParams, fHelp); + } + + if (strCommand == "connect") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + } + + if (strCommand == "count") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return getmasternodecount(newParams, fHelp); + } + + if (strCommand == "current") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return masternodecurrent(newParams, fHelp); + } + + if (strCommand == "debug") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return masternodedebug(newParams, fHelp); + } + + if (strCommand == "start" || strCommand == "start-alias" || strCommand == "start-many" || strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") { + return startmasternode(params, fHelp); + } + + if (strCommand == "genkey") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return createmasternodekey(newParams, fHelp); + } + + if (strCommand == "list-conf") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return listmasternodeconf(newParams, fHelp); + } + + if (strCommand == "outputs") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return getmasternodeoutputs(newParams, fHelp); + } + + if (strCommand == "status") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return getmasternodestatus(newParams, fHelp); + } + + if (strCommand == "winners") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return getmasternodewinners(newParams, fHelp); + } + + if (strCommand == "calcscore") { + UniValue newParams(UniValue::VARR); + // forward params but skip command + for (unsigned int i = 1; i < params.size(); i++) { + newParams.push_back(params[i]); + } + return getmasternodescores(newParams, fHelp); + } + + return NullUniValue; +} + UniValue listmasternodes(const UniValue& params, bool fHelp) { std::string strFilter = ""; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 74858ac73f..82e8ee56dd 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -343,8 +343,9 @@ static const CRPCCommand vRPCCommands[] = // {"hidden", "setmocktime", &setmocktime, true, false, false}, /* Dapscoin features */ - {"dapscoin", "listmasternodes", &listmasternodes, true, true, false}, - {"dapscoin", "getmasternodecount", &getmasternodecount, true, true, false}, + {"dapscoin", "masternode", &masternode, true, true, false}, + {"dapscoin", "listmasternodes", &listmasternodes, true, true, false}, + {"dapscoin", "getmasternodecount", &getmasternodecount, true, true, false}, {"dapscoin", "getcurrentseesawreward", &getcurrentseesawreward, true, true, false}, {"dapscoin", "getseesawrewardratio", &getseesawrewardratio, true, true, false}, {"dapscoin", "getseesawrewardwithheight", &getseesawrewardwithheight, true, true, false}, diff --git a/src/rpc/server.h b/src/rpc/server.h index 24be590ad5..8220da493e 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -300,6 +300,7 @@ extern UniValue reconsiderblock(const UniValue& params, bool fHelp); extern UniValue getinvalid(const UniValue& params, bool fHelp); extern UniValue getpoolinfo(const UniValue& params, bool fHelp); +extern UniValue masternode(const UniValue& params, bool fHelp); extern UniValue listmasternodes(const UniValue& params, bool fHelp); extern UniValue getmasternodecount(const UniValue& params, bool fHelp); extern UniValue createmasternodebroadcast(const UniValue& params, bool fHelp); From f5333d0697e85450112c5c85f3495cd268dfad8a Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sat, 28 Dec 2019 21:29:24 +0100 Subject: [PATCH 0046/1888] Updated es_ES translation (#36) * Add files via upload * Update dapscoin_es_ES.ts --- src/qt/locale/dapscoin_es_ES.ts | 4885 +++++++++++++++++++++++++++++-- 1 file changed, 4614 insertions(+), 271 deletions(-) diff --git a/src/qt/locale/dapscoin_es_ES.ts b/src/qt/locale/dapscoin_es_ES.ts index 54a683f35a..f670e2fc0d 100644 --- a/src/qt/locale/dapscoin_es_ES.ts +++ b/src/qt/locale/dapscoin_es_ES.ts @@ -3,15 +3,15 @@ AddressBookPage Right-click to edit address or label - Botón derecho para editar dirección o etiqueta + Click derecho para editar dirección o etiqueta Create a new address - Crear una nueva dirección + Crear nueva dirección &New - Nueva + &Nuevo Copy the currently selected address to the system clipboard @@ -19,15 +19,15 @@ &Copy - Copiar + &Copiar Delete the currently selected address from the list - Quitar la dirección seleccionada de la lista + Borrar la dirección seleccionada de la lista &Delete - Eliminar + Borrar Export the data in the current tab to a file @@ -35,7 +35,7 @@ &Export - Exportar + &Exportar C&lose @@ -43,15 +43,15 @@ Choose the address to send coins to - Elija la dirección a la cual enviar moneda + Escoja la dirección a la cual desee enviar las monedas Choose the address to receive coins with - Elija la dirección desde la que recibir moneda + Escoja la dirección en la cual recibirá las monedas C&hoose - Elegir + &Escoger Sending addresses @@ -63,11 +63,11 @@ These are your DAPS addresses for sending payments. Always check the amount and the receiving address before sending coins. - Estas son sus direcciones de DAPS para enviar pagos. Compruebe siempre la cantidad así como la dirección de destino antes de enviar moneda. + Estas son sus direcciones DAPS para realizar pagos. Verifique siempre la cantidad y la dirección de recepción antes de enviar monedas. These are your DAPS addresses for receiving payments. It is recommended to use a new receiving address for each transaction. - Estas son sus direcciones de DAPS para recibir pagos. Es recomendable que use una dirección nueva para cada transacción. + Estas son sus direcciones DAPS para recibir pagos. Es recomendable usar una nueva dirección de recepción para cada transacción. &Copy Address @@ -79,23 +79,23 @@ &Edit - &Editar + Editar Export Address List - Exportar listado de direcciones + Exportar lista de direcciones Comma separated file (*.csv) - Archivo de valores separados por comas (*.csv) + Archivo separado por comas (*.csv) Exporting Failed - La exportación falló + Exportación fallida There was an error trying to save the address list to %1. Please try again. - Se produjo un error al intentar guardar el listado de direcciones a %1. Por favor, inténtelo de nuevo. + Ha habido un error intentando guardar la lista de direcciones %1. Por favor inténtelo de nuevo. @@ -117,39 +117,39 @@ AskPassphraseDialog Passphrase Dialog - Clave de seguridad + Diálogo de contraseña Enter passphrase - Introduzca clave de seguridad + Introduzca la contraseña New passphrase - Nueva clave de seguridad + Nueva contraseña Repeat new passphrase - Repita la clave de seguridad + Repetir nueva contraseña Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - Sirve simplemente para deshabilitar el envío de dinero cuando la cuenta del SO ha sido comprometida. No suministra seguridad real. + Sirve para desactivar el envío de dinero cuando la cuenta del SO está comprometida. No provee de una seguridad real For anonymization and staking only - Para solo anonimizar y staking + Desbloquear solo para anonimización y staking Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. - Introduzca la nueva clave de seguridad para el monedero.<br/>Por favor, use una clave de seguridad de <b>diez o más caracteres aleatorios</b>, u <b> ocho o más palabras. + Escriba la nueva contraseña para la Wallet. <br/>Por favor utilice una contraseña de <b>10 o más caracteres aleatorios</b>, u <b> ocho o más palabras</b> Encrypt wallet - Encriptar monedero + Cifrar monedero This operation needs your wallet passphrase to unlock the wallet. - Esta operación requiere su clave de seguridad para desbloquear el monedero. + Esta operación requiere su contraseña para desbloquear el monedero Unlock wallet @@ -157,109 +157,98 @@ This operation needs your wallet passphrase to decrypt the wallet. - Esta operación requiere su clave de seguridad para desencriptar el monedero. + Esta operación requiere su contraseña para descifrar el monedero Decrypt wallet - Desencriptar monedero + Descifrar monedero Change passphrase - Cambio de clave de seguridad + Cambiar contraseña Enter the old and new passphrase to the wallet. - Introduzca sus claves de seguridad antigua y nueva. + Ingrese la antigua y la nueva contraseña para el monedero Confirm wallet encryption - Confirmar encriptación del monedero + Confirme el cifrado del monedero DAPS will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your DAPSs from being stolen by malware infecting your computer. - DAPS se cerrará ahora para completar el proceso de encriptación. Recuerde que la encriptación no le protege completamente del robo de sus DAPSs frente a malware que infecte su ordenador. + DAPS se cerrará para finalizar el proceso de cifrado. Recuerde que cifrar su monedero no garantiza que sus DAPSs no sean robados mediante malware de su ordenador. Are you sure you wish to encrypt your wallet? - ¿Está seguro de que quiere encriptar su monedero? + ¿Está seguro de que desea cifrar su monedero? Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR DAPS</b>! - Advertencia: si encripta su monedero y pierde su clave de seguridad, ¡<b>PERDERÁ TODOS SUS DAPS</b>! + Atención: Si cifra su monedero y pierde su contraseña, perderá <b> TODOS SUS DAPS</b>! Wallet encrypted - Monedero encriptado + Monedero cifrado IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. - IMPORTNTE: cualquier copia de seguridad que haya efectuado de su fichero de monedero debería ser reemplazada por la que se genere ahora para el archivo de monedero encriptado. Por razones de seguridad, las copias de seguridad previas del archivo de monedero sin encriptar serán inutilizadas tan pronto como comience a ussar el nuevo archivo de monedero encriptado. + IMPORTANTE: Cualquier copia de seguridad anterior que haya realizado de su monedero debe ser reemplazada por la nueva copia de seguridad cifrada. Por razones de seguridad, las copias de seguridad anteriores del monedero sin cifrar pasarán a ser obsoletas tan pronto empiece a utilizar el nuevo monedero cifrado. Wallet encryption failed - La encriptación del monedero ha fallado + El cifrado del monedero ha fallado Wallet encryption failed due to an internal error. Your wallet was not encrypted. - La encriptación del monedero ha fallado por un error interno. Su monedero no ha sido encriptado. + El cifrado del monedero ha fallado debido a un error interno. Su monedero no ha sido cifrado. The supplied passphrases do not match. - Las claves de seguridad suministradas no coinciden. + Las contraseñas introducidas no coinciden. Wallet unlock failed - El desbloqueo del monedero ha fallado + Desbloqueo del monedero fallido The passphrase entered for the wallet decryption was incorrect. - La clave de seguridad introducida para la desencriptación del monedero es incorrecta. + La contraseña introducida para el descifrado del monedero es incorrecta. Wallet decryption failed - La desecriptación del monedero ha fallado. + Descifrado del monedero fallido Wallet passphrase was successfully changed. - La clave de seguridad del monedero se ha cambiado correctamente. + Se cambió la contraseña con éxito. Warning: The Caps Lock key is on! - Advertencia: la tecla Bloq Mayús está activada! - - - - BanTableModel - - IP/Netmask - IP/Netmask - - - Banned Until - Prohibido hasta + Aviso: La tecla Mayúsculas está encendida! Bip38ToolDialog BIP 38 Tool - Utilidad BIP 38 + Herramienta BIP 38 &BIP 38 Encrypt - Encriptar &BIP 38 + &Cifrado BIP 38 - Address: - Dirección: + Enter a Dapscoin Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. + Introduzca la dirección DAPS que querría cifrar usando BIP 38. Introduzca una contraseña en el campo central. Haga clic en cifrar para generar la clave privada cifrada. - Enter a DAPS Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. - Ingrese una dirección DAPS que le gustaría encriptar usando BIP 38. Ingrese una contraseña en el cuadro del medio. Presione encriptar para calcular la clave privada encriptada. + Address: + Dirección: - The DAPS address to encrypt - La dirección DAPS a encriptar + The DAPS address to sign the message with + La dirección DAPS con la que desee firmar el mensaje Choose previously used address @@ -267,63 +256,67 @@ Alt+A - Alt+A + Alt + A Paste address from clipboard - Pegar dirección del portapapeles + Pegar dirección desde el portapapeles Alt+P - Alt+P + Alt + P Passphrase: - Clave de seguridad: + Contraseña: Encrypted Key: - Clave encriptada: + Clave cifrada: Copy the current signature to the system clipboard Copiar la firma actual al portapapeles del sistema - Encrypt the private key for this DAPS address - Cifrar la llave privada para esta dirección DAPS + Sign the message to prove you own this DAPS address + Firme el mensaje para demostrar que eres el propietario de esta dirección DAPS - Reset all fields - Limpiar todos los campos + Encrypt &Key + Cifrar &Clave - The encrypted private key - La llave privada cifrada + Reset all sign message fields + Limpiar todos los campos de firma de mensaje - Decrypt the entered key using the passphrase - Descifrar la llave ingresada usando la frase de contraseña + Clear &All + Limpiar &Todo - Encrypt &Key - Encriptar Clave + &BIP 38 Decrypt + &Descifrado BIP 38 - Clear &All - Limpiar todo + Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. + Introduzca la clave cifrada privada BIP 38. Introduzca la contraseña en el campo central. Haga clic en descifrar clave para generar la clave privada. Después de que la clave sea descifrada, pulsando en 'Importar dirección' añadirá esta clave privada al monedero. - &BIP 38 Decrypt - Desencriptar BIP 38 + The DAPS address the message was signed with + La dirección DAPS con la que se firmó el mensaje - Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. - Ingrese la clave privada cifrada BIP 38. Ingrese la frase de contraseña en el cuadro del medio. Haga clic en Descifrar clave para calcular la clave privada. Después de descifrar la clave, al hacer clic en "Importar dirección" para agregar esta clave privada al monedero. + Verify the message to ensure it was signed with the specified DAPS address + Verifica el mensaje para asegurar que fue firmado con la dirección DAPS especificada Decrypt &Key - Descifrar clave + Descifrar &Clave + + + Reset all verify message fields + Limpiar todos los campos de verificación de mensaje Decrypted Key: @@ -335,7 +328,7 @@ Click "Decrypt Key" to compute key - Haga clic en "Descifrar clave" para calcular la clave + Haga clic en "Descifrar clave" para generar la clave The entered passphrase is invalid. @@ -347,7 +340,7 @@ The entered address is invalid. - La dirección introducida es inválida. + La dirección introducida es inválida Please check the address and try again. @@ -365,268 +358,4618 @@ Private key for the entered address is not available. La clave privada para la dirección introducida no está disponible. - + + Failed to decrypt. + Falló el descifrado + + + Please check the key and passphrase and try again. + Por favor compruebe la clave y la contraseña e inténtelo de nuevo. + + + Data Not Valid. + Datos no válidos. + + + Please try again. + Por favor inténtelo de nuevo. + + + Please wait while key is imported + Por favor espere mientras la clave es importada + + + Key Already Held By Wallet + Llave Ya Presente En El Monedero + + + Error Adding Key To Wallet + Error Añadiendo la Clave en la Wallet + + + Successfully Added Private Key To Wallet + Clave privada añadida a la wallet con éxito + + BitcoinGUI + + Wallet + Wallet + + + Node + Nodo + + + &Overview + &Visión general + + + Show general overview of wallet + Mostrar visión general de la wallet + + + &Send + &Enviar + + + &Receive + &Recibir + + + &Transactions + &Transacciones + + + Browse transaction history + Navegar por el historial de transacciones + + + E&xit + S&alir + + + Quit application + Cerrar aplicación + + + About &Qt + Sobre &Qt + + + Show information about Qt + Mostrar información sobre Qt + + + &Options... + &Opciones... + + + &Show / Hide + &Mostrar / Esconder + + + Show or hide the main Window + Mostrar o esconder la ventana principal + + + &Encrypt Wallet... + &Encriptar wallet... + + + Encrypt the private keys that belong to your wallet + Encriptar las claves privadas que pertenecen a tu wallet + + + &Backup Wallet... + &Copia de seguridad de la wallet... + + + Backup wallet to another location + Copia de seguridad de la wallet a otra ubicación + + + &Change Passphrase... + &Cambiar contraseña... + + + Change the passphrase used for wallet encryption + Cambiar contraseña usada para la encriptación de la wallet + + + &Unlock Wallet... + &Desbloquear wallet... + Unlock wallet Desbloquear monedero - - - BlockExplorer - - - ClientModel - - - CoinControlDialog - (no label) - (sin etiqueta) + &Lock Wallet + &Bloquear Wallet - - - EditAddressDialog - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - MasternodeList - Address - Dirección + Sign &message... + Firmar &mensaje.. - - - MultiSendDialog - Alt+A - Alt+A + &Verify message... + &Verificar mensaje... - Address: - Dirección: + &Information + &Información - (no label) - (sin etiqueta) + Show diagnostic information + Mostrar información de diagnóstico - - - MultisigDialog - - - ObfuscationConfig - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - Address - Dirección + &Debug console + &Consola de depuración - Label - Etiqueta + Open debugging console + Abrir consola de depuración - - - RecentRequestsTableModel - Label - Etiqueta + &Network Monitor + &Monitor de red - (no label) - (sin etiqueta) + Show network monitor + Mostrar monitor de red - - - SendCoinsDialog - Clear &All - Limpiar todo + &Peers list + &Lista de Peers - (no label) - (sin etiqueta) + Show peers info + Mostrar información de peers - - - SendCoinsEntry - Choose previously used address - Escoja una dirección usada previamente + Wallet &Repair + &Reparación de la wallet - Alt+A - Alt+A + Show wallet repair options + Mostrar opciones de reparación de la wallet - Paste address from clipboard - Pegar dirección del portapapeles + Open configuration file + Abrir archivo configuración - Alt+P - Alt+P + Show Automatic &Backups + Mostrar &copias de seguridad automatizadas - - - ShutdownWindow - - - SignVerifyMessageDialog - The DAPS address to sign the message with - Dirección DAPS con la que firmar el mensaje + Show automatically created wallet backups + Mostrar las copias de seguridad creadas automáticamente - Choose previously used address - Escoja una dirección usada previamente + &Sending addresses... + &Direcciones de envío... - Alt+A - Alt+A + Show the list of used sending addresses and labels + Mostrar la lista y etiquetas de direcciones de envío usadas - Paste address from clipboard - Pegar dirección del portapapeles + &Receiving addresses... + &Dirección receptora - Alt+P - Alt+P + Show the list of used receiving addresses and labels + Mostrar la lista de las direcciones y etiquetas usadas - Copy the current signature to the system clipboard - Copiar la firma actual al portapapeles del sistema + Open &URI... + Abrir &URI... - Sign the message to prove you own this DAPS address - Firme el mensaje para probar que Ud. es el propietario de esta dirección DAPS + &Command-line options + &Opciones de linea de comandos + + + Processed %n blocks of transaction history. + Procesado %n bloque del historial de transacciones.Procesados %n bloques del historial de transacciones. - Reset all sign message fields - Limpiar todos los campos de firma de mensaje + Synchronizing additional data: %p% + Sincronizando datos adicionales: %p% - Clear &All - Limpiar todo + &File + &Archivo - The entered address is invalid. - La dirección introducida es inválida. + &Settings + &Ajustes - Please check the address and try again. - Por favor compruebe la dirección e inténtelo de nuevo. + &Tools + &Herramientas - The entered address does not refer to a key. - La dirección introducida no se refiere a ninguna clave. + &Help + &Ayuda - Wallet unlock was cancelled. - El desbloqueo del monedero fue cancelado. + Tabs toolbar + Herramienta de pestañas - Private key for the entered address is not available. - La clave privada para la dirección introducida no está disponible. + DAPS + Núcleo DAPS - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - Address - Dirección + Send coins to a DAPS address + Enviar coins a una dirección DAPS - - - TransactionView - Comma separated file (*.csv) - Archivo de valores separados por comas (*.csv) + Request payments (generates QR codes and dapscoin: URIs) + Solicitud de pago (genera un código QR y URIs) - Label - Etiqueta + &Privacy + &Privacidad - Address - Dirección + &Masternodes + Nodos &Maestros - Exporting Failed - La exportación falló + Browse masternodes + Explorar nodos maestros - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - &Export - &Exportar + &About DAPS + &Sobre el núcleo de DAPS - Export the data in the current tab to a file - Exportar los datos de la pestaña actual a un archivo + Show information about DAPS + Mostrar información sobre el núcleo de DAPS - - + + Modify configuration options for DAPS + Modificar las opciones de configuración de DAPS + + + Sign messages with your DAPS addresses to prove you own them + Firmar mensajes con sus direcciones DAPS para demostrar que le pertenecen + + + Verify messages to ensure they were signed with specified DAPS addresses + Verificar mensajes para asegurar que están firmados con la dirección DAPS especificada + + + &BIP38 tool + &Herramienta BIP38 + + + Encrypt and decrypt private keys using a passphrase + Encriptar y desencriptar las llaves privadas usando una contraseña + + + &MultiSend + &MultiEnvío + + + MultiSend Settings + Configuración de MultiEnvío + + + Open Wallet &Configuration File + Abrir Fichero de &Configuración del Monedero + + + Open &Masternode Configuration File + Abrir Fichero de Configuración de Nodos &Maestros + + + Open Masternode configuration file + Abrir Fichero de Configuración de Nodos Maestros + + + Open a DAPS: URI or payment request + Abrir un DAPS: URI o solicitud de pago + + + &Blockchain explorer + Explorador de &Bloques + + + Block explorer window + Ventana del explorador de bloques + + + Show the DAPS help message to get a list with possible DAPS command-line options + Mostrar la ayuda de DAPS para obtener una lista de posibles opciones en línea de comandos + + + DAPS client + Cliente DAPS + + + %n active connection(s) to DAPS network + %n conexión(es) activa a la red DAPS%n conexion(es) activas a la red DAPS + + + Synchronizing with network... + Sincronizando con la red... + + + Importing blocks from disk... + Importando bloques de disco... + + + Reindexing blocks on disk... + Reindexando bloques en el disco... + + + No block source available... + Fuente de bloques no disponible... + + + Up to date + Actualizado + + + %n hour(s) + %n hora%n horas + + + %n day(s) + %n día%n días + + + %n week(s) + %n semana%n semanas + + + %1 and %2 + %1 y %2 + + + %n year(s) + %n año%n años + + + Catching up... + Recogiendo... + + + Last received block was generated %1 ago. + El último bloque recibido se generó hace %1. + + + Transactions after this will not yet be visible. + Las transacciones posteriores todavía no son visibles. + + + Error + Error + + + Warning + Advertencia + + + Information + Información + + + Sent transaction + Transacción enviada + + + Incoming transaction + Transacción entrante + + + Sent MultiSend transaction + Transacción MultiEnvío emitida + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Fecha: %1 +Cantidad: %2 +Tipo: %3 +Dirección: %4 + + + + Staking is active + MultiSend: %1 + La recompensa de participación está activa +MultiEnvío: %1 + + + Active + Activo + + + Not Active + Inactivo + + + Staking is not active + MultiSend: %1 + Staking inactiva +MultiEnvío: %1 + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + El monedero está <b>encriptado</b> y actualmente <b>desbloqueado</b> + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> for anonimization and staking only + El monedero está <b>encriptado</b> y actualmente <b>desbloqueado</b> sólo para anonimato y prueba de participación. + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + El monedero está <b>encriptado</b> y actualmente <b>bloqueado</b> + + + + BlockExplorer + + Blockchain Explorer + Explorador de Cadena de Bloques + + + Back + Atrás + + + Forward + Adelante + + + Address / Block / Transaction + Dirección / Bloque / Transacción + + + Search + Buscar + + + TextLabel + EtiquetaDeTexto + + + Not all transactions will be shown. To view all transactions you need to set txindex=1 in the configuration file (dapscoin.conf). + No se muestran todas las transacciones. Para ver todas las transacciones introduzca la línea "txindex=1" en el archivo de configuración (dapscoin.conf). + + + + ClientModel + + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5) + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Desconocido: %5) + + + Network Alert + Alerta de Red + + + + CoinControlDialog + + Quantity: + Cantidad: + + + Bytes: + Octetos: + + + Amount: + Cantidad: + + + Priority: + Prioridad: + + + Fee: + Comisión: + + + Coin Selection + Selección de Moneda + + + Dust: + Calderilla: + + + After Fee: + Con Comisión: + + + Change: + Cambio: + + + (un)select all + (de)seleccionar todos + + + toggle lock state + cambiar estado de bloqueo + + + Tree mode + Modo de Árbol + + + List mode + Modo de Lista + + + (1 locked) + (1 bloqueado) + + + Amount + Cantidad + + + Received with label + Recibido con etiqueta + + + Received with address + Recibido con dirección + + + Type + Tipo + + + Date + Fecha + + + Confirmations + Confirmaciones + + + Confirmed + Confirmado + + + Priority + Prioridad + + + Copy address + Copiar dirección + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar código de transacción + + + Lock unspent + Bloquear no gastados + + + Unlock unspent + Desbloquear no gastados + + + Copy quantity + Copiar cantidad + + + Copy fee + Copiar comisión + + + Copy after fee + Copiar después de comisión + + + Copy bytes + Copiar octetos + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar calderilla + + + Copy change + Copiar cambio + + + Please switch to "List mode" to use this function. + Por favor cambie a "Modo de Lista" para utilizar esta función. + + + highest + la más alta + + + higher + más alta + + + high + alta + + + medium-high + medio-alta + + + Can vary +/- %1 duff(s) per input. + Puede variar +/- %1 duff(s) por entrada. + + + medium + media + + + low-medium + baja-media + + + low + baja + + + lower + muy baja + + + lowest + la más baja + + + (%1 locked) + (%1 bloqueado) + + + none + ninguno + + + yes + + + + no + no + + + This label turns red, if the transaction size is greater than 1000 bytes. + Esta etiqueta se pone roja, si el tamaño de la transacción es mayor de 1000 bytes. + + + This means a fee of at least %1 per kB is required. + Esto significa que se requiere una comisión de al menos %1 por kB. + + + Can vary +/- 1 byte per input. + Puede variar +/- 1 byte por entrada. + + + Transactions with higher priority are more likely to get included into a block. + Las transacciones con alta prioridad tienen más probabilidades de ser incluidas en un bloque. + + + This label turns red, if the priority is smaller than "medium". + Esta etiqueta se vuelve roja, si la prioridad es inferior a "media". + + + This label turns red, if any recipient receives an amount smaller than %1. + Esta etiqueta se vuelve roja, si algún destinatario recibe una cantidad menor que %1. + + + (no label) + (sin etiqueta) + + + change from %1 (%2) + cambio desde %1 (%2) + + + (change) + (cambio) + + + + EditAddressDialog + + Edit Address + Editar Dirección + + + &Label + &Etiqueta + + + The label associated with this address list entry + La etiqueta asociada con esta entrada de la libreta de direcciones + + + &Address + &Dirección + + + The address associated with this address list entry. This can only be modified for sending addresses. + La dirección asociada con esta entrada de la libreta de direcciones. Ésta sólo puede ser modificada en las direcciones de envío. + + + New receiving address + Nueva dirección de cobro + + + New sending address + Nueva dirección de envío + + + Edit receiving address + Editar dirección de cobro + + + Edit sending address + Editar dirección de envío + + + The entered address "%1" is not a valid DAPS address. + La dirección introducida "%1" no es una dirección DAPS válida. + + + The entered address "%1" is already in the address book. + La dirección introducida "%1" ya está en la libreta de direcciones. + + + Could not unlock wallet. + No se pudo desbloquear el monedero. + + + New key generation failed. + La generación de llave nueva falló. + + + + FreespaceChecker + + A new data directory will be created. + Se creará una nueva carpeta de datos. + + + name + nombre + + + Directory already exists. Add %1 if you intend to create a new directory here. + El directorio ya existe, Añada %1 si pretende crear una nueva carpeta aquí. + + + Path already exists, and is not a directory. + La ruta ya existe, y no es una carpeta. + + + Cannot create data directory here. + No se puede crear un directorio de datos aquí. + + + + HelpMessageDialog + + version + versión + + + DAPS + Núcleo DAPS + + + (%1-bit) + (%1-bit) + + + About DAPS + Acerca de DAPS + + + Command-line options + Opciones de línea de comandos + + + Usage: + Uso: + + + command-line options + opciones de línea de comandos + + + UI Options: + Opciones de interfaz de usuario: + + + Choose data directory on startup (default: %u) + Elija la carpeta de datos al arrancar (por defecto: %u) + + + Show splash screen on startup (default: %u) + Mostrar pantalla de bienvenida al arrancar (por defecto: %u) + + + Set language, for example "de_DE" (default: system locale) + Seleccionar el idioma, por ejemplo "es_ES" (por defecto: idioma del sistema) + + + Start minimized + Arrancar minimizado + + + Set SSL root certificates for payment request (default: -system-) + Elegir certificado raíz SSL para solicitud de pago (por defecto: -sistema-) + + + + Intro + + Welcome + Bienvenido/a + + + Welcome to DAPS. + Bienvenido/a a DAPS. + + + As this is the first time the program is launched, you can choose where DAPS will store its data. + Al ser la primera vez que se inicia el programa, usted puede elegir dónde guardará DAPS sus datos. + + + DAPS will download and store a copy of the DAPS block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + DAPS descargará y guardará una copia de la cadena de bloques DAPS. Por lo menos %1GB de datos serán guardados en esta carpeta, y crecerá con el tiempo. El monedero también se guardará en esta carpeta. + + + Use the default data directory + Usar la carpeta de datos por defecto + + + Use a custom data directory: + Usar una carpeta de datos personalizada: + + + DAPS + Núcleo DAPS + + + Error: Specified data directory "%1" cannot be created. + Error: La carpeta de datos especificada "%1" no pudo ser creada. + + + Error + Error + + + %1 GB of free space available + %1 GB de espacio libre en disco + + + (of %1 GB needed) + (de %1 GB necesarios) + + + + MasternodeList + + Form + Formulario + + + My Masternodes + Mis Nodos Maestros + + + Note: Status of your masternodes in local wallet can potentially be slightly incorrect.<br />Always wait for wallet to sync additional data and then double check from another node<br />if your node should be running but you still see "MISSING" in "Status" field. + Nota: El estado de tus nodos maestros en el monedero local podría ser incorrecto.<br />Siempre espere a que el monedero sincronice la información adicional y entonces compruébelo desde otro nodo<br />si su nodo debería estar funcionando pero aún vee el mensaje "FALTA" en el campo "Estado". + + + Alias + Apodo + + + Address + Dirección + + + Protocol + Protocolo + + + Status + Estado + + + Active + Activo + + + Last Seen (UTC) + Visto por última vez (UTC) + + + Pubkey + Llave pública + + + S&tart alias + &Iniciar apodo + + + Start &all + Iniciar &todo + + + Start &MISSING + Iniciar &FALTAN + + + &Update status + Estado de &Actualización + + + Status will be updated automatically in (sec): + El estado se actualizará automáticamente en (seg): + + + 0 + 0 + + + Start alias + Iniciar apodo + + + Confirm masternode start + Confirmar inicio del nodo maestro + + + Are you sure you want to start masternode %1? + ¿Está seguro de que quiere arrancar el nodo maestro %1? + + + Confirm all masternodes start + Confirmar el arranque de todos los nodos maestros + + + Are you sure you want to start ALL masternodes? + ¿Estás seguro de querer arrancar TODOS los nodos maestros? + + + Command is not available right now + El comando no está disponible en este momento + + + You can't use this command until masternode list is synced + No se puede utilizar este comando hasta que la lista de nodos maestros esté sincronizada + + + Confirm missing masternodes start + Confirmar arranque de nodos maestros no encontrados + + + Are you sure you want to start MISSING masternodes? + ¿Estás seguro de querer arrancar los nodos maestros NO ENCONTRADOS? + + + + MultiSendDialog + + MultiSend + MultiEnvío + + + Enter whole numbers 1 - 100 + Introduzca números enteros 1 - 100 + + + Enter % to Give (1-100) + Introduzca % a Dar (1-100) + + + Enter Address to Send to + Introduzca Dirección a la cual Enviar + + + MultiSend allows you to automatically send up to 100% of your stake or masternode reward to a list of other DAPS addresses after it matures. +To Add: enter percentage to give and DAPS address to add to the MultiSend vector. +To Delete: Enter address to delete and press delete. +MultiSend will not be activated unless you have clicked Activate + MultiEnvío le permite enviar automáticamente hasta el 100% de recompensa de participación o de nodo maestro a una lista de otras direcciones DAPS después de su maduración. +Para Añadir: introduzca porcentaje a enviar y las direcciones DAPS a añadir al vector MultiEnvío. +Para Eliminar: Introduzca la dirección a eliminar y pulse la tecla delete. +MultiEnvío no se activará a menos que haga usted click en Activar + + + Add to MultiSend Vector + Añadir al vector MultiSend + + + Add + Añadir + + + Deactivate MultiSend + Desactivar MultiEnvío + + + Deactivate + Desactivar + + + Choose an address from the address book + Seleccione una dirección de la libreta de direcciones + + + Alt+A + Alt + A + + + Percentage of stake to send + Porcentaje de capital a enviar + + + Percentage: + Porcentaje: + + + Address to send portion of stake to + Dirección a enviar porción de la recompensa + + + Address: + Dirección: + + + Delete Address From MultiSend Vector + Borrar Dirección De Vector MultiEnvío + + + Delete + Borrar + + + Activate MultiSend + Activar MultiEnvío + + + Activate + Activar + + + View MultiSend Vector + Ver Vector MultiEnvío + + + View MultiSend + Ver MultiEnvío + + + Send For Stakes + Enviar Para Participaciones + + + Send For Masternode Rewards + Enviar Para Recomensas De Nodos Maestros + + + The entered address: + + La dirección introducida: + + + + is invalid. +Please check the address and try again. + es inválida. +Por favor compruebe la dirección e inténtelo de nuevo. + + + The total amount of your MultiSend vector is over 100% of your stake reward + + La cantidad total de su vector MultiEnvío es superior al 100% de su recompensa + + + + Please Enter 1 - 100 for percent. + Por favor Introduzca 1 - 100 por ciento. + + + MultiSend Vector + + Vector MultiEnvío + + + + Removed + Borrado + + + Could not locate address + + No se pudo localizar la dirección + + + + + MultisigDialog + + Status: + Estado: + + + Quantity Selected: + Cantidad Seleccionada: + + + 0 + 0 + + + Amount: + Cantidad: + + + + ObfuscationConfig + + Configure Obfuscation + Configurar Ofuscación + + + Basic Privacy + Privacidad Básica + + + High Privacy + Alta Privacidad + + + Maximum Privacy + Máxima Privacidad + + + Please select a privacy level. + Por favor selecciones un nivel de privacidad. + + + Use 2 separate masternodes to mix funds up to 1000000 DAPS + Use 2 nodos maestros diferentes para mezclar los fondos hasta los 1000000 DAPS + + + Use 8 separate masternodes to mix funds up to 1000000 DAPS + Use 8 nodos maestros diferentes para mezclar fondos hasta los 1000000 DAPS + + + Use 16 separate masternodes + Use 16 nodos maestros diferentes + + + This option is the quickest and will cost about ~0.025 DAPS to anonymize 10000 DAPS + Esta opción es la más rápida y costará alrededor de ~0.025 DAPS para anonimizar 10000 DAPS + + + This option is moderately fast and will cost about 0.05 DAPS to anonymize 10000 DAPS + Esta opción es moderadamente rápida y costará cerca de 0.05 DAPS para anonimizar 10000 DAPS. + + + This is the slowest and most secure option. Using maximum anonymity will cost + Esta es la opción más lenta pero más segura. Usar el máximo anonimato costará + + + 0.1 DAPS per 10000 DAPS you anonymize. + 0.1 DAPS por 10000 DAPS que anonimizas. + + + Obfuscation Configuration + Configuración de Ofuscación + + + Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening DAPS's configuration screen. + La Ofuscación se configuró correctamente en modo básico (%1 y 2 rondas). Puedes cambiar esto en cualquier momento accediendo a la ventana de configuración de DAPS. + + + Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening DAPS's configuration screen. + La Ofuscación se activó correctamente en modo alto (%1 y 8 rondas). Usted puede cambiar esto en cualquier momento abriendo la ventana de configuración de DAPS. + + + Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening DAPS's configuration screen. + La Ofuscación se activó correctamente en su grado máximo (%1 y 16 rondas). Usted puede cambiar ésto en cualquier momento en la ventana de configuración de DAPS. + + + + OpenURIDialog + + Open URI + Abrir URI + + + Open payment request from URI or file + Abrir solicitud de pago de URI o archivo + + + URI: + URI: + + + Select payment request file + Seleccione el fichero que contiene la solicitud de pago + + + Select payment request file to open + Seleccione el fichero de solicitud de pago que desea abrir + + + + OptionsDialog + + Options + Opciones + + + &Main + &Principal + + + Size of &database cache + Tamaño del caché de &base de datos + + + MB + MB + + + Number of script &verification threads + Número de procesos de &verificación de scripts + + + (0 = auto, <0 = leave that many cores free) + (0 = auto, <0 = dejar libres tal número de cores) + + + W&allet + &Monedero + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + Si deselecciona el gasto de cambio no confirmado, las entradas de una transacción<br/>no podrán ser usadas hasta que esa transacción tenga al menos una confirmación.<br/>Esto también afecta a cómo se calcula su balance actual. + + + Automatically open the DAPS client port on the router. This only works when your router supports UPnP and it is enabled. + Abrir automáticamente el puerto del cliente DAPS en el enrutador. Ésto sólo funciona si su enrutador soporta UPnP y esta función está activada. + + + Accept connections from outside + Aceptar conexiones del exterior + + + Allow incoming connections + Permitir conexiones entrantes + + + &Connect through SOCKS5 proxy (default proxy): + &Conectar a través de un proxy SOCKS5 (proxy por defecto): + + + Expert + Experto + + + Automatically start DAPS after logging in to the system. + Arrancar DAPS automáticamente después de identificarse en Windows. + + + &Start DAPS on system login + &Arrancar DAPS al inicio del sistema + + + Whether to show coin control features or not. + Mostrar las características de control de monedas individuales, o no + + + Enable coin &control features + Activar funciones de control de &monedas + + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + Mostrar pestaña adicional listando todos sus nodos maestros en la primera sub-pestaña<br/>y todos los nodos maestros de la red en la segunda sub-pestaña. + + + Show Masternodes Tab + Mostrar la pestaña de Nodos Maestros + + + &Spend unconfirmed change + &Gastar cambio no confirmado + + + &Network + &Red + + + The user interface language can be set here. This setting will take effect after restarting DAPS. + El idioma de interface de usuario puede seleccionarse aquí. Este ajuste tomará efecto después de reiniciar DAPS. + + + Language missing or translation incomplete? Help contributing translations here: +https://www.transifex.com/dapscoin-project/dapscoin-project-translations + ¿Falta su lenguaje o la traducción está incompleta? Contribuya con las traducciones aquí: +https://www.transifex.com/dapscoin-project/dapscoin-project-translations + + + Map port using &UPnP + Mapear un puerto utilizando &UPnP + + + Connect to the DAPS network through a SOCKS5 proxy. + Conectar a la red DAPS mediante un proxy SOCKS5. + + + Proxy &IP: + &IP del proxy: + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + Dirección IP del proxy (p.e. IPv4: 127.0.0.1 / IPv6: ::1) + + + &Port: + &Puerto: + + + Port of the proxy (e.g. 9050) + Puerto del proxy (p.e. 9050) + + + &Window + &Ventana + + + Show only a tray icon after minimizing the window. + Mostrar sólo un icono en la bandeja al minimizar la ventana. + + + &Minimize to the tray instead of the taskbar + &Minimizar a la bandeja en lugar de a la barra de tareas + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimizar en lugar de cerrar la aplicación cuando se cierra la ventana. Cuando active esta opción, tendrá que cerrar la aplicación seleccionando Salir desde el menú. + + + M&inimize on close + M&inimizar al cerrar + + + &Display + &Mostrar + + + User Interface &language: + &Idioma de la interface de usuario: + + + User Interface Theme: + Tema de la Interface de Usuario: + + + &Unit to show amounts in: + &Unidad para mostrar cantidades: + + + Choose the default subdivision unit to show in the interface and when sending coins. + Seleccionar la subdivisión a mostrar por defecto en la interface y al enviar monedas. + + + Decimal digits + Dígitos decimales + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Direcciones web de terceras partes (p.e. un explorador de bloques) que aparecen en la pestaña de transacciones como objetos contextuales del menú. %s en la dirección web es reemplazada por el identificador de la transacción. Múltiples direcciones web están separadas por una barra vertical (|). + + + Third party transaction URLs + Direcciones web de transacciones de terceras partes + + + Active command-line options that override above options: + Opciones de línea de comando activas que anulan las opciones anteriores: + + + Reset all client options to default. + Resetear todas las opciones de cliente a su valor por defecto. + + + &Reset Options + Opciones de &Reset + + + &OK + &OK + + + &Cancel + &Cancelar + + + I don't care + No me preocupa + + + default + por defecto + + + none + ninguno + + + Confirm options reset + Confirmar reinicio de las opciones + + + Client restart required to activate changes. + Se requiere un reinicio del cliente para activar los cambios. + + + Client will be shutdown, do you want to proceed? + El cliente se cerrará, ¿procedemos? + + + This change would require a client restart. + Este cambio requerirá un reinicio del cliente. + + + The supplied proxy address is invalid. + La dirección proxy indicada es inválida. + + + + OverviewPage + + Form + Formulario + + + DAPS Balances + Balances DAPS + + + Available: + Disponible: + + + Your current spendable balance + Tu balance actualmente disponible + + + Pending: + Pendiente: + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + Total de transacciones que aún deben ser confirmadas, y todavía no cuentan en el balance disponible + + + Immature: + Inmaduro: + + + Staked or masternode rewards that has not yet matured + Recompensa de participación o de nodo maestro que aún no ha madurado + + + The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet. + La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red DAPS después de establecer una conexión, pero este proceso aún no se ha completado. + + + Unconfirmed transactions to watch-only addresses + Transacciones no confirmadas a direcciones sólo de lectura + + + Staked or masternode rewards in watch-only addresses that has not yet matured + Recompensa de participación o de nodo maestro en direcciones de sólo lectura que todavía no han madurado + + + Total: + Total: + + + Your current total balance + Su balance total actual + + + Current total balance in watch-only addresses + Balance total actual en direcciones de sólo lectura + + + Watch-only: + Sólo-lectura: + + + Your current balance in watch-only addresses + Su balance actual en direcciones de sólo lectura + + + Spendable: + Disponible: + + + DAPS: + DAPS: + + + 0 % + 0 % + + + 0.000 000 00 DAPS + 0.000 000 00 DAPS + + + Recent transactions + Transacciones recientes + + + out of sync + desincronizado + + + + PaymentServer + + Payment request error + Error en la solicitud de pago + + + URI handling + Manejo de URI + + + Payment request fetch URL is invalid: %1 + Solicitud de pago via web inválida: %1 + + + Payment request file handling + Manejo del fichero de solicitud de pago + + + Invalid payment address %1 + Dirección de pago inválida %1 + + + Cannot start dapscoin: click-to-pay handler + No se puede iniciar dapscoin: módulo click-to-pay + + + URI cannot be parsed! This can be caused by an invalid DAPS address or malformed URI parameters. + ¡El identificador de la dirección no puede ser analizado! Esto puede ser causado por una dirección DAPS inválida o parámetros del identificador malformados. + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + El fichero de solicitud de pago no se pudo leer! Esto puede estar causado por una solicitud de pago inválida. + + + Payment request rejected + Solicitud de pago rechazada + + + Payment request network doesn't match client network. + La solicitud de pago no coincide con la red del cliente. + + + Payment request has expired. + La solicitud de pago ha expirado. + + + Payment request is not initialized. + La solicitud de pago no está inicializada. + + + Unverified payment requests to custom payment scripts are unsupported. + Solicitudes de pago no verificadas a scripts de pago personalizado no están soportadas. + + + Requested payment amount of %1 is too small (considered dust). + La cantidad de pago solicitada de %1 es demasiado pequeña (se considera calderilla). + + + Refund from %1 + Reembolso desde %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + La solicitud de pago %1 es demasiado larga (%2 bytes, permitidos %3 bytes). + + + Payment request DoS protection + Protección de Denegación de Servicio para la solicitud de pago + + + Error communicating with %1: %2 + Error de comunicación con %1: %2 + + + Payment request cannot be parsed! + ¡La solicitud de pago no se pudo procesar! + + + Bad response from server %1 + Respuesta inadecuada del servidor %1 + + + Network request error + Error de Red + + + Payment acknowledged + Pago confirmado + + + + PeerTableModel + + Address/Hostname + Dirección/Nombre Host + + + Version + Versión + + + Ping Time + Intervalo de Ping + + + + QObject + + Amount + Cantidad + + + Enter a DAPS address (e.g. %1) + Introduzca una dirección DAPS (p.e. %1) + + + %1 d + %1 d + + + %1 h + %1 h + + + %1 m + %1 m + + + %1 s + %1 s + + + NETWORK + RED + + + BLOOM + BLOOM + + + UNKNOWN + DESCONOCIDO + + + None + Ninguno + + + N/A + N/A + + + %1 ms + %1 ms + + + + QRImageWidget + + &Save Image... + &Guardar Imagen... + + + &Copy Image + &Copiar Imagen + + + Save QR Code + Guardar Código QR + + + PNG Image (*.png) + Imagen PNG (*.png) + + + + RPCConsole + + Tools window + Ventana de herramientas + + + &Information + &Información + + + General + General + + + Name + Nombre + + + Client name + Nombre de cliente + + + N/A + N/A + + + Number of connections + Número de conexiones + + + &Open + &Abrir + + + Startup time + Tiempo de funcionamiento + + + Network + Red + + + Last block time + Momento del último bloque + + + Debug log file + Fichero de depuración + + + Using OpenSSL version + Usando la versión OpenSSL + + + Build date + Fecha de compilación + + + Current number of blocks + Número actual de bloques + + + Client version + Versión del cliente + + + Using BerkeleyDB version + Usando BerkeleyDB versión + + + Block chain + Cadena de bloques + + + Open the DAPS debug log file from the current data directory. This can take a few seconds for large log files. + Abrir el fichero de depuración DAPS en el directorio actual de datos. Esto puede llevar unos segundos para ficheros de depuración grandes. + + + Number of Masternodes + Número de Nodos Maestros + + + &Console + &Consola + + + Clear console + Limpiar consola + + + &Network Traffic + &Tráfico de Red + + + &Clear + &Limpiar + + + Totals + Totales + + + Received + Recibidos + + + Sent + Enviados + + + &Peers + &Nodos conectados + + + Select a peer to view detailed information. + Seleccione un nodo conectado para ver información detallada. + + + Direction + Dirección + + + Protocol + Protocolo + + + Version + Versión + + + Services + Servicios + + + Starting Height + Altura de inicio + + + Sync Height + Altura de sincronía + + + Ban Score + Puntuación de Baneo + + + Connection Time + Tiempo de Conexión + + + Last Send + Último Envío + + + Last Receive + Última Recepción + + + Bytes Sent + Bytes Enviados + + + Bytes Received + Bytes Recibidos + + + Ping Time + Intervalo de Ping + + + &Wallet Repair + Reparar &Monedero + + + Wallet In Use: + Monedero En Uso: + + + Salvage wallet + Salvar monedero + + + Attempt to recover private keys from a corrupt wallet.dat. + Intentar recuperar las llaves privadas de un archivo wallet.dat corrupto. + + + Rescan blockchain files + Reescanear ficheros de cadena de bloques + + + Rescan the block chain for missing wallet transactions. + Reescanear la cadena de bloques buscando transacciones que faltan en el monedero. + + + Recover transactions 1 + Recuperar transacciones 1 + + + Recover transactions from blockchain (keep meta-data, e.g. account owner). + Recuperar transacciones desde la cadena de bloques (mantener meta-datos, p.e. propietario de la cuenta,etc). + + + Recover transactions 2 + Recuperar transacciones 2 + + + Recover transactions from blockchain (drop meta-data). + Recuperar transacciones desde la cadena de bloques (ignorar meta-datos). + + + Upgrade wallet format + Actualizar formato del monedero + + + Rebuild block chain index from current blk000??.dat files. + Reconstruir el índice de la cadena de bloques desde los archivos blk000??.dat actuales. + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. + Los botones de más abajo reiniciarán el programa con comandos especiales para reparar el monedero, solucionar problemas con cadenas de bloques corruptas o buscar transacciones obsoletas o perdidas + + + Wallet repair options. + Opciones de reparación de monedero. + + + Upgrade wallet to latest format on startup. (Note: this is NOT an update of the wallet itself!) + Actualizar el monedero al último formato en el arranque. (Nota: esto NO es una actualización del monedero como tal!) + + + Rebuild index + Reconstruir índice + + + In: + Dentro: + + + Out: + Fuera: + + + Welcome to the DAPS RPC console. + Bienvenido a la consola RPC de DAPS. + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Use las teclas arriba y abajo para navegar por la historia, y <b>Ctrl-L</b> para limpiar la pantalla. + + + Type <b>help</b> for an overview of available commands. + Escriba <b>help</b> para ver una lista de posibles comandos. + + + %1 B + %1 B + + + %1 KB + %1 KB + + + %1 MB + %1 MB + + + %1 GB + %1 GB + + + via %1 + via %1 + + + never + nunca + + + Inbound + Entrantes + + + Outbound + Salientes + + + Unknown + Desconocido + + + Fetching... + Descargando... + + + + ReceiveCoinsDialog + + Reuse one of the previously used receiving addresses.<br>Reusing addresses has security and privacy issues.<br>Do not use this unless re-generating a payment request made before. + Reutilizar una de las direcciones de recepción anteriores.<br>Reutilizar direcciones de recepción tiene implicaciones de seguridad y privacidad.<br>No la utilizar al menos que esté re-generando una solicitud de pago anterior. + + + R&euse an existing receiving address (not recommended) + R&eutilizar una dirección de recepción existente (no recomendado) + + + &Message: + &Mensaje: + + + An optional label to associate with the new receiving address. + Una etiqueta opcional a asociar con la nueva dirección de recepción. + + + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the DAPS network. + Un mensaje opcional a adjuntar a la solicitud de pago, que será mostrado cuando se abra la solicitud. Nota: El mensaje no se envía junto al pago por la red DAPS. + + + An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the DAPS network. + Un mensaje opcional a adjuntar a la solicitud de pago, que será mostrado cuando se abra la solicitud. <br>Nota: El mensaje no se envía junto al pago por la red DAPS. + + + Use this form to request payments. All fields are <b>optional</b>. + Use este formulario para solicitar pagos. Todos los campos <b>opcionales</b>. + + + &Label: + &Etiqueta: + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + Una cantidad opcional a solicitar. Deje esto vacío o en cero para no pedir una cantidad específica. + + + &Amount: + &Cantidad: + + + &Request payment + &Solicitud de pago + + + Clear all fields of the form. + Limpiar todos los campos del formulario. + + + Clear + Limpiar + + + Requested payments history + Historial de peticiones de pago + + + Show the selected request (does the same as double clicking an entry) + Mostrar la solicitud seleccionada (lo mismo que hacer doble click en una entrada) + + + Show + Mostrar + + + Remove the selected entries from the list + Quitar las entradas seleccionadas de la lista + + + Remove + Quitar + + + Copy label + Copiar etiqueta + + + Copy message + Copiar mensaje + + + Copy amount + Copiar cantidad + + + + ReceiveRequestDialog + + QR Code + Código QR + + + Copy &URI + Copiar &Identificador + + + Copy &Address + Copiar &Dirección + + + &Save Image... + &Guardar Imagen... + + + Request payment to %1 + Solicitar pago a %1 + + + Payment information + Información de pago + + + URI + URI (identificador de recurso) + + + Address + Dirección + + + Amount + Cantidad + + + Label + Etiqueta + + + Message + Mensaje + + + Resulting URI too long, try to reduce the text for label / message. + El identificador de recurso es demasiado largo, intente reducir el texto para la etiqueta / mensaje. + + + Error encoding URI into QR Code. + Error codificando el identificador de recurso dentro del código QR. + + + + RecentRequestsTableModel + + Date + Fecha + + + Label + Etiqueta + + + Message + Mensaje + + + Amount + Cantidad + + + (no label) + (sin etiqueta) + + + (no message) + (no hay mensajes) + + + (no amount) + (sin cantidad) + + + + SendCoinsDialog + + Send Coins + Enviar Monedas + + + Coin Control Features + Funciones de Control de Monedas + + + Insufficient funds! + ¡Fondos insuficientes! + + + Quantity: + Cantidad: + + + Bytes: + Octetos: + + + Amount: + Cantidad: + + + Priority: + Prioridad: + + + medium + media + + + Fee: + Comisión: + + + Dust: + Calderilla: + + + no + no + + + After Fee: + Con Comisión: + + + Change: + Cambio: + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Si esto está activado, pero la dirección de cambio está vacía o es inválida, el cambio será mandado a una nueva dirección generada. + + + Custom change address + Dirección de cambio personalizada + + + Split UTXO + Partir UTXO + + + # of outputs + # de salidas + + + UTXO Size: + Tamaño de UTXO: + + + 0 DAPS + 0 DAPS + + + Transaction Fee: + Comisión de transacción: + + + Choose... + Elegir... + + + collapse fee-settings + minimizar los ajustes de comisión + + + Minimize + Minimizar + + + per kilobyte + por kilobyte + + + total at least + total por lo menos + + + (read the tooltip) + (leer el consejo) + + + Custom: + Personalizado: + + + (Smart fee not initialized yet. This usually takes a few blocks...) + (La comisión automática no se ha inicializado todavía. Esto normalmente necesita unos cuantos bloques...) + + + Confirmation time: + Tiempo de confirmación: + + + Open Coin Control... + Abrir Control de Monedas... + + + Coins automatically selected + Monedas seleccionadas automáticamente + + + If the custom fee is set to 1000 uDAPSs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uDAPSs in fee,<br />while "at least" pays 1000 uDAPSs. For transactions bigger than a kilobyte both pay by kilobyte. + Si la comisión personalizada se fija en 1000 uDAPSs y la transacción necesita sólo 250 bytes, entonces la opción "por kilobyte" sólo pagará 250 uDAPSs de comisión,<br/>mientras "por lo menos" pagará 1000 uDAPSs. Para transacciones que midan más de un kilobyte ambas pagan por kilobyte. + + + If the custom fee is set to 1000 uDAPSs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uDAPSs in fee,<br />while "total at least" pays 1000 uDAPSs. For transactions bigger than a kilobyte both pay by kilobyte. + Si la comisión personalizada se fija en 1000 uDAPSs y la transacción necesita sólo 250 bytes, entonces la opción "por kilobyte" sólo pagará 250 uDAPSs de comisión,<br/>mientras "por lo menos" pagará 1000 uDAPSs. Para transacciones que midan más de un kilobyte ambas pagan por kilobyte. + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for DAPS transactions than the network can process. + Pagar sólo la comisión mínima está bien mientras haya menos volumen de transacciones que espacio en los bloques.<br/>Pero tenga en cuenta que esto podría acabar en una transacción que nunca se confirme si hay más demanda de transacciones DAPS de las que la red puede procesar. + + + normal + normal + + + fast + rápido + + + Recommended + Recomendada + + + Send as zero-fee transaction if possible + Enviar como transacción sin comisiones si es posible + + + (confirmation may take longer) + (la primera confirmación puede tardar más) + + + Confirm the send action + Confirmar la acción de enviar + + + S&end + &Enviar + + + Clear all fields of the form. + Limpiar todos los campos del formulario. + + + Clear &All + Limpiar &Todo + + + Send to multiple recipients at once + Enviar a varios destinatarios al mismo tiempo + + + Add &Recipient + Añadir Destinata&rio + + + Anonymized DAPS + DAPS anonimizados + + + Balance: + Saldo: + + + Copy quantity + Copiar cantidad + + + Copy amount + Copiar cantidad + + + Copy fee + Copiar comisión + + + Copy after fee + Copiar después de comisión + + + Copy bytes + Copiar octetos + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar calderilla + + + Copy change + Copiar cambio + + + The split block tool does not work when sending to outside addresses. Try again. + La herramienta de separación de bloques no funciona cuando se envía a direcciones exteriores. Inténtelo otra vez. + + + The split block tool does not work with multiple addresses. Try again. + La herramienta de división de bloques no funciona con varias direcciones. Inténtelo otra vez. + + + using + usando + + + anonymous funds + fondos anónimos + + + Warning: Invalid DAPS address + Advertencia: Direcciones DAPS inválidas + + + any available funds (not recommended) + cualquier fondo disponible (no recomendado) + + + %1 to %2 + %1 a %2 + + + Are you sure you want to send? + ¿Está seguro de querer enviar? + + + are added as transaction fee + son añadidos como comisión de transacción + + + Total Amount = <b>%1</b><br />= %2 + Cantidad total = <b>%1</b><br />= %2 + + + Confirm send coins + Confirmar enviar monedas + + + A fee %1 times higher than %2 per kB is considered an insanely high fee. + Una comisión %1 veces más alta que %2 por kB se considera exageradamente alta. + + + Estimated to begin confirmation within %n block(s). + Estimamos que la confirmación empezará dentro de %n bloque.Estimamos que la confirmación empezará dentro de %n bloques. + + + The recipient address is not valid, please recheck. + La dirección de destino no es válida, por favor compruébelo de nuevo. + + + split into %1 outputs using the UTXO splitter. + separado en %1 salidas usando el separador UTXO. + + + <b>(%1 of %2 entries displayed)</b> + <b>(%1 de %2 entradas mostradas)</b> + + + The amount to pay must be larger than 0. + La cantidad a pagar debe ser mayor de 0. + + + The amount exceeds your balance. + La cantidad excede su saldo. + + + The total exceeds your balance when the %1 transaction fee is included. + El total excede su saldo si contamos la comisión de %1 . + + + Duplicate address found, can only send to each address once per send operation. + Hemos encontrado una dirección duplicada, sólo podemos enviar a cada dirección una vez por envío. + + + Transaction creation failed! + ¡Fallo al crear la transacción! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + ¡La transacción fue rechazada! Esto puede ocurrir si alguna de sus monedas ya se gastó con anterioridad, por ejemplo, si estuvo usted usando una copia de su monedero wallet.dat y gastó allí monedas pero no las marcó como gastadas aquí. + + + Error: The wallet was unlocked only to anonymize coins. + Error: El monedero se desbloqueó sólo para anonimizar monedas. + + + Error: The wallet was unlocked only to anonymize coins. Unlock canceled. + Error: El monedero ya fue desbloqueado para anonimizar monedas. El desbloqueo total se ha cancelado. + + + Pay only the minimum fee of %1 + Pagar sólo la comisión mínima de %1 + + + Warning: Unknown change address + Advertencia: Dirección de cambio desconocida + + + (no label) + (sin etiqueta) + + + + SendCoinsEntry + + This is a normal payment. + Esto es un pago normal. + + + Pay &To: + Pagar &A: + + + The DAPS address to send the payment to + La dirección DAPS a la cual enviar el pago + + + Choose previously used address + Escoja una dirección usada previamente + + + Alt+A + Alt + A + + + Paste address from clipboard + Pegar dirección desde el portapapeles + + + Alt+P + Alt + P + + + Remove this entry + Quitar esta entrada + + + &Label: + &Etiqueta: + + + Enter a label for this address to add it to the list of used addresses + Introduzca una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas + + + A&mount: + Ca&ntidad: + + + Message: + Mensaje: + + + A message that was attached to the DAPS: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the DAPS network. + Un mensaje adjunto al DAPS: En recurso web especificado será guardado junto a la transacción para su referencia. Nota: Este mensaje no se enviará por la red DAPS. + + + This is an unverified payment request. + Esta es una solicitud de pago no verificada. + + + Pay To: + Pagar A: + + + Memo: + Texto libre: + + + This is a verified payment request. + Esta es una solicitud de pago verificada. + + + Enter a label for this address to add it to your address book + Introduzca una etiqueta para esta dirección para añadirla a su libreta de direcciones + + + + ShutdownWindow + + DAPS is shutting down... + El programa DAPS se está cerrando... + + + Do not shut down the computer until this window disappears. + No apague el equipo hasta que esta ventana desaparezca. + + + + SignVerifyMessageDialog + + Signatures - Sign / Verify a Message + Firmas - Firmar / Verificar un Mensaje + + + &Sign Message + &Firmar Mensaje + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Usted puede firmar mensajes con su dirección para probar que son auténticos. Tenga cuidado con firmar algo corto o vago como "hola", pues los ataques de phising pueden engañarle para que firme su identidad para ellos. Sólo firme textos detallados con los que esté de acuerdo. + + + The DAPS address to sign the message with + La dirección DAPS con la que desee firmar el mensaje + + + Choose previously used address + Escoja una dirección usada previamente + + + Alt+A + Alt + A + + + Paste address from clipboard + Pegar dirección desde el portapapeles + + + Alt+P + Alt + P + + + Enter the message you want to sign here + Introduzca el mensaje que quiere firmar aquí + + + Signature + Firma + + + Copy the current signature to the system clipboard + Copiar la firma actual al portapapeles del sistema + + + Sign the message to prove you own this DAPS address + Firme el mensaje para demostrar que eres el propietario de esta dirección DAPS + + + The DAPS address the message was signed with + La dirección DAPS con la que se firmó el mensaje + + + Verify the message to ensure it was signed with the specified DAPS address + Verifica el mensaje para asegurar que fue firmado con la dirección DAPS especificada + + + Sign &Message + Firmar &Mensaje + + + Reset all sign message fields + Limpiar todos los campos de firma de mensaje + + + Clear &All + Limpiar &Todo + + + &Verify Message + &Verificar Mensaje + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + Introduzca la dirección de firma, mensaje (asegúrese de que copia los puntos y aparte, espacios, tabuladores, etc. exactamente) y la firma debajo para verificar el mensaje. Vaya con cuidado de no leer más en la firma de loque está en el mensaje firmado propiamente dicho, para evitar ser engañado por un ataque "hombre en el medio". + + + Verify &Message + Verificar &Mensaje + + + Reset all verify message fields + Limpiar todos los campos de verificación de mensaje + + + Click "Sign Message" to generate signature + Haga click en "Firmar Mensaje" para generar la firma + + + The entered address is invalid. + La dirección introducida es inválida + + + Please check the address and try again. + Por favor compruebe la dirección e inténtelo de nuevo. + + + The entered address does not refer to a key. + La dirección introducida no se refiere a ninguna clave. + + + Wallet unlock was cancelled. + El desbloqueo del monedero fue cancelado. + + + Private key for the entered address is not available. + La clave privada para la dirección introducida no está disponible. + + + Message signing failed. + La firma del mensaje falló. + + + Message signed. + Mensaje firmado. + + + The signature could not be decoded. + La firma no pudo ser decodificada. + + + Please check the signature and try again. + Por favor compruebe la firma e inténtelo otra vez. + + + The signature did not match the message digest. + La firma no coincide con el resumen del mensaje. + + + Message verification failed. + Falló la verificación del mensaje. + + + Message verified. + Mensaje verificado. + + + + SplashScreen + + DAPS + Núcleo DAPS + + + Version %1 + Versión %1 + + + The Bitcoin Core developers + Los desarrolladores de Bitcoin Core + + + The Dash Core developers + Los desarrolladores de Dash Core + + + The DAPS Project developers + Los desarrolladores de DAPS + + + [testnet] + [testnet] + + + + TrafficGraphWidget + + KB/s + KB/s + + + + TransactionDesc + + Open for %n more block(s) + Abierto para %n bloque másAbierto para %n bloques más + + + Open until %1 + Abierto hasta %1 + + + conflicted + conflictivo (bloque huérfano?) + + + %1/offline + %1/offline + + + %1/unconfirmed + %1/sin confirmar + + + %1 confirmations + %1 confirmaciones + + + Status + Estado + + + , has not been successfully broadcast yet + , no ha sido correctamente transmitida todavía + + + , broadcast through %n node(s) + , retransmitido a través de %n nodo, retransmitido a través de %n nodos + + + Date + Fecha + + + Source + Fuente + + + Generated + Generado + + + From + De + + + unknown + desconocido + + + To + A + + + own address + dirección propia + + + watch-only + sólo-lectura + + + label + etiqueta + + + Credit + Crédito + + + matures in %n more block(s) + madurará dentro de %n bloquemadurará dentro de %n bloques + + + not accepted + rechazado + + + Debit + Débito + + + Total debit + Débito total + + + Total credit + Abonos totales + + + Transaction fee + Comisión de transacción + + + Net amount + Cantidad neta + + + Message + Mensaje + + + Comment + Comentario + + + Transaction ID + ID de la transacción + + + Output index + Índice de salida + + + Merchant + Comerciante + + + Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + Las monedas generadas deben madurarse %1 bloques hasta que puedan ser gastadas de nuevo. Cuando generaste este bloque, se retransmitió a la red para añadirse a la cadena de bloques. Si falla en unirse a la cadena, su estado cambiará a "no aceptado" y no se podrá gastar de nuevo (bloque huérfano). Esto puede ocurrir ocasionalmente si otro nodo genera un bloque casi al mismo tiempo que el tuyo. + + + Debug information + Información de depuración + + + Transaction + Transacción + + + Inputs + Entradas + + + Amount + Cantidad + + + true + verdad + + + false + falso + + + + TransactionDescDialog + + Transaction details + Detalles de transacción + + + This pane shows a detailed description of the transaction + Este panel muestra una descripción detallada de la transacción + + + + TransactionTableModel + + Date + Fecha + + + Type + Tipo + + + Address + Dirección + + + Open for %n more block(s) + Abierto para %n bloque másAbierto por %n bloques más + + + Open until %1 + Abierto hasta %1 + + + Offline + Desconectado + + + Unconfirmed + Sin confirmar + + + Confirming (%1 of %2 recommended confirmations) + Confirmando (%1 de %2 confirmaciones recomendadas) + + + Confirmed (%1 confirmations) + Confirmado (%1 confirmaciones) + + + Conflicted + Huérfano + + + Immature (%1 confirmations, will be available after %2) + Prematuro (%1 confirmaciones, estará disponible después de %2) + + + This block was not received by any other nodes and will probably not be accepted! + ¡Este bloque no fue recibido por los otros nodos y probablemente no será aceptado! + + + Received with + Recibido con + + + Masternode Reward + Recompensa de Nodo Maestro + + + Received from + Recibido desde + + + Received via Obfuscation + Recibido por medio de Ofuscación + + + Obfuscation Denominate + Ofuscación Denominada + + + Obfuscation Collateral Payment + Pago Colateral de Ofuscación + + + Obfuscation Make Collateral Inputs + La Ofuscación Crea Entradas Colaterales + + + Obfuscation Create Denominations + Ofuscación Crea Billetes + + + Sent to + Enviado a + + + Orphan Block - Generated but not accepted. This does not impact your holdings. + Bloque Huérfano - Generado pero no aceptado. Esto no afecta a su saldo. + + + Payment to yourself + Pago a usted mismo + + + Minted + Creación de moneda + + + Mined + Minado + + + Obfuscated + Ofuscado + + + watch-only + sólo-lectura + + + (n/a) + (n/a) + + + Transaction status. Hover over this field to show number of confirmations. + Estado de la transacción. Pase el ratón sobre este campo para mostrar el número de confirmaciones. + + + Date and time that the transaction was received. + Fecha y hora a la que se recibió la transacción. + + + Type of transaction. + Tipo de transacción. + + + Whether or not a watch-only address is involved in this transaction. + Indica si hay o no una dirección de sólo lectura relacionada en esta transacción + + + Destination address of transaction. + Dirección de destino de la transacción. + + + Amount removed from or added to balance. + Cantidad quitada o añadida al balance. + + + + TransactionView + + All + Todos + + + Today + Hoy + + + This week + Esta semana + + + This month + Este mes + + + Last month + Último mes + + + This year + Este año + + + Range... + Intervalo... + + + Most Common + Más Común + + + Received with + Recibido con + + + Sent to + Enviado a + + + Obfuscated + Ofuscado + + + Obfuscation Make Collateral Inputs + La Ofuscación Crea Entradas Colaterales + + + Obfuscation Create Denominations + Ofuscación Crea Billetes + + + Obfuscation Denominate + Ofuscación Denominada + + + Obfuscation Collateral Payment + Pago Colateral de Ofuscación + + + To yourself + A usted mismo + + + Mined + Minado + + + Minted + Creación de moneda + + + Masternode Reward + Recompensa de Nodo Maestro + + + Other + Otro + + + Enter address or label to search + Introduzca dirección o etiqueta para buscar + + + Min amount + Cantidad mínima + + + Copy address + Copiar dirección + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar código de transacción + + + Edit label + Editar etiqueta + + + Show transaction details + Mostrar detalles de transacción + + + Export Transaction History + Exportar Histórico de Transacciones + + + Comma separated file (*.csv) + Archivo separado por comas (*.csv) + + + Confirmed + Confirmado + + + Watch-only + Sólo-lectura + + + Date + Fecha + + + Type + Tipo + + + Label + Etiqueta + + + Address + Dirección + + + ID + ID + + + Exporting Failed + Exportación fallida + + + There was an error trying to save the transaction history to %1. + Hubo un error intentando guardar el historial de transacciones a %1. + + + Exporting Successful + Exportación Correcta + + + The transaction history was successfully saved to %1. + El historial de transacción fue guardado satisfactoriamente a %1. + + + Range: + Rango: + + + to + a + + + + UnitDisplayStatusBarControl + + Unit to show amounts in. Click to select another unit. + Unidad en la que mostrar cantidades. Click para seleccionar otra unidad. + + + + WalletFrame + + No wallet has been loaded. + No se ha cargado ningún monedero. + + + + WalletModel + + Send Coins + Enviar Monedas + + + + WalletView + + &Export + &Exportar + + + Export the data in the current tab to a file + Exportar los datos de la pestaña actual a un archivo + + + Selected amount: + Cantidad seleccionada: + + + Backup Wallet + Copia del Monedero + + + Wallet Data (*.dat) + Datos del Monedero (*.dat) + + + Backup Failed + La copia de seguridad Falló + + + There was an error trying to save the wallet data to %1. + Hubo un error intentando guardar los datos del monedero a %1. + + + Backup Successful + Copia de Seguridad Satisfactoria + + + The wallet data was successfully saved to %1. + Los datos del monedero se guardaron correctamente a %1. + + + dapscoin-core + + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + (1= mantener los metadatos tx p.e. dueño de la cuenta e información de la solicitud de pago, 2 = ignorar metadatos tx) + + + Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times + Permitir conexiones JSON-RPC desde la fuente especificada. Valido para <ip> sea una única IP (ej: 1.2.3.4), una red/mascara de red (ej: 1.2.3.4/255.255.255.0) o una red/CIDR (ej: 1.2.3.4/24). Esta opción puede ser especificada múltiples veces. + + + An error occurred while setting up the RPC address %s port %u for listening: %s + Un error ocurrió mientras se ajustaba la dirección RPC %s puerto %u para escucha en: %s + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Conectarse a la IP seleccionada y siempre escuchar de ella. Usar la forma [host]:puerto para IPv6 + + + Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 + Escuchar únicamente a la dirección IP indicada y a nodos de la lista blanca. Use la notación [host]:puerto para IPv6 + + + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + Escuchar únicamente a la tarjeta de red indicada para conexiones JSON-RPC. Use la notación [host]:puerto para IPv6. Esta opción puede ser especificada varias veces (por defecto: escuchar en todas las tarjetas de red) + + + Calculated accumulator checkpoint is not what is recorded by block index + El punto de chequeo del acumulador que hemos calculado no coincide con lo guardado en el índice de bloques + + + Cannot obtain a lock on data directory %s. DAPS is probably already running. + No se puede obtener un bloqueo sobre el directorio de datos %s. DAPS esta probablemente en ejecución. + + + Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto) + Cambiar el comportamiento automático de votación de presupuesto final. modo=auto: Votar sólo por coincidencia exacta de un presupuesto finalizado con el generado por mí. (cadena, por defecto: auto) + + + Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:%u) + Limite continuo de transacciones gratuitas <n>*1000 bytes por minuto (default:%u) + + + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Crear nuevos archivos con el permiso predeterminado del sistema, en vez de umask 077 (solamente efectivo con la funcionalidad del monedero desabilitada) + + + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + Borrar todas las transacciones del monedero y solo recuperar partes de la cadena de bloque a traves de -rescan al inicio. + + + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + Distribuido bajo licencia MIT software license, ver el archivo adjunto COPYING or <http://www.opensource.org/licenses/mit-license.php> + + + Enter regression test mode, which uses a special chain in which blocks can be solved instantly. + Entrar en el modo prueba de regresión, el cual usa una cadena especial en el cual los bloques pueden ser resueltos instantaneamente. + + + Error: Listening for incoming connections failed (listen returned error %s) + Error: La escucha para conexiones entrantes falló (la escucha retorno error %s) + + + Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Error: Argumento -socks no soportado. No se permite utilizar la versión SOCKS, solo proxies de SOCKS5 están soportados. + + + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + Ejecutar un comando cuando una alerta relevante es recibida o estamos teniendo una realmente larga bifurcación (%s en cmd is reemplazado por el mensaje) + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Ejecutar un comando cuando una transacción del monedero cambie (%s en cmd is reemplazado por TxID) + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Ejecutar comando cuando el mejor bloque cambie (%s en cmd es reemplazado por el block hash) + + + Fees (in DAPS/Kb) smaller than this are considered zero fee for relaying (default: %s) + Comisiones (en DAPS/Kb) menores a esta son consideradas gratuitas para la propagación de la transacción (default: %s) + + + Fees (in DAPS/Kb) smaller than this are considered zero fee for transaction creation (default: %s) + Comisiones (en DAPS/Kb) menores a esta son consideradas gratuitas para la creación de la transacción (default: %s) + + + Flush database activity from memory pool to disk log every <n> megabytes (default: %u) + Trasladar la actividad de la base de datos en el pool de memoria al log de disco cada <n> megabytes (default: %u) + + + Found unconfirmed denominated outputs, will wait till they confirm to continue. + Se encontró salidas denominadas sin confirmar, se esperará hasta que se confirmen para continuar. + + + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + Si paytxfee no esta definido, incluir suficiente comisión de manera que la transacción se vuelva confirmada en promedio dentro de n bloques (predeterminado: %u) + + + In this mode -genproclimit controls how many blocks are generated immediately. + En este modo -genproclimit controla cuantos bloques son generados inmediatamente. + + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Importe inválido para -maxtxfee=<amount>:'%s' (debe ser al menos la comisión minrelay de %s para prevenir transacciones atascadas) + + + Keep the specified amount available for spending at all times (default: 0) + Mantener la cantidad especificada disponible para gastar en todo momento (por defecto: 0) + + + Log transaction priority and fee per kB when mining blocks (default: %u) + Prioridad del registro de transacciones por kB cuando se esta minando bloques (predeterminado: %u) + + + Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) + Mantener un indice de transacción completo, utilizado por la llamada rpc getrawtransaction (predeterminado: %u) + + + Maximum size of data in data carrier transactions we relay and mine (default: %u) + Tamaño máximo de datos en transacciones de transmisiones de datos que pasamos y minamos (predeterminado: %u) + + + Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s) + Comisión máxima total para usar en una única transacción de billetera, definirlo muy bajo puede abortar transacciones largas (predeterminado: %s) + + + Number of seconds to keep misbehaving peers from reconnecting (default: %u) + Número de segundos a mantener pares con mal comportamiento de reconectarse (predeterminado: %u) + + + Obfuscation uses exact denominated amounts to send funds, you might simply need to anonymize some more coins. + La ofuscación utiliza importes en denominaciones exactas para enviar fondos, puedes simplemente necesitar anonimizar algunas monedas mas. + + + Output debugging information (default: %u, supplying <category> is optional) + Saluda de información de depuración (predeterminado: %u, proveyendo <category> es opcional) + + + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + Consultar por direcciones de pares vía búsqueda en DNS, si cantidad de direcciones esta bajo (predeterminado: 1 a menos que se utilice -connect) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Credenciales aleatorias para cada conexión proxy. Esto habilita el aislamiento del flujos de datos Tor (por defecto: %u) + + + Require high priority for relaying free or low-fee transactions (default:%u) + Requerir alta prioridad para transmitir transacción de libre o baja comisión (predeterminado: %u) + + + Send trace/debug info to console instead of debug.log file (default: %u) + Enviar info de traza/debug a la consola en lugar del archivo debug.log (predeterminado: %u) + + + Set maximum size of high-priority/low-fee transactions in bytes (default: %d) + Define tamaño máximo de transacción alta prioridad/baja comisión en bytes (predeterminado: %d) + + + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) + Define el número de hilos para el script de verificación (%u a %d, 0 = auto, <0 = dejar esa cantidad de núcleos libres, predeterminado: %d) + + + Set the number of threads for coin generation if enabled (-1 = all cores, default: %d) + Define el número de hilos para generación de moneda si esta habilitado (-1 = todos los núcleos, predeterminado: %d) + + + Show N confirmations for a successfully locked transaction (0-9999, default: %u) + Mostrar N confirmaciones para una transacción cerrada exitosamente (0-9999, predefinido: %u) + + + Support filtering of blocks and transaction with bloom filters (default: %u) + Soportar filtrado de bloques y transacciones con filtros bloom (por defecto: %u) + + + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + Este producto incluye software desarrollado por el Proyecto OpenSSL para uso en OpenSSL Toolkit <https://www.openssl.org/> y software de cifrado escrito por Eric Young y software de UPnP escrito por Thomas Bernard. + + + To use dapscoind, or the -server option to dapscoin-qt, you must set an rpcpassword in the configuration file: +%s +It is recommended you use the following random password: +rpcuser=dapscoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +It is also recommended to set alertnotify so you are notified of problems; +for example: alertnotify=echo %%s | mail -s "DAPS Alert" admin@foo.com + + Para usar dapscoind, o la opción -server de dapscoin-qt, debes definir un rpcpassword en el archivo de configuración: +%s +Es recomendado que uses la siguiente contraseña aleatoria: +rpcuser=dapscoin +rpcrpcpassword=%s +(No necesitas recordar esta contraseña) +El nombre de usuario y contraseña NO DEBEN ser los mismos. +Si el archivo no existe, crearlo con permisos de solo lectura para el propietario. +También es recomendado definir alertnotify de manera que seas notificado de problemas; +por ejemplo: alertnotify=echo %%s | mail -s "DAPS Alert" admin@foo.com + + + + Unable to bind to %s on this computer. DAPS is probably already running. + Imposible conectar a %s en esta computadora. Es probable que DAPS ya este corriendo. + + + Unable to locate enough Obfuscation denominated funds for this transaction. + Imposible localizar suficientes fondos denominados de Ofuscación para esta transacción. + + + Unable to locate enough Obfuscation non-denominated funds for this transaction that are not equal 10000 DAPS. + Imposible localizar suficientes fondos no-denominados de Ofuscación para esta transacción que no es igual a 10000 DAPS. + + + Unable to locate enough funds for this transaction that are not equal 10000 DAPS. + Imposible localizar fondos suficientes para esta transacción que no es igual a 10000 DAPS. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) + Utilizar un proxy SOCKS5 diferente para alcanzar pares vía el servicio oculto Tor (predefinido: %s) + + + Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction. + Advertencia: -maxtxfee esta muy alto! Comisiones así de altas pueden ser pagadas en una única transacción. + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Advertencia: -paytxfee esta muy alta! Esta es la comisión de transacción que pagarás si envías una transacción. + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong DAPS will not work properly. + Advertencia: Por favor verifique que la fecha y hora de su computadora sean correctas! Si su reloj esta fuera de hora DAPS no funcionará adecuadamente. + + + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + Advertencia: La red parece no estar concordando totalmente! Algunos mineros parecen estar experimentando problemas. + + + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. + Advertencia: No estamos apareciendo totalmente en concordancia con nuestros pares! Podrías necesitar una actualización, o otros nodos pueden necesitar una actualización. + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Advertencia: error leyendo wallet.dat! Todas las claves leídas correctamente, pero datos de transacción or entradas en el libro de direcciones podrían estar faltando o ser incorrectas. + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Advertencia: wallet.dat esta dañado, datos salvados! El wallet.dat original esta grabado como wallet.{timestamp}.bak en %s; si tu saldo o transacciones son incorrectas deberías restaurar de un backup. + + + Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. + Pares de la whitelist conectados desde la mascara de red o direcciones IP dada. Puede ser especificado múltiples veces. + + + Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway + Pares de la Whitelist no pueden ser banneados por DoS y sus transacciones son siempre transmitidas, aún si ellas están ya en la mempool, util por ejemplo para un gateway. + + + You must specify a masternodeprivkey in the configuration. Please see documentation for help. + Debes especificar un masternodeprivkey en la configuración. Por favor mira la documentación por ayuda. + + + (53572 could be used only on mainnet) + (53572 puede ser utilizado solo en mainnet) + + + (default: %s) + (predeterminado: %s) + + + (default: 1) + (predeterminado: 1) + + + (must be 53572 for mainnet) + (debe ser 53572 para un mainnet) + + + Accept command line and JSON-RPC commands + Aceptar linea de mandato y mandatos JSON-RPC + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceptar conexiones desde afuera (predeterminado: 1 sin opción -proxy o -connect) + + + Accept public REST requests (default: %u) + Aceptar peticiones públicas REST (predeterminado: %u) + + + Acceptable ciphers (default: %s) + Métodos de cifrado aceptables (predeterminado: %s) + + + Add a node to connect to and attempt to keep the connection open + Agregar un nodo a conectarse y intentar mantener abierta la conexión + + + Allow DNS lookups for -addnode, -seednode and -connect + Permitir búsquedas DNS para -addnode, -seednode y -connect + + + Already have that input. + Ya tiene esa entrada. + + + Always query for peer addresses via DNS lookup (default: %u) + Siempre consultar por direcciones de pares vía búsqueda DNS (predeterminado: %u) + + + Attempt to recover private keys from a corrupt wallet.dat + Intentar recuperar claves privadas desde un wallet.dat dañado + + + Automatically create Tor hidden service (default: %d) + Crear automáticamente servicio Tor oculto (por defecto: %d) + + + Block creation options: + Opciones de creación de bloque: + + + Calculating missing accumulators... + Calculando acumuladores pendientes... + + + Can't denominate: no compatible inputs left. + No se puede denominar: quedaron entradas no compatibles. + + + Can't find random Masternode. + No se puede encontrar un Masternode al azar. + + + Can't mix while sync in progress. + No se puede mezclar mientras la sincronización esta en progreso. + + + Cannot downgrade wallet + No se puede volver a una versión anterior de la billetera + + + Cannot resolve -bind address: '%s' + No se puede resolver la dirección -bind: '%s' + + + Cannot resolve -externalip address: '%s' + No se puede resolver la dirección -externalip: '%s' + + + Cannot resolve -whitebind address: '%s' + No se puede resolver la dirección -whitebind: '%s' + + + Cannot write default address + No se puede escribir la dirección predeterminada + + + Collateral not valid. + Colateral no válido. + + + Connect only to the specified node(s) + Conectar solo a el/los nodo(s) especificados + + + Connect through SOCKS5 proxy + Conectar a través de proxy SOCKS5 + + + Connect to a node to retrieve peer addresses, and disconnect + Conectar a un nodo para obtener direcciones de pares, y desconectar + + + Connection options: + Opciones de conexión: + + + Copyright (C) 2009-%i The Bitcoin Core Developers + Copyright (C) 2009-%i The Bitcoin Core Developers + + + Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2014-%i The Dash Core Developers + + + Copyright (C) 2015-%i The DAPS Project developers + Copyright (C) 2015-%i The DAPS Project developers + + + Corrupted block database detected + Se detectó base de datos de bloques dañado + + + Could not parse -rpcbind value %s as network address + El valor %s de -rpcbind no pudo ser leído como una dirección de red. + + + Could not parse masternode.conf + No se pudo analizar el contenido de masternode.conf + + + Debugging/Testing options: + Opciones de Depuración/Pruebas: + + + Disable OS notifications for incoming transactions (default: %u) + Desactivar notificaciones del sistema para transacciones extrantes (por defecto: %u) + + + Disable safemode, override a real safe mode event (default: %u) + Desactiva modo seguro, invalida un evento modo seguro real (predeterminado: %u) + + + Discover own IP address (default: 1 when listening and no -externalip) + Descubrir direcciones IP propia (predeterminado: 1 cuando se esta a la escucha y sin opción -externalip) + + + Do not load the wallet and disable wallet RPC calls + No cargar la billetera y desactivar las llamadas RPC de billetera + + + Do you want to rebuild the block database now? + ¿Quieres reconstruir la base de datos de bloques ahora? + + + Done loading + Realizando carga + + + Enable the client to act as a masternode (0-1, default: %u) + Habilitar al cliente para actuar como un nodo maestro (0-1. predeterminado: %u) + + + Entries are full. + Las entradas están llenas. + + + Error connecting to Masternode. + Error al conectar al Nodo Maestro + + + Error initializing block database + Error al inicializar base de datos de bloques + + + Error initializing wallet database environment %s! + Error al inicializar ambiente %s de base de datos de billetera! + + + Error loading block database + Error al cargar base de datos de bloques + + + Error loading wallet.dat + Error al cargar wallet.dat + + + Error loading wallet.dat: Wallet corrupted + Error al cargar wallet.dat: Billetera dañada + + + Error loading wallet.dat: Wallet requires newer version of DAPS + Error al cargar wallet.dat: La Billetera requiere una nueva versión del Núcleo DAPS + + + Error opening block database + Error al abrir la base de datos de bloques + + + Error reading from database, shutting down. + Error al leer desde la base de datos, apagando. + + + Error recovering public key. + Error al recuperar clave pública. + + + Error + Error + + + Error: A fatal internal error occured, see debug.log for details + Error: Un error interno fatal a ocurrido, ver debug.log para mas detalles + + + Error: Can't select current denominated inputs + Error: No se pudo seleccionar las entradas denominadas actuales + + + Error: Disk space is low! + Error: El espacio en disco esta bajo! + + + Error: Unsupported argument -tor found, use -onion. + Error: Se encontró argumento no soportado -tor, utilizar -onion. + + + Error: Wallet locked, unable to create transaction! + Error: Billetera bloqueada, imposible crear transacción! + + + Error: You already have pending entries in the Obfuscation pool + Error: Ya tienes entradas pendientes en el pool de Ofuscación + + + Failed to listen on any port. Use -listen=0 if you want this. + Falló la escucha en cualquiera de los puertos. Usar -listen=0 si quieres esto. + + + Failed to read block + Falló al leer el bloque + + + Fee (in DAPS/kB) to add to transactions you send (default: %s) + Comisión (en DAPS/kB) para agregar a la transacción que envías (predeterminado: %s) + + + Finalizing transaction. + Finalizando transacción. + + + Force safe mode (default: %u) + Forzar modo seguro (predeterminado: %u) + + + Found enough users, signing ( waiting %s ) + Se han encontrado suficientes usuarios, firmando ( esperando %s ) + + + Found enough users, signing ... + Se han encontrado suficientes usuarios, firmando ... + + + Generate coins (default: %u) + Generando monedas: (predeterminado: %u) + + + How many blocks to check at startup (default: %u, 0 = all) + Cuantos bloques a probar al iniciar (predeterminado: %u, 0 = todos) + + + If <category> is not supplied, output all debugging information. + Si <category> no es proveído, dar salida a toda la información de depuración. + + + Importing... + Importando... + + + Imports blocks from external blk000??.dat file + Importar bloques desde archivo externo blk000??.dat + + + Include IP addresses in debug output (default: %u) + Incluir direcciones IP en salida de depuración (predeterminado: %u) + + + Incompatible mode. + Modo incompatible. + + + Incompatible version. + Versión imcompatible. + + + Incorrect or no genesis block found. Wrong datadir for network? + Bloque de génesis incorrecto o no encontrado. datadir equivocado para red? + + + Information + Información + + + Initialization sanity check failed. DAPS is shutting down. + La prueba de salud de inicialización ha fallado. DAPS se cerrará. + + + Input is not valid. + La entrada no es válida. + + + Insufficient funds + Fondos insuficientes + + + Insufficient funds. + Fondos insuficientes. + + + Invalid -onion address or hostname: '%s' + Dirección o nombre de equipo -onion inválido: '%s' + + + Invalid -proxy address or hostname: '%s' + Dirección o nombre de equipo -proxy inválido: '%s' + + + Invalid amount for -maxtxfee=<amount>: '%s' + Importe inválido para -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Importe inválido para -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Importe inválido para -mintxfee=<amount>: '%s' + + + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + Importe inválido para -paytxfee=<amount>: '%s' (debe ser al menos %s) + + + Invalid amount for -paytxfee=<amount>: '%s' + Importe inválido para -paytxfee=<amount>: '%s' + + + Invalid amount for -reservebalance=<amount> + Importe inválido para -reservebalance=<amount> + + + Invalid amount + Cantidad incorrecta + + + Invalid masternodeprivkey. Please see documenation. + Valor de masternodeprivkey es inválido. Por favor ver la documentación. + + + Invalid netmask specified in -whitelist: '%s' + Máscara de red inválida especificada en -whitelist: '%s' + + + Invalid port detected in masternode.conf + Puerto inválido ha sido detectado en masternode.conf + + + Invalid private key. + Clave pública inválida. + + + Invalid script detected. + Script inválido detectado. + + + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! + Esto es una versión pre-release de prueba - use bajo su propia responsabilidad - ¡No lo utilice para recompensa de participación ni aplicaciones de comercio! + + + mints deleted + + creaciones de moneda borradas + + + + mints updated, + creaciones de moneda actualizadas, + + + unconfirmed transactions removed + + transacciones sin confirmar eliminadas + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + ¡La transacción fue rechazada! Esto puede ocurrir si alguna de sus monedas ya se gastó con anterioridad, por ejemplo, si estuvo usted usando una copia de su monedero wallet.dat y gastó allí monedas pero no las marcó como gastadas aquí. + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Error: ¡Esta transacción requiere una tasa de al menos %s debido a la cantidad enviada, su complejidad, o el uso de fondos recibidos recientemente! + + + Error: Unsupported argument -checklevel found. Checklevel must be level 4. + Error: Se ha especificado un argumento no soportado -checklevel. El Checklevel debe ser siempre 4. + + + <category> can be: + <category>puede ser: + + + Attempt to force blockchain corruption recovery + Intentar forzar la recuperación de la cadena de bloques corrupta + + + Display the stake modifier calculations in the debug.log file. + Incluir los cálculos de recompensa por participación en el fichero debug.log. + + + Display verbose coin stake messages in the debug.log file. + Incluir mensajes explícitos de recompensa por participación en el fichero debug.log. + + + Enable publish hash block in <address> + Activar inclusión del hash del bloque en <address> + + + Enable publish hash transaction in <address> + Activar inclusión del hash de la transacción en <address> + + + Enable publish raw block in <address> + Activar inclusión del bloque en bruto en <address> + + + Enable publish raw transaction in <address> + Activar inclusión de la transacción en bruto en <address> + + + Enable staking functionality (0-1, default: %u) + Activar funcionalidad de recompensa por participación (0-1, por defecto: %u) + + + Keep at most <n> unconnectable transactions in memory (default: %u) + Mantener como máximo <n> transacciones no conectables en memoria (predeterminado: %u) + + + Last Obfuscation was too recent. + La última Ofuscación fue demasiado reciente. + + + Last successful Obfuscation action was too recent. + La última acción de Ofuscación exitosa fue demasiado reciente. + + + Limit size of signature cache to <n> entries (default: %u) + Tamaño límite del cache de firmas a <n> entradas (predeterminado: %u) + + + Line: %d + Linea: %d + + + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + Escuchar por conexiones JSON-RPC en <port> (predeterminado: %u o testnet: %u) + + + Listen for connections on <port> (default: %u or testnet: %u) + Escuchar por conexiones en <port> (predeterminado: %u o testnet: %u) + + + Loading addresses... + Cargando direcciones... + + + Loading block index... + Cargando índice de bloque... + + + Loading budget cache... + Cargando cache de presupuestos... + + + Loading masternode cache... + Cargando cache de nodos maestros... + + + Loading masternode payment cache... + Cargando cache de pagos de nodos maestros + + + Loading wallet... (%3.2f %%) + Cargando monedero: (%3.2f %%) + + + Loading wallet... + Cargando monedero... + + + Lock is already in place. + Bloqueo esta en su lugar. + + + Lock masternodes from masternode configuration file (default: %u) + Bloquear nodos maestros desde el archivo de configuración de nodo maestro (predeterminado: %u) + + + Maintain at most <n> connections to peers (default: %u) + Mantener como máximo <n> conexiones a pares (predeterminado: %u) + + + Masternode options: + Opciones de Masternode: + + + Masternode queue is full. + La cola del Nodo Maestro esta llena. + + + Masternode: + Nodo maestro: + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Buffer de recepción máximo por conexión, <n>*1000 bytes (predeterminado: %u) + + + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + Máximo buffer de envío por conexión, <n>*1000 bytes (predeterminado: %u) + + + Missing input transaction information. + Información de transacciones de entrada perdidas. + + + Mixing in progress... + Mezcla en progreso... + + + Need to specify a port with -whitebind: '%s' + Necesita especificar un puerto con -whitebind: '%s' + + + No Masternodes detected. + No se han detectado Masternodes. + + + No compatible Masternode found. + No hay un Masternode compatible encontrado. + + + No funds detected in need of denominating. + No hay fondos detectados necesarios de denominación. + + + No matching denominations found for mixing. + No hemos encontrado billetes coincidentes para mezclado. + + + Node relay options: + Opciones de transmisión del nodo: + + + Non-standard public key detected. + Clave pública no-estandar ha sido detectada. + + + Not compatible with existing transactions. + No es compatible con las transacciones salientes. + + + Not enough file descriptors available. + No hay suficientes descriptores de archivo disponibles. + + + Not in the Masternode list. + No en la lista Masternode. + + + Number of automatic wallet backups (default: 10) + Número de Copias de seguridad automáticas de monedero (predeterminado: 10) + + + Obfuscation is idle. + La Ofuscación está sin uso. + + + Obfuscation request complete: + Pedido de Ofuscacion completado: + + + Obfuscation request incomplete: + Pedido de Ofuscación incompleto: + + + Only accept block chain matching built-in checkpoints (default: %u) + Solo aceptar cadena de bloque emparejada con puntos de verificación construidos (predeterminado: %u) + + + Only connect to nodes in network <net> (ipv4, ipv6 or onion) + Solo conectar a nodos en la red <net> (ipv4, ipv6 o onion) + + + Options: + Opciones: + + + Password for JSON-RPC connections + Contraseña para conexiones JSON-RPC + + + Prepend debug output with timestamp (default: %u) + Agregar timestamp a la salida de depuración (predeterminado: %u) + + + Print version and exit + Mostrar versión y salir + + + RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions) + Opciones RPC SSL: (ver el Bitcoin Wiki para instrucciones de instalación SSL) + + + RPC server options: + Opciones del servidor RPC: + + + RPC support for HTTP persistent connections (default: %d) + Soporte RPC para conexiones persistentes HTTP (predeterminado %d) + + + Randomly drop 1 of every <n> network messages + Aleatoriamente dejar caer 1 de cada <n> mensajes de red + + + Randomly fuzz 1 of every <n> network messages + Aleatoriamente esfumar 1 de cada <n> mensajes de red + + + Rebuild block chain index from current blk000??.dat files + Reconstruir el indice de la cadena de bloque desde el corriente archivo blk000??.dat + + + Receive and display P2P network alerts (default: %u) + Recibir y mostrar alertas de red P2P (predeterminado: %u) + + + Relay and mine data carrier transactions (default: %u) + Transmitir y minar datos de transacciones enviadas (predeterminado: %u) + + + Relay non-P2SH multisig (default: %u) + Transmitir no-P2SH multisig (predeterminado: %u) + + + Rescan the block chain for missing wallet transactions + Reescanear la cadena de bloques en busca de transacciones perdidas del monedero + + + Rescanning... + Reescaneado... + + + Run a thread to flush wallet periodically (default: %u) + Ejecutar un hilo de ejecución para nivelar el monedero periódicamente (predeterminado: %u) + + + Run in the background as a daemon and accept commands + Ejecutar en segundo plano como demonio y aceptar comandos + + + Send transactions as zero-fee transactions if possible (default: %u) + Enviar transacciones como transacciones cero-comisión si es posible (predeterminado: %u) + + + Server certificate file (default: %s) + Archivo certificado del servidor (predeterminado: %s) + + + Server private key (default: %s) + Clave privada del servidor (predeterminado: %s) + + + Session not complete! + Sesión no completa! + + + Session timed out. + La sesión expiró. + + + Set database cache size in megabytes (%d to %d, default: %d) + Definir tamaño de cache de base de datos en megabytes (%d a %d, predeterminado: %d) + + + Set external address:port to get to this masternode (example: %s) + Definir dirección:puerto externo para alcanzar este nodo maestro (ejemplo: %s) + + + Set key pool size to <n> (default: %u) + Definir el tamaño del pool de llaves a <n> (predeterminado: %u) + + + Set maximum block size in bytes (default: %d) + Ajustar el tamaño máximo de bloque en bytes (predeterminado: %d) + + + Set minimum block size in bytes (default: %u) + Ajustar el tamaño mínimo de bloque en bytes (predeterminado: %u) + + + Set the masternode private key + Ajustar la clave privada de masternode + + + Set the number of threads to service RPC calls (default: %d) + Definir el número de hilos para llamadas al servicio RPC (predeterminado: %d) + + + Sets the DB_PRIVATE flag in the wallet db environment (default: %u) + Definir la bandera DB_PRIVATE en la db de la billetera del ambiente (predeterminado: %u) + + + Show all debugging options (usage: --help -help-debug) + Mostrar todas las opciones de depuración (uso: --help-debug) + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Encojer el archivo debug.log en el cliente al inicio (predeterminado: 1 cuando no hay -debug) + + + Signing failed. + La firma falló. + + + Signing timed out. + Se agotó el tiempo para la firma. + + + Signing transaction failed + La firma de la transacción falló + + + Specify configuration file (default: %s) + Especifique el archivo de configuración (predeterminado: %s) + + + Specify connection timeout in milliseconds (minimum: 1, default: %d) + Especificar el timeout de conexión en mili segundos (mínimo: 1, predeterminado: %d) + + + Specify data directory + Especifique el directorio de datos + + + Specify masternode configuration file (default: %s) + Especifique el archivo de configuración masternode (predeterminado: %s) + + + Specify pid file (default: %s) + Especifique el archivo pid (predeterminado: %s) + + + Specify wallet file (within data directory) + Especifique el archivo monedero (dentro del directorio de datos) + + + Specify your own public address + Especifique su propia dirección pública + + + Spend unconfirmed change when sending transactions (default: %u) + Gastar cambio no confirmado cuando se envían transacciones (predeterminado: %u) + + + Staking options: + Opciones de recompensa por participación: + + + Stop running after importing blocks from disk (default: %u) + Parar la ejecución después de importar bloques desde el disco (predeterminado: %u) + + + Submitted following entries to masternode: %u / %d + Se enviaron las siguientes entradas a masternode: %u / %d + + + Submitted to masternode, waiting for more entries ( %u / %d ) %s + Enviado a masternode, esperando por mas entradas (%u / %d) %s + + + Submitted to masternode, waiting in queue %s + Enviado a masternode, quedando en espera %s + + + Synchronization failed + Falló la sincronización + + + Synchronization finished + Sincronización finalizada! + + + Synchronization pending... + Sincronización pendiente... + + + Synchronizing budgets... + Sincronizando presupuestos... + + + Synchronizing masternode winners... + Sincronizando ganadores masternode... + + + Synchronizing masternodes... + Sincronizando masternodes... + + + This help message + Este mensaje de ayuda + + + This is experimental software. + Esto es software experimental. + + + This is intended for regression testing tools and app development. + Esto esta destinado para herramientas de prueba de regresión y desarrollo de aplicaciones. + + + This is not a Masternode. + Este no es un nodo maestro. + + + Threshold for disconnecting misbehaving peers (default: %u) + Limite para desconexión de peers de mal desempeño (predeterminado: %u) + + + Tor control port password (default: empty) + Contraseña del puerto de control Tor (por defecto: vacío) + + + Tor control port to use if onion listening enabled (default: %s) + Puerto de control Tor a utilizar si está activada la escucha Onion (por defecto: %s) + + + Transaction amount too small + El monto de la transacción es demasiado pequeño + + + Transaction amounts must be positive + El monto de la transacción debe ser positivo + + + Transaction created successfully. + Transacción creada satisfactoriamente. + + + Transaction fees are too high. + La comision de transacción es demasiado alta. + + + Transaction not valid. + La transacción no es valida. + + + Transaction too large for fee policy + La transacción es demasiado grande para la política de comisión. + + + Transaction too large + La transacción es demasiado grande + + + Transmitting final transaction. + Transmitiendo la transacción final. + + + Unable to bind to %s on this computer (bind returned error %s) + Imposible enlazar %s en esta computadora (enlace retorna error %s) + + + Unknown network specified in -onlynet: '%s' + Red especificada desconocida en -onlynet: '%s' + + + Unknown state: id = %u + Estado desconocido: id = %u + + + Upgrade wallet to latest format + Actualizar el monedero al formato ultimo + + + Use OpenSSL (https) for JSON-RPC connections + Usar OpenSSL (https) para conexiones JSON-RPC + + + Use UPnP to map the listening port (default: %u) + Usar UPnP para mapear el puerto de escucha (predeterminado: %u) + + + Use UPnP to map the listening port (default: 1 when listening) + Usar UPnP para mapear el puerto de escucha (predeterminado: 1 cuando esta en escucha) + + + Use the test network + Usar la red de prueba + + + Username for JSON-RPC connections + Nombre de usuario para conexiones JSON-RPC + + + Value more than Obfuscation pool maximum allows. + Valor mayor al máximo pool de Ofuscación permitido. + + + Verifying blocks... + Verificando bloques... + + + Verifying wallet... + Verificando el monedero... + + + Wallet %s resides outside data directory %s + La billetera %s esta ubicada fuera del directorio de datos %s + + + Wallet is locked. + Monedero bloqueado. + + + Wallet needed to be rewritten: restart DAPS to complete + Monedero necesita ser reescrito: reinicie DAPS para completar + + + Wallet options: + Opciones del Monedero: + + + Wallet window title + Monedero titulo de ventana + + + Warning + Advertencia + + + Warning: This version is obsolete, upgrade required! + Advertencia: Esta versión es obsoleta, se requiere actualizar! + + + Warning: Unsupported argument -benchmark ignored, use -debug=bench. + Advertencia: Argumento no soportado -benchmark ignorado, use -debug=bench + + + Warning: Unsupported argument -debugnet ignored, use -debug=net. + Advertencia: Argumento no soportado -debugnet ignorado, use -debug=net. + + + Will retry... + Probando... + + + You need to rebuild the database using -reindex to change -txindex + Usted necesita reconstruir la base de datos usando -reindex para cambiar -txindex + + + Your entries added successfully. + Su entrada a sido agregada satisfactoriamente. + + + Your transaction was accepted into the pool! + Su transacción ha sido aceptada en el pool! + Zapping all transactions from wallet... Saltando todas las transacciones del monedero... @@ -641,7 +4984,7 @@ wallet.dat corrupt, salvage failed - wallet.dat corrupto, recuperación fallida + wallet.dat esta corrupto, fallo al guardar From 6275c8dc64e05a3aae1de8952245d7bcaf38c367 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 19:52:42 -0500 Subject: [PATCH 0047/1888] [Wallet] Remove un-necessary CheckTransaction call when loading wallet. --- src/wallet/walletdb.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index a5d8b04b14..077a9e9154 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -564,8 +564,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW ssKey >> hash; CWalletTx wtx; ssValue >> wtx; - CValidationState state; - if (!(CheckTransaction(wtx, false, false, state) && (wtx.GetHash() == hash) && state.IsValid())) + if (wtx.GetHash() != hash) return false; if (wtx.nOrderPos == -1) @@ -825,8 +824,8 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; + LOCK(pwallet->cs_wallet); try { - LOCK(pwallet->cs_wallet); int nMinVersion = 0; if (Read((string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) From a80f39613af674ab9f3fb12dda7603a789a329f0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 19:56:09 -0500 Subject: [PATCH 0048/1888] [Performance][Wallet][QT][Model] TransactionTableModel multi-thread initialization + tx filter sort speed improved. --- build-aux/m4/bitcoin_qt.m4 | 6 ++- depends/packages/qt.mk | 4 +- src/qt/transactiontablemodel.cpp | 67 ++++++++++++++++++++++++++++---- src/wallet/wallet.cpp | 11 ++++++ src/wallet/wallet.h | 2 + 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index c828cc09d0..df721eb125 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -428,7 +428,7 @@ dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ m4_ifdef([PKG_CHECK_MODULES],[ QT_LIB_PREFIX=Qt5 - qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" + qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets Qt5Concurrent" BITCOIN_QT_CHECK([ PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) @@ -460,7 +460,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_LIBS="$LIBS" BITCOIN_QT_CHECK([ if test "x$qt_include_path" != x; then - QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" + QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus -I$qt_include_path/QtConcurrent" CPPFLAGS="$QT_INCLUDES $CPPFLAGS" fi ]) @@ -468,6 +468,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtPlugin],,BITCOIN_QT_FAIL(QtCore headers missing))]) BITCOIN_QT_CHECK([AC_CHECK_HEADER([QApplication],, BITCOIN_QT_FAIL(QtGui headers missing))]) BITCOIN_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, BITCOIN_QT_FAIL(QtNetwork headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtConcurrent],, BITCOIN_QT_FAIL(QtConcurrent headers missing))]) BITCOIN_QT_CHECK([ if test "x$bitcoin_qt_want_version" = xauto; then @@ -502,6 +503,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Network not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Concurrent],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Concurrent not found))) QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index e3fea4a916..ff04603c22 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -7,7 +7,7 @@ $(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352 $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase -$(package)_qt_libs=corelib network widgets gui plugins testlib +$(package)_qt_libs=corelib network widgets gui plugins testlib concurrent $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) @@ -76,7 +76,7 @@ $(package)_config_opts += -no-feature-lcdnumber $(package)_config_opts += -no-feature-pdf $(package)_config_opts += -no-feature-printer $(package)_config_opts += -no-feature-printdialog -$(package)_config_opts += -no-feature-concurrent +$(package)_config_opts += -feature-concurrent $(package)_config_opts += -no-feature-sql $(package)_config_opts += -no-feature-statemachine $(package)_config_opts += -no-feature-syntaxhighlighter diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index eda16a20da..bb8d759bcd 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include + +#define SINGLE_THREAD_MAX_TXES_SIZE 4000 // Amount column is right-aligned it contains numbers static int column_alignments[] = { @@ -71,16 +75,63 @@ class TransactionTablePriv /* Query entire wallet anew from core. */ void refreshWallet() - { - if (wallet->IsLocked()) return; - cachedWallet.clear(); - { - LOCK2(cs_main, wallet->cs_wallet); - for (std::map::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { - if (TransactionRecord::showTransaction(it->second)) - cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second)); + { + if (wallet->IsLocked()) return; + cachedWallet.clear(); + + std::vector walletTxes = wallet->getWalletTxs(); + + // Divide the work between multiple threads to speedup the process if the vector is larger than 4k txes + std::size_t txesSize = walletTxes.size(); + if (txesSize > SINGLE_THREAD_MAX_TXES_SIZE) { + + // Simple way to get the processors count + std::size_t threadsCount = (QThreadPool::globalInstance()->maxThreadCount() / 2 ) + 1; + + // Size of the tx subsets + std::size_t const subsetSize = txesSize / (threadsCount + 1); + std::size_t totalSumSize = 0; + QList>> tasks; + + // Subsets + run task + for (std::size_t i = 0; i < threadsCount; ++i) { + tasks.append( + QtConcurrent::run( + convertTxToRecords, + this, + wallet, + std::vector(walletTxes.begin() + totalSumSize, walletTxes.begin() + totalSumSize + subsetSize) + ) + ); + totalSumSize += subsetSize; + } + + // Now take the remaining ones and do the work here + std::size_t const remainingSize = txesSize - totalSumSize; + cachedWallet.append(convertTxToRecords(this, wallet, + std::vector(walletTxes.end() - remainingSize, walletTxes.end()) + )); + + for (QFuture> &future : tasks) { + future.waitForFinished(); + cachedWallet.append(future.result()); + } + } else { + // Single thread flow + cachedWallet.append(convertTxToRecords(this, wallet, walletTxes)); + } + } + + static QList convertTxToRecords(TransactionTablePriv* tablePriv, const CWallet* wallet, const std::vector& walletTxes) { + QList cachedWallet; + for (const auto &tx : walletTxes) { + if (TransactionRecord::showTransaction(tx)) { + QList records = TransactionRecord::decomposeTransaction(wallet, tx); + cachedWallet.append(records); } } + + return cachedWallet; } /* Update our model of the wallet incrementally, to synchronize our model of the wallet diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8633d4a26e..b3a22fb8ac 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -164,6 +164,17 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const return &(it->second); } +std::vector CWallet::getWalletTxs() +{ + LOCK(cs_wallet); + std::vector result; + result.reserve(mapWallet.size()); + for (const auto& entry : mapWallet) { + result.emplace_back(entry.second); + } + return result; +} + bool CWallet::checkPassPhraseRule(const char* pass) { bool upper = false; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f734fb3700..1379733200 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -427,6 +427,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface const CWalletTx* GetWalletTx(const uint256& hash) const; + std::vector getWalletTxs(); + //! check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { From 8a98a7615900e0ef7c0b1878a75a8802890340e4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 20:06:18 -0500 Subject: [PATCH 0049/1888] [Qt] Fix warning dialog popup for the Blockchain Explorer --- src/qt/blockexplorer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index eadbc4a683..395e12ebe8 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -417,7 +417,7 @@ void BlockExplorer::showEvent(QShowEvent*) m_History.push_back(text); updateNavButtons(); - if (!GetBoolArg("-txindex", false)) { + if (!GetBoolArg("-txindex", true)) { QString Warning = tr("Not all transactions will be shown. To view all transactions you need to set txindex=1 in the configuration file (dapscoin.conf)."); QMessageBox::warning(this, "DAPS Blockchain Explorer", Warning, QMessageBox::Ok); } From 2bae4cb71e516de5f64ef5c2f2cd0d9535f0ff62 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 20:39:03 -0500 Subject: [PATCH 0050/1888] Optimize PNGs with optimize-pngs.py --- contrib/devtools/optimize-pngs.py | 76 ++++++++++++++++++++ share/pixmaps/bitcoin128.png | Bin 6959 -> 6007 bytes share/pixmaps/bitcoin16.png | Bin 1099 -> 1033 bytes share/pixmaps/bitcoin256.png | Bin 16088 -> 14940 bytes share/pixmaps/bitcoin32.png | Bin 1774 -> 1497 bytes share/pixmaps/bitcoin64.png | Bin 3166 -> 2807 bytes share/pixmaps/nsis-header.png | Bin 3470 -> 2730 bytes src/qt/res/icons/add.png | Bin 1408 -> 1216 bytes src/qt/res/icons/address-book.png | Bin 679 -> 469 bytes src/qt/res/icons/automint_active.png | Bin 1137 -> 884 bytes src/qt/res/icons/automint_inactive.png | Bin 583 -> 421 bytes src/qt/res/icons/bitcoin.png | Bin 1377 -> 868 bytes src/qt/res/icons/bitcoin_testnet.png | Bin 16701 -> 13012 bytes src/qt/res/icons/bittrex.png | Bin 19488 -> 18057 bytes src/qt/res/icons/browse.png | Bin 1476 -> 1294 bytes src/qt/res/icons/cashbook.png | Bin 2810 -> 1714 bytes src/qt/res/icons/clock1.png | Bin 1241 -> 914 bytes src/qt/res/icons/clock2.png | Bin 1241 -> 914 bytes src/qt/res/icons/clock3.png | Bin 1238 -> 924 bytes src/qt/res/icons/clock4.png | Bin 1242 -> 920 bytes src/qt/res/icons/clock5.png | Bin 1237 -> 932 bytes src/qt/res/icons/collapse.png | Bin 1703 -> 967 bytes src/qt/res/icons/configure.png | Bin 1251 -> 943 bytes src/qt/res/icons/connect0_16.png | Bin 860 -> 665 bytes src/qt/res/icons/connect1_16.png | Bin 475 -> 281 bytes src/qt/res/icons/connect2_16.png | Bin 656 -> 453 bytes src/qt/res/icons/connect3_16.png | Bin 929 -> 716 bytes src/qt/res/icons/connect4_16.png | Bin 1205 -> 993 bytes src/qt/res/icons/dapsico.png | Bin 1377 -> 868 bytes src/qt/res/icons/debugwindow.png | Bin 5432 -> 4677 bytes src/qt/res/icons/edit.png | Bin 1417 -> 1223 bytes src/qt/res/icons/editcopy.png | Bin 830 -> 617 bytes src/qt/res/icons/editpaste.png | Bin 625 -> 441 bytes src/qt/res/icons/expand.png | Bin 1729 -> 976 bytes src/qt/res/icons/explorer.png | Bin 6472 -> 2060 bytes src/qt/res/icons/export.png | Bin 2229 -> 2049 bytes src/qt/res/icons/eye.png | Bin 686 -> 439 bytes src/qt/res/icons/eye_minus.png | Bin 765 -> 514 bytes src/qt/res/icons/eye_plus.png | Bin 827 -> 580 bytes src/qt/res/icons/facebook.png | Bin 429 -> 316 bytes src/qt/res/icons/filesave.png | Bin 1476 -> 1294 bytes src/qt/res/icons/history.png | Bin 1238 -> 1022 bytes src/qt/res/icons/import.png | Bin 1086 -> 827 bytes src/qt/res/icons/instagram.png | Bin 3438 -> 2509 bytes src/qt/res/icons/key.png | Bin 462 -> 270 bytes src/qt/res/icons/lock_closed.png | Bin 611 -> 380 bytes src/qt/res/icons/lock_open.png | Bin 604 -> 374 bytes src/qt/res/icons/medium.png | Bin 639 -> 525 bytes src/qt/res/icons/notsynced.png | Bin 1280 -> 1003 bytes src/qt/res/icons/onion.png | Bin 2739 -> 2533 bytes src/qt/res/icons/overview.png | Bin 494 -> 210 bytes src/qt/res/icons/privacy.png | Bin 5627 -> 4140 bytes src/qt/res/icons/qr-code.png | Bin 5075 -> 3183 bytes src/qt/res/icons/qrcode.png | Bin 386 -> 166 bytes src/qt/res/icons/quit.png | Bin 2127 -> 1833 bytes src/qt/res/icons/receive_dark.png | Bin 2999 -> 2731 bytes src/qt/res/icons/received.png | Bin 481 -> 285 bytes src/qt/res/icons/reddit.png | Bin 2478 -> 1969 bytes src/qt/res/icons/remove.png | Bin 1167 -> 887 bytes src/qt/res/icons/reward.png | Bin 481 -> 285 bytes src/qt/res/icons/send.png | Bin 487 -> 275 bytes src/qt/res/icons/send_dark.png | Bin 2853 -> 2587 bytes src/qt/res/icons/sent.png | Bin 481 -> 285 bytes src/qt/res/icons/staking_inactive.png | Bin 473 -> 185 bytes src/qt/res/icons/staking_waiting.png | Bin 864 -> 658 bytes src/qt/res/icons/steemit.png | Bin 1489 -> 1121 bytes src/qt/res/icons/synced.png | Bin 1074 -> 829 bytes src/qt/res/icons/telegram.png | Bin 641 -> 638 bytes src/qt/res/icons/trade.png | Bin 786 -> 375 bytes src/qt/res/icons/transaction0.png | Bin 479 -> 294 bytes src/qt/res/icons/transaction0_dark.png | Bin 416 -> 225 bytes src/qt/res/icons/transaction2.png | Bin 552 -> 361 bytes src/qt/res/icons/transaction_conflicted.png | Bin 435 -> 236 bytes src/qt/res/icons/twitter.png | Bin 1028 -> 650 bytes src/qt/res/icons/tx_inout.png | Bin 1081 -> 812 bytes src/qt/res/icons/tx_input.png | Bin 966 -> 736 bytes src/qt/res/icons/tx_mined.png | Bin 2161 -> 1948 bytes src/qt/res/icons/tx_output.png | Bin 566 -> 326 bytes src/qt/res/icons/unit_dapscoin.png | Bin 588 -> 320 bytes src/qt/res/icons/unit_mdapscoin.png | Bin 583 -> 331 bytes src/qt/res/icons/unit_tdapscoin.png | Bin 564 -> 315 bytes src/qt/res/icons/unit_tmdapscoin.png | Bin 574 -> 322 bytes src/qt/res/icons/unit_tudapscoin.png | Bin 576 -> 323 bytes src/qt/res/icons/unit_udapscoin.png | Bin 582 -> 326 bytes src/qt/res/icons/wallet.png | Bin 3206 -> 2814 bytes src/qt/res/movies/spinner-000.png | Bin 1182 -> 962 bytes src/qt/res/movies/spinner-001.png | Bin 1110 -> 890 bytes src/qt/res/movies/spinner-002.png | Bin 1116 -> 896 bytes src/qt/res/movies/spinner-003.png | Bin 1143 -> 914 bytes src/qt/res/movies/spinner-004.png | Bin 1126 -> 898 bytes src/qt/res/movies/spinner-005.png | Bin 1124 -> 896 bytes src/qt/res/movies/spinner-006.png | Bin 1153 -> 918 bytes src/qt/res/movies/spinner-007.png | Bin 1180 -> 970 bytes src/qt/res/movies/spinner-008.png | Bin 1156 -> 946 bytes src/qt/res/movies/spinner-009.png | Bin 1168 -> 964 bytes src/qt/res/movies/spinner-010.png | Bin 1113 -> 913 bytes src/qt/res/movies/spinner-011.png | Bin 1139 -> 934 bytes src/qt/res/movies/spinner-012.png | Bin 1142 -> 918 bytes src/qt/res/movies/spinner-013.png | Bin 1139 -> 927 bytes src/qt/res/movies/spinner-014.png | Bin 1136 -> 901 bytes src/qt/res/movies/spinner-015.png | Bin 1087 -> 881 bytes src/qt/res/movies/spinner-016.png | Bin 1125 -> 904 bytes src/qt/res/movies/spinner-017.png | Bin 1153 -> 926 bytes src/qt/res/movies/spinner-018.png | Bin 1121 -> 892 bytes src/qt/res/movies/spinner-019.png | Bin 1117 -> 911 bytes src/qt/res/movies/spinner-020.png | Bin 1145 -> 925 bytes src/qt/res/movies/spinner-021.png | Bin 1137 -> 913 bytes src/qt/res/movies/spinner-022.png | Bin 1137 -> 915 bytes src/qt/res/movies/spinner-023.png | Bin 1122 -> 894 bytes src/qt/res/movies/spinner-024.png | Bin 1183 -> 953 bytes src/qt/res/movies/spinner-025.png | Bin 1145 -> 939 bytes src/qt/res/movies/spinner-026.png | Bin 1156 -> 951 bytes src/qt/res/movies/spinner-027.png | Bin 1143 -> 944 bytes src/qt/res/movies/spinner-028.png | Bin 1168 -> 967 bytes src/qt/res/movies/spinner-029.png | Bin 1162 -> 959 bytes src/qt/res/movies/spinner-030.png | Bin 1123 -> 910 bytes src/qt/res/movies/spinner-031.png | Bin 1124 -> 897 bytes src/qt/res/movies/spinner-032.png | Bin 1136 -> 899 bytes src/qt/res/movies/spinner-033.png | Bin 1185 -> 940 bytes src/qt/res/movies/spinner-034.png | Bin 1169 -> 945 bytes 120 files changed, 76 insertions(+) create mode 100644 contrib/devtools/optimize-pngs.py diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py new file mode 100644 index 0000000000..e9481dbbcf --- /dev/null +++ b/contrib/devtools/optimize-pngs.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' +Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text). +#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text +''' +import os +import sys +import subprocess +import hashlib +from PIL import Image # pip3 install Pillow + +def file_hash(filename): + '''Return hash of raw file contents''' + with open(filename, 'rb') as f: + return hashlib.sha256(f.read()).hexdigest() + +def content_hash(filename): + '''Return hash of RGBA contents of image''' + i = Image.open(filename) + i = i.convert('RGBA') + data = i.tobytes() + return hashlib.sha256(data).hexdigest() + +pngcrush = 'pngcrush' +git = 'git' +folders = ["src/qt/res/movies", "src/qt/res/icons", "share/pixmaps"] +basePath = subprocess.check_output([git, 'rev-parse', '--show-toplevel'], universal_newlines=True, encoding='utf8').rstrip('\n') +totalSaveBytes = 0 +noHashChange = True + +outputArray = [] +for folder in folders: + absFolder=os.path.join(basePath, folder) + for file in os.listdir(absFolder): + extension = os.path.splitext(file)[1] + if extension.lower() == '.png': + print("optimizing {}...".format(file), end =' ') + file_path = os.path.join(absFolder, file) + fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)} + fileMetaMap['contentHashPre'] = content_hash(file_path) + + try: + subprocess.call([pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + except: + print("pngcrush is not installed, aborting...") + sys.exit(0) + + #verify + if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8'): + print("PNG file "+file+" is corrupted after crushing, check out pngcursh version") + sys.exit(1) + + fileMetaMap['sha256New'] = file_hash(file_path) + fileMetaMap['contentHashPost'] = content_hash(file_path) + + if fileMetaMap['contentHashPre'] != fileMetaMap['contentHashPost']: + print("Image contents of PNG file {} before and after crushing don't match".format(file)) + sys.exit(1) + + fileMetaMap['psize'] = os.path.getsize(file_path) + outputArray.append(fileMetaMap) + print("done") + +print("summary:\n+++++++++++++++++") +for fileDict in outputArray: + oldHash = fileDict['sha256Old'] + newHash = fileDict['sha256New'] + totalSaveBytes += fileDict['osize'] - fileDict['psize'] + noHashChange = noHashChange and (oldHash == newHash) + print(fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n") + +print("completed. Checksum stable: "+str(noHashChange)+". Total reduction: "+str(totalSaveBytes)+" bytes") diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png index 76a1cccccdef1586b4db69edefb5ee696fb84ad6..2850ff96f42af60dee16162e5f9d881683a9de4b 100644 GIT binary patch literal 6007 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 KRIgLDkNzJMcRxx1 literal 6959 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 DXZ1_) diff --git a/share/pixmaps/bitcoin16.png b/share/pixmaps/bitcoin16.png index 6e89fccad1b841136d54fae3827a31879da5ad24..e9078c3acecf643fa8776536541c9e7ff2d5d77a 100644 GIT binary patch delta 45 zcmX@j(aAAEd1HzcGskvM7sn8Z%ej-=nAeN)UuunEth{%xg8>LUUHx3vIVCg!0B!>h A)c^nh delta 110 zcmeC=IL$FZ*`9&3z$3Dlfq`2Xgc%uT&5>YWU{FZ*2=ZlMs8VHMXlQ0&`1v15zhq!2 zHDF+PmB7GYHG_dcJbzOBQMZkXGRz!1JY5_^DsJUWc4b~Kmd|jhHHPuQCLW+#1_n=8 KKbLh*2~7a#wjMJ8 diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png index ea6e94659dc66e314f48809135894149474b81cd..ed360021cf5892028b5b26eeba9ec8ac48ae6ae9 100644 GIT binary patch literal 14940 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 literal 16088 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 z z-{=$I_<(kSxo038QfqzD(JiNpVTewQK&%vJns9$*$9;!jILS{Rjo;9dzQ2cd6*w8# z5hnhbf^72*FnYQ%hY2s|D>&jHtDd_n>Om5|Pv3rBvp7CKrp8cV%~7OY0$HNXWz1mub_WV@N+6@ya1S$9DMqcTsgRi`P)T&H2X<-XhfBN73m6 ze7l)=bg?AuSBl(j4_}tKvQ7*x{%D;}j_C)y>G_#-)((ih()nc5t4wRr&RJ4H4W#J8 zg_W$QaE4V{=vt;QFt|ITT>UWI-_{vG<&JM9&po`Urj&`BQ z_|n=zZBtk}qz&>z;XTYqZj&u=_uf4}=Q5}5$y~Wwvcn%QtKIdqir0GxEYSn%3jw)yY%B4o8RNd=H!DUOSN29lD z%X-Lp!SJ1@PPc0#L<>fthbRrvJP2TzAB4#O%GKl7rtU$W>_gR{*F(&n>AS%9w<(dU zk%6w^*7J<1f+kUd)8x+59LM-Bkbc$y5vHer$#n2AjevkgNn_bU91)-vr6Urv)nyOO ze}$z6RK}$I49%FK2tJ?tjkY_7X{;n|p}Ze`LVzI!i*bb7jGMjb$Navb9<7z~^34pk zQ$90#tF<9Kg5du6qy_k8h#GjCcic;2#^cfdY)owmWYY)JC>Il9Bu}7vnA~Ci@5KY@ zPd4|_wuC5>hPv-Wc=+M1ro`QC+{>)zQ^i}cgWdI|~ZJLrG!+ z`f_x%bPS2I{M`DF@uL}JL#PzARiqF<^Q3;3QGfSF5;r)yIYM9aQ`nS5YPq7Kj%tO3 z{hRavT-BJ2=2&kO)pu3ki_SJTg|7TeC~2@N7EF?4jKJ&U1!yw68;;lpjBN}(=e%#KSxAm z2?6Z3FOXVP`cszpyw1Wg{)1nmWC_tU)B)Jl)3u$md!*+AF87nfj4bTkXWy@|tN#%K zeUT_ScmAREhgP6Rg(256c9W0eSFf)+LZN6}rK2GAe@J-!Z%*rF^QBTObA;=`1xN!& zbJMV%+V(X^n9!JKJh;?tW@+!E>-Lp@P@(Qx9gCa6`l1m;?U}S4M{voOo$x~yl#X>G zyF=4W@r|<_HO)WU%rE~XaKUl0A}z(|ea)HyQG2CAiBBt<#o)V%bbwTY9zxDWQlF(D z|ESx=)w?$LZgA(LRbKpz6U7PH88uidd=;Fz$JwN7-(HGs-Uq!q1hLFLPje-VVW%$F zpmm9MaFo>Dr)H~8-#5ZXJL-6bjqww19g5joNK&nljK*%iJgOl znpSC*N89CU`l(f$!uR^?b7v}**)%^)vBl39lIQ~hH z?cEXApSS)wy`81}o+~RydRmE&##V+FR%Sp#I5q@!LB|QD+E#R>DMTKvwdN4MDj-cs zROhU)a78~N$j0Y1TsMhf#ih9lLOvu0+LqkaaA!5Gg&YTa3v{IB2Uvl5JO|-(9-WV> z-)#0iu}U=wk%YT%rW;F$QVrsQHY4e*MasmZQUaIa?iCD=a_bQfut!yrhXhOKXxsJB z3_o?d**6$m#F$<>-HP5XJNtHbzsJ1qpKEu~A01>Q27-FN9SR1_^GRKM0oj^xfXG zL9^;Lmd?5aCp2e60|z%xP4np@*73x#F{EQM;vz|p+xChDb}~X?9+u#vtVaB~Cn@dV zwD%={QRq=Z#4t2~YWzguyXMLr1U17_d~1#OarJ2J)fWZn=LeO{L5ql5tHP>dkbnAjNHp){f%YKS}&2*KdxxwSppOL_Lgao*b9-Gl!n?zr=6cxONZc6ijSOwNpD)>4w)UFABTu- zNP9QZBM=}AHy9s-4u&ir?uhhyTk-2^=gjkcn`0=f*m{)SLH`||MM91t5kWrd6UuM@G@LJaQ+~LO7P!RhHLTnn?se-G zy?&=S#Zhs(-{TX<)8Leg>VuvN)T^r`+A6P&DE`)WoxZbeJ|CJ+97w^x*{Y^fC|q_y z*ELx32M>Sv1KbFvXr!4dz87q%Shj(@)L3jhZxF!15ZW`#{sV^xyj9;@YxM)3r~{sik{VHHExNa` z<8ubEC2=bAMK3H)ja{Q-68$b86;%ZgA5WgG>-+zfzLv@ehqdWE`Yf zuv`SK9&8-t0rS>X@-myI z4O$x=G7$L`t(J8r5Wd^2Wd9s<8U!l;;Gu|iK|I^^9H!Ecx)pG*I6j-Dwmdgi@cke^ z;a+W`%71D4w>vFtdu_i=|0cVPazQ;ruk0lJqp!RugoySFRTH0JF&y1TPS79fUAezJsF2f9NOrP8>dz>O4PWf_k6^gwnUNK7ubF z9fEc{28zN*^OYa>+A@UKvC~HX2>*F{{P1zP!Wt=LVag=Dqt@!b`;wm)(ol9)bA!of zn3jq8*;5N*4#@NR6^1ekM#Kxy*&+jUnAR|$Et46@eD}MK4=Zd zJ2>GLf4~Q*pT_3LN3s(~O)HZ1=eJ5=T9Djzpd|J0hW!F_YM^cKrT(gdrH}neLVN-fk1i0PPySN0N*H(f2DyX!R1e=hcAim;DX% zrADOosnt87na6#T`lhOiHrFmop*j%A#w0%Hj!-7*QgvWtXE(2exF7D06hS z2D9rP2M}a~`Xb`NIZD~%d7g}chvSG)k*F&@II2 z+{oSM(-K|?K{Pe6I|!8tEl{ySLFx*@0bULLJK$UKGw{APB3p9w)xGO0cj>Zu|Fq1| zAzK`W*(*CQA}+_0z5iY7{mnCq;od7rolbfeuMNWFI~^qD*Y+42BsLq*A>W^VkWY!3 z8qN5H345KD(d&@d-OPwt0x-M0MzFo}3lh1&e)qJ+YIF2r@kr{jIpO00LQuZDp=^x0 zpbny(b;f-5Wc#&dm0^zn>d*~P_a+3y`?J`h=e!Ra2uJU)E_=9~QzyE~gAJ9f zJU9-qHY?a)NPHfn3PzLaIP~YvA593vR9+-yk@IvCbFk|k8xLc;!h zX**YCgM^wgkiSYq33r5aLgZt7Alm`B7#UxuN`b*eSc1V zUAQ7i@;i4%J0!fN?*+lL-Bx0$+f|@X+uf_gJ_6^!BrT35CG$--K%#{df{h~CO-Skf z%v<)p`QD*Oi*)7)XS*BIKB*BR7xUJr7k;?eaAqJ zy}cMBtwh43MbLF(sQaNOC%oN$B>Na&CW|K%Y+tTK*vD9gmk0^5ERqc5mJkffL$C_m z0q`n%9eLrsT(+3$FJARV?j38~1UDOQUm`i=AQ~%)Y1+REee*giD+d`N?jj~56U8iYg2H-(MlX0|kFJ_~4j12C&H z+R(qwUz(=m%(oH0u()RMaoyQT_}q5*yWXVY^?%e@LgYe`=|}MZUuDaEj)CX38T(DG zQM=Y)hMWL|NFMuCf`&@< zR^a~hdFaIZsZ8X4=mlqCRoIQLkAs>aszU(u%R3up7LK@lp-jYhi2CdEiG3#bdnmp? zwxxwwdxS6!o_IfDXWB=HI{-}(e^gd5Hi zkFJg`R&SRr>l&L&wd)dMNTv=mN#hteiKW6P-EYxRR;9_KdMPmj)ZUlWpETMo-4cu( z?AI!xg;%I)9oV+x9esU)NXb>(+|G==2%k*eO;Z~Lml^QW8b670ll|D9ph@&O8!U6< zYF$8}CZ-2`Qt~*2#mUiK#xMho>PL(RMa%v2JL^c}t2HEv4mWTZnm;Yi2)9`oIpTjsD;f8Em*J{F!oBw$* z@&6wFxq(O^rOMQ*HR%Bqy%}|yd3f`Vi2~sVfs~5V-x`9J$DwJFY9-Q~;SXB;Ax;k+ zzN!Y;Xk~hpFEcOq|FjgB(bZxile^Tpsj*lyv|fZjpHg`Cmx;fW%dRgYKK5itwdNPb zuauz$&)Po^_7qI3KfCq~E+W(O6cn+g4by#8&|0i~Yc}nc)auxq_{kz=T4}7+t3|M9 zI@7gly*p8s!yi=b1#Ry~OKvy5tkfUs3FX3ye{-7s zo9GfyuT*zWSgJk@^QSB2aio293i}L5|6o{~i+ssHS#m##O-;~}ff{iHooxXOm4l)d zqJC*!y>c%qUs}hauoxY-w7fHF)6UL~Fvm`8gAY6~b7Gi5qy;ngq`%ro=0_hkeJH)# zcj9HKw@@>gqYT_U-2%)Qdou@*y)NIZW;zTkz0_JG)o!)hr^TU&z^uQ?-R~yD1c9!O zKW*QZkI+g#YY<=ma8vZ<`U+;4$!}BkC%4W1IwDckUz@byWQKj&~_4 z89vJ!7D73F?;#YpYv=%NPFMPV4RCW$ZNv|58J1)MO)o( zU6bkVvOzF`_ZNe0sYqWkX ztxeF*aR2oUJYNA3izqj~SWl<<@{o<5J#XISNuVKP^ zDvc}-+Q&m+rwc}hiwxVi3_;TJI-Vreh`OJQexpOrw4wc&XSIlke8yh?W!>!llRK8J z&(YHhI1Lk0JlK4H#OLy0-4$p(uWdJ-lm21*qbCW~$B<)*4k2G0aK1*n(Ogki;0dYj zvF~VgI5~RpPmm)=>KT0pAN|7Wt?>#0+Oz9=0b6SObdW zY!4ehdB?QhRmo!=5Lp~KE8~**aD@I%<38vV)O>b*CO~TgdKbuh>%#ham`H{=vfbk& z61~^Y|7`2KuNa_Em%G~8c^2Q02ZD#TvcZIW)^lrN3{*K+Bj7u6o{f8B0AJARfzVSz zHk6$7kUZ4px+SqPj897v>3`hi4QvzlIc&KpWD;U$$>qq z7j0CLeFh7Em2$W8OZ1#C&Y5ikZysb^DDI3wYcoE%4_|@9C9+~y0BkX-)ws7~o^b5R zc8J4(+sR>0*Tx=;3S}m6U9{f0b2!9h^>SIajn7S4=L0wX59>3)NWE31H%rE`&?aJ} z$+H7i#h&cpbey|H=#&B1DdamfN~AV5oF0EOR~%;A#sl`oQFYHp>6ZR25HaaKiV2+oyS*At)J=&oaN~7ssFb}qF^CYJ{hj; zAc_{rD|a|^3d>X+Qu4`d%4=f!hh{$(jwTA#8wsWuNltqDa-7@D0~$eR>t?DwoAUBa zH0iMY7{jn7*Nx#&l*uSXsKG&s1QS1X2y8LN>**3A>``&n2n)Y0eeUBF$cz zmX5N&ab1er=Qq~94!P-|d`0NH-iJ(jM3AWD!GRn89I5VJQHY#bvS?5@xVnXu7tfG} zJ~2JpB|s-7KJWG+g<*`hEl$+`&z&9aRfa9{DA_>3zN^u0zA%CY2+bS)m z{k2`ZwKKIV2r5{^Tsqpf=)0Bk=Z-2c;9&6l& za@2MMpuNMLqmj0X(L?5w^8QJ4G84T6o1E^7=Ayg()Ov3ZwGZEHaQ9$53QdF)|7+RN zddR_QnHgphIi9#&%-X=IHpnI)@`qC^>FEWJrprY%erlzxvdGg290=5hjUgBwHnr87 zcLWnri}!aNZXAA(G5i;DxfG7BnzlN%nYCM<`K#*x$arqYvo*v{>$kg5QDEnwfUG`Vf)2W{e@VSgC>< z#~3o+oRZgA!={qbq+|cPCc|+oBgY)?nlPT=@W|@$tBv3cqFl@ugijb~IaU|%QNa1c zxT>#hG4l!5pYj{DF1~s&WPAwCNMOs$%dZIr2x`pMHu(uKaVwBBuvG&)%;L}N}NhKFfJq?uHVip#-RZW z_Bm@DAa?q|>omj>H4y5_VkwSU8OoXMM#`fW`%QpE;ByawR0H`H`8*hxhUadgT896Q zpzz~;V@|P5Nmo@F|DdhU-NVhIh9#9`uKlEEm-F<5i-KPVRl^lS_S;a;%Bv3uX8-#N zQ<@}Sk(JO`>eyUp#@(*>JX!j~$IS`3orFvH#z%60mMi(9xm1IcRff=5y_R37(%r%2 zLj+_thXeKETkH{C#BHY|gqT5SKv35@6r8dK=V1B3ph@=s`zS5@>;)0X%@q@WT951i Qr_upADP_r0aYO(A0cZagA^-pY diff --git a/share/pixmaps/bitcoin32.png b/share/pixmaps/bitcoin32.png index 56f235e951a7eb35bf4c23b56f7c0ce8a9c6b019..90d532882e4095b58a19027562128caf23fd118d 100644 GIT binary patch delta 1480 zcmV;(1vmQc4cQBjBYy>;NklQ@>UVn2M8e{0g7mn3YsD&BCjC9MFe^1hC`$Uh@c`YD+nqs?*u%Za}mds z^%MJ}X7bLQ`DVG_ch2wre&?KfU;x1WO=C|1{O164Yr0u?M}IeeDl<;8l9VELI=z(T z@5^HcgZIyfv6?ZahtPVY!t(OTT6I#;ckzdB=!EYdqGHp76vDM&odzgN|$ zSZ`PFkYBXX0mwYX%CeL!=lg7@EY-KWEg5GGc6uU^POt&lL|bq`lfG>OcH>1r zdoEL!-i)*jkAFF~`{=mxoHI`jpr@mUmFJ#e34XiWoZpjaY~Qrv!DN#pk2C^fGiC{R z&2X#B+>&O}+R!?B06m>OtpCq`w#z3jl$_bWB_1&t0U|a=+Lw&Crv1Lcq!ZS6?f^d! znIM3!TU~5$V2~Z(t8ld)i>D^4wFF1~!PnRmyk;&R@qZnX1>fndF0Go~*VD%|*EPZb zG;Oz7jk0-(y@4?)&yYPf&id}&b0y{BVUI?lLA`mn}q=sB^OSY=}QJ2CfGhiIR%j3HJdS( z$bdfw(0^2;0*6Ud4PvcQ_!@g$IeX%_R|Em<@{J1>qx1U%i*+q|iP0$?4ei0vz#i;T zp7jgm9Dw?Q3YNX=z{^q_V+0~CGR0I7z`D-^3Mm*bDLg6VLHx>{@JG?_(1d}AZZ+A3 zCTMNA#sOf(K=Y-m5GC0J<}aGUgY1#nj$H!VTz_IB1Od2x;B=Wgm^h@fB0d*}*WlnF z4BYOAf&Kw}4)EvwEA`tH2(t(Q*C~!*{kl01igMm#03}No1b`IZpy2dz=;9#m7#j)f z^xgqJvpm4(BM)ABo<=UPNfgHSn=f7k*Y_PEYg-2Y?LT)Vq-;uteQWmcz#ITF>Ho=! zdVfIxPKMGp0zfB7i#oy`9{)iB<}a9XXXJ=Xq+<^9`F?N*yNsqy1F4aRVY_P#Y<1cU zUoQ%RjvF0Np(y8NILv_m+!d9A06dIbYpI=zbuHlJ!2%9oZ$LZ;^iUa^1OPUzdlC>! z&X|m}6!AGcICVssz8wd!eu4auAOO5{j(?vhxi%|U_y4g~F6W%Gt5511Z(SAx9?FhdFWO-M4JS-!Lg!puYXeqDJj z4@}8R`g=}y1(B{fTqvu7A$P7IfU<0*A-3Tz5i&qp((1z`OjxxOR)5a+ z9N&pPG+D||zh<7_x%0~E=LG?% z&Ns3+kL^1MHPM{6=h)v$jVLD@UQ~_;gA>7Xh8s^#pIPpB6))#ifx`=@UyO_%+npnA zzjjl&6=U`?b#0U03S-Yk`j8w@BY!$qa26V?8vq9kZVi=J@U*``xYb6mdd-Yei~|dQ zpI^^dN%neTeh);5zfp8t*F4+a(*79NaeEiT2E!^8zb?dN>nGiLD@Hab`6vh(zv-}7 zkZEhb)Jw2$sMNJ;1Go~A zrukxYBN-ZvQ7xC7S!PW7JnVo~G@NLgj2@hj2yoy+c`i1v$s}oSXYZ2%XsEivhth(? ze4VY1(Sh#MTV`%vq8r+muucLm)FZbU3DbfdSh@>aN_)|ZJE!}2w$9hl9i?w ij~>9&|BU{30R94{CTKq!Fjap50000(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ?bV)=(RCwC#mwRwj)g8yb=iGDm?kl@l zHrZXw!X`AtCPAnf%Gi|f7$IaBb?^Z*bnIviqb);cssmP~LVt&8rK3$}oDS26V>Adp zrh?ci0)Y@KNf-qUNn8xCki?jc<^f4|bD!t*kA)S?V`=~Kk9ua#Klh%wzt8V?zQ4yM zLI`}Di{e{e-vO|1K1d8F00KY&Ep^Q>4HFWRkQh#&ucLQvPkYa*zRtddqeG*4hN^o3 zaK)(%c(XIl1b=b^b@?T;-}X(P)@7(V92ri83uhuLoCR)i0D#luyv`o^rUJukF3ZbgiIMyZgCizfq$%U*12U5mjAr;-m)VZ{)|Zh zCe#2S1hOLILm9Doo4ibFyD?z)HTch@~_v&)c}go(~EnIS8jjm)5L+PRPe$-y{#_wOPqKtyji4(=t3`6ogM#tX1IUY&15#^eG`eo;da20;h6M{;#AOa>O%4R zuN_@)Syp<0XhYjAt?#$oVRzZbgWBj-<^U7WTMb+%qC zlcc2RIOpIN$FiT5cH3O zX@8;TY|kP9`=Ih*qjO=04ho7J@-XH+6d^X?j?jkS2Yxt7NLAy1=P5TnkTCfJ@#p`ND%^4 z(-AI;;E6XjBX+(QTUTzz9UJb#=Dl0-_Pd`N}`R?Q^5z;gvXd z;tUS_eSZ=l8L@a;5!y2xL!5I^O5nfA4*=*s-38fh1G6Q?cXdllg5Uz4ED!G8w0{P& zVnbW~DQx-IHZ<)$hG*AqPYU%)1++Po*0ccr9RFF%G;gSt3NDhN)lKxA`5cMi1TXs-Pjp?|#TXnLyw(S|mxd1@`@-F_>yga#%v6qXj%-3Y)Q z_q2>Sp#-h=IVRzfnQg>?k^OaTm4b5PdVL@UP z@-;Jo5CYm*vb!k`WkQkaV;Zs}!OwsF`sN?|!~QNqHQ@HSr`7ShBQ0&U2#A9R!WKP+fKNpr3zs&5iD41UW zr^l5N?~M(m*8p@!yI3H&fT0^0iVb;t&wa7Dzx%6&@yqd|_@&VwN=!;PJ6h@q9SjH}n7i002ovPDHLkV1g5r BNMry2 diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png index b82645dc5f78b4049fab827233b9b0132ece2c07..1d3ad055774fdc01e2ea8402998ce0ced8766d35 100644 GIT binary patch delta 2800 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 A5C8xG diff --git a/share/pixmaps/nsis-header.png b/share/pixmaps/nsis-header.png index 36ad07532c4bba566204c956f94b84c04850b68a..93cd83b171685badfd1fa7e0b36f5185161e23f3 100644 GIT binary patch delta 2723 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 delta 3469 zcmV;84RZ3T6^(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ}6iGxuRCwC#n`=;1XPU=<=hk#L%}rX= zk*lI|iI)JANCvPnJA-DD$rvN1M#ofYWj4;{gBvn6mDD=BI)A3(e3;Ty{1Pk7j#-mb zR&vpqsS23HiGWH*M5A(1xyU7g0urFR>FYWBp`jzv4c(eJ*{y!6y1M8-=k51A|M$84 z|L=>SX_`jZ{!g12c0m}#u!TVkTNuQ!g+cuPVsfw-T81oie9_LOx@NkXx)}VjAIn!( zG*u%q#>njC1b>pVQ%KKU#De?NF~yn?rSKZL7beU^F-C8W^2H}-Ia7I>-qv15hemN& z?ReZCymxwUR}_T^lOAJ?k-2GeS^Dq_zW?Y0#3sasz5I^?(c|{ecD9w1@6~dqvYwmQ z2GP(EMG;XF5JV9H0R+%A4NcWhJu0fI0uYxF$MSz#L4QF>5sM$pK-S4&Z{JH09X1E2 z|N1$9*>{+$7p@{oB09YeQ5He-g64lT5D-vR73Y`(x64g(b{bE-u#Vi~JPgssu*dHO zh;Emg&;MM5(J}P1U9Vrg=16P8XW0A<5FDXcI&M)vaQ;j3Mb{w(fh5 z2OfJ6y?@CN_WEsR8?n*V*g55MbCMZz;_MJX)HE7v8`-sX2WT1wlObT#O#r7e=ny3l zm(zuF%!wcfQ?7M8UD&O5wjbWf(p5{5l&`@)T3*RJI}Zl+u!bljDcLC$Y$&3jq$ngO z{cH9w1AhPFq3vYkX9oN}lsN*#Cz{F3&tz@clYi5KP+L(=RryDBH+4-rR$)mI#ifs6 z43NntwU5_Yukp@~gSf_=(*g)!v)C{v&u0CL8`$>8G72}W!eMiud8XbYD+)S&1p7+& z(%aU1n}e-EJ7;XvMoV2Y3NHpmp&iWqoSett(A&iVW@AAV+TKBWMKHNQ_x_~0J}?G4hqPc89=J7s0rwx zyS4JN{j{8Fp8VPKuhUZ39MU-5OS)ec^qVbuyAH zA&B0;5d!3G(OX|Xd;1ty>M!GQx$oLRW1}|SD0_X{Yq}acXI$+74OR8uTFpCJ{?VlQ zG#ov1N8_~AHT#{X2;j6kIr%{i*RNimltu*v+zvNmqhnZyEm(#vSjS%$y9Mj86@QoA zHSW+cEW;Mu4wn!7$wd_OMgv2ALtL!BKz~>NH{zh~rY^rJ>(;sxj8)y@=uoVnq>$n* zYe>pU4tP!TEs+>#vBW2u`Ca8J{NdEAtbKl6U?5L5`v>uQdoLa5JJ3`OS&`8+FXyvc z?P!{YG0I5v>{wzG;)qFzB_<)3IDc~-QM00bQL8uUiJLPEoj$?`nm?<3RECHaZUea!gH<7k%0rQt65fvYeCaar5F?TlNI`YkxpwOyrD{Sg<0U$@S~VP(cjFic2R) zQR$woK5#;%E8aR>D zfw_*wn;Qqf(6yU% zHFhFM0_H@sch_Qq_YDY`;!M8CT=Ap($u7E&KmGa*-umsE{CLZ1ivM{HZ4FnbI`9#r z1H*`tmrtUC>hXjQVt0Sgbt(`ytf@FoLsdQ2X;heos(<>BWW7L?VbhMy(?<0~!`5=D znSq{u8Y=7QZ0hveyiHQAPBl+j7&1WG@-+H7dhxj3NV1HqQvk4A#t=mTNs`8;)mvp& z&A06|p{06U9wbFZXV8(7ok~Qcp1LC^`Rvd!<|Td)K@;$JJcy!*-lz|q?4D{4D%DQM z4TB;6Re$9l1r1_BN#UegospjvP`DoG>8Jep{q*3Y|WJx+5pK(RrOYDRW6(z97VU5Ll{;Pk%H|5{HB3hBI--V0I7+N>)uPp8Hc> z0*MkEvp4$|=QM;6Yq)e>ySoF(81$ZpSiY@j1s78;QeeM|G>{3_9-yu%3Tzu5IO4?OxHH+u%DIdq&OuYY~W=*6(DGuDonN&m?W)_Zwag7_k{EGpA$-89>%4JhbiyT&zA%^WU3j|Dv4} z@7GeWzK{ogx{`#{IbN;v7Jb_kYhqzeIwSSMO z_$WLcm9C~v#zt)Y&fi^75pMFDG9Ainl(fM|?1@>0cic9*;yGLWTvp7qO>eIUw;OyPziTI!lO@m?+M z4Ocku(tmOPk8)U;la6Ut6yk*9GOpMRT^r;~uc=-tA}ca4y?^&x(sLJ0I*%IYe2KpmJdmsPvgmTSXsy4(ftSkZIDglUq)6xt5nqEf zacKB<@WziUqIr)!I-O3^mM>t_j?HA`XQ7YOhdq9;Km_mM;lB1>8Y=7g4~t-cP>I{6+IoCiWJ?cJDx(u+hO0+RwFd z>GKxa&$ZFp*30P4QGYa#I!T5TWr-MbG;`ACl9Zi7+R`+#3+^K(e2o7e58_0W4fWon z=|m&VC!6^4at~i!AHwZ)qiGtFA`?3&j+CrqmaNQV$;u4k=FUQiP{JPmu7DV}@3w{i v_bd!z*uo%&EevAV!XSo04BL0d{&xTgSoe3<0K)2W` zd-Liapr8S-Q7~W>^25WTh=CH_) zbF(-4V;_t@v;Tp&4?lijckUf#kbqy}Rl) zCqy%11rQCQ8cBp`uZ?|Tu0YcAJR)TkYy}`c^3KDJ zdhy^M`weJtoPQ8norI0{~GmMxNRU?{`dK*s5I`5=3$bYX4dub5ioB1VY z`wt#a@4=PRs$+8jyvLk}7%9H`nf0kD`J@X&uZZzpS2jYYgL2RlhfWn`?6VuYXxC-dwD5J5WuMQtd_%QeCScFe8u> z%P|3Ls5+XVYRoRRxo~5S@2<{pqrC#XP1duw7ci4DHvsD(WN`nW4;bHG`J03H?djXU z)amlae3MJ_O)k&3__Nt!u@l!8a7t?)G=Pw`s&AK$>J=MA6Yu}{GasG5NX>ha8P^xv zn}2#aZ3rQIP}WrCbGAxm5r6c9vRtj zl8K#rHo9I2cP|Q zH-T;cA{vabB4?sjFj*8#)CSj^-JSJY&38x-eN3G-^3%WqG&&MHZ+B-v`-IxiL{MK^B(s;ibTdkU2-@ zJ-K((yr&*~=|+(=Srp7>+0Y!AC3aVwfOkT0u0M0{sd>*xk#YTIa~Zh2?EuZ`sl~BF zhhM&W;g{!ULvX(aFS++p3&9m3NG2`MoOe!sx^nH~=JeG0%|7>kaup5{<004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x1eZxfK~z}7wU^6_ z990yDzjN=cs_vfjJQ70!3I+m-2u8%LeC%Di%pahj0k=UgpnonjaWNaoBD&G7NZhy( zvlBH6MiNkhA()3z$4qo4-I-U{z2~^7>h77$BjIyp9S-!~br}pk@Hk_bll=bMD(Nm=~rKifi2X;1qhevjG zWB>!LgGB>1C>hQv84-x8BQH4~fIw0u)&Q|iK{SX8Nvc`54Zw_~N-ya!xEcwmmG}3A zZ4ZE`kyNcrN;KQxfFe~I3{p~%(IG~6041qXrnDh=GJl9rIbjerjT3(y2b2^OeFu^V zQTtBF03w;e7-<+|4=72K^)wAst3oM|w7QN+RR!Y!i1@b z0cvJe?QXxbS>!RMO6{Nl4bKxox0kSq9mgi#n0>RVU9D1L3L=G$r*noK|(-OKF(@dLE=fgl`s?ojrE&fO-$E8djg13*bHG zJj6)x)n~^;5S!jVGev1y1ym!Y3MBROtwu7tBVaX`bt<9=Km6V0`?&>h4oT2YgiyIE zB3P=gLjdQd0%n!!I8+_`0ksB5wG#~MeLckOqDnQ7B_#pR$P(?aRr8$Q< zhdGCcgL;Vfm^j=@w<~3NS^(OIUw_g>_SUtswNlt4tsTc@dgq?4_=+r$hYVR;DLa=h zz6G4UkAHKWle6anK=;JE=kDir`_&`+*utV#76v2B0wO9MINLcn`^6|(9P4qs9)Cc9 zsUl~xku#BHwDOE1cp}^Omn>CHzdoj$1v8C;siL5rR{+i6Ss65e{~KW4FeJSHU1Mo?j7wsW3tGZY8DkpqhPX;)5cI@5#NR;XTdZ zD>sUqnWCVTWn&2%2VkC9t~mkkgy7s@q}@<5p)CxH{^hW7#!%_{bsW{mVrN zE(>0A@1+rfD?*S)o;mNF{B-U2Q;R2#9Upbge*t-82Gfitt6cy903~!qSZ8!(VRU6W zV{&C-bY%cCFflnTFgPtTGgL4$IxsalG&wCWG&(RaGfli!0000bbVXQnWMOn=I&E)c wX=Zr#GdeIeIy5;gFf=+aFhURn>Hq)$07*qoM6N<$g5c3@2LJ#7 diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png index 8727ab8dfd133a189bf20d301bb9e4b2a59dde02..8c9052b9076d8b5b5a798679f8fab4987e98f049 100644 GIT binary patch delta 444 zcmV;t0Ym<$1=RzPBYy#$NklsZ_Tqi6Dhsz%Kmvz=01+-RF-Z`{(AjxAdF-jh z1i8h;WI4yG!GDcpY^Bu#Kp)x9z7703Ff`bf!Jz$fJAXu$@%PG5gT)~}nr$=4#WRbP zsKK3iTOml=p$w-~;3!YRfER`_sOMY?-xUj2vMPCe4L{ZF%jja@QiiO8`WjhADAPGX znwaLMz*(7L)+)UsVINxxNAW?fhQEis>?xk|DREJp;WY`33&dP8@U;f~fTu95cj@u{ mAzY;uh5yIyHP(e)*dA|G*F6&G?P!Yt0000{XE)7O>#F^4!at6_iWT3-eR#$%o?jv*e$-(K_AaB-A5@bSF@-@j+~6P@|^ zv{St;tsgv4Vecv`2-LeG7jweZkB?7p(&F7yf);ty{|t|M>v;0$vq$l3?=~w*PT&6f z+1kqd^0=^-bML?Wp8YKNbG7k$!AXC57TN4%-NEo*wI{^M+KaQ;sfYX73WE)s4t#Z) z!f9^uS8UJQ848x0UWKkHKCasQ??C{Y_QWp?8`4wbzr0R--+%pe5cg6`$B6w`r1LJ6 z$+|C(-Sv)@`>kgEiX|P2s`(4Oci&ok{O~M3ZsOwN*zuvZeNNn9YtW z@|FRcgy;E0GcKOx=A(Ec^pp9nt<%(HE*wx)IAF2eLuK_Bg)@m3=MvWIsGTqtI@xx1 z*1_C88p1*)Oa@Liv9~w+@8;xL+h@k{>(X^g(ZXk$Chb=>ua;PpCDb2h&lZ_|kXbTZ z(c{e1M>?|(2=CDrwwvjA;mlUCy0fC|5`#C_bhEv(xO{QvfmEMp_E+ggW-hgPoqGAe zTb+*&nwC9kO@001DMxtmjMk9HcYYo(YxlM^O;DY*;+9Bx#lZH~;_u diff --git a/src/qt/res/icons/automint_active.png b/src/qt/res/icons/automint_active.png index 7909d609dcc8b17d2aeae808a8a878b6035dcf3d..3cb7a5469bd4f3b35f6a7789db338097732069b4 100644 GIT binary patch delta 214 zcmV;{04e|R2=oS!Be7qH0)MqhL_t&-83n<;Nf@in@axzz`VJCFR2=M8>0ED24!dyjzL?LLIXfiir%yjpeV1W%}W6QotKiTHO>f7 z>0~y$91Ipsw>zKg-%b`)Qr#`<)OG!IcvJo&$=VrLu6g`PBuO?#c<`NM1sEG7k!nYQ QbN~PV07*qoM6N<$f)iX^4*&oF delta 468 zcmeyu_K{l59eatVuPggw4sm8y!~W2FmAD%ItS`&+$8_w=U+6f*Qlw zj~IzBYy#GNklC`SDK~8#j06gAUFcv+7t+4@G5Tv7=z~RzTaN3s#*` zM%%8;(bb(w5zBvPGRdH6@9gQ*6`V6*lX|<6#c~`7k_BZovufD#(P z-aiHbE$gnL>0aZ}k%%ByC`4&x;Z7YPf$079FLw_w_n#`Bx-pwlOBOgX(fd7G4g!!Co`+NWZ002ovP6b4+LSTZ^`Mf;< delta 559 zcmZ3=e4J&1ayVq z_J^+ZWnf^e_H=O!(KzpW(bqd9k>Tja`^E2N-H&f@J0>;PtMy8+TFMvMTcRPSx4mT& zukAH+)Qxeyv55b|vRnKv6I=zpIPFW#zh$v>k@4p{V$Dw?>t+ARoO?89g7qq!Ud3E_ z)td`DZSSx9yJwTR=;cGN4s3pSwDEnc+%Dew^ZNR4Vz`?6rrEx{e(TSZ$psP_XRgHe z@XAg<-TUK7cS!WtXJ?e1^uF1x&p*$%DD}_+)twF3-aUEq;&{u|*RwY}a;Nu36fIcX zyk?8l{Ye|klow>)vGn%StY4Jro%H`xnr8P=`{2%){hs-`uP=(txtQLYwRzf+q&M6} z#a&v4!8hu;4wdDR=z6eq|Uc&_ZB`?BD=otBfc6keIHSh6ff@?q%D z@IyD8CU`GhvEtT-WqC&%|5c}QPW|=cZu7e}84(-TWrja~_~NocBX@Zg|2J2b`jtLv zr{vGyUG?w3QdRla&u{m3?>){nYxm37!rzyRyZ6mwwKh}R=62gNGxf#ag6&fO85+Y| zemaIey910I)e_f;l9a@fRIB8oR3OD*WMF8iYha;kWE^5(Y-M0-Wdh`ySQ!`?`|b%t g(U6;;l9^V?V5EUdhm!!yE1(VrPgg&ebxsLQ0PwH;%m4rY diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png index a0ea01a76aa147a4f58986ed43bfbbd62b6cdcac..80e82ad637df0fa85a899a238da9c3f11014af74 100644 GIT binary patch delta 846 zcmaFJ^@MGLay_%Qr;B4q#jUruW2bI55MX=Y;ozk5V1dOAD-Av|_M?u4418V9j}l%# zILv5K@ja>f-1g-yz8o`E4z%o!oASXyZL+=MB8?M;e_so^YrOc7p2*^sKr~w5e4yU5 zwsp-XPWkn7nageF#4xYv`tLq{$AdO~mykb9F&`XSj^6*h|7P8q-3|^-*?Sn`1PYGX zyTq;F%*t7C!K_*T!37SF?M@DD43gyVCU;=5VEjf3ThC{abs7uQok<2 z%Du_8|DJ;Tt3tbl4rV*KzH=(p;^V2M|K+OJ#JLX^z^Fm*W?d&dbxDK~|5=qfD; zKAYwntRmc`@<8UX70YCStSb^hir;z{~=HA;HmwfSzg3a+cx37yrX%NgmOg9 z$tlYBGMT2{RC=Lx!KESKyo~fzxBqz!4NvnAS|3`qD^pNmtGU;={sr9K=QYGqIt5RC z5Im?`&-6s4=*o)ak1wcl9DOEm<$l@Dv=>uk85eTPi!FBVNLkKh$Ry#|ZeYZ8!H`Lr zfq~7MruGSRTBw^(_e{(b!OLOP7DRUIQ{xn@B`0IhUzH5C2OYHv(la#mEWiN2k*uv{1 zq|9Sitzp_!cRkA0tKizb{UtJu_pENspMQM9{icKKEaf?8n`tF%+S&Ty@s^X^qS?HY z7Acu>IwqBDaEY=x_^Bo8wy%((&TR*;-T=v~kKPrDGM&8i_Q@5FOB>{v?e01}*z_lc z)vzhB;17S{;dWcrdcPgFWDOU)Pv|y};JTS=WK8Nw%g`%-1L8XWeUSN;WXwJ*S##InHt~RBoti^ zUkKGqPb9eL#OBPL8?^1R*;&CV6)0(E;JDFBmwHj5Q+>!O4H-CB{dz7+N Q3R literal 1377 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 QxBvhE07*qoM6N<$f^&v31ONa4 literal 19488 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

$H#B_f{w5Dx<|w+ zUuGXlv9Q4ABFu(L)qJ@o-R5}`$?)F1LGKbIW)xs$F_5h15^}ZQn*AvVPYNXcg;qim zoKSpnp(a!;852qexPu~S-{yx}~HIRy`%2~Knz`$1xBiusHR zkH4lU#C+UFXBNe59!>%?!Z-QC{o6gKHx53K-A>J{trz#h%k#af4Bt$o9c}9a8knXO z*@V@LFhj5fr+1$aCnWPJk&}t?7@ZAUhsMRf3*0;sN#oKk+THbg&a~WYIIj%Lcu;Yo zn^1m83;dRL{B|2iUXA#M2xd&)h*<41P1I82VB&>(fLI3n@H%j>^p{8l@=5`ZLOWbS z)za<_9(z~JZM;F=oN&PM9M2XcN!afs$sE+5Sd}jKz9VnkR}XGDo^oxtT&sYlFZkPX zwGYmg>Lf7$h#YAR1-7-vuPXT6P!uE7eXgL$u*}o69 zzI*+Sv%sj)Sgj5dc=kw@zVHp{^LltIucGl-Yl^?zuk*tdzOBq&u=Ct*e|i*15h#aM z9kQFbNRdhid=`<~yXWPIsYjFWR-p?t2myvH3L#O`3S8!XmY3F!AjX0$N`j(lz%pnc zvaL7Wsgy*hTAgMVdas~;dX&C6u9+2_(DA$F)_=JEQL-7F$LDB4&;l6Is8qRk%W5!g zO8XY`s(X^9dKriS^rJ(qM7Jb@E%QCW^yu|gq=u2%k6*C63y_7wkcg&Ujtx)0MD&2A z_4rX*ps}C#!gAds{1V^28$Nr}>i;lp>0U%zEBtjd@dt(Y?i z?0XB+o(0hb6pN__P<4f`KA{GefSc1#Re}c+)3?aS-BvY@h?y+v&e_ZWg z;XRISzq6FeJ#|mXmtacc(eSIIS~GF_=j)S_G{w$;<<`uPP-LBkX3YS z3FhbD8AILZ1kGLC4|~uUq+Y$Nisp1qLR*!w&?C~8cKYZ#RN4&rQjyNW1T^cH^iTcs zl76Sk7kl3NJ{+@MM(k%wu2b{F^yMue_>i2L8}g(#HhsQeF=3THXby2b-&%Z^W7N(Pf1YjNrt#H7CKz)bjh5mKi4

"), QT_TRANSLATE_NOOP("dapscoin-core", "Enable staking functionality (0-1, default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Enable the client to act as a masternode (0-1, default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Entries are full."), -QT_TRANSLATE_NOOP("dapscoin-core", "Error connecting to Masternode."), +QT_TRANSLATE_NOOP("dapscoin-core", "Error in CreateTransaction. Please try again."), +QT_TRANSLATE_NOOP("dapscoin-core", "Error in CreateTransactionBulletProof. Please try again."), QT_TRANSLATE_NOOP("dapscoin-core", "Error initializing block database"), QT_TRANSLATE_NOOP("dapscoin-core", "Error initializing wallet database environment %s!"), QT_TRANSLATE_NOOP("dapscoin-core", "Error loading block database"), @@ -289,87 +270,57 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Error reading from database, shutting down." QT_TRANSLATE_NOOP("dapscoin-core", "Error recovering public key."), QT_TRANSLATE_NOOP("dapscoin-core", "Error"), QT_TRANSLATE_NOOP("dapscoin-core", "Error: A fatal internal error occured, see debug.log for details"), -QT_TRANSLATE_NOOP("dapscoin-core", "Error: Can't select current denominated inputs"), +QT_TRANSLATE_NOOP("dapscoin-core", "Error: A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("dapscoin-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("dapscoin-core", "Error: Unsupported argument -tor found, use -onion."), -QT_TRANSLATE_NOOP("dapscoin-core", "Error: Wallet locked, unable to create transaction!"), -QT_TRANSLATE_NOOP("dapscoin-core", "Error: You already have pending entries in the Obfuscation pool"), -QT_TRANSLATE_NOOP("dapscoin-core", "Failed to calculate accumulator checkpoint"), +QT_TRANSLATE_NOOP("dapscoin-core", "Failed to generate RingCT for Sweeping transaction"), +QT_TRANSLATE_NOOP("dapscoin-core", "Failed to generate bulletproof for Sweeping transaction"), +QT_TRANSLATE_NOOP("dapscoin-core", "Failed to generate bulletproof"), QT_TRANSLATE_NOOP("dapscoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), -QT_TRANSLATE_NOOP("dapscoin-core", "Failed to read block index"), +QT_TRANSLATE_NOOP("dapscoin-core", "Failed to parse host:port string"), QT_TRANSLATE_NOOP("dapscoin-core", "Failed to read block"), -QT_TRANSLATE_NOOP("dapscoin-core", "Failed to write block index"), QT_TRANSLATE_NOOP("dapscoin-core", "Fee (in DAPS/kB) to add to transactions you send (default: %s)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Finalizing transaction."), QT_TRANSLATE_NOOP("dapscoin-core", "Force safe mode (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Found enough users, signing ( waiting %s )"), -QT_TRANSLATE_NOOP("dapscoin-core", "Found enough users, signing ..."), QT_TRANSLATE_NOOP("dapscoin-core", "Generate coins (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "How many blocks to check at startup (default: %u, 0 = all)"), QT_TRANSLATE_NOOP("dapscoin-core", "If is not supplied, output all debugging information."), QT_TRANSLATE_NOOP("dapscoin-core", "Importing..."), QT_TRANSLATE_NOOP("dapscoin-core", "Imports blocks from external blk000??.dat file"), QT_TRANSLATE_NOOP("dapscoin-core", "Include IP addresses in debug output (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Incompatible mode."), -QT_TRANSLATE_NOOP("dapscoin-core", "Incompatible version."), QT_TRANSLATE_NOOP("dapscoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("dapscoin-core", "Information"), QT_TRANSLATE_NOOP("dapscoin-core", "Initialization sanity check failed. DAPS is shutting down."), -QT_TRANSLATE_NOOP("dapscoin-core", "Input is not valid."), -QT_TRANSLATE_NOOP("dapscoin-core", "Insufficient funds"), +QT_TRANSLATE_NOOP("dapscoin-core", "Input commitments are not correct"), QT_TRANSLATE_NOOP("dapscoin-core", "Insufficient funds."), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid -onion address or hostname: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid -proxy address or hostname: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -maxtxfee=: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -minrelaytxfee=: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -mintxfee=: '%s'"), +QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -%s=: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -paytxfee=: '%s' (must be at least %s)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -paytxfee=: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount for -reservebalance="), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid amount"), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid masternodeprivkey. Please see documenation."), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid port detected in masternode.conf"), QT_TRANSLATE_NOOP("dapscoin-core", "Invalid private key."), -QT_TRANSLATE_NOOP("dapscoin-core", "Invalid script detected."), QT_TRANSLATE_NOOP("dapscoin-core", "Keep at most unconnectable transactions in memory (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Last Obfuscation was too recent."), -QT_TRANSLATE_NOOP("dapscoin-core", "Last successful Obfuscation action was too recent."), QT_TRANSLATE_NOOP("dapscoin-core", "Limit size of signature cache to entries (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Line: %d"), QT_TRANSLATE_NOOP("dapscoin-core", "Listen for JSON-RPC connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Listen for connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Loading addresses..."), +QT_TRANSLATE_NOOP("dapscoin-core", "Loading banlist..."), QT_TRANSLATE_NOOP("dapscoin-core", "Loading block index..."), QT_TRANSLATE_NOOP("dapscoin-core", "Loading budget cache..."), QT_TRANSLATE_NOOP("dapscoin-core", "Loading masternode cache..."), QT_TRANSLATE_NOOP("dapscoin-core", "Loading masternode payment cache..."), -QT_TRANSLATE_NOOP("dapscoin-core", "Loading wallet... (%3.2f %%)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Loading wallet..."), -QT_TRANSLATE_NOOP("dapscoin-core", "Lock is already in place."), QT_TRANSLATE_NOOP("dapscoin-core", "Lock masternodes from masternode configuration file (default: %u)"), +QT_TRANSLATE_NOOP("dapscoin-core", "Lookup(): Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Maintain at most connections to peers (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Masternode options:"), -QT_TRANSLATE_NOOP("dapscoin-core", "Masternode queue is full."), -QT_TRANSLATE_NOOP("dapscoin-core", "Masternode:"), QT_TRANSLATE_NOOP("dapscoin-core", "Maximum per-connection receive buffer, *1000 bytes (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Maximum per-connection send buffer, *1000 bytes (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Missing input transaction information."), -QT_TRANSLATE_NOOP("dapscoin-core", "Mixing in progress..."), QT_TRANSLATE_NOOP("dapscoin-core", "Need to specify a port with -whitebind: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "No Masternodes detected."), -QT_TRANSLATE_NOOP("dapscoin-core", "No compatible Masternode found."), -QT_TRANSLATE_NOOP("dapscoin-core", "No funds detected in need of denominating."), -QT_TRANSLATE_NOOP("dapscoin-core", "No matching denominations found for mixing."), QT_TRANSLATE_NOOP("dapscoin-core", "Node relay options:"), -QT_TRANSLATE_NOOP("dapscoin-core", "Non-standard public key detected."), -QT_TRANSLATE_NOOP("dapscoin-core", "Not compatible with existing transactions."), QT_TRANSLATE_NOOP("dapscoin-core", "Not enough file descriptors available."), -QT_TRANSLATE_NOOP("dapscoin-core", "Not in the Masternode list."), QT_TRANSLATE_NOOP("dapscoin-core", "Number of automatic wallet backups (default: 10)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Obfuscation is idle."), -QT_TRANSLATE_NOOP("dapscoin-core", "Obfuscation request complete:"), -QT_TRANSLATE_NOOP("dapscoin-core", "Obfuscation request incomplete:"), QT_TRANSLATE_NOOP("dapscoin-core", "Only accept block chain matching built-in checkpoints (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Only connect to nodes in network (ipv4, ipv6 or onion)"), QT_TRANSLATE_NOOP("dapscoin-core", "Options:"), @@ -377,15 +328,12 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Password for JSON-RPC connections"), QT_TRANSLATE_NOOP("dapscoin-core", "Preparing for resync..."), QT_TRANSLATE_NOOP("dapscoin-core", "Prepend debug output with timestamp (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Print version and exit"), -QT_TRANSLATE_NOOP("dapscoin-core", "RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)"), QT_TRANSLATE_NOOP("dapscoin-core", "RPC server options:"), -QT_TRANSLATE_NOOP("dapscoin-core", "RPC support for HTTP persistent connections (default: %d)"), QT_TRANSLATE_NOOP("dapscoin-core", "Randomly drop 1 of every network messages"), QT_TRANSLATE_NOOP("dapscoin-core", "Randomly fuzz 1 of every network messages"), QT_TRANSLATE_NOOP("dapscoin-core", "Rebuild block chain index from current blk000??.dat files"), -QT_TRANSLATE_NOOP("dapscoin-core", "Recalculating coin supply may take 30-60 minutes..."), -QT_TRANSLATE_NOOP("dapscoin-core", "Recalculating supply statistics may take 30-60 minutes..."), -QT_TRANSLATE_NOOP("dapscoin-core", "Receive and display P2P network alerts (default: %u)"), +QT_TRANSLATE_NOOP("dapscoin-core", "Recalculating DAPS supply..."), +QT_TRANSLATE_NOOP("dapscoin-core", "Reindex the DAPS money supply statistics"), QT_TRANSLATE_NOOP("dapscoin-core", "Reindex the accumulator database"), QT_TRANSLATE_NOOP("dapscoin-core", "Relay and mine data carrier transactions (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Relay non-P2SH multisig (default: %u)"), @@ -394,9 +342,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("dapscoin-core", "Run a thread to flush wallet periodically (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Run in the background as a daemon and accept commands"), QT_TRANSLATE_NOOP("dapscoin-core", "Send transactions as zero-fee transactions if possible (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Server certificate file (default: %s)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Server private key (default: %s)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Session not complete!"), QT_TRANSLATE_NOOP("dapscoin-core", "Session timed out."), QT_TRANSLATE_NOOP("dapscoin-core", "Set database cache size in megabytes (%d to %d, default: %d)"), QT_TRANSLATE_NOOP("dapscoin-core", "Set external address:port to get to this masternode (example: %s)"), @@ -422,9 +367,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Specify your own public address"), QT_TRANSLATE_NOOP("dapscoin-core", "Spend unconfirmed change when sending transactions (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Staking options:"), QT_TRANSLATE_NOOP("dapscoin-core", "Stop running after importing blocks from disk (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Submitted following entries to masternode: %u / %d"), -QT_TRANSLATE_NOOP("dapscoin-core", "Submitted to masternode, waiting for more entries ( %u / %d ) %s"), -QT_TRANSLATE_NOOP("dapscoin-core", "Submitted to masternode, waiting in queue %s"), QT_TRANSLATE_NOOP("dapscoin-core", "SwiftX options:"), QT_TRANSLATE_NOOP("dapscoin-core", "Synchronization failed"), QT_TRANSLATE_NOOP("dapscoin-core", "Synchronization finished"), @@ -435,33 +377,27 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Synchronizing masternodes..."), QT_TRANSLATE_NOOP("dapscoin-core", "This help message"), QT_TRANSLATE_NOOP("dapscoin-core", "This is experimental software."), QT_TRANSLATE_NOOP("dapscoin-core", "This is intended for regression testing tools and app development."), -QT_TRANSLATE_NOOP("dapscoin-core", "This is not a Masternode."), QT_TRANSLATE_NOOP("dapscoin-core", "Threshold for disconnecting misbehaving peers (default: %u)"), +QT_TRANSLATE_NOOP("dapscoin-core", "Too many decoys"), QT_TRANSLATE_NOOP("dapscoin-core", "Tor control port password (default: empty)"), QT_TRANSLATE_NOOP("dapscoin-core", "Tor control port to use if onion listening enabled (default: %s)"), QT_TRANSLATE_NOOP("dapscoin-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("dapscoin-core", "Transaction amounts must be positive"), -QT_TRANSLATE_NOOP("dapscoin-core", "Transaction created successfully."), -QT_TRANSLATE_NOOP("dapscoin-core", "Transaction fees are too high."), -QT_TRANSLATE_NOOP("dapscoin-core", "Transaction not valid."), QT_TRANSLATE_NOOP("dapscoin-core", "Transaction too large for fee policy"), QT_TRANSLATE_NOOP("dapscoin-core", "Transaction too large"), -QT_TRANSLATE_NOOP("dapscoin-core", "Transmitting final transaction."), QT_TRANSLATE_NOOP("dapscoin-core", "Unable to bind to %s on this computer (bind returned error %s)"), +QT_TRANSLATE_NOOP("dapscoin-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("dapscoin-core", "Unknown network specified in -onlynet: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Unknown state: id = %u"), QT_TRANSLATE_NOOP("dapscoin-core", "Upgrade wallet to latest format"), -QT_TRANSLATE_NOOP("dapscoin-core", "Use OpenSSL (https) for JSON-RPC connections"), QT_TRANSLATE_NOOP("dapscoin-core", "Use UPnP to map the listening port (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Use UPnP to map the listening port (default: 1 when listening)"), QT_TRANSLATE_NOOP("dapscoin-core", "Use a custom max chain reorganization depth (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Use the test network"), +QT_TRANSLATE_NOOP("dapscoin-core", "User Agent comment (%s) contains unsafe characters."), QT_TRANSLATE_NOOP("dapscoin-core", "Username for JSON-RPC connections"), -QT_TRANSLATE_NOOP("dapscoin-core", "Value more than Obfuscation pool maximum allows."), QT_TRANSLATE_NOOP("dapscoin-core", "Verifying blocks..."), QT_TRANSLATE_NOOP("dapscoin-core", "Verifying wallet..."), QT_TRANSLATE_NOOP("dapscoin-core", "Wallet %s resides outside data directory %s"), -QT_TRANSLATE_NOOP("dapscoin-core", "Wallet is locked."), QT_TRANSLATE_NOOP("dapscoin-core", "Wallet needed to be rewritten: restart DAPS to complete"), QT_TRANSLATE_NOOP("dapscoin-core", "Wallet options:"), QT_TRANSLATE_NOOP("dapscoin-core", "Wallet window title"), @@ -469,12 +405,10 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Warning"), QT_TRANSLATE_NOOP("dapscoin-core", "Warning: This version is obsolete, upgrade required!"), QT_TRANSLATE_NOOP("dapscoin-core", "Warning: Unsupported argument -benchmark ignored, use -debug=bench."), QT_TRANSLATE_NOOP("dapscoin-core", "Warning: Unsupported argument -debugnet ignored, use -debug=net."), -QT_TRANSLATE_NOOP("dapscoin-core", "Will retry..."), QT_TRANSLATE_NOOP("dapscoin-core", "You need to rebuild the database using -reindex to change -txindex"), -QT_TRANSLATE_NOOP("dapscoin-core", "Your entries added successfully."), -QT_TRANSLATE_NOOP("dapscoin-core", "Your transaction was accepted into the pool!"), QT_TRANSLATE_NOOP("dapscoin-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("dapscoin-core", "ZeroMQ notification options:"), +QT_TRANSLATE_NOOP("dapscoin-core", "isValid(): Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "on startup"), QT_TRANSLATE_NOOP("dapscoin-core", "wallet.dat corrupt, salvage failed"), }; diff --git a/src/qt/locale/dapscoin_en.ts b/src/qt/locale/dapscoin_en.ts index f990c5ed33..c3868fe544 100644 --- a/src/qt/locale/dapscoin_en.ts +++ b/src/qt/locale/dapscoin_en.ts @@ -104,7 +104,7 @@ &Edit - + Export Address List Export Address List @@ -127,7 +127,7 @@ AddressTableModel - + Label Label @@ -165,27 +165,22 @@ Repeat new passphrase - + Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - For anonymization and staking only - For anonymization and staking only + For staking only + - + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. - - This operation needs your wallet passphrase to unlock the wallet. - This operation needs your wallet passphrase to unlock the wallet. - - - + This operation needs your wallet passphrase to decrypt the wallet. This operation needs your wallet passphrase to decrypt the wallet. @@ -195,7 +190,7 @@ Enter the old and new passphrase to the wallet. - + DAPS will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your DAPSs from being stolen by malware infecting your computer. @@ -205,12 +200,17 @@ Are you sure you wish to encrypt your wallet? - + Encrypt Wallet - + + This operation needs your wallet passphrase to unlock the wallet.<br/><br/>(Wallet may appear not responding as it rescans for all transactions)<br/><br/> + + + + Unlock Wallet @@ -225,7 +225,7 @@ - + Confirm Wallet Encryption @@ -254,7 +254,7 @@ BanTableModel - + IP/Netmask @@ -396,7 +396,7 @@ - + The entered passphrase is invalid. @@ -476,12 +476,12 @@ BitcoinGUI - + Node Node - + &Overview &Overview @@ -496,7 +496,7 @@ &Receive - + E&xit E&xit @@ -506,18 +506,17 @@ Quit application - - + About &Qt About &Qt - + Show information about Qt Show information about Qt - + &Show / Hide &Show / Hide @@ -617,7 +616,7 @@ Open configuration file - + Show &DAPScoin Folder @@ -627,7 +626,7 @@ - + Show Automatic &Backups Show Automatic &Backups @@ -692,7 +691,7 @@ Open &URI... - + %n Active Connections @@ -708,7 +707,7 @@ - + Date: %1 Amount: %2 Type: %3 @@ -723,12 +722,12 @@ Confirmations: %5 - + Staking Enabled - + Enabling Staking... @@ -739,12 +738,12 @@ Confirmations: %5 - + &File &File - + &Settings &Settings @@ -754,12 +753,12 @@ Confirmations: %5 - + Keychain Wallet - + &History @@ -769,7 +768,7 @@ Confirmations: %5 - + Modify settings @@ -789,7 +788,7 @@ Confirmations: %5 &Network - + &Debug Console @@ -799,12 +798,12 @@ Confirmations: %5 - + &Blockchain Explorer - + &Tools &Tools @@ -814,17 +813,22 @@ Confirmations: %5 &Help - + DAPS - + &Masternodes - + + - Lite Mode + + + + &About DAPS @@ -834,7 +838,7 @@ Confirmations: %5 - + &MultiSend @@ -849,7 +853,7 @@ Confirmations: %5 - + Open &Masternode Configuration File @@ -859,7 +863,7 @@ Confirmations: %5 - + Open a DAPS: URI or payment request @@ -970,6 +974,16 @@ Confirmations: %5 + &Frequently Asked Questions + + + + + Frequently Asked Questions + + + + &Blockhain Explorer API @@ -1019,17 +1033,27 @@ Confirmations: %5 - + + &Check For Updates + + + + + Check For Updates + + + + Social - + DAPS client - + Up to date Up to date @@ -1087,7 +1111,26 @@ Confirmations: %5 Transactions after this will not yet be visible. - + + Loading Blocks... + + + + + + Syncing Blocks... + + + + + %n Blocks + + + + + + + Error Error @@ -1118,16 +1161,21 @@ Confirmations: %5 + No Active Peers + + + + Syncing MN List... - - Consolidating Transactions… + + Tor is <b>enabled</b>: %1 - + Wallet is <b>encrypted</b> and currently <b>unlocked</b> Wallet is <b>encrypted</b> and currently <b>unlocked</b> @@ -1183,15 +1231,10 @@ Confirmations: %5 ClientModel - + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5) - - - Network Alert - Network Alert - CoinControlDialog @@ -1372,12 +1415,12 @@ Confirmations: %5 Copy change - + Please switch to "List mode" to use this function. - + highest highest @@ -1738,7 +1781,7 @@ lowercase letters, numbers, symbols) - + All Types @@ -1896,31 +1939,6 @@ lowercase letters, numbers, symbols) (of %1 GB needed) - - LockDialog - - - Transaction Details - - - - - Would you like to lock your keychain wallet now? - -(Staking will also be stopped) - - - - - Lock - - - - - Cancel - - - MasternodeList @@ -1979,7 +1997,7 @@ lowercase letters, numbers, symbols) - + Start alias @@ -2145,7 +2163,7 @@ MultiSend will not be activated unless you have clicked Activate - + The entered address: @@ -2430,7 +2448,7 @@ p, li { white-space: pre-wrap; } Select payment request file - + Select payment request file to open Select payment request file to open @@ -2650,6 +2668,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations + + Hide empty balances + + + + + Hide orphan stakes in transaction lists + + + + + Hide orphan stakes + + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. @@ -2690,33 +2724,33 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsdefault - + none none - + Confirm options reset Confirm options reset - + Client restart required to activate changes. Client restart required to activate changes. - + Client will be shutdown, do you want to proceed? Client will be shutdown, do you want to proceed? - + This change would require a client restart. This change would require a client restart. - + The supplied proxy address is invalid. The supplied proxy address is invalid. @@ -2740,24 +2774,24 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + On - - + + Off - + Staking Mode: - + Backup Wallet Backup Wallet @@ -2787,12 +2821,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Change current passphrase - + Old passphrase @@ -2817,12 +2851,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Quantity of DAPS to keep as spendable (not staking) - + Enabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking. @@ -2842,12 +2876,42 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + + Network Settings + + + + + Automatically open the DAPS client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Map port using &UPnP + Map port using &UPnP + + + + Window Settings + + + + + &Minimize to the tray instead of the taskbar + &Minimize to the tray instead of the taskbar + + + + M&inimize on close + M&inimize on close + + + Two Factor Authentication - + Remember my authentication code for @@ -2901,7 +2965,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Balance @@ -2926,7 +2990,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsTotal of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - + Recent Transactions @@ -2937,13 +3001,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - - The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet. - - - - + Spendable: Spendable: @@ -2956,8 +3014,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations PaymentServer - - + + @@ -2982,12 +3040,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsInvalid payment address %1 - + Cannot start dapscoin: click-to-pay handler - + URI cannot be parsed! This can be caused by an invalid DAPS address or malformed URI parameters. @@ -3072,7 +3130,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations PeerTableModel - + Address/Hostname Address/Hostname @@ -3095,7 +3153,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsAmount - + %1 d %1 d @@ -3149,7 +3207,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations QRImageWidget - + &Save Image... &Save Image... @@ -3182,7 +3240,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations&Information - + General General @@ -3197,8 +3255,8 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsClient name - - + + @@ -3210,7 +3268,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + @@ -3232,7 +3290,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsN/A - + Number of connections Number of connections @@ -3302,7 +3360,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsNumber of Masternodes - + &Console &Console @@ -3327,12 +3385,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsTotals - + Received Received - + Sent Sent @@ -3348,7 +3406,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3474,7 +3532,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Data Directory @@ -3484,7 +3542,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Recover transactions 2 Recover transactions 2 @@ -3784,6 +3842,11 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsCopy amount Copy amount + + + Copy address + Copy address + ReceiveRequestDialog @@ -3856,7 +3919,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations RecentRequestsTableModel - + Date Date @@ -3871,17 +3934,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsMessage - + + Address + Address + + + Amount Amount - + (no label) (no label) - + (no message) (no message) @@ -4112,7 +4180,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsCopy change - + Destination @@ -4137,10 +4205,15 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Copy + + + OK + + Warning: Invalid PIVX address @@ -4344,7 +4417,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsClick "Sign Message" to generate signature - + The entered address is invalid. The entered address is invalid. @@ -4414,11 +4487,16 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsSplashScreen - DAPS + DAPS Coin Keychain Wallet - + + DAPS Coin Lite Mode Wallet + + + + Version %1 Version %1 @@ -4732,7 +4810,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations TransactionTableModel - + Date Date @@ -4815,47 +4893,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsReceived from - - Received via Obfuscation - - - - - Obfuscation Denominate - - - - - Obfuscation Collateral Payment - - - - - Obfuscation Make Collateral Inputs - - - - - Obfuscation Create Denominations - - - - + Confirmed Count. - + Sent to Sent to - + Orphan Block - Generated but not accepted. This does not impact your holdings. - + Payment to yourself Payment to yourself @@ -4869,23 +4922,18 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsMined Mined - - - Obfuscated - Obfuscated - watch-only watch-only - + (n/a) (n/a) - + Transaction status. Hover over this field to show number of confirmations. Transaction status. Hover over this field to show number of confirmations. @@ -4970,47 +5018,22 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - Obfuscated - Obfuscated + To yourself + To yourself - Obfuscation Make Collateral Inputs - + Mined + Mined - Obfuscation Create Denominations + Minted - Obfuscation Denominate - - - - - Obfuscation Collateral Payment - - - - - To yourself - To yourself - - - - Mined - Mined - - - - Minted - - - - - Masternode Reward + Masternode Reward @@ -5019,17 +5042,17 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsOther - + Enter address or label to search Enter address or label to search - + Min amount Min amount - + Copy address Copy address @@ -5059,7 +5082,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsShow transaction details - + + Hide orphan stakes + + + + Export Transaction History Export Transaction History @@ -5280,7 +5308,7 @@ Please try again. - + Resulting URI too long, try to reduce the text for label / message. Resulting URI too long, try to reduce the text for label / message. @@ -5321,49 +5349,11 @@ Please try again. UnitDisplayStatusBarControl - + Unit to show amounts in. Click to select another unit. Unit to show amounts in. Click to select another unit. - - UnlockDialog - - - Transaction Details - - - - - Enter your passphrase: - - - - - (Wallet may appear not responding as it rescans for all transactions) - - - - - Unlock - - - - - Cancel - - - - - Wallet unlock failed - Wallet unlock failed - - - - The passphrase entered for the wallet decryption was incorrect. - The passphrase entered for the wallet decryption was incorrect. - - WalletFrame @@ -5375,7 +5365,7 @@ Please try again. WalletModel - + Send Coins Send Coins @@ -5383,7 +5373,7 @@ Please try again. WalletView - + &Export &Export @@ -5515,6 +5505,11 @@ Please try again. Execute command when the best block changes (%s in cmd is replaced by block hash) Execute command when the best block changes (%s in cmd is replaced by block hash) + + + Execute command when the best block changes and its size is over (%s in cmd is replaced by block hash, %d with the block size) + + Fees (in DAPS/Kb) smaller than this are considered zero fee for relaying (default: %s) @@ -5582,11 +5577,6 @@ Please try again. - Obfuscation uses exact denominated amounts to send funds, you might simply need to anonymize some more coins. - - - - Output debugging information (default: %u, supplying <category> is optional) Output debugging information (default: %u, supplying <category> is optional) @@ -5640,6 +5630,11 @@ Please try again. Support filtering of blocks and transaction with bloom filters (default: %u) + + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + + There is an internal error in generating bulletproofs. Please try again later. @@ -5657,21 +5652,6 @@ Please try again. - Unable to locate enough Obfuscation denominated funds for this transaction. - - - - - Unable to locate enough Obfuscation non-denominated funds for this transaction that are not equal 10000 DAPS. - - - - - Unable to locate enough Obfuscation non-denominated funds for this transaction that are not equal 1000000 DAPS. - - - - Unable to locate enough funds for this transaction that are not equal 10000 DAPS. @@ -5785,11 +5765,6 @@ Please try again. Allow DNS lookups for -addnode, -seednode and -connect Allow DNS lookups for -addnode, -seednode and -connect - - - Already have that input. - Already have that input. - Always query for peer addresses via DNS lookup (default: %u) @@ -5816,30 +5791,10 @@ Please try again. Cannot downgrade wallet - - Cannot resolve -bind address: '%s' - Cannot resolve -bind address: '%s' - - - - Cannot resolve -externalip address: '%s' - Cannot resolve -externalip address: '%s' - - - - Cannot resolve -whitebind address: '%s' - Cannot resolve -whitebind address: '%s' - - - + Cannot write default address Cannot write default address - - - Collateral not valid. - Collateral not valid. - Connect only to the specified node(s) @@ -5936,12 +5891,7 @@ Please try again. Enable the client to act as a masternode (0-1, default: %u) - - Entries are full. - Entries are full. - - - + Error initializing block database Error initializing block database @@ -5992,11 +5942,6 @@ Please try again. - Error: Can't select current denominated inputs - Error: Can't select current denominated inputs - - - Error: Disk space is low! Error: Disk space is low! @@ -6005,16 +5950,6 @@ Please try again. Error: Unsupported argument -tor found, use -onion. Error: Unsupported argument -tor found, use -onion. - - - Error: Wallet locked, unable to create transaction! - Error: Wallet locked, unable to create transaction! - - - - Error: You already have pending entries in the Obfuscation pool - - Failed to listen on any port. Use -listen=0 if you want this. @@ -6030,26 +5965,11 @@ Please try again. Fee (in DAPS/kB) to add to transactions you send (default: %s) - - - Finalizing transaction. - Finalizing transaction. - Force safe mode (default: %u) Force safe mode (default: %u) - - - Found enough users, signing ( waiting %s ) - Found enough users, signing ( waiting %s ) - - - - Found enough users, signing ... - Found enough users, signing ... - Generate coins (default: %u) @@ -6080,16 +6000,6 @@ Please try again. Include IP addresses in debug output (default: %u) Include IP addresses in debug output (default: %u) - - - Incompatible mode. - Incompatible mode. - - - - Incompatible version. - Incompatible version. - Incorrect or no genesis block found. Wrong datadir for network? @@ -6107,11 +6017,6 @@ Please try again. - Input is not valid. - Input is not valid. - - - Insufficient funds. Insufficient funds. @@ -6121,30 +6026,10 @@ Please try again. - - Invalid amount for -maxtxfee=<amount>: '%s' - Invalid amount for -maxtxfee=<amount>: '%s' - - - - Invalid amount for -minrelaytxfee=<amount>: '%s' - Invalid amount for -minrelaytxfee=<amount>: '%s' - - - - Invalid amount for -mintxfee=<amount>: '%s' - Invalid amount for -mintxfee=<amount>: '%s' - - - + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) - - - Invalid amount for -paytxfee=<amount>: '%s' - Invalid amount for -paytxfee=<amount>: '%s' - Invalid amount for -reservebalance=<amount> @@ -6171,22 +6056,17 @@ Please try again. Invalid private key. - - Invalid script detected. - Invalid script detected. - - - + SwiftX options: - + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! - + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) @@ -6196,17 +6076,12 @@ Please try again. - - SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - - - - + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - + <category> can be: @@ -6216,7 +6091,7 @@ Please try again. - + Append comment to the user agent string @@ -6266,7 +6141,12 @@ Please try again. - + + Cannot resolve -%s address: '%s' + + + + Copyright (C) 2015-%i The PIVX Core Developers @@ -6316,7 +6196,17 @@ Please try again. - + + Error in CreateTransaction. Please try again. + + + + + Error in CreateTransactionBulletProof. Please try again. + + + + Error loading wallet.dat: Wallet requires newer version of DAPScoin @@ -6326,7 +6216,7 @@ Please try again. - + Failed to generate RingCT for Sweeping transaction @@ -6346,19 +6236,19 @@ Please try again. - + Input commitments are not correct - - Keep at most <n> unconnectable transactions in memory (default: %u) - Keep at most <n> unconnectable transactions in memory (default: %u) + + Invalid amount for -%s=<amount>: '%s' + - - Last Obfuscation was too recent. - + + Keep at most <n> unconnectable transactions in memory (default: %u) + Keep at most <n> unconnectable transactions in memory (default: %u) @@ -6385,6 +6275,11 @@ Please try again. Loading addresses... Loading addresses... + + + Loading banlist... + + Loading block index... @@ -6425,16 +6320,6 @@ Please try again. Masternode options: Masternode options: - - - Masternode queue is full. - Masternode queue is full. - - - - Masternode: - Masternode: - Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) @@ -6445,66 +6330,26 @@ Please try again. Maximum per-connection send buffer, <n>*1000 bytes (default: %u) Maximum per-connection send buffer, <n>*1000 bytes (default: %u) - - - Missing input transaction information. - Missing input transaction information. - Need to specify a port with -whitebind: '%s' Need to specify a port with -whitebind: '%s' - - - No matching denominations found for mixing. - No matching denominations found for mixing. - Node relay options: Node relay options: - - - Non-standard public key detected. - Non-standard public key detected. - - - - Not compatible with existing transactions. - Not compatible with existing transactions. - Not enough file descriptors available. Not enough file descriptors available. - - - Not in the Masternode list. - Not in the Masternode list. - Number of automatic wallet backups (default: 10) Number of automatic wallet backups (default: 10) - - - Obfuscation is idle. - - - - - Obfuscation request complete: - - - - - Obfuscation request incomplete: - - Only accept block chain matching built-in checkpoints (default: %u) @@ -6565,11 +6410,6 @@ Please try again. Recalculating DAPS supply... - - - Receive and display P2P network alerts (default: %u) - Receive and display P2P network alerts (default: %u) - Reindex the DAPS money supply statistics @@ -6615,11 +6455,6 @@ Please try again. Send transactions as zero-fee transactions if possible (default: %u) Send transactions as zero-fee transactions if possible (default: %u) - - - Session not complete! - Session not complete! - Session timed out. @@ -6745,21 +6580,6 @@ Please try again. Stop running after importing blocks from disk (default: %u) Stop running after importing blocks from disk (default: %u) - - - Submitted following entries to masternode: %u / %d - Submitted following entries to masternode: %u / %d - - - - Submitted to masternode, waiting for more entries ( %u / %d ) %s - Submitted to masternode, waiting for more entries ( %u / %d ) %s - - - - Submitted to masternode, waiting in queue %s - Submitted to masternode, waiting in queue %s - Synchronization failed @@ -6805,11 +6625,6 @@ Please try again. This is intended for regression testing tools and app development. This is intended for regression testing tools and app development. - - - This is not a Masternode. - This is not a Masternode. - Threshold for disconnecting misbehaving peers (default: %u) @@ -6840,21 +6655,6 @@ Please try again. Transaction amounts must be positive Transaction amounts must be positive - - - Transaction created successfully. - Transaction created successfully. - - - - Transaction fees are too high. - Transaction fees are too high. - - - - Transaction not valid. - Transaction not valid. - Transaction too large for fee policy @@ -6865,11 +6665,6 @@ Please try again. Transaction too large Transaction too large - - - Transmitting final transaction. - Transmitting final transaction. - Unable to bind to %s on this computer (bind returned error %s) @@ -6885,11 +6680,6 @@ Please try again. Unknown network specified in -onlynet: '%s' Unknown network specified in -onlynet: '%s' - - - Unknown state: id = %u - Unknown state: id = %u - Upgrade wallet to latest format @@ -6925,11 +6715,6 @@ Please try again. Username for JSON-RPC connections Username for JSON-RPC connections - - - Value more than Obfuscation pool maximum allows. - - Verifying blocks... @@ -6980,26 +6765,11 @@ Please try again. Warning: Unsupported argument -debugnet ignored, use -debug=net. Warning: Unsupported argument -debugnet ignored, use -debug=net. - - - Will retry... - Will retry... - You need to rebuild the database using -reindex to change -txindex You need to rebuild the database using -reindex to change -txindex - - - Your entries added successfully. - Your entries added successfully. - - - - Your transaction was accepted into the pool! - Your transaction was accepted into the pool! - Zapping all transactions from wallet... From b60063c864bb78571bc4eebf61ef6179dd9b024c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 31 Mar 2020 17:55:06 -0400 Subject: [PATCH 0307/1888] Use cached inInitialBlockDownload --- src/qt/bitcoingui.cpp | 4 ++-- src/qt/overviewpage.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 80deefc36c..13fa800335 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1167,7 +1167,7 @@ void BitcoinGUI::setNumBlocks(int count) } if (count == 0) { blockCount->setText(tr("Loading Blocks...")); - } else if (IsInitialBlockDownload()) { + } else if (clientModel->inInitialBlockDownload()) { blockCount->setText(tr("Syncing Blocks...")); } else { blockCount->setText(tr("%n Blocks", "", count)); @@ -1326,7 +1326,7 @@ void BitcoinGUI::setStakingStatus() stakingAction->setIcon(QIcon(":/icons/staking_inactive")); return; } - if (IsInitialBlockDownload()) { + if (clientModel->inInitialBlockDownload()) { LogPrint("staking","Checking Staking Status: Syncing...\n"); stakingState->setText(tr("Syncing Blocks...")); stakingState->setToolTip("Syncing Blocks"); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index af5e464c97..766feb9f7e 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -330,7 +330,7 @@ void OverviewPage::showBlockSync(bool fShow) int count = clientModel->getNumBlocks(); ui->labelBlockCurrent->setText(QString::number(count)); - if (count == 0 && isSyncingBlocks){ + if (count == 0 || clientModel->inInitialBlockDownload()){ ui->labelBlockCurrent->setText("???"); ui->labelBlockStatus->setText("(loading)"); ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); From 6d8a6722f26eea8779d5d0680de2c28b4a814736 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 6 Apr 2020 18:35:35 -0400 Subject: [PATCH 0308/1888] Remove getChainHeight() --- src/qt/clientmodel.cpp | 9 --------- src/qt/clientmodel.h | 1 - 2 files changed, 10 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index b7b31a1ef9..14af3eabcf 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -120,15 +120,6 @@ QString ClientModel::getLastBlockHash() const return QString::fromStdString(nHash.GetHex()); } -int ClientModel::getChainHeight() const -{ - LOCK(cs_main); - if (chainActive.Tip()) - return chainActive.Tip()->nHeight; - else - return 0; -} - double ClientModel::getVerificationProgress() const { return Checkpoints::GuessVerificationProgress(cacheTip); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index fbf50c0f14..b81ae476b2 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -62,7 +62,6 @@ class ClientModel : public QObject int getNumBlocks(); QDateTime getLastBlockDate() const; QString getLastBlockHash() const; - int getChainHeight() const; double getVerificationProgress() const; quint64 getTotalBytesRecv() const; From 5523c43df295ca34395dbd81710d12e1c9fe2c03 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 14 Apr 2020 22:51:22 -0400 Subject: [PATCH 0309/1888] Remove (loading) status from showBlockSync -> no longer required --- src/qt/overviewpage.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 766feb9f7e..16ccc02076 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -330,12 +330,7 @@ void OverviewPage::showBlockSync(bool fShow) int count = clientModel->getNumBlocks(); ui->labelBlockCurrent->setText(QString::number(count)); - if (count == 0 || clientModel->inInitialBlockDownload()){ - ui->labelBlockCurrent->setText("???"); - ui->labelBlockStatus->setText("(loading)"); - ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); - ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); - } else if (isSyncingBlocks){ + if (isSyncingBlocks){ ui->labelBlockStatus->setText("(syncing)"); ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); From 0808571a5b9ae75a5e7df64c9f4684071bd10753 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Apr 2020 18:09:49 -0400 Subject: [PATCH 0310/1888] Shutdown: remove PID file at the very end. --- src/init.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 6035cad0ad..9d6651d343 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -251,6 +251,9 @@ void PrepareShutdown() } #endif + // Disconnect all slots + UnregisterAllValidationInterfaces(); + #ifndef WIN32 try { boost::filesystem::remove(GetPidFile()); @@ -258,7 +261,6 @@ void PrepareShutdown() LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); } #endif - UnregisterAllValidationInterfaces(); } /** From 577ea91ac2169c1327a3c35294f7ddf11f9af6e1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 21 Apr 2020 22:50:26 -0400 Subject: [PATCH 0311/1888] Comment fValid error for now --- src/key.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/key.cpp b/src/key.cpp index 8adb383725..d3d0e7eceb 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -79,7 +79,7 @@ CPrivKey CKey::GetPrivKey() const CPubKey CKey::GetPubKey() const { - assert(fValid); + //assert(fValid); CPubKey result; int clen = 65; int ret = secp256k1_ec_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed); From 2bfbfaf336bd17d584f2914e6138277ea5bc82c7 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sun, 26 Apr 2020 12:01:22 +0200 Subject: [PATCH 0312/1888] Update walletdb.cpp --- src/wallet/walletdb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 67aee45952..090871376d 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -6,7 +6,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "walletdb.h" +#include "wallet/walletdb.h" #include "base58.h" #include "protocol.h" From c68ac22f6badc8430afb3510a34f05110e52d4e0 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sun, 26 Apr 2020 12:06:46 +0200 Subject: [PATCH 0313/1888] Update wallet.h --- src/wallet/wallet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6c1ff288c1..9fd4112321 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -21,8 +21,8 @@ #include "guiinterface.h" #include "util.h" #include "validationinterface.h" -#include "wallet_ismine.h" -#include "walletdb.h" +#include "wallet/wallet_ismine.h" +#include "wallet/walletdb.h" #include #include From c4a6c6baedee389bec2af9d935dab562255098be Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sun, 26 Apr 2020 12:20:00 +0200 Subject: [PATCH 0314/1888] Update wallet_ismine.cpp --- src/wallet/wallet_ismine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index 98629a2297..b76c21e23e 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -5,7 +5,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "wallet_ismine.h" +#include "wallet/wallet_ismine.h" #include "key.h" #include "keystore.h" From e85b3adad23b1a3cb064cbdaadf70c8cd7e9933e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 18:59:20 -0400 Subject: [PATCH 0315/1888] Add support for building Android dependencies --- depends/Makefile | 5 +++++ depends/hosts/android.mk | 3 +++ depends/packages/openssl.mk | 1 + 3 files changed, 9 insertions(+) create mode 100644 depends/hosts/android.mk diff --git a/depends/Makefile b/depends/Makefile index ee046e3e45..e5a64857dd 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -53,6 +53,11 @@ full_host_os:=$(subst $(host_arch)-$(host_vendor)-,,$(canonical_host)) host_os:=$(findstring linux,$(full_host_os)) host_os+=$(findstring darwin,$(full_host_os)) host_os+=$(findstring mingw32,$(full_host_os)) + +ifeq (android,$(findstring android,$(full_host_os))) +host_os:=android +endif + host_os:=$(strip $(host_os)) ifeq ($(host_os),) host_os=$(full_host_os) diff --git a/depends/hosts/android.mk b/depends/hosts/android.mk new file mode 100644 index 0000000000..ff1b07d55b --- /dev/null +++ b/depends/hosts/android.mk @@ -0,0 +1,3 @@ +android_AR=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ar +android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang++ +android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 432f19bd35..44dc3f0c28 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -62,6 +62,7 @@ $(package)_config_opts_m68k_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw +$(package)_config_opts_android=linux-generic64 endef define $(package)_preprocess_cmds From bcbe11db8512b9e642f322fde15f36df74ab8816 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:01:38 -0400 Subject: [PATCH 0316/1888] Add example Android host-platform-triplet and options --- depends/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/depends/README.md b/depends/README.md index d983dfef34..7859f2f11c 100644 --- a/depends/README.md +++ b/depends/README.md @@ -27,8 +27,12 @@ Common `host-platform-triplets` for cross compilation are: - `aarch64-linux-gnu` for Linux ARM 64 bit - `riscv32-linux-gnu` for Linux RISC-V 32 bit - `riscv64-linux-gnu` for Linux RISC-V 64 bit +- `aarch64-linux-android` for Android ARM 64 bit -No other options are needed, the paths are automatically configured. +The paths are automatically configured and no other options are needed unless targeting Android. +In that case one needs to set `ANDROID_API_LEVEL` and `ANDROID_TOOLCHAIN_BIN`: + + make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin NO_QT=1 NO_WALLET=1 ### Install the required dependencies: Ubuntu & Debian From 346f7ddeed50b87fe272504146c4ce5ec9e69b1c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:02:23 -0400 Subject: [PATCH 0317/1888] Add ranlib to android.mk hosts file (fix OSX Android NDK build) --- depends/hosts/android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/hosts/android.mk b/depends/hosts/android.mk index ff1b07d55b..c2a30d7a4d 100644 --- a/depends/hosts/android.mk +++ b/depends/hosts/android.mk @@ -1,3 +1,4 @@ android_AR=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ar android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang++ android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang +android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ranlib From ea67b398f65ecfdabca149adc490de510842e4c3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:12:03 -0400 Subject: [PATCH 0318/1888] Add config opts and patch for aarch64_android build of Qt --- depends/packages/packages.mk | 1 + depends/packages/qt.mk | 18 ++++++++++++++++- .../patches/qt/fix_android_qmake_conf.patch | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 depends/patches/qt/fix_android_qmake_conf.patch diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index ffa0ae3e0c..75ae23deca 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -5,6 +5,7 @@ qt_packages = qrencode protobuf zlib qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans +qt_android_packages=qt qt_darwin_packages=qt qt_mingw32_packages=qt diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d6cb26ce2a..bac25d5e55 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -8,7 +8,7 @@ $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent -$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=f7474f260a1382549720081bf2359a3d425ec3bf7d31976c512834303d30d73b @@ -19,6 +19,8 @@ $(package)_qttools_sha256_hash=fce6e0fd39a40bcef880c669080087dba94af1ec442296222 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) +$(package)_config_opts_aarch64_android = -xplatform android-clang -android-sdk $(ANDROID_SDK) -android-ndk $(ANDROID_NDK) -android-ndk-platform android-$(ANDROID_API_LEVEL) -device-option CROSS_COMPILE="$(host)-" -egl -qpa xcb -no-eglfs -opengl es2 -qt-freetype -no-fontconfig -L $(host_prefix)/lib -I $(host_prefix)/include + define $(package)_set_vars $(package)_config_opts_release = -release $(package)_config_opts_debug = -debug @@ -114,6 +116,19 @@ $(package)_config_opts_sparc64_linux += -platform linux-g++ -xplatform linux-g++ $(package)_config_opts_alpha_linux += -platform linux-g++ -xplatform linux-g++-64 $(package)_config_opts_m68k_linux += -platform linux-g++ -xplatform linux-g++-32 $(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_aarch64_android = -xplatform android-clang +$(package)_config_opts_aarch64_android += -android-sdk $(ANDROID_SDK) +$(package)_config_opts_aarch64_android += -android-ndk $(ANDROID_NDK) +$(package)_config_opts_aarch64_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) +$(package)_config_opts_aarch64_android += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_aarch64_android += -egl +$(package)_config_opts_aarch64_android += -qpa xcb +$(package)_config_opts_aarch64_android += -no-eglfs +$(package)_config_opts_aarch64_android += -opengl es2 +$(package)_config_opts_aarch64_android += -qt-freetype +$(package)_config_opts_aarch64_android += -no-fontconfig +$(package)_config_opts_aarch64_android += -L $(host_prefix)/lib +$(package)_config_opts_aarch64_android += -I $(host_prefix)/include $(package)_build_env = QT_RCC_TEST=1 $(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 endef @@ -163,6 +178,7 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\ patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch &&\ patch -p1 -i $($(package)_patch_dir)/xkb-default.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_android_qmake_conf.patch &&\ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ diff --git a/depends/patches/qt/fix_android_qmake_conf.patch b/depends/patches/qt/fix_android_qmake_conf.patch new file mode 100644 index 0000000000..13bfff9776 --- /dev/null +++ b/depends/patches/qt/fix_android_qmake_conf.patch @@ -0,0 +1,20 @@ +--- old/qtbase/mkspecs/android-clang/qmake.conf ++++ new/qtbase/mkspecs/android-clang/qmake.conf +@@ -30,7 +30,7 @@ + QMAKE_CFLAGS += -target mips64el-none-linux-android + + QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH +-QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a ++QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -nostdlib++ + QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ + -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \ + -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \ +@@ -40,7 +40,7 @@ + ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH + + ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so +-ANDROID_CXX_STL_LIBS = -lc++ ++ANDROID_CXX_STL_LIBS = -lc++_shared + + QMAKE_ARM_CFLAGS_RELEASE = -Oz + QMAKE_ARM_CFLAGS_RELEASE_WITH_DEBUGINFO = -g -Oz From 364aa2aecf3acd7e581c4b035491ca86debc483c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:18:56 -0400 Subject: [PATCH 0319/1888] Add full Android build example command and instructions on getting SDK/NDK --- depends/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/depends/README.md b/depends/README.md index 7859f2f11c..09a147ec52 100644 --- a/depends/README.md +++ b/depends/README.md @@ -30,9 +30,14 @@ Common `host-platform-triplets` for cross compilation are: - `aarch64-linux-android` for Android ARM 64 bit The paths are automatically configured and no other options are needed unless targeting Android. -In that case one needs to set `ANDROID_API_LEVEL` and `ANDROID_TOOLCHAIN_BIN`: +Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level). +In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set. +If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted. +This is an example command for a default build with no disabled dependencies: + + ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin + - make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin NO_QT=1 NO_WALLET=1 ### Install the required dependencies: Ubuntu & Debian From b5b6ea9183d0512033f911787c3ba0fdc39b1679 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:20:12 -0400 Subject: [PATCH 0320/1888] Fix Android zlib cross compilation issue (https://stackoverflow.com/questions/21396988/zlib-build-not-configuring-properly-with-cross-compiler-ignores-ar) --- depends/packages/zlib.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 1600b11a01..420516e041 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -11,6 +11,7 @@ $(package)_build_opts+=RANLIB="$($(package)_ranlib)" $(package)_build_opts+=AR="$($(package)_ar)" $(package)_build_opts_darwin+=AR="$($(package)_libtool)" $(package)_build_opts_darwin+=ARFLAGS="-o" +$(package)_config_opts_aarch64_android+=CHOST=$(host) endef define $(package)_config_cmds From 9ace5f9349b0ffd37a7eb61564d743bf42a98f3d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:23:16 -0400 Subject: [PATCH 0321/1888] Define TARGET_OS when host is android --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index de49a2efef..a8ac27a03c 100644 --- a/configure.ac +++ b/configure.ac @@ -349,6 +349,11 @@ case $host in AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" ;; + *android*) + dnl make sure android stays above linux for hosts like *linux-android* + TARGET_OS=android + LEVELDB_TARGET_FLAGS="-DOS_ANDROID" + ;; *linux*) TARGET_OS=linux ;; From f9d1c5ab3e200fdf7b5c435a27f0184e785f0fe3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:24:39 -0400 Subject: [PATCH 0322/1888] Update bitcoin_qt.m4 Fix to allow configure to detect at --- build-aux/m4/bitcoin_qt.m4 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index df721eb125..17af0d32b6 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -134,8 +134,10 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ if test "x$bitcoin_cv_need_acc_widget" = xyes; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(AccessibleFactory)], [-lqtaccessiblewidgets]) fi - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) - AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + if test "x$TARGET_OS" != xandroid; then + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) + AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + fi if test "x$TARGET_OS" = xwindows; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) From a799ed314efb6b044e5ca72626b7b782dc8dfcd9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:27:46 -0400 Subject: [PATCH 0323/1888] Patch libevent when building for Android (fix arc4random_addrandom) --- depends/packages/libevent.mk | 13 +++- .../fix_android_arc4random_addrandom.patch | 68 +++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 depends/patches/libevent/fix_android_arc4random_addrandom.patch diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 5f622f8e6e..20fae3c989 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -3,10 +3,17 @@ $(package)_version=2.1.8-stable $(package)_download_path=https://github.com/libevent/libevent/archive/ $(package)_file_name=release-$($(package)_version).tar.gz $(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d +$(package)_patches=fix_android_arc4random_addrandom.patch -define $(package)_preprocess_cmds - ./autogen.sh -endef +ifneq (,$(findstring android,$(host))) + define $(package)_preprocess_cmds + ./autogen.sh && patch -p1 < $($(package)_patch_dir)/fix_android_arc4random_addrandom.patch + endef +else + define $(package)_preprocess_cmds + ./autogen.sh + endef +endif define $(package)_set_vars $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples diff --git a/depends/patches/libevent/fix_android_arc4random_addrandom.patch b/depends/patches/libevent/fix_android_arc4random_addrandom.patch new file mode 100644 index 0000000000..5bcc64bef6 --- /dev/null +++ b/depends/patches/libevent/fix_android_arc4random_addrandom.patch @@ -0,0 +1,68 @@ +From cadae3ab7abf45e61ecae8aac39d97d1f3cbd336 Mon Sep 17 00:00:00 2001 +From: Lawrence Nahum +Date: Sun, 3 Dec 2017 22:56:09 +0100 +Subject: [PATCH] fixup + +--- + configure.ac | 1 + + evutil_rand.c | 3 +++ + include/event2/util.h | 4 ++-- + 3 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7528d37..3bb2121 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -341,6 +341,7 @@ dnl Checks for library functions. + AC_CHECK_FUNCS([ \ + accept4 \ + arc4random \ ++ arc4random_addrandom \ + arc4random_buf \ + eventfd \ + epoll_create1 \ +diff --git a/evutil_rand.c b/evutil_rand.c +index 046a14b..3f0bf2c 100644 +--- a/evutil_rand.c ++++ b/evutil_rand.c +@@ -191,6 +191,7 @@ evutil_secure_rng_get_bytes(void *buf, size_t n) + { + ev_arc4random_buf(buf, n); + } ++#ifdef HAVE_ARC4RANDOM_ADDRANDOM + + void + evutil_secure_rng_add_bytes(const char *buf, size_t n) +@@ -199,6 +200,8 @@ evutil_secure_rng_add_bytes(const char *buf, size_t n) + n>(size_t)INT_MAX ? INT_MAX : (int)n); + } + ++#endif ++ + void + evutil_free_secure_rng_globals_(void) + { +diff --git a/include/event2/util.h b/include/event2/util.h +index dd4bbb6..a9a169d 100644 +--- a/include/event2/util.h ++++ b/include/event2/util.h +@@ -841,7 +841,7 @@ int evutil_secure_rng_init(void); + */ + EVENT2_EXPORT_SYMBOL + int evutil_secure_rng_set_urandom_device_file(char *fname); +- ++#ifdef HAVE_ARC4RANDOM_ADDRANDOM + /** Seed the random number generator with extra random bytes. + + You should almost never need to call this function; it should be +@@ -858,7 +858,7 @@ int evutil_secure_rng_set_urandom_device_file(char *fname); + */ + EVENT2_EXPORT_SYMBOL + void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); +- ++#endif + #ifdef __cplusplus + } + #endif +-- +2.14.3 From b0cf75d374f5148ac617b418743b2298641454c2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:29:02 -0400 Subject: [PATCH 0324/1888] builds: remove superfluous config_opts_aarch64_android --- depends/packages/qt.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index bac25d5e55..b4aaf222ab 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -19,8 +19,6 @@ $(package)_qttools_sha256_hash=fce6e0fd39a40bcef880c669080087dba94af1ec442296222 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) -$(package)_config_opts_aarch64_android = -xplatform android-clang -android-sdk $(ANDROID_SDK) -android-ndk $(ANDROID_NDK) -android-ndk-platform android-$(ANDROID_API_LEVEL) -device-option CROSS_COMPILE="$(host)-" -egl -qpa xcb -no-eglfs -opengl es2 -qt-freetype -no-fontconfig -L $(host_prefix)/lib -I $(host_prefix)/include - define $(package)_set_vars $(package)_config_opts_release = -release $(package)_config_opts_debug = -debug @@ -121,6 +119,7 @@ $(package)_config_opts_aarch64_android += -android-sdk $(ANDROID_SDK) $(package)_config_opts_aarch64_android += -android-ndk $(ANDROID_NDK) $(package)_config_opts_aarch64_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) $(package)_config_opts_aarch64_android += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_aarch64_android += -android-arch arm64-v8a $(package)_config_opts_aarch64_android += -egl $(package)_config_opts_aarch64_android += -qpa xcb $(package)_config_opts_aarch64_android += -no-eglfs From f306f03f4e7c6fa456f53e1e07417a3f70b8b7fa Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:30:55 -0400 Subject: [PATCH 0325/1888] Qt: patch androidjnimain.cpp to make sure JNI is initialised when statically compiled --- depends/packages/qt.mk | 3 ++- .../patches/qt/fix_android_jni_static.patch | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 depends/patches/qt/fix_android_jni_static.patch diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index b4aaf222ab..420cf7f80c 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -8,7 +8,7 @@ $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent -$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=f7474f260a1382549720081bf2359a3d425ec3bf7d31976c512834303d30d73b @@ -178,6 +178,7 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch &&\ patch -p1 -i $($(package)_patch_dir)/xkb-default.patch &&\ patch -p1 -i $($(package)_patch_dir)/fix_android_qmake_conf.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch &&\ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch new file mode 100644 index 0000000000..2f6ff00f40 --- /dev/null +++ b/depends/patches/qt/fix_android_jni_static.patch @@ -0,0 +1,18 @@ +--- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp ++++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp +@@ -890,6 +890,14 @@ + __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); + return -1; + } ++ ++ const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, env)); ++ if (ret != 0) ++ { ++ __android_log_print(ANDROID_LOG_FATAL, "Qt", "initJNI failed"); ++ return ret; ++ } ++ + QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + + m_javaVM = vm; + From a4425c5b569a48042d9250443e87e60876647432 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:32:32 -0400 Subject: [PATCH 0326/1888] depends: export dynamic JNI symbols from static qtforandroid.a --- build-aux/m4/bitcoin_qt.m4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 17af0d32b6..4f5caab52f 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -148,6 +148,9 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ AX_CHECK_LINK_FLAG([[-framework IOKit]],[QT_LIBS="$QT_LIBS -framework IOKit"],[AC_MSG_ERROR(could not iokit framework)]) _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)],[-lqcocoa]) AC_DEFINE(QT_QPA_PLATFORM_COCOA, 1, [Define this symbol if the qt platform is cocoa]) + elif test "x$TARGET_OS" = xandroid; then + QT_LIBS="-Wl,--export-dynamic,--undefined=JNI_OnLoad -lqtforandroid -ljnigraphics -landroid -lqtfreetype -lQt5EglSupport $QT_LIBS" + AC_DEFINE(QT_QPA_PLATFORM_ANDROID, 1, [Define this symbol if the qt platform is android]) fi fi CPPFLAGS=$TEMP_CPPFLAGS @@ -361,6 +364,9 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ if test -d "$qt_plugin_path/accessible"; then QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" fi + if test -d "$qt_plugin_path/platforms/android"; then + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms/android -lqtfreetype -lEGL" + fi if test "x$use_pkgconfig" = xyes; then : dnl m4_ifdef([PKG_CHECK_MODULES],[ From 71971658e0da0247c3991363bc531480b421429a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 19:55:24 -0400 Subject: [PATCH 0327/1888] Android: add all arch support Add support for armv7a, i686 and x86_64 archs to android.mk Add -fPIC to depends file as anddroid requires it see https://stackoverflow.com/questions/30498776/position-independent-executables-and-android --- depends/hosts/android.mk | 7 +++++++ depends/packages/boost.mk | 5 +++++ depends/packages/libevent.mk | 1 + depends/packages/openssl.mk | 6 +++++- depends/packages/qrencode.mk | 1 + depends/packages/qt.mk | 32 +++++++++++++++++++------------- depends/packages/zeromq.mk | 1 + depends/packages/zlib.mk | 2 +- 8 files changed, 40 insertions(+), 15 deletions(-) diff --git a/depends/hosts/android.mk b/depends/hosts/android.mk index c2a30d7a4d..4784f77a72 100644 --- a/depends/hosts/android.mk +++ b/depends/hosts/android.mk @@ -1,4 +1,11 @@ +ifeq ($(HOST),armv7a-linux-android) +android_AR=$(ANDROID_TOOLCHAIN_BIN)/arm-linux-androideabi-ar +android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang++ +android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang +android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/arm-linux-androideabi-ranlib +else android_AR=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ar android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang++ android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ranlib +endif \ No newline at end of file diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index a7226ad7e0..9248e94fb4 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -15,6 +15,10 @@ $(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win3 $(package)_config_opts_x86_64_mingw32=address-model=64 $(package)_config_opts_i686_mingw32=address-model=32 $(package)_config_opts_i686_linux=address-model=32 architecture=x86 +$(package)_config_opts_i686_android=address-model=32 +$(package)_config_opts_aarch64_android=address-model=64 +$(package)_config_opts_x86_64_android=address-model=64 +$(package)_config_opts_armv7a_android=address-model=32 $(package)_config_opts_s390x_linux=address-model=64 $(package)_config_opts_sparc64_linux=address-model=64 $(package)_config_opts_alpha_linux=address-model=64 @@ -26,6 +30,7 @@ $(package)_archiver_darwin=$($(package)_libtool) $(package)_config_libraries=chrono,filesystem,program_options,system,thread,test $(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC +$(package)_cxxflags_android=-fPIC endef define $(package)_preprocess_cmds diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 20fae3c989..f60f257718 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -19,6 +19,7 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples $(package)_config_opts_release=--disable-debug-mode $(package)_config_opts_linux=--with-pic + $(package)_config_opts_android=--with-pic endef define $(package)_config_cmds diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 44dc3f0c28..c909416798 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -62,7 +62,11 @@ $(package)_config_opts_m68k_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw -$(package)_config_opts_android=linux-generic64 +$(package)_config_opts_android=-fPIC +$(package)_config_opts_aarch64_android=linux-generic64 +$(package)_config_opts_x86_64_android=linux-generic64 +$(package)_config_opts_armv7a_android=linux-generic32 +$(package)_config_opts_i686_android=linux-generic32 endef define $(package)_preprocess_cmds diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 313e4adf2a..f81fb100be 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -7,6 +7,7 @@ $(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19 define $(package)_set_vars $(package)_config_opts=--disable-shared -without-tools --disable-sdltest $(package)_config_opts_linux=--with-pic +$(package)_config_opts_android=--with-pic endef define $(package)_preprocess_cmds diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 420cf7f80c..9b69bc32c5 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -114,20 +114,26 @@ $(package)_config_opts_sparc64_linux += -platform linux-g++ -xplatform linux-g++ $(package)_config_opts_alpha_linux += -platform linux-g++ -xplatform linux-g++-64 $(package)_config_opts_m68k_linux += -platform linux-g++ -xplatform linux-g++-32 $(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" -$(package)_config_opts_aarch64_android = -xplatform android-clang -$(package)_config_opts_aarch64_android += -android-sdk $(ANDROID_SDK) -$(package)_config_opts_aarch64_android += -android-ndk $(ANDROID_NDK) -$(package)_config_opts_aarch64_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) -$(package)_config_opts_aarch64_android += -device-option CROSS_COMPILE="$(host)-" + +$(package)_config_opts_android = -xplatform android-clang +$(package)_config_opts_android += -android-sdk $(ANDROID_SDK) +$(package)_config_opts_android += -android-ndk $(ANDROID_NDK) +$(package)_config_opts_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) +$(package)_config_opts_android += -device-option CROSS_COMPILE="$(host)-" +$(package)_config_opts_android += -egl +$(package)_config_opts_android += -qpa xcb +$(package)_config_opts_android += -no-eglfs +$(package)_config_opts_android += -opengl es2 +$(package)_config_opts_android += -qt-freetype +$(package)_config_opts_android += -no-fontconfig +$(package)_config_opts_android += -L $(host_prefix)/lib +$(package)_config_opts_android += -I $(host_prefix)/include + $(package)_config_opts_aarch64_android += -android-arch arm64-v8a -$(package)_config_opts_aarch64_android += -egl -$(package)_config_opts_aarch64_android += -qpa xcb -$(package)_config_opts_aarch64_android += -no-eglfs -$(package)_config_opts_aarch64_android += -opengl es2 -$(package)_config_opts_aarch64_android += -qt-freetype -$(package)_config_opts_aarch64_android += -no-fontconfig -$(package)_config_opts_aarch64_android += -L $(host_prefix)/lib -$(package)_config_opts_aarch64_android += -I $(host_prefix)/include +$(package)_config_opts_armv7a_android += -android-arch armeabi-v7a +$(package)_config_opts_x86_64_android += -android-arch x86_64 +$(package)_config_opts_i686_android += -android-arch i686 + $(package)_build_env = QT_RCC_TEST=1 $(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index dfbc50580c..4a5dd91201 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -8,6 +8,7 @@ $(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_ define $(package)_set_vars $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts_linux=--with-pic + $(package)_config_opts_android=--with-pic $(package)_cxxflags=-std=c++11 endef diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 420516e041..b86ed24845 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -11,7 +11,7 @@ $(package)_build_opts+=RANLIB="$($(package)_ranlib)" $(package)_build_opts+=AR="$($(package)_ar)" $(package)_build_opts_darwin+=AR="$($(package)_libtool)" $(package)_build_opts_darwin+=ARFLAGS="-o" -$(package)_config_opts_aarch64_android+=CHOST=$(host) +$(package)_config_opts_android+=CHOST=$(host) endef define $(package)_config_cmds From 4257c8809bbb9a2156c6d74ac903b8230f16e835 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 20:17:22 -0400 Subject: [PATCH 0328/1888] build: bump libevent to 2.1.11 in depends from https://github.com/bitcoin/bitcoin/pull/17008 --- depends/packages/libevent.mk | 18 ++--- .../fix_android_arc4random_addrandom.patch | 68 ------------------- 2 files changed, 6 insertions(+), 80 deletions(-) delete mode 100644 depends/patches/libevent/fix_android_arc4random_addrandom.patch diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index f60f257718..d01ae597c7 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -1,22 +1,16 @@ package=libevent -$(package)_version=2.1.8-stable +$(package)_version=2.1.11-stable $(package)_download_path=https://github.com/libevent/libevent/archive/ $(package)_file_name=release-$($(package)_version).tar.gz -$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d -$(package)_patches=fix_android_arc4random_addrandom.patch +$(package)_sha256_hash=229393ab2bf0dc94694f21836846b424f3532585bac3468738b7bf752c03901e -ifneq (,$(findstring android,$(host))) - define $(package)_preprocess_cmds - ./autogen.sh && patch -p1 < $($(package)_patch_dir)/fix_android_arc4random_addrandom.patch - endef -else - define $(package)_preprocess_cmds - ./autogen.sh - endef -endif +define $(package)_preprocess_cmds + ./autogen.sh +endef define $(package)_set_vars $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples + $(package)_config_opts += --disable-dependency-tracking --enable-option-checking $(package)_config_opts_release=--disable-debug-mode $(package)_config_opts_linux=--with-pic $(package)_config_opts_android=--with-pic diff --git a/depends/patches/libevent/fix_android_arc4random_addrandom.patch b/depends/patches/libevent/fix_android_arc4random_addrandom.patch deleted file mode 100644 index 5bcc64bef6..0000000000 --- a/depends/patches/libevent/fix_android_arc4random_addrandom.patch +++ /dev/null @@ -1,68 +0,0 @@ -From cadae3ab7abf45e61ecae8aac39d97d1f3cbd336 Mon Sep 17 00:00:00 2001 -From: Lawrence Nahum -Date: Sun, 3 Dec 2017 22:56:09 +0100 -Subject: [PATCH] fixup - ---- - configure.ac | 1 + - evutil_rand.c | 3 +++ - include/event2/util.h | 4 ++-- - 3 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 7528d37..3bb2121 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -341,6 +341,7 @@ dnl Checks for library functions. - AC_CHECK_FUNCS([ \ - accept4 \ - arc4random \ -+ arc4random_addrandom \ - arc4random_buf \ - eventfd \ - epoll_create1 \ -diff --git a/evutil_rand.c b/evutil_rand.c -index 046a14b..3f0bf2c 100644 ---- a/evutil_rand.c -+++ b/evutil_rand.c -@@ -191,6 +191,7 @@ evutil_secure_rng_get_bytes(void *buf, size_t n) - { - ev_arc4random_buf(buf, n); - } -+#ifdef HAVE_ARC4RANDOM_ADDRANDOM - - void - evutil_secure_rng_add_bytes(const char *buf, size_t n) -@@ -199,6 +200,8 @@ evutil_secure_rng_add_bytes(const char *buf, size_t n) - n>(size_t)INT_MAX ? INT_MAX : (int)n); - } - -+#endif -+ - void - evutil_free_secure_rng_globals_(void) - { -diff --git a/include/event2/util.h b/include/event2/util.h -index dd4bbb6..a9a169d 100644 ---- a/include/event2/util.h -+++ b/include/event2/util.h -@@ -841,7 +841,7 @@ int evutil_secure_rng_init(void); - */ - EVENT2_EXPORT_SYMBOL - int evutil_secure_rng_set_urandom_device_file(char *fname); -- -+#ifdef HAVE_ARC4RANDOM_ADDRANDOM - /** Seed the random number generator with extra random bytes. - - You should almost never need to call this function; it should be -@@ -858,7 +858,7 @@ int evutil_secure_rng_set_urandom_device_file(char *fname); - */ - EVENT2_EXPORT_SYMBOL - void evutil_secure_rng_add_bytes(const char *dat, size_t datlen); -- -+#endif - #ifdef __cplusplus - } - #endif --- -2.14.3 From af5411d454aa28948c1226db19e1321e621a1111 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 20:20:24 -0400 Subject: [PATCH 0329/1888] depends: update README.md with working Android targets and API levels --- depends/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/depends/README.md b/depends/README.md index 09a147ec52..b2093d76a6 100644 --- a/depends/README.md +++ b/depends/README.md @@ -27,11 +27,17 @@ Common `host-platform-triplets` for cross compilation are: - `aarch64-linux-gnu` for Linux ARM 64 bit - `riscv32-linux-gnu` for Linux RISC-V 32 bit - `riscv64-linux-gnu` for Linux RISC-V 64 bit +- `armv7a-linux-android` for Android ARM 32 bit - `aarch64-linux-android` for Android ARM 64 bit +- `i686-linux-android` for Android x86 32 bit +- `x86_64-linux-android` for Android x86 64 bit The paths are automatically configured and no other options are needed unless targeting Android. Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level). In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set. + +API levels from 24 to 29 have been tested to work. + If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted. This is an example command for a default build with no disabled dependencies: From 9e714402fe39efc020c721ef37693877ca7f5777 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 28 Apr 2020 20:22:04 -0400 Subject: [PATCH 0330/1888] depends: move README.md Android instructions to a separate section --- depends/README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/depends/README.md b/depends/README.md index b2093d76a6..c2fff2ae95 100644 --- a/depends/README.md +++ b/depends/README.md @@ -32,18 +32,7 @@ Common `host-platform-triplets` for cross compilation are: - `i686-linux-android` for Android x86 32 bit - `x86_64-linux-android` for Android x86 64 bit -The paths are automatically configured and no other options are needed unless targeting Android. -Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level). -In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set. - -API levels from 24 to 29 have been tested to work. - -If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted. -This is an example command for a default build with no disabled dependencies: - - ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin - - +The paths are automatically configured and no other options are needed unless targeting [Android](#Android). ### Install the required dependencies: Ubuntu & Debian @@ -101,6 +90,18 @@ options will be passed to bitcoin's configure. In this case, `--disable-wallet`. download-win: run 'make download-win' to fetch all sources needed for win builds download-linux: run 'make download-linux' to fetch all sources needed for linux builds +### Android + +Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level). +In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set. + +API levels from 24 to 29 have been tested to work. + +If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted. +This is an example command for a default build with no disabled dependencies: + + ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin + ### Other documentation - [description.md](description.md): General description of the depends system From b704fc3e7785100e33c6e3a5becaf56a3a4b5898 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 29 Apr 2020 16:41:05 -0400 Subject: [PATCH 0331/1888] [depends] boost: update to 1.70 from https://github.com/bitcoin/bitcoin/pull/15461 --- build-aux/m4/ax_boost_base.m4 | 260 +++++++++++++++++--------------- build-aux/m4/ax_boost_system.m4 | 10 +- depends/packages/boost.mk | 6 +- 3 files changed, 148 insertions(+), 128 deletions(-) diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 3f24d5ddc6..d540395763 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html # =========================================================================== # # SYNOPSIS @@ -33,7 +33,15 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 45 + +# example boost program (need to pass version) +m4_define([_AX_BOOST_BASE_PROGRAM], + [AC_LANG_PROGRAM([[ +#include +]],[[ +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); +]])]) AC_DEFUN([AX_BOOST_BASE], [ @@ -44,110 +52,121 @@ AC_ARG_WITH([boost], or disable it (ARG=no) @<:@ARG=yes@:>@ ])], [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ac_boost_path="" - else - want_boost="yes" - ac_boost_path="$withval" - fi + AS_CASE([$withval], + [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], + [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], + [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) ], [want_boost="yes"]) AC_ARG_WITH([boost-libdir], - AS_HELP_STRING([--with-boost-libdir=LIB_DIR], - [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), - [ - if test -d "$withval" - then - ac_boost_lib_path="$withval" - else - AC_MSG_ERROR(--with-boost-libdir expected directory name) - fi - ], - [ac_boost_lib_path=""] -) + [AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. + Note that this will override library path detection, + so use this parameter only if default library detection fails + and you know exactly where your boost libraries are located.])], + [ + AS_IF([test -d "$withval"], + [_AX_BOOST_BASE_boost_lib_path="$withval"], + [AC_MSG_ERROR([--with-boost-libdir expected directory name])]) + ], + [_AX_BOOST_BASE_boost_lib_path=""]) -if test "x$want_boost" = "xyes"; then - boost_lib_version_req=ifelse([$1], ,1.20.0,$1) - boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` - boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` - boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` - boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` - if test "x$boost_lib_version_req_sub_minor" = "x" ; then - boost_lib_version_req_sub_minor="0" - fi - WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` - AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +AS_IF([test "x$want_boost" = "xyes"], + [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) +AC_SUBST(BOOST_CPPFLAGS) +AC_SUBST(BOOST_LDFLAGS) +]) + + +# convert a version string in $2 to numeric and affect to polymorphic var $1 +AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ + AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], + [AC_MSG_ERROR([You should at least specify libboost major version])]) + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) +]) + +dnl Run the detection of boost should be run only if $want_boost +AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ + _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) succeeded=no + + AC_REQUIRE([AC_CANONICAL_HOST]) dnl On 64-bit systems check for system libraries in both lib64 and lib. dnl The former is specified by FHS, but e.g. Debian does not adhere to dnl this (as it rises problems for generic multi-arch support). dnl The last entry in the list is chosen by default when no libraries dnl are found, e.g. when only header-only libraries are installed! - libsubdirs="lib" - ax_arch=`uname -m` - case $ax_arch in - x86_64) - libsubdirs="lib64 libx32 lib lib64" - ;; - ppc64|s390x|sparc64|aarch64) - libsubdirs="lib64 lib lib64" - ;; - esac + AS_CASE([${host_cpu}], + [x86_64],[libsubdirs="lib64 libx32 lib lib64"], + [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"], + [libsubdirs="lib"] + ) dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give dnl them priority over the other paths since, if libs are found there, they dnl are almost assuredly the ones desired. - AC_REQUIRE([AC_CANONICAL_HOST]) - libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs" - - case ${host_cpu} in - i?86) - libsubdirs="lib/i386-${host_os} $libsubdirs" - ;; - esac - - dnl some arches may advertise a cpu type that doesn't line up with their - dnl prefix's cpu type. For example, uname may report armv7l while libs are - dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's - dnl value for an extra chance of finding the correct path. - libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs" + AS_CASE([${host_cpu}], + [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], + [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] + ) dnl first we check the system location for boost libraries dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM - if test "$ac_boost_path" != ""; then - BOOST_CPPFLAGS="-I$ac_boost_path/include" - for ac_boost_path_tmp in $libsubdirs; do - if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then - BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp" - break - fi - done - elif test "$cross_compiling" != yes; then - for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then - for libsubdir in $libsubdirs ; do - if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ + AC_MSG_RESULT([yes]) + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ + AC_MSG_RESULT([yes]) + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + ], + [AC_MSG_RESULT([no])]) + done],[ + AC_MSG_RESULT([no])]) + ],[ + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done - BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir" - BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" break; fi done - fi + ]) dnl overwrite ld flags if we have required special directory with dnl --with-boost-libdir parameter - if test "$ac_boost_lib_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_lib_path" - fi + AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"], + [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"]) + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)]) CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" export CPPFLAGS @@ -158,19 +177,11 @@ if test "x$want_boost" = "xyes"; then AC_REQUIRE([AC_PROG_CXX]) AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) @@ -178,30 +189,50 @@ if test "x$want_boost" = "xyes"; then dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version - if test "x$succeeded" != "xyes"; then + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi _version=0 - if test "$ac_boost_path" != ""; then - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then + if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp fi VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + dnl if we found something and BOOST_LDFLAGS was unset before + dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here. + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi fi else - if test "$cross_compiling" != yes; then - for ac_boost_path in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then + if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp - best_path=$ac_boost_path + best_path=$_AX_BOOST_BASE_boost_path fi done fi @@ -209,7 +240,7 @@ if test "x$want_boost" = "xyes"; then VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" - if test "$ac_boost_lib_path" = ""; then + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then for libsubdir in $libsubdirs ; do if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done @@ -217,7 +248,7 @@ if test "x$want_boost" = "xyes"; then fi fi - if test "x$BOOST_ROOT" != "x"; then + if test -n "$BOOST_ROOT" ; then for libsubdir in $libsubdirs ; do if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done @@ -226,7 +257,7 @@ if test "x$want_boost" = "xyes"; then stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` V_CHECK=`expr $stage_version_shorten \>\= $_version` - if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) BOOST_CPPFLAGS="-I$BOOST_ROOT" BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" @@ -241,34 +272,24 @@ if test "x$want_boost" = "xyes"; then export LDFLAGS AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes - ],[: + ],[ ]) AC_LANG_POP([C++]) fi - if test "$succeeded" != "yes" ; then - if test "$_version" = "0" ; then - AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) else AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) fi # execute ACTION-IF-NOT-FOUND (if present): ifelse([$3], , :, [$3]) else - AC_SUBST(BOOST_CPPFLAGS) - AC_SUBST(BOOST_LDFLAGS) AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) # execute ACTION-IF-FOUND (if present): ifelse([$2], , :, [$2]) @@ -276,6 +297,5 @@ if test "x$want_boost" = "xyes"; then CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" -fi ]) diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4 index 9c78280fca..207d7be8de 100644 --- a/build-aux/m4/ax_boost_system.m4 +++ b/build-aux/m4/ax_boost_system.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html # =========================================================================== # # SYNOPSIS @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 17 +#serial 19 AC_DEFUN([AX_BOOST_SYSTEM], [ @@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM], ax_cv_boost_system, [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], + [[boost::system::error_category *a = 0;]])], ax_cv_boost_system=yes, ax_cv_boost_system=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) @@ -83,7 +84,6 @@ AC_DEFUN([AX_BOOST_SYSTEM], LDFLAGS_SAVE=$LDFLAGS if test "x$ax_boost_user_system_lib" = "x"; then - ax_lib= for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -108,7 +108,7 @@ AC_DEFUN([AX_BOOST_SYSTEM], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the boost_system library!) + AC_MSG_ERROR(Could not find a version of the library!) fi if test "x$link_system" = "xno"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 9248e94fb4..3c86ffab74 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_64_0 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.64.0/source/ +$(package)_version=1_70_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.70.0/source/ $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 +$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 define $(package)_set_vars $(package)_config_opts_release=variant=release From 8b093cdc8e97400518e3deb3d28ca23aff4c6172 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 29 Apr 2020 16:50:57 -0400 Subject: [PATCH 0332/1888] build: Fix boost detection on Ubuntu ARM 18.04 Update ax_boost_base.m4 to version in progress: autoconf-archive/autoconf-archive#198 This is a temporary workaround for the problem in the 0.19.0 release; please pull in the upstream version when ready (see BTC#17010). --- build-aux/m4/ax_boost_base.m4 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index d540395763..74537dc40f 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 45 +#serial 49 # example boost program (need to pass version) m4_define([_AX_BOOST_BASE_PROGRAM], @@ -113,6 +113,7 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ dnl are found, e.g. when only header-only libraries are installed! AS_CASE([${host_cpu}], [x86_64],[libsubdirs="lib64 libx32 lib lib64"], + [mips*64*],[libsubdirs="lib64 lib32 lib lib64"], [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"], [libsubdirs="lib"] ) @@ -125,8 +126,14 @@ AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] ) + dnl some arches may advertise a cpu type that doesn't line up with their + dnl prefix's cpu type. For example, uname may report armv7l while libs are + dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's + dnl value for an extra chance of finding the correct path. + libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs" + dnl first we check the system location for boost libraries - dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl this location is chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) From 4446ac4f4a73a403da5205a692971d1ab68bbf2d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 4 May 2020 08:44:05 -0400 Subject: [PATCH 0333/1888] Show symbol for inbound/outbound in peer table from https://github.com/bitcoin/bitcoin/pull/13537 --- src/qt/peertablemodel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index a56021edf8..131d4c86f0 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -162,7 +162,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const if (role == Qt::DisplayRole) { switch (index.column()) { case Address: - return QString::fromStdString(rec->nodeStats.addrName); + // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection + return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName); case Subversion: return QString::fromStdString(rec->nodeStats.cleanSubVer); case Ping: From f4e0d0f6ac3945148822e5b7374a12382ae57468 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Apr 2020 20:45:43 -0400 Subject: [PATCH 0334/1888] [GUI] Don't log to console by default. Default `-printtoconsole` to false for the GUI. GUI programs should not print to the console unnecessarily. For example, when launched by the window manager, the output might end up in the X session log file, resulting in duplicate logging. On Windows, it is pointless as well because bitcoin-qt isn't a console application. --- src/qt/dapscoin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index cad2f40f36..58bfb5df6a 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -420,6 +420,10 @@ void BitcoinApplication::startThread() void BitcoinApplication::parameterSetup() { + // Default printtoconsole to false for the GUI. GUI programs should not + // print to the console unnecessarily. + SoftSetBoolArg("-printtoconsole", false); + InitLogging(); InitParameterInteraction(); } From fdac6a6b324bfdf2e50639dd9f8fbf405cf30481 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 17:55:49 -0400 Subject: [PATCH 0335/1888] build: remove unnecessary macOS qt patching Patching in kCGMouseButtonLeft should not be required. Looks like this hasn't been needed since qt 5.5 or so: https://codereview.qt-project.org/c/qt/qtbase/+/115138 --- depends/packages/qt.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 9b69bc32c5..50a6c473ef 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -165,7 +165,6 @@ define $(package)_preprocess_cmds sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \ - sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ From 17d48dddfef2551f8fc1983111e32660689ae834 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 17:56:23 -0400 Subject: [PATCH 0336/1888] build: remove unnecessary qt xcb patching The lines that this sed command was modifying were removed some time ago. Relevant upstream change: https://code.qt.io/cgit/qt/qtbase.git/commit/src/plugins/platforms/xcb/qxcbxsettings.cpp?id=538b9f504c0de11c473a40aed66df9900ac1c6c4 --- depends/packages/qt.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 50a6c473ef..b452b26655 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -163,7 +163,6 @@ define $(package)_preprocess_cmds sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ - sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\ From 39d5ca72bdf4c072fb9709804578350ec8336596 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 18:07:26 -0400 Subject: [PATCH 0337/1888] [Depends] Include qt-gif plugin. --- build-aux/m4/bitcoin_qt.m4 | 1 + depends/packages/qt.mk | 2 +- src/qt/dapscoin.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 4f5caab52f..2575798f55 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -137,6 +137,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ if test "x$TARGET_OS" != xandroid; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QGifPlugin)],[-lqgif]) fi if test "x$TARGET_OS" = xwindows; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 9b69bc32c5..fc3a626dd0 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -32,7 +32,6 @@ $(package)_config_opts += -no-cups $(package)_config_opts += -no-egl $(package)_config_opts += -no-eglfs $(package)_config_opts += -no-freetype -$(package)_config_opts += -no-gif $(package)_config_opts += -no-glib $(package)_config_opts += -no-icu $(package)_config_opts += -no-iconv @@ -64,6 +63,7 @@ $(package)_config_opts += -pkg-config $(package)_config_opts += -prefix $(host_prefix) $(package)_config_opts += -qt-libpng $(package)_config_opts += -qt-libjpeg +$(package)_config_opts += -gif $(package)_config_opts += -qt-pcre $(package)_config_opts += -qt-harfbuzz $(package)_config_opts += -system-zlib diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index cad2f40f36..9aaa70fe89 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -77,6 +77,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif +Q_IMPORT_PLUGIN(QGifPlugin); #endif #define DEBUG_BACKTRACE 1 From ddc94de2e99ec90e3a43a085f1fbffd1e0a7faf7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 18:30:48 -0400 Subject: [PATCH 0338/1888] [GUI][Bug] Fix "Select all" / "Unselect all" logic in coincontrol Prioritize the action described by the button: - if "Select All", then verify that all entries are checked, otherwise check them - if "Unselect All", then verify that all entries are unchecked, otherwise uncheck them. --- src/qt/coincontroldialog.cpp | 21 +++++++++++---------- src/qt/coincontroldialog.h | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 5c05cb1c04..3ceeea0c9d 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -187,20 +187,21 @@ void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) // (un)select all void CoinControlDialog::buttonSelectAllClicked() { - Qt::CheckState state = Qt::Checked; - for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { - if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked) { - state = Qt::Unchecked; - break; - } - } + // "Select all": if some entry is unchecked, then check it + // "Unselect all": if some entry is checked, then uncheck it + Qt::CheckState wantedState = fSelectAllToggled ? Qt::Checked : Qt::Unchecked; ui->treeWidget->setEnabled(false); for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) - if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state) - ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state); + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != wantedState) + ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, wantedState); ui->treeWidget->setEnabled(true); - if (state == Qt::Unchecked) + if (!fSelectAllToggled) { coinControl->UnSelectAll(); // just to be sure + ui->pushButtonSelectAll->setText(tr("Select all")); + } else { + ui->pushButtonSelectAll->setText(tr("Unselect all")); + } + fSelectAllToggled = !fSelectAllToggled; CoinControlDialog::updateLabels(model, this); updateDialogLabels(); } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index dc557635b7..44f0b0a1b0 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -63,6 +63,7 @@ class CoinControlDialog : public QDialog int sortColumn; Qt::SortOrder sortOrder; bool fMultisigEnabled; + bool fSelectAllToggled{true}; // false when pushButtonSelectAll text is "Unselect All" QMenu* contextMenu; QTreeWidgetItem* contextMenuItem; From b509a67f7d5c0b6943c77148290e7b6454112f71 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 18:48:58 -0400 Subject: [PATCH 0339/1888] Translate (loading)/{syncing) --- src/qt/forms/overviewpage.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 8ad333f802..9c5b3aeff7 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -156,7 +156,7 @@ - (loading) + (loading) Qt::AlignHCenter|Qt::AlignTop @@ -416,7 +416,7 @@ true - (syncing) + (syncing) Qt::AlignCenter From 1c11e079c46837c0229eac76ec7f051e11d553ff Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 18:50:13 -0400 Subject: [PATCH 0340/1888] Fix missing __func__ --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 9d6651d343..721568e8b6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -968,7 +968,7 @@ bool AppInit2(bool isDaemon) if (fDisableWallet) { #endif if (SoftSetBoolArg("-staking", false)) - LogPrintf("%s : parameter interaction: wallet functionality not enabled -> setting -staking=0\n"); + LogPrintf("%s : parameter interaction: wallet functionality not enabled -> setting -staking=0\n", __func__); #ifdef ENABLE_WALLET } #endif From c4bc3e07446db30e01eddfde8831dfe900116c91 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 5 May 2020 19:10:31 -0400 Subject: [PATCH 0341/1888] Fix incorrect CheckBlock() -> ConnectBlock() --- src/main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 321d4aa9fd..7136d1b6a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2904,33 +2904,33 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Check it again in case a previous version let a bad block in if (!fAlreadyChecked && !CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; - //move this code from checkBlock to ConnectBlock functions to check for forks + //Check PoA block time if (block.IsPoABlockByVersion() && !CheckPoAblockTime(block)) { - return state.Invalid(error("CheckBlock() : Time elapsed between two PoA blocks is too short"), + return state.Invalid(error("ConnectBlock(): Time elapsed between two PoA blocks is too short"), REJECT_INVALID, "time-too-new"); } //Check PoA block not auditing PoS blocks audited by its previous PoA block if (block.IsPoABlockByVersion() && !CheckPoABlockNotAuditingOverlap(block)) { - return state.Invalid(error("CheckBlock() : PoA block auditing PoS blocks previously audited by its parent"), + return state.Invalid(error("ConnectBlock(): PoA block auditing PoS blocks previously audited by its parent"), REJECT_INVALID, "overlap-audit"); } /** - * @todo Audit checkblock + * @Audit ConnectBlock */ if (block.IsProofOfAudit()) { //Check PoA consensus rules if (!CheckPoAContainRecentHash(block)) { - return state.DoS(100, error("CheckBlock() : PoA block should contain only non-audited recent PoS blocks")); + return state.DoS(100, error("ConnectBlock(): PoA block should contain only non-audited recent PoS blocks")); } if (!CheckNumberOfAuditedPoSBlocks(block)) { - return state.DoS(100, error("CheckBlock() : A PoA block should audit at least 59 PoS blocks")); + return state.DoS(100, error("ConnectBlock(): A PoA block should audit at least 59 PoS blocks")); } if (!CheckPoABlockNotContainingPoABlockInfo(block)) { - return state.DoS(100, error("CheckBlock() : A PoA block should not audit any existing PoA blocks")); + return state.DoS(100, error("ConnectBlock(): A PoA block should not audit any existing PoA blocks")); } } From cb8896a576083ba635b09a952d3c48c917bcb70c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 19:28:07 -0400 Subject: [PATCH 0342/1888] Temporarily remove qt-gif as requirement --- build-aux/m4/bitcoin_qt.m4 | 1 - src/qt/dapscoin.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 2575798f55..4f5caab52f 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -137,7 +137,6 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ if test "x$TARGET_OS" != xandroid; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) - _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QGifPlugin)],[-lqgif]) fi if test "x$TARGET_OS" = xwindows; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 9cad271a08..d546c27f61 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -77,7 +77,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif -Q_IMPORT_PLUGIN(QGifPlugin); +//Q_IMPORT_PLUGIN(QGifPlugin); #endif #define DEBUG_BACKTRACE 1 From 1c8d4b1fc3f4aae652475b8197a8495ac6939d8d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 19:43:22 -0400 Subject: [PATCH 0343/1888] Remove incorrectly placed ifdef/endif --- src/init.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 721568e8b6..3ee85ea9d8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -966,10 +966,8 @@ bool AppInit2(bool isDaemon) #ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); if (fDisableWallet) { -#endif if (SoftSetBoolArg("-staking", false)) LogPrintf("%s : parameter interaction: wallet functionality not enabled -> setting -staking=0\n", __func__); -#ifdef ENABLE_WALLET } #endif From 93d52eb96e676ad5db7bbd8c384586eca2950ca1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:24:19 -0400 Subject: [PATCH 0344/1888] depends: only use dbus with qt on linux --- depends/packages/qt.mk | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index b50b80b78c..8316019c77 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -25,7 +25,6 @@ $(package)_config_opts_debug = -debug $(package)_config_opts += -bindir $(build_prefix)/bin $(package)_config_opts += -c++std c++11 $(package)_config_opts += -confirm-license -$(package)_config_opts += -dbus-runtime $(package)_config_opts += -hostprefix $(build_prefix) $(package)_config_opts += -no-compile-examples $(package)_config_opts += -no-cups @@ -86,8 +85,10 @@ $(package)_config_opts += -no-feature-udpsocket $(package)_config_opts += -no-feature-wizard $(package)_config_opts += -no-feature-xml +$(package)_config_opts_darwin = -no-dbus + ifneq ($(build_os),darwin) -$(package)_config_opts_darwin = -xplatform macx-clang-linux +$(package)_config_opts_darwin += -xplatform macx-clang-linux $(package)_config_opts_darwin += -device-option MAC_SDK_PATH=$(OSX_SDK) $(package)_config_opts_darwin += -device-option MAC_SDK_VERSION=$(OSX_SDK_VERSION) $(package)_config_opts_darwin += -device-option CROSS_COMPILE="$(host)-" @@ -102,6 +103,7 @@ $(package)_config_opts_linux += -system-freetype $(package)_config_opts_linux += -no-feature-sessionmanager $(package)_config_opts_linux += -fontconfig $(package)_config_opts_linux += -no-opengl +$(package)_config_opts_linux += -dbus-runtime $(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++ $(package)_config_opts_i686_linux = -xplatform linux-g++-32 $(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 @@ -113,7 +115,11 @@ $(package)_config_opts_powerpc64le_linux += -platform linux-g++ -xplatform linux $(package)_config_opts_sparc64_linux += -platform linux-g++ -xplatform linux-g++-64 $(package)_config_opts_alpha_linux += -platform linux-g++ -xplatform linux-g++-64 $(package)_config_opts_m68k_linux += -platform linux-g++ -xplatform linux-g++-32 -$(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" + +$(package)_config_opts_mingw32 = -no-opengl +$(package)_config_opts_mingw32 += -no-dbus +$(package)_config_opts_mingw32 += -xplatform win32-g++ +$(package)_config_opts_mingw32 += -device-option CROSS_COMPILE="$(host)-" $(package)_config_opts_android = -xplatform android-clang $(package)_config_opts_android += -android-sdk $(ANDROID_SDK) @@ -123,6 +129,7 @@ $(package)_config_opts_android += -device-option CROSS_COMPILE="$(host)-" $(package)_config_opts_android += -egl $(package)_config_opts_android += -qpa xcb $(package)_config_opts_android += -no-eglfs +$(package)_config_opts_android += -no-dbus $(package)_config_opts_android += -opengl es2 $(package)_config_opts_android += -qt-freetype $(package)_config_opts_android += -no-fontconfig From 9931b1914a8df47d1c3287e3c75b58b58e5bc68f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:33:39 -0400 Subject: [PATCH 0345/1888] depends: don't configure xcb_proto xcb_proto's configure doesn't understand --disable-shared or --with-pic. All the package does it put a stack of xml files into a directory to be used by libxcb. --- depends/packages/xcb_proto.mk | 5 ----- 1 file changed, 5 deletions(-) diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 44110394bd..01203a0718 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -4,11 +4,6 @@ $(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 $(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 -define $(package)_set_vars - $(package)_config_opts=--disable-shared - $(package)_config_opts_linux=--with-pic -endef - define $(package)_config_cmds $($(package)_autoconf) endef From 3edd7b039ce322a57803546d8e5e3783ddc3c852 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:40:44 -0400 Subject: [PATCH 0346/1888] build: Fix behavior when ALLOW_HOST_PACKAGES unset --- depends/config.site.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/config.site.in b/depends/config.site.in index e633752066..1f5cde5cc9 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -59,7 +59,7 @@ PKG_CONFIG="`which pkg-config` --static" # avoid ruining the cache. Sigh. export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig if test -z "@allow_host_packages@"; then - export PKGCONFIG_LIBDIR= + export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig fi CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" From 06d6335b3116f112ef1cd997e1b7bb180edbc617 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:44:57 -0400 Subject: [PATCH 0347/1888] depends: Consistent use of package variable All other mk files use the package variable consistently except for the two instances here, which have always been here, since depends was introduced in 0.10. --- depends/packages/boost.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 3c86ffab74..d451c8ce7e 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -34,11 +34,11 @@ $(package)_cxxflags_android=-fPIC endef define $(package)_preprocess_cmds - echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam + echo "using $($(package)_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$($(package)_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam endef define $(package)_config_cmds - ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries) + ./bootstrap.sh --without-icu --with-libraries=$($(package)_config_libraries) endef define $(package)_build_cmds From f1858edbcea6a88e7064e25b62b1e9c5a92a04e2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:51:27 -0400 Subject: [PATCH 0348/1888] depends: qt: Fix C{,XX}FLAGS pickup --- depends/packages/qt.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 8316019c77..662e4b4dcb 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -197,9 +197,9 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix_s390x_powerpc_mips_mipsel_architectures.patch &&\ echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ - sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_LFLAGS = |!host_build: QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ - sed -i.old "s|QMAKE_CXXFLAGS = |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf + sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf endef define $(package)_config_cmds From 5f556ea1693cf26092705f1bae78a1a40f42675a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:53:52 -0400 Subject: [PATCH 0349/1888] depends: qt: Fix LDFLAGS pickup QMAKE_LFLAGS was removed from qtbase/mkspecs/win32-g++/qmake.conf in 39fc377bf105ba09e2a8f9acae467dc789b96525. Here, we add it back in with our LDFLAGS from depends before the first occurance of any QMAKE_LFLAGS_* variable settings. --- depends/packages/qt.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 662e4b4dcb..5a11d18c45 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -198,8 +198,8 @@ define $(package)_preprocess_cmds echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ - sed -i.old "s|QMAKE_LFLAGS = |!host_build: QMAKE_LFLAGS = $($(package)_ldflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ - sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf + sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf endef define $(package)_config_cmds From e8d0f7c6af8f52e6c81b223abaebe4ee53954d1f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 17:55:29 -0400 Subject: [PATCH 0350/1888] depends: qt: Fix C{,XX} pickup --- depends/packages/qt.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5a11d18c45..7ec5600535 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -199,7 +199,9 @@ define $(package)_preprocess_cmds echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ - sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf + sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf && \ + sed -i.old "s|QMAKE_CC = clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \ + sed -i.old "s|QMAKE_CXX = clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf endef define $(package)_config_cmds From 1fb0121b312c757a6a85079a84c9ea3162130397 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 18:10:44 -0400 Subject: [PATCH 0351/1888] depends: zlib: Move toolchain options to configure zlib has its own custom configure script, see comment in zlib.mk for more details --- depends/packages/zlib.mk | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index b86ed24845..12675691b9 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -5,24 +5,26 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 define $(package)_set_vars -$(package)_build_opts= CC="$($(package)_cc)" -$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" -$(package)_build_opts+=RANLIB="$($(package)_ranlib)" -$(package)_build_opts+=AR="$($(package)_ar)" -$(package)_build_opts_darwin+=AR="$($(package)_libtool)" -$(package)_build_opts_darwin+=ARFLAGS="-o" +$(package)_config_opts= CC="$($(package)_cc)" +$(package)_config_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" +$(package)_config_opts+=RANLIB="$($(package)_ranlib)" +$(package)_config_opts+=AR="$($(package)_ar)" +$(package)_config_opts_darwin+=AR="$($(package)_libtool)" +$(package)_config_opts_darwin+=ARFLAGS="-o" $(package)_config_opts_android+=CHOST=$(host) endef +# zlib has its own custom configure script that takes in options like CC, +# CFLAGS, RANLIB, AR, and ARFLAGS from the environment rather than from +# command-line arguments. define $(package)_config_cmds - ./configure --static --prefix=$(host_prefix) + env $($(package)_config_opts) ./configure --static --prefix=$(host_prefix) endef define $(package)_build_cmds - $(MAKE) $($(package)_build_opts) libz.a + $(MAKE) libz.a endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts) + $(MAKE) DESTDIR=$($(package)_staging_dir) install endef - From 2b977f28c0b7e72ac248b61c8946ea30a58ae2cf Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 18:16:47 -0400 Subject: [PATCH 0352/1888] depends: xtrans: Configure flags cleanup. xtrans does not understand the --with-pic and --disable-shared flags we pass it because it is not a library. Instead, we should pass it flags that disable features/packages we're not using so they don't get a chance to sneak in. --- depends/packages/xtrans.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk index 1993ff8344..6201d1d270 100644 --- a/depends/packages/xtrans.mk +++ b/depends/packages/xtrans.mk @@ -6,7 +6,7 @@ $(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc335 $(package)_dependencies= define $(package)_set_vars -$(package)_config_opts_linux=--with-pic --disable-shared + $(package)_config_opts_linux=--disable-docs --without-xmlto --without-fop --without-xsltproc endef define $(package)_preprocess_cmds From 066c0110aa2faa2e92ee8b99d87c5f7b4336bb9c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 18:29:21 -0400 Subject: [PATCH 0353/1888] build: prune dbus from depends --- depends/packages/dbus.mk | 23 ----------------------- depends/packages/packages.mk | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 depends/packages/dbus.mk diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk deleted file mode 100644 index 0460a2f2e4..0000000000 --- a/depends/packages/dbus.mk +++ /dev/null @@ -1,23 +0,0 @@ -package=dbus -$(package)_version=1.10.18 -$(package)_download_path=https://dbus.freedesktop.org/releases/dbus -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=6049ddd5f3f3e2618f615f1faeda0a115104423a7996b7aa73e2f36e38cc514a -$(package)_dependencies=expat - -define $(package)_set_vars - $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-shared --without-x -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -C dbus libdbus-1.la -endef - -define $(package)_stage_cmds - $(MAKE) -C dbus DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-dbusincludeHEADERS install-nodist_dbusarchincludeHEADERS && \ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 75ae23deca..892d02e98a 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -3,7 +3,7 @@ packages:=boost openssl libevent qt_native_packages = native_protobuf qt_packages = qrencode protobuf zlib -qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans qt_android_packages=qt qt_darwin_packages=qt From ef258feefacd0cd53582a3ac5da1bab0fe8d530d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 21:09:18 -0400 Subject: [PATCH 0354/1888] build: disable libxcb extensions Because we pass -qt-xcb to Qt, it will compile in a set of xcb helper libraries and extensions. So skip building all of the libxcb extensions when we build libcxb in depends. More info is available here: https://doc.qt.io/qt-5.9/linux-requirements.html --- depends/packages/libxcb.mk | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index 3ddd5a7dd9..ab2e89dfbe 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -7,6 +7,18 @@ $(package)_dependencies=xcb_proto libXau xproto define $(package)_set_vars $(package)_config_opts=--disable-static +# Because we pass -qt-xcb to Qt, it will compile in a set of xcb helper libraries and extensions, +# so we skip building all of the extensions here. +# More info is available from: https://doc.qt.io/qt-5.9/linux-requirements.html +$(package)_config_opts += --disable-composite --disable-damage --disable-dpms +$(package)_config_opts += --disable-dri2 --disable-dri3 --disable-glx +$(package)_config_opts += --disable-present --disable-randr --disable-record +$(package)_config_opts += --disable-render --disable-resource --disable-screensaver +$(package)_config_opts += --disable-shape --disable-shm --disable-sync +$(package)_config_opts += --disable-xevie --disable-xfixes --disable-xfree86-dri +$(package)_config_opts += --disable-xinerama --disable-xinput --disable-xkb +$(package)_config_opts += --disable-xprint --disable-selinux --disable-xtest +$(package)_config_opts += --disable-xv --disable-xvmc endef define $(package)_preprocess_cmds From 05ea88764a03700b98b86dba7077558d5d97fc15 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 21:29:37 -0400 Subject: [PATCH 0355/1888] build: ignore macOS make deploy artefacts & add them to clean-local --- .gitignore | 3 +++ Makefile.am | 1 + 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5d30879824..2d2d19ae71 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,9 @@ qrc_*.cpp # Mac specific .DS_Store build +osx_volname +dist/ +*.background.tiff #lcov *.gcno diff --git a/Makefile.am b/Makefile.am index eb5b832ca9..414c5e90ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -228,3 +228,4 @@ CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) clean-local: rm -rf test_dapscoin.coverage/ total.coverage/ $(OSX_APP) + rm -rf osx_volname dist/ dpi36.background.tiff dpi72.background.tiff From 6f3242192cec47f305a7a55c73095f2251d61dfe Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 22:26:49 -0400 Subject: [PATCH 0356/1888] depends: add ability to skip building qrencode --- depends/Makefile | 7 ++++++- depends/README.md | 1 + depends/config.site.in | 3 +++ depends/packages/packages.mk | 4 +++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/depends/Makefile b/depends/Makefile index e5a64857dd..ba716341ea 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -5,6 +5,7 @@ WORK_PATH = $(BASEDIR)/work BASE_CACHE ?= $(BASEDIR)/built SDK_PATH ?= $(BASEDIR)/SDKs NO_QT ?= +NO_QR ?= NO_WALLET ?= NO_ZMQ ?= NO_UPNP ?= @@ -95,7 +96,10 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_CXX) --version 2>/dev/null) $(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null) $(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) -qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) +qrencode_packages_$(NO_QR) = $(qrencode_packages) + +qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) $(qrencode_packages_) + wallet_packages_$(NO_WALLET) = $(wallet_packages) upnp_packages_$(NO_UPNP) = $(upnp_packages) zmq_packages_$(NO_ZMQ) = $(zmq_packages) @@ -147,6 +151,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_ -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ -e 's|@no_qt@|$(NO_QT)|' \ + -e 's|@no_qr@|$(NO_QR)|' \ -e 's|@no_zmq@|$(NO_ZMQ)|' \ -e 's|@no_wallet@|$(NO_WALLET)|' \ -e 's|@no_upnp@|$(NO_UPNP)|' \ diff --git a/depends/README.md b/depends/README.md index c2fff2ae95..c34185013c 100644 --- a/depends/README.md +++ b/depends/README.md @@ -73,6 +73,7 @@ The following can be set when running make: make FOO=bar SDK_PATH: Path where sdk's can be found (used by macOS) FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up NO_QT: Don't download/build/cache qt and its dependencies + NO_QR: Don't download/build/cache packages needed for enabling qrencode NO_ZMQ: Don't download/build/cache packages needed for enabling zeromq NO_WALLET: Don't download/build/cache libs needed to enable the wallet NO_UPNP: Don't download/build/cache packages needed for enabling upnp diff --git a/depends/config.site.in b/depends/config.site.in index 1f5cde5cc9..9842a672e6 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -20,6 +20,9 @@ if test -z $with_protoc_bindir && test -z "@no_qt@"; then with_protoc_bindir=$depends_prefix/native/bin fi +if test -z $with_qrencode && test -n "@no_qr@"; then + with_qrencode=no +fi if test -z $enable_wallet && test -n "@no_wallet@"; then enable_wallet=no diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 892d02e98a..c760a63a1f 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,7 +1,9 @@ packages:=boost openssl libevent qt_native_packages = native_protobuf -qt_packages = qrencode protobuf zlib +qt_packages = protobuf zlib + +qrencode_packages = qrencode qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans From ab362b38722c8836cbd49fc2abd7fb1f623a54bb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 22:32:41 -0400 Subject: [PATCH 0357/1888] build: disable libjpeg in qt --- depends/packages/qt.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 7ec5600535..ae1ea38dd8 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -36,6 +36,7 @@ $(package)_config_opts += -no-icu $(package)_config_opts += -no-iconv $(package)_config_opts += -no-kms $(package)_config_opts += -no-linuxfb +$(package)_config_opts += -no-libjpeg $(package)_config_opts += -no-libudev $(package)_config_opts += -no-mtdev $(package)_config_opts += -no-openvg @@ -61,7 +62,6 @@ $(package)_config_opts += -pch $(package)_config_opts += -pkg-config $(package)_config_opts += -prefix $(host_prefix) $(package)_config_opts += -qt-libpng -$(package)_config_opts += -qt-libjpeg $(package)_config_opts += -gif $(package)_config_opts += -qt-pcre $(package)_config_opts += -qt-harfbuzz From 4c1cce713fab30a45a4b90dfe3f91aa1cca49223 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 6 May 2020 22:33:31 -0400 Subject: [PATCH 0358/1888] build: remove jpeg lib check from bitcoin_qt.m4 --- build-aux/m4/bitcoin_qt.m4 | 1 - 1 file changed, 1 deletion(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index 4f5caab52f..d918aa6db0 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -498,7 +498,6 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ ]) BITCOIN_QT_CHECK(AC_CHECK_LIB([z] ,[main],,AC_MSG_WARN([zlib not found. Assuming qt has it built-in]))) - BITCOIN_QT_CHECK(AC_SEARCH_LIBS([jpeg_create_decompress] ,[qtjpeg jpeg],,AC_MSG_WARN([libjpeg not found. Assuming qt has it built-in]))) if test x$bitcoin_cv_qt58 = xno; then BITCOIN_QT_CHECK(AC_SEARCH_LIBS([png_error] ,[qtpng png],,AC_MSG_WARN([libpng not found. Assuming qt has it built-in]))) BITCOIN_QT_CHECK(AC_SEARCH_LIBS([pcre16_exec], [qtpcre pcre16],,AC_MSG_WARN([libpcre16 not found. Assuming qt has it built-in]))) From 900556e6a39f6767ef6cc115a2e86fff7e1574ab Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 8 May 2020 12:47:31 -0400 Subject: [PATCH 0359/1888] build: don't embed a build-id when building libdmg-hfsplus --- depends/packages/native_libdmg-hfsplus.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/native_libdmg-hfsplus.mk b/depends/packages/native_libdmg-hfsplus.mk index a4ffb6046c..3a784cccdd 100644 --- a/depends/packages/native_libdmg-hfsplus.mk +++ b/depends/packages/native_libdmg-hfsplus.mk @@ -10,7 +10,7 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin .. + cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin -DCMAKE_C_FLAGS="-Wl,--build-id=none" .. endef define $(package)_build_cmds From 55d561e39fc601e1e52eb3b8d8b086e140537edb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 14 May 2020 13:27:00 -0400 Subject: [PATCH 0360/1888] Make connect=0 disable automatic outbound connections. Otherwise it just responds to this obvious bit of configuration by trying to connect to "0" in a loop. Coming from upstream@515e2642eb45bda56156b1213b25fb4886d3fdbe --- src/init.cpp | 6 +++--- src/net.cpp | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3ee85ea9d8..2cd06a68cc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -405,13 +405,13 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); strUsage += HelpMessageOpt("-bantime=", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), 86400)); strUsage += HelpMessageOpt("-bind=", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); - strUsage += HelpMessageOpt("-connect=", _("Connect only to the specified node(s)")); + strUsage += HelpMessageOpt("-connect=", _("Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections")); strUsage += HelpMessageOpt("-discover", _("Discover own IP address (default: 1 when listening and no -externalip)")); strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + _("(default: 1)")); - strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)")); + strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)")); strUsage += HelpMessageOpt("-externalip=", _("Specify your own public address")); strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); - strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); + strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)")); strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); diff --git a/src/net.cpp b/src/net.cpp index e2408d442e..922c68175b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1736,8 +1736,9 @@ void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { // Initiate outbound connections from -addnode threadGroup.create_thread(boost::bind(&TraceThread, "addcon", &ThreadOpenAddedConnections)); - // Initiate outbound connections - threadGroup.create_thread(boost::bind(&TraceThread, "opencon", &ThreadOpenConnections)); + // Initiate outbound connections unless connect=0 + if (!mapArgs.count("-connect") || mapMultiArgs["-connect"].size() != 1 || mapMultiArgs["-connect"][0] != "0") + threadGroup.create_thread(boost::bind(&TraceThread, "opencon", &ThreadOpenConnections)); // Process messages threadGroup.create_thread(boost::bind(&TraceThread, "msghand", &ThreadMessageHandler)); From d84183b6737ceeca4c3be3e9bedc922b0ee4e59f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 14 May 2020 20:07:18 -0400 Subject: [PATCH 0361/1888] Remove MultisigDialog --- contrib/dapscoin-qt.pro | 2 - src/Makefile.qt.include | 4 - src/qt/bitcoingui.cpp | 31 - src/qt/bitcoingui.h | 7 - src/qt/coincontroldialog.cpp | 4 - src/qt/coincontroldialog.h | 1 - src/qt/forms/multisigdialog.ui | 838 -------------------------- src/qt/multisigdialog.cpp | 1025 -------------------------------- src/qt/multisigdialog.h | 72 --- src/qt/walletframe.cpp | 8 - src/qt/walletframe.h | 2 - src/qt/walletview.cpp | 8 - src/qt/walletview.h | 2 - 13 files changed, 2004 deletions(-) delete mode 100644 src/qt/forms/multisigdialog.ui delete mode 100644 src/qt/multisigdialog.cpp delete mode 100644 src/qt/multisigdialog.h diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index bd2a11cdb1..d3a9978ee8 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -200,7 +200,6 @@ HEADERS += src/activemasternode.h \ src/qt/macnotificationhandler.h \ src/qt/masternodelist.h \ src/qt/multisenddialog.h \ - src/qt/multisigdialog.h \ src/qt/networkstyle.h \ src/qt/notificator.h \ src/qt/openuridialog.h \ @@ -521,7 +520,6 @@ SOURCES += src/activemasternode.cpp \ src/qt/intro.cpp \ src/qt/masternodelist.cpp \ src/qt/multisenddialog.cpp \ - src/qt/multisigdialog.cpp \ src/qt/networkstyle.cpp \ src/qt/notificator.cpp \ src/qt/openuridialog.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index bf93d3e995..319e5a11b8 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -53,7 +53,6 @@ QT_FORMS_UI = \ qt/forms/intro.ui \ qt/forms/masternodelist.ui \ qt/forms/multisenddialog.ui \ - qt/forms/multisigdialog.ui\ qt/forms/openuridialog.ui \ qt/forms/optionsdialog.ui \ qt/forms/optionspage.ui \ @@ -98,7 +97,6 @@ QT_MOC_CPP = \ qt/moc_macnotificationhandler.cpp \ qt/moc_masternodelist.cpp \ qt/moc_multisenddialog.cpp \ - qt/moc_multisigdialog.cpp\ qt/moc_notificator.cpp \ qt/moc_openuridialog.cpp \ qt/moc_optionsdialog.cpp \ @@ -182,7 +180,6 @@ BITCOIN_QT_H = \ qt/macnotificationhandler.h \ qt/masternodelist.h \ qt/multisenddialog.h \ - qt/multisigdialog.h\ qt/networkstyle.h \ qt/notificator.h \ qt/openuridialog.h \ @@ -338,7 +335,6 @@ BITCOIN_QT_CPP += \ qt/historypage.cpp \ qt/masternodelist.cpp \ qt/multisenddialog.cpp \ - qt/multisigdialog.cpp\ qt/openuridialog.cpp \ qt/overviewpage.cpp \ qt/optionspage.cpp \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 13fa800335..69840d30a0 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -86,9 +86,6 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai sendCoinsAction(0), usedSendingAddressesAction(0), usedReceivingAddressesAction(0), - multisigCreateAction(0), - multisigSpendAction(0), - multisigSignAction(0), aboutAction(0), receiveCoinsAction(0), // privacyAction(0), @@ -435,13 +432,6 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels")); - multisigCreateAction = new QAction(QIcon(":/icons/address-book"), tr("&Multisignature creation..."), this); - multisigCreateAction->setStatusTip(tr("Create a new multisignature address and add it to this wallet")); - multisigSpendAction = new QAction(QIcon(":/icons/send"), tr("&Multisignature spending..."), this); - multisigSpendAction->setStatusTip(tr("Spend from a multisignature address")); - multisigSignAction = new QAction(QIcon(":/icons/editpaste"), tr("&Multisignature signing..."), this); - multisigSignAction->setStatusTip(tr("Sign with a multisignature address")); - openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a DAPS: URI or payment request")); openBlockExplorerAction = new QAction(QIcon(":/icons/explorer"), tr("&Blockchain Explorer"), this); @@ -510,9 +500,6 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); connect(multiSendAction, SIGNAL(triggered()), this, SLOT(gotoMultiSendDialog())); - connect(multisigCreateAction, SIGNAL(triggered()), this, SLOT(gotoMultisigCreate())); - connect(multisigSpendAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSpend())); - connect(multisigSignAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSign())); } #endif // ENABLE_WALLET connect(facebookAction, SIGNAL(triggered()), this, SLOT(facebookActionClicked())); @@ -764,9 +751,6 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); changePassphraseAction->setEnabled(enabled); - multisigCreateAction->setEnabled(enabled); - multisigSpendAction->setEnabled(enabled); - multisigSignAction->setEnabled(enabled); usedSendingAddressesAction->setEnabled(enabled); usedReceivingAddressesAction->setEnabled(enabled); openAction->setEnabled(enabled); @@ -1025,21 +1009,6 @@ void BitcoinGUI::gotoSendCoinsPage(QString addr) if (walletFrame) walletFrame->gotoSendCoinsPage(addr); } -void BitcoinGUI::gotoMultisigCreate() -{ - if (walletFrame) walletFrame->gotoMultisigDialog(0); -} - -void BitcoinGUI::gotoMultisigSpend() -{ - if (walletFrame) walletFrame->gotoMultisigDialog(1); -} - -void BitcoinGUI::gotoMultisigSign() -{ - if (walletFrame) walletFrame->gotoMultisigDialog(2); -} - void BitcoinGUI::gotoMultiSendDialog() { multiSendAction->setChecked(true); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 5a9d82ffd1..1200181511 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -98,9 +98,6 @@ class BitcoinGUI : public QMainWindow QAction* sendCoinsAction; QAction* usedSendingAddressesAction; QAction* usedReceivingAddressesAction; - QAction* multisigCreateAction; - QAction* multisigSpendAction; - QAction* multisigSignAction; QAction* aboutAction; QAction* receiveCoinsAction; QAction* optionsAction; @@ -244,10 +241,6 @@ private Q_SLOTS: void gotoSendCoinsPage(QString addr = ""); /** Show MultiSend Dialog */ void gotoMultiSendDialog(); - /** Show MultiSig Dialog */ - void gotoMultisigCreate(); - void gotoMultisigSpend(); - void gotoMultisigSign(); /** Show open dialog */ void openClicked(); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 3ceeea0c9d..733abea839 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -19,7 +19,6 @@ #include "main.h" #include "obfuscation.h" #include "wallet/wallet.h" -#include "multisigdialog.h" #include // for 'map_list_of()' @@ -516,9 +515,6 @@ void CoinControlDialog::updateDialogLabels() // Amount nAmount += model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]); } - MultisigDialog* multisigDialog = (MultisigDialog*)this->parentWidget(); - - multisigDialog->updateCoinControl(nAmount, nQuantity); } void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 44f0b0a1b0..90a30cf3b2 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -18,7 +18,6 @@ class WalletModel; -class MultisigDialog; class CCoinControl; class CTxMemPool; diff --git a/src/qt/forms/multisigdialog.ui b/src/qt/forms/multisigdialog.ui deleted file mode 100644 index 84216251f7..0000000000 --- a/src/qt/forms/multisigdialog.ui +++ /dev/null @@ -1,838 +0,0 @@ - - - MultisigDialog - - - - 0 - 0 - 801 - 504 - - - - - 0 - 0 - - - - Multisignature Address Interactions - - - - - - QScrollArea{border: 1px solid #5b4c7c;} -QFrame{background-color:#f2f0f0;} -QLabel{background-color:#ffffff;} -QFrame > QLabel{background-color:#f2f0f0;} - - - 0 - - - - - 0 - 0 - - - - Create MultiSignature &Address - - - - - - - - - 0 - 0 - - - - How many people must sign to verify a transaction - - - 1 - - - 16 - - - 1 - - - - - - - Enter the minimum number of signatures required to sign transactions - - - - - - - - - - - Address Label: - - - - - - - - - - - - - - Add another address that could sign to verify a transaction from the multisig address. - - - &Add Address / Key - - - - :/icons/add:/icons/add - - - false - - - - - - - - 0 - 0 - - - - Local addresses or public keys that can sign: - - - - - - - Qt::Horizontal - - - - 40 - 10 - - - - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 759 - 165 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - 0 - 0 - - - - Create a new multisig address - - - -3 - - - C&reate - - - - :/icons/filesave:/icons/filesave - - - false - - - - - - - Status: - - - - - - - - 0 - 0 - - - - - 16777215 - 75 - - - - true - - - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - 0 - 0 - - - - Use below to quickly import an address by its redeem. Don't forget to add a label before clicking import! -Keep in mind, the wallet will rescan the blockchain to find transactions containing the new address. -Please be patient after clicking import. - - - false - - - true - - - - - - - - - - 0 - 0 - - - - &Import Redeem - - - - :/icons/receiving_addresses:/icons/receiving_addresses - - - - - - - - 0 - 0 - - - - - - - - - - - &Create MultiSignature Tx - - - - - - - - - - - - - 0 - 0 - - - - Inputs: - - - - - - - - 0 - 0 - - - - Coin Control - - - - - - - 10 - - - - - Quantity Selected: - - - - - - - 0 - - - - - - - Amount: - - - - - - - 0 - - - - - - - - - - 0 - 0 - - - - Add an input to fund the outputs - - - Add a Raw Input - - - - :/css/default:/css/default - - - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 98 - 28 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - Address / Amount: - - - - - - - - 0 - 0 - - - - Add destinations to send DAPS to - - - Add &Destination - - - - :/icons/add:/icons/add - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 98 - 28 - - - - - - - - - - Qt::Vertical - - - - 20 - 20 - - - - - - - - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - Create a transaction object using the given inputs to the given outputs - - - Cr&eate - - - - :/icons/export:/icons/export - - - false - - - true - - - - - - - - 0 - 0 - - - - Status: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - - - - - - - - - - - - - txScrollArea:{ - border: 1px solid #5b4c7c; -} -keyScrollArea:{ - border: 1px solid #5b4c7c; -} -txScrollArea:{ - border: 1px solid #5b4c7c; -} - - - &Sign MultiSignature Tx - - - - - - - - Transaction Hex: - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - Sign the transaction from this wallet or from provided private keys - - - S&ign - - - - :/icons/edit:/icons/edit - - - false - - - true - - - - - - - false - - - - 0 - 0 - - - - <html><head/><body><p>DISABLED until transaction has been signed enough times.</p></body></html> - - - false - - - Co&mmit - - - - :/icons/send:/icons/send - - - true - - - - - - - - - - 0 - 0 - - - - Add private keys to sign the transaction with - - - Add Private &Key - - - - :/icons/add:/icons/add - - - - - - - Sign with only private keys (Not Recommened) - - - - - - - - - - - - - Status: - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Qt::ScrollBarAsNeeded - - - true - - - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 98 - 28 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp deleted file mode 100644 index eff5aaafb6..0000000000 --- a/src/qt/multisigdialog.cpp +++ /dev/null @@ -1,1025 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "multisigdialog.h" -#include "forms/ui_multisigdialog.h" - -#include "askpassphrasedialog.h" -#include "primitives/transaction.h" -#include "addressbookpage.h" -#include "utilstrencodings.h" -#include "core_io.h" -#include "script/script.h" -#include "base58.h" -#include "coins.h" -#include "keystore.h" -#include "init.h" -#include "wallet/wallet.h" -#include "script/sign.h" -#include "script/interpreter.h" -#include "utilmoneystr.h" -#include "guiutil.h" -#include "qvalidatedlineedit.h" -#include "bitcoinamountfield.h" - -#include -#include -#include -#include -#include -#include - - -MultisigDialog::MultisigDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), - ui(new Ui::MultisigDialog), - model(0) -{ - ui->setupUi(this); - multisigTx = CMutableTransaction(); - - //flag to show keyScrollArea on first priv key added - isFirstPrivKey = true; - isFirstRawTx = true; - ui->keyScrollArea->hide(); - ui->txInputsScrollArea->hide(); - - connect(ui->commitButton, SIGNAL(clicked()), this, SLOT(commitMultisigTx())); - - //populate lists with initial objects - on_addAddressButton_clicked(); - on_addAddressButton_clicked(); - on_addDestinationButton_clicked(); - - this->setStyleSheet(GUIUtil::loadStyleSheet()); -} - -MultisigDialog::~MultisigDialog() -{ - delete ui; -} - -void MultisigDialog::setModel(WalletModel *model) -{ - this->model = model; -} - -void MultisigDialog::showTab(int index) -{ - ui->multisigTabWidget->setCurrentIndex(index); - this->show(); -} - -void MultisigDialog::updateCoinControl(CAmount nAmount, unsigned int nQuantity) -{ - ui->labelAmount_int->setText(QString::fromStdString(FormatMoney(nAmount))); - ui->labelQuantity_int->setText(QString::number(nQuantity)); -} - -/** -* Private Slots -*/ -//slot for pasting addresses -void MultisigDialog::pasteText() -{ - QWidget* pasteButton = qobject_cast(sender()); - if(!pasteButton)return; - - QFrame* addressFrame = qobject_cast(pasteButton->parentWidget()); - if(!addressFrame)return; - - QValidatedLineEdit* vle = addressFrame->findChild("address"); - if(!vle)return; - - vle->setText(QApplication::clipboard()->text()); -} - -//slot for deleting QFrames with the delete buttons -void MultisigDialog::deleteFrame() -{ - QWidget *buttonWidget = qobject_cast(sender()); - if(!buttonWidget)return; - - //if deleting last raw input/priv key, hide scroll area - if(buttonWidget->objectName() == "inputDeleteButton" && ui->inputsList->count() == 1){ - isFirstRawTx = true; - ui->txInputsScrollArea->hide(); - }else if(buttonWidget->objectName() == "keyDeleteButton" && ui->keyList->count() == 1){ - isFirstPrivKey = true; - ui->keyScrollArea->hide(); - } - - QFrame* frame = qobject_cast(buttonWidget->parentWidget()); - if(!frame)return; - - delete frame; -} - -//slot to open address book dialog -void MultisigDialog::addressBookButtonReceiving() -{ - QWidget* addressButton = qobject_cast(sender()); - if(!addressButton)return; - - QFrame* addressFrame = qobject_cast(addressButton->parentWidget()); - if(!addressFrame)return; - - QValidatedLineEdit* vle = addressFrame->findChild("address"); - if(!vle)return; - - if (model && model->getAddressTableModel()) { - AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); - dlg.setModel(model->getAddressTableModel()); - if (dlg.exec()) { - vle->setText(dlg.getReturnValue()); - } - } -} - -//create address -void MultisigDialog::on_addMultisigButton_clicked() -{ - if(!model) - return; - - int m = ui->enterMSpinbox->value(); - - vector keys; - - for (int i = 0; i < ui->addressList->count(); i++) { - QWidget* address = qobject_cast(ui->addressList->itemAt(i)->widget()); - QValidatedLineEdit* vle = address->findChild("address"); - - if(!vle->text().isEmpty()){ - keys.push_back(vle->text().toStdString()); - } - } - - addMultisig(m, keys); -} - -void MultisigDialog::on_importAddressButton_clicked(){ - if(!model) - return; - - string sRedeem = ui->importRedeem->text().toStdString(); - - if(sRedeem.empty()){ - ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); - ui->addMultisigStatus->setText("Import box empty!"); - return; - } - - vector vRedeem; - size_t pos = 0; - - //search redeem input delimited by space - while ((pos = sRedeem.find(" ")) != std::string::npos) { - vRedeem.push_back(sRedeem.substr(0, pos)); - sRedeem.erase(0, pos + 1); - } - - vector keys(vRedeem.begin()+1, vRedeem.end()-1); - - addMultisig(stoi(vRedeem[0]), keys); - - // rescan to find txs associated with imported address - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - pwalletMain->ReacceptWalletTransactions(); -} - -bool MultisigDialog::addMultisig(int m, vector keys){ - try{ - string error; - CScript redeem; - - if(!createRedeemScript(m, keys, redeem, error)){ - throw runtime_error(error.data()); - } - - if (::IsMine(*pwalletMain, redeem) == ISMINE_SPENDABLE){ - throw runtime_error("The wallet already contains this script"); - } - - if(!pwalletMain->AddCScript(redeem)){ - throw runtime_error("Failure: address invalid or already exists"); - } - - CScriptID innerID(redeem); - string label = ui->multisigAddressLabel->text().toStdString(); - pwalletMain->SetAddressBook(innerID, label, "receive"); - if (!pwalletMain->AddMultiSig(redeem)){ - throw runtime_error("Failure: unable to add address as watch only"); - } - - ui->addMultisigStatus->setStyleSheet("QLabel { color: black; }"); - ui->addMultisigStatus->setText("Multisignature address " + - QString::fromStdString(CBitcoinAddress(innerID).ToString()) + - " has been added to the wallet.\nSend the redeem below for other owners to import:\n" + - QString::fromStdString(redeem.ToString())); - }catch(const runtime_error& e) { - ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); - ui->addMultisigStatus->setText(tr(e.what())); - return false; - } - return true; -} - - -//spend -void MultisigDialog::on_createButton_clicked() -{ - if(!model) - return; - - vector vUserIn; - vector vUserOut; - try{ - //Add inputs from Coin Control if any are selected - if (CoinControlDialog::coinControl->HasSelected()) { - vector vSelected; - CoinControlDialog::coinControl->ListSelected(vSelected); - for (auto outpoint : vSelected) - vUserIn.emplace_back(CTxIn(outpoint)); - }else{//check for raw inputs - for(int i = 0; i < ui->inputsList->count(); i++){ - QWidget* input = qobject_cast(ui->inputsList->itemAt(i)->widget()); - QLineEdit* txIdLine = input->findChild("txInputId"); - if(txIdLine->text().isEmpty()){ - ui->createButtonStatus->setStyleSheet("QLabel { color: red; }"); - ui->createButtonStatus->setText(tr("Invalid Tx Hash.")); - return; - } - - QSpinBox* txVoutLine = input->findChild("txInputVout"); - int nOutput = txVoutLine->value(); - if(nOutput < 0){ - ui->createButtonStatus->setStyleSheet("QLabel { color: red; }"); - ui->createButtonStatus->setText(tr("Vout position must be positive.")); - return; - } - - uint256 txid = uint256S(txIdLine->text().toStdString()); - CTxIn in(COutPoint(txid, nOutput)); - vUserIn.emplace_back(in); - } - } - - //validate destinations - bool validInput = true; - for(int i = 0; i < ui->destinationsList->count(); i++){ - QWidget* dest = qobject_cast(ui->destinationsList->itemAt(i)->widget()); - QValidatedLineEdit* addr = dest->findChild("destinationAddress"); - BitcoinAmountField* amt = dest->findChild("destinationAmount"); - CBitcoinAddress address; - - bool validDest = true; - - if(!model->validateAddress(addr->text())){ - addr->setValid(false); - validDest = false; - }else{ - address = CBitcoinAddress(addr->text().toStdString()); - } - - if(!amt->validate()){ - amt->setValid(false); - validDest = false; - } - - if(!validDest){ - validInput = false; - continue; - } - - CScript scriptPubKey = GetScriptForDestination(address.Get()); - CTxOut out(amt->value(), scriptPubKey); - vUserOut.push_back(out); - } - - - //if all user data valid create a multisig tx - if(validInput){ - //clear member variable - multisigTx = CMutableTransaction(); - - string error; - string fee; - if(!createMultisigTransaction(vUserIn, vUserOut, fee, error)){ - throw runtime_error(error); - } - - //display status string - ui->createButtonStatus->setStyleSheet("QTextEdit{ color: black }"); - - QString status(strprintf("Transaction has successfully created with a fee of %s.\n" - "The transaction has been automatically imported to the sign tab.\n" - "Please continue on to sign the tx from this wallet, to access the hex to send to other owners.", fee).c_str()); - - ui->createButtonStatus->setText(status); - ui->transactionHex->setText(QString::fromStdString(EncodeHexTx(multisigTx))); - - } - }catch(const runtime_error& e){ - ui->createButtonStatus->setStyleSheet("QTextEdit{ color: red }"); - ui->createButtonStatus->setText(tr(e.what())); - } -} - -bool MultisigDialog::createMultisigTransaction(vector vUserIn, vector vUserOut, string& feeStringRet, string& errorRet) -{ - try{ - //attempt to access the given inputs - CCoinsViewCache view = getInputsCoinsViewCache(vUserIn); - - //retrieve total input val and change dest - CAmount totalIn = 0; - vector vInputVals; - CScript changePubKey; - bool fFirst = true; - - for(CTxIn in : vUserIn){ - const CCoins* coins = view.AccessCoins(in.prevout.hash); - if(!coins->IsAvailable(in.prevout.n) || coins == NULL){ - continue; - } - CTxOut prevout = coins->vout[in.prevout.n]; - CScript privKey = prevout.scriptPubKey; - - vInputVals.push_back(prevout.nValue); - totalIn += prevout.nValue; - - if(!fFirst){ - if(privKey != changePubKey){ - throw runtime_error("Address mismatch! Inputs must originate from the same multisignature address."); - } - }else{ - fFirst = false; - changePubKey = privKey; - } - } - - CAmount totalOut = 0; - - //retrieve total output val - for(CTxOut out : vUserOut){ - totalOut += out.nValue; - } - - if(totalIn < totalOut){ - throw runtime_error("Not enough DAPS provided as input to complete transaction (including fee)."); - } - - //calculate change amount - CAmount changeAmount = totalIn - totalOut; - CTxOut change(changeAmount, changePubKey); - - //generate random position for change - unsigned int changeIndex = secp256k1_rand32() % (vUserOut.size() + 1); - - //insert change into random position - if(changeIndex < vUserOut.size()){ - vUserOut.insert(vUserOut.begin() + changeIndex, change); - }else{ - vUserOut.emplace_back(change); - } - - //populate tx - CMutableTransaction tx; - tx.vin = vUserIn; - tx.vout = vUserOut; - - const CCoins* coins = view.AccessCoins(tx.vin[0].prevout.hash); - - if(coins == NULL || !coins->IsAvailable(tx.vin[0].prevout.n)){ - throw runtime_error("Coins unavailable (unconfirmed/spent)"); - } - - CScript prevPubKey = coins->vout[tx.vin[0].prevout.n].scriptPubKey; - - //get payment destination - CTxDestination address; - if(!ExtractDestination(prevPubKey, address)){ - throw runtime_error("Could not find address for destination."); - } - - CScriptID hash = boost::get(address); - CScript redeemScript; - - if (!pwalletMain->GetCScript(hash, redeemScript)){ - throw runtime_error("could not redeem"); - } - txnouttype type; - vector addresses; - int nReq; - if(!ExtractDestinations(redeemScript, type, addresses, nReq)){ - throw runtime_error("Could not extract destinations from redeem script."); - } - - for(CTxIn& in : tx.vin){ - in.scriptSig.clear(); - //scale estimate to account for multisig scriptSig - for(unsigned int i = 0; i < 50*(nReq+addresses.size()); i++){ - in.scriptSig << INT64_MAX; - } - } - - //calculate fee - unsigned int nBytes = tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); - CAmount fee = ::minRelayTxFee.GetFee(nBytes); - - if(tx.vout.at(changeIndex).nValue > fee){ - tx.vout.at(changeIndex).nValue -= fee; - feeStringRet = strprintf("%d",((double)fee)/COIN).c_str(); - }else{ - throw runtime_error("Not enough DAPS provided to cover fee"); - } - - //clear junk from script sigs - for(CTxIn& in : tx.vin){ - in.scriptSig.clear(); - } - multisigTx = tx; - }catch(const runtime_error& e){ - errorRet = e.what(); - return false; - } - return true; -} - -//sign -void MultisigDialog::on_signButton_clicked() -{ - if(!model) - return; - try{ - //parse tx hex - CTransaction txRead; - if(!DecodeHexTx(txRead, ui->transactionHex->text().toStdString())){ - throw runtime_error("Failed to decode transaction hex!"); - } - - CMutableTransaction tx(txRead); - - //check if transaction is already fully verified - if(isFullyVerified(tx)){ - this->multisigTx = tx; - ui->commitButton->setEnabled(true); - ui->signButtonStatus->setText("This transaction is ready to commit. \nThe commit button in now enabled."); - return; - } - - string errorOut = string(); - bool fComplete = signMultisigTx(tx, errorOut, ui->keyList); - - if(!errorOut.empty()){ - throw runtime_error(errorOut.data()); - }else{ - this->multisigTx = tx; - } - - ui->signButtonStatus->setStyleSheet("QTextEdit{ color: black }"); - ui->signButtonStatus->setText(buildMultisigTxStatusString(fComplete, tx)); - - }catch(const runtime_error& e){ - ui->signButtonStatus->setStyleSheet("QTextEdit{ color: red }"); - ui->signButtonStatus->setText(tr(e.what())); - } -} - -/*** - *private helper functions - */ -QString MultisigDialog::buildMultisigTxStatusString(bool fComplete, const CMutableTransaction& tx) -{ - string sTxHex = EncodeHexTx(tx); - - if(fComplete){ - ui->commitButton->setEnabled(true); - string sTxId = tx.GetHash().GetHex(); - string sTxComplete = "Complete: true!\n" - "The commit button has now been enabled for you to finalize the transaction.\n" - "Once the commit button is clicked, the transaction will be published and coins transferred " - "to their destinations.\nWARNING: THE ACTIONS OF THE COMMIT BUTTON ARE FINAL AND CANNOT BE REVERSED."; - - return QString(strprintf("%s\nTx Id:\n%s\nTx Hex:\n%s",sTxComplete, sTxId, sTxHex).c_str()); - } else { - string sTxIncomplete = "Complete: false.\n" - "You may now send the hex below to another owner to sign.\n" - "Keep in mind the transaction must be passed from one owner to the next for signing.\n" - "Ensure all owners have imported the redeem before trying to sign. (besides creator)"; - - return QString(strprintf("%s\nTx Hex: %s", sTxIncomplete, sTxHex).c_str()); - } -} - - -CCoinsViewCache MultisigDialog::getInputsCoinsViewCache(const vector& vin) -{ - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - { - LOCK(mempool.cs); - CCoinsViewCache& viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(&viewChain, mempool); - view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - - for(const CTxIn& txin : vin) { - const uint256& prevHash = txin.prevout.hash; - view.AccessCoins(prevHash); // this is certainly allowed to fail - } - - view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long - } - - return view; -} - - -bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, QVBoxLayout* keyList) -{ - //will be set false if all inputs are not fully signed(valid) - bool fComplete = true; - - //if keyslist is not default value AND has items in list then true - bool fGivenKeys = (keyList != nullptr) && (keyList->count() > 0); - - try{ - - //copy of vin for reference before vin is mutated - vector oldVin(tx.vin); - CBasicKeyStore privKeystore; - - //if keys were given, attempt to collect redeem and scriptpubkey - if(fGivenKeys){ - for(int i = 0; i < keyList->count(); i++){ - QWidget* keyFrame = qobject_cast(keyList->itemAt(i)->widget()); - QLineEdit* key = keyFrame->findChild("key"); - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(key->text().toStdString())) - throw runtime_error("Invalid private key"); - CKey cKey = vchSecret.GetKey(); - if (!cKey.IsValid()) - throw runtime_error("Private key outside allowed range"); - privKeystore.AddKey(cKey); - } - - for(CTxIn& txin : tx.vin){ - //get inputs - CTransaction txVin; - uint256 hashBlock; - if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)) - throw runtime_error("txin could not be found"); - - if (hashBlock == 0) - throw runtime_error("txin is unconfirmed"); - - //get pubkey from input - CScript prevPubKey = txVin.vout[txin.prevout.n].scriptPubKey; - - //get payment destination - CTxDestination address; - if(!ExtractDestination(prevPubKey, address)){ - throw runtime_error("Could not find address for destination."); - } - - //get redeem script related to destination - CScriptID hash = boost::get(address); - CScript redeemScript; - - if (!pwalletMain->GetCScript(hash, redeemScript)){ - errorOut = "could not redeem"; - } - privKeystore.AddCScript(redeemScript); - } - }else{ - if (model->getEncryptionStatus() == model->Locked) { - if (!model->requestUnlock(AskPassphraseDialog::Context::Multi_Sig, true).isValid()) { - // Unlock wallet was cancelled - throw runtime_error("Error: Your wallet is locked. Please enter the wallet passphrase first."); - } - } - } - - //choose between local wallet and provided - const CKeyStore& keystore = fGivenKeys ? privKeystore : *pwalletMain; - - //attempt to sign each input from local wallet - int nIn = 0; - for(CTxIn& txin : tx.vin){ - //get inputs - CTransaction txVin; - uint256 hashBlock; - if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)) - throw runtime_error("txin could not be found"); - - if (hashBlock == 0) - throw runtime_error("txin is unconfirmed"); - - txin.scriptSig.clear(); - CScript prevPubKey = txVin.vout[txin.prevout.n].scriptPubKey; - - //sign what we can - SignSignature(keystore, prevPubKey, tx, nIn); - - //merge in any previous signatures - txin.scriptSig = CombineSignatures(prevPubKey, tx, nIn, txin.scriptSig, oldVin[nIn].scriptSig); - - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, nIn))){ - fComplete = false; - } - nIn++; - } - - ui->signButtonStatus->setText(buildMultisigTxStatusString(fComplete, tx)); - - }catch(const runtime_error& e){ - errorOut = string(e.what()); - fComplete = false; - } - return fComplete; -} - -// quick check for an already fully signed tx -bool MultisigDialog::isFullyVerified(CMutableTransaction& tx){ - try{ - int nIn = 0; - for(CTxIn& txin : tx.vin){ - CTransaction txVin; - uint256 hashBlock; - if (!GetTransaction(txin.prevout.hash, txVin, hashBlock, true)){ - throw runtime_error("txin could not be found"); - } - if (hashBlock == 0){ - throw runtime_error("txin is unconfirmed"); - } - - //get pubkey from this input as output in last tx - CScript prevPubKey = txVin.vout[txin.prevout.n].scriptPubKey; - - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&tx, nIn))){ - return false; - } - - nIn++; - } - }catch(const runtime_error& e){ - return false; - } - - return true; -} - -void MultisigDialog::commitMultisigTx() -{ - CMutableTransaction tx(multisigTx); - try{ -#ifdef ENABLE_WALLET - CWalletTx wtx(pwalletMain, tx); - CReserveKey keyChange(pwalletMain); - if (!pwalletMain->CommitTransaction(wtx, keyChange)) - throw runtime_error(string("Transaction rejected - Failed to commit")); -#else - uint256 hashTx = tx.GetHash(); - CCoinsViewCache& view = *pcoinsTip; - const CCoins* existingCoins = view.AccessCoins(hashTx); - bool fOverrideFees = false; - bool fHaveMempool = mempool.exists(hashTx); - bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; - - if (!fHaveMempool && !fHaveChain) { - // push to local node and sync with wallets - CValidationState state; - if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) { - if (state.IsInvalid()) - throw runtime_error(strprintf("Transaction rejected - %i: %s", state.GetRejectCode(), state.GetRejectReason())); - else - throw runtime_error(string("Transaction rejected - ") + state.GetRejectReason()); - } - } else if (fHaveChain) { - throw runtime_error("transaction already in block chain"); - } - RelayTransaction(tx); -#endif - //disable commit if successfully committed - ui->commitButton->setEnabled(false); - ui->signButtonStatus->setText(strprintf("Transaction has been successfully published with transaction ID:\n %s", tx.GetHash().GetHex()).c_str()); - }catch(const runtime_error& e){ - ui->signButtonStatus->setText(e.what()); - } -} - -bool MultisigDialog::createRedeemScript(int m, vector vKeys, CScript& redeemRet, string& errorRet) -{ - try{ - int n = vKeys.size(); - //gather pub keys - if (n < 1) - throw runtime_error("a Multisignature address must require at least one key to redeem"); - if (n < m) - throw runtime_error( - strprintf("not enough keys supplied " - "(got %d keys, but need at least %d to redeem)", - m, n)); - if (n > 15) - throw runtime_error("Number of addresses involved in the Multisignature address creation > 15\nReduce the number"); - - vector pubkeys; - pubkeys.resize(n); - - int i = 0; - for(vector::iterator it = vKeys.begin(); it != vKeys.end(); ++it) { - string keyString = *it; - #ifdef ENABLE_WALLET - // Case 1: DAPS address and we have full public key: - CBitcoinAddress address(keyString); - if (pwalletMain && address.IsValid()) { - CKeyID keyID; - if (!address.GetKeyID(keyID)) { - throw runtime_error( - strprintf("%s does not refer to a key", keyString)); - } - CPubKey vchPubKey; - if (!pwalletMain->GetPubKey(keyID, vchPubKey)) - throw runtime_error( - strprintf("no full public key for address %s", keyString)); - if (!vchPubKey.IsFullyValid()){ - string sKey = keyString.empty()?"(empty)":keyString; - throw runtime_error(" Invalid public key: " + sKey ); - } - pubkeys[i++] = vchPubKey; - } - - //case 2: hex pub key - else - #endif - if (IsHex(keyString)) { - CPubKey vchPubKey(ParseHex(keyString)); - if (!vchPubKey.IsFullyValid()){ - throw runtime_error(" Invalid public key: " + keyString); - } - pubkeys[i++] = vchPubKey; - } else { - throw runtime_error(" Invalid public key: " + keyString); - } - } - //populate redeem script - //OP_N for required signatures - redeemRet << redeemRet.EncodeOP_N(m); - //public keys - for(CPubKey& key : pubkeys){ - vector vKey= ToByteVector(key); - redeemRet << vKey; - } - //OP_N for total pubkeys - redeemRet << redeemRet.EncodeOP_N(pubkeys.size()); - redeemRet << OP_CHECKMULTISIG; - return true; - }catch(const runtime_error& e){ - errorRet = string(e.what()); - return false; - } -} - -/*** - * Begin QFrame object creation methods - */ -//creates an address object on the create tab -void MultisigDialog::on_addAddressButton_clicked() -{ - //max addresses 15 - if(ui->addressList->count() > 14){ - ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); - ui->addMultisigStatus->setText(tr("Maximum possible addresses reached. (16)")); - return; - } - - QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - QFrame* addressFrame = new QFrame(); - sizePolicy.setHeightForWidth(addressFrame->sizePolicy().hasHeightForWidth()); - addressFrame->setSizePolicy(sizePolicy); - addressFrame->setFrameShape(QFrame::StyledPanel); - addressFrame->setFrameShadow(QFrame::Raised); - addressFrame->setObjectName(QStringLiteral("addressFrame")); - - QVBoxLayout* frameLayout = new QVBoxLayout(addressFrame); - frameLayout->setSpacing(1); - frameLayout->setObjectName(QStringLiteral("frameLayout")); - frameLayout->setContentsMargins(6, 6, 6, 6); - - QHBoxLayout* addressLayout = new QHBoxLayout(); - addressLayout->setSpacing(0); - addressLayout->setObjectName(QStringLiteral("addressLayout")); - - QLabel* addressLabel = new QLabel(addressFrame); - addressLabel->setObjectName(QStringLiteral("addressLabel")); - addressLabel->setText(QApplication::translate("MultisigDialog", strprintf("Address / Key %i:", ui->addressList->count()+1).c_str() , 0)); - addressLayout->addWidget(addressLabel); - - QValidatedLineEdit* address = new QValidatedLineEdit(addressFrame); - address->setObjectName(QStringLiteral("address")); - addressLayout->addWidget(address); - - QPushButton* addressBookButton = new QPushButton(addressFrame); - addressBookButton->setObjectName(QStringLiteral("addressBookButton")); - QIcon icon3; - icon3.addFile(QStringLiteral(":/icons/address-book"), QSize(), QIcon::Normal, QIcon::Off); - addressBookButton->setIcon(icon3); - addressBookButton->setAutoDefault(false); - connect(addressBookButton, SIGNAL(clicked()), this, SLOT(addressBookButtonReceiving())); - - addressLayout->addWidget(addressBookButton); - - QPushButton* addressPasteButton = new QPushButton(addressFrame); - addressPasteButton->setObjectName(QStringLiteral("addressPasteButton")); - QIcon icon4; - icon4.addFile(QStringLiteral(":/icons/editpaste"), QSize(), QIcon::Normal, QIcon::Off); - addressPasteButton->setIcon(icon4); - addressPasteButton->setAutoDefault(false); - connect(addressPasteButton, SIGNAL(clicked()), this, SLOT(pasteText())); - - addressLayout->addWidget(addressPasteButton); - - QPushButton* addressDeleteButton = new QPushButton(addressFrame); - addressDeleteButton->setObjectName(QStringLiteral("addressDeleteButton")); - QIcon icon5; - icon5.addFile(QStringLiteral(":/icons/remove"), QSize(), QIcon::Normal, QIcon::Off); - addressDeleteButton->setIcon(icon5); - addressDeleteButton->setAutoDefault(false); - connect(addressDeleteButton, SIGNAL(clicked()), this, SLOT(deleteFrame())); - - addressLayout->addWidget(addressDeleteButton); - frameLayout->addLayout(addressLayout); - - ui->addressList->addWidget(addressFrame); -} - -void MultisigDialog::on_pushButtonCoinControl_clicked() -{ - CoinControlDialog coinControlDialog(this, true); - coinControlDialog.setModel(model); - coinControlDialog.exec(); -} - -void MultisigDialog::on_addInputButton_clicked() -{ - if(isFirstRawTx){ - isFirstRawTx = false; - ui->txInputsScrollArea->show(); - } - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - - QFrame* txInputFrame = new QFrame(ui->txInputsWidget); - sizePolicy.setHeightForWidth(txInputFrame->sizePolicy().hasHeightForWidth()); - txInputFrame->setFrameShape(QFrame::StyledPanel); - txInputFrame->setFrameShadow(QFrame::Raised); - txInputFrame->setObjectName(QStringLiteral("txInputFrame")); - - QVBoxLayout* frameLayout = new QVBoxLayout(txInputFrame); - frameLayout->setSpacing(1); - frameLayout->setObjectName(QStringLiteral("txInputFrameLayout")); - frameLayout->setContentsMargins(6, 6, 6, 6); - - QHBoxLayout* txInputLayout = new QHBoxLayout(); - txInputLayout->setObjectName(QStringLiteral("txInputLayout")); - - QLabel* txInputIdLabel = new QLabel(txInputFrame); - txInputIdLabel->setObjectName(QStringLiteral("txInputIdLabel")); - txInputIdLabel->setText(QApplication::translate("MultisigDialog", strprintf("%i. Tx Hash: ", ui->inputsList->count()+1).c_str(), 0)); - txInputLayout->addWidget(txInputIdLabel); - - QLineEdit* txInputId = new QLineEdit(txInputFrame); - txInputId->setObjectName(QStringLiteral("txInputId")); - - txInputLayout->addWidget(txInputId); - - QSpacerItem* horizontalSpacer = new QSpacerItem(10, 20, QSizePolicy::Fixed, QSizePolicy::Minimum); - txInputLayout->addItem(horizontalSpacer); - - QLabel* txInputVoutLabel = new QLabel(txInputFrame); - txInputVoutLabel->setObjectName(QStringLiteral("txInputVoutLabel")); - txInputVoutLabel->setText(QApplication::translate("MultisigDialog", "Vout Position: ", 0)); - - txInputLayout->addWidget(txInputVoutLabel); - - QSpinBox* txInputVout = new QSpinBox(txInputFrame); - txInputVout->setObjectName("txInputVout"); - sizePolicy.setHeightForWidth(txInputVout->sizePolicy().hasHeightForWidth()); - txInputVout->setSizePolicy(sizePolicy); - txInputLayout->addWidget(txInputVout); - - QPushButton* inputDeleteButton = new QPushButton(txInputFrame); - inputDeleteButton->setObjectName(QStringLiteral("inputDeleteButton")); - QIcon icon; - icon.addFile(QStringLiteral(":/icons/remove"), QSize(), QIcon::Normal, QIcon::Off); - inputDeleteButton->setIcon(icon); - inputDeleteButton->setAutoDefault(false); - connect(inputDeleteButton, SIGNAL(clicked()), this, SLOT(deleteFrame())); - txInputLayout->addWidget(inputDeleteButton); - - frameLayout->addLayout(txInputLayout); - - ui->inputsList->addWidget(txInputFrame); -} - -void MultisigDialog::on_addDestinationButton_clicked() -{ - QFrame* destinationFrame = new QFrame(ui->destinationsScrollAreaContents); - destinationFrame->setObjectName(QStringLiteral("destinationFrame")); - destinationFrame->setFrameShape(QFrame::StyledPanel); - destinationFrame->setFrameShadow(QFrame::Raised); - - QVBoxLayout* frameLayout = new QVBoxLayout(destinationFrame); - frameLayout->setObjectName(QStringLiteral("destinationFrameLayout")); - QHBoxLayout* destinationLayout = new QHBoxLayout(); - destinationLayout->setSpacing(0); - destinationLayout->setObjectName(QStringLiteral("destinationLayout")); - QLabel* destinationAddressLabel = new QLabel(destinationFrame); - destinationAddressLabel->setObjectName(QStringLiteral("destinationAddressLabel")); - - destinationLayout->addWidget(destinationAddressLabel); - - QValidatedLineEdit* destinationAddress = new QValidatedLineEdit(destinationFrame); - destinationAddress->setObjectName(QStringLiteral("destinationAddress")); - - destinationLayout->addWidget(destinationAddress); - - QSpacerItem* horizontalSpacer = new QSpacerItem(10, 20, QSizePolicy::Fixed, QSizePolicy::Minimum); - destinationLayout->addItem(horizontalSpacer); - - QLabel* destinationAmountLabel = new QLabel(destinationFrame); - destinationAmountLabel->setObjectName(QStringLiteral("destinationAmountLabel")); - - destinationLayout->addWidget(destinationAmountLabel); - - BitcoinAmountField* destinationAmount = new BitcoinAmountField(destinationFrame); - destinationAmount->setObjectName(QStringLiteral("destinationAmount")); - - destinationAddressLabel->setText(QApplication::translate("MultisigDialog", strprintf("%i. Address: ", ui->destinationsList->count()+1).c_str(), 0)); - destinationAmountLabel->setText(QApplication::translate("MultisigDialog", "Amount: ", 0)); - - destinationLayout->addWidget(destinationAmount); - - QPushButton* destinationDeleteButton = new QPushButton(destinationFrame); - destinationDeleteButton->setObjectName(QStringLiteral("destinationDeleteButton")); - QIcon icon; - icon.addFile(QStringLiteral(":/icons/remove"), QSize(), QIcon::Normal, QIcon::Off); - destinationDeleteButton->setIcon(icon); - destinationDeleteButton->setAutoDefault(false); - connect(destinationDeleteButton, SIGNAL(clicked()), this, SLOT(deleteFrame())); - destinationLayout->addWidget(destinationDeleteButton); - - frameLayout->addLayout(destinationLayout); - - ui->destinationsList->addWidget(destinationFrame); -} - -void MultisigDialog::on_addPrivKeyButton_clicked() -{ - if(isFirstPrivKey){//on first click the scroll area must show - isFirstPrivKey = false; - ui->keyScrollArea->show(); - } - - if(ui->keyList->count() > 14){ - ui->signButtonStatus->setStyleSheet("QTextEdit{ color: red }"); - ui->signButtonStatus->setText(tr("Maximum (15)")); - return; - } - - QFrame* keyFrame = new QFrame(ui->keyScrollAreaContents); - - keyFrame->setObjectName(QStringLiteral("keyFrame")); - keyFrame->setFrameShape(QFrame::StyledPanel); - keyFrame->setFrameShadow(QFrame::Raised); - - QHBoxLayout* keyLayout = new QHBoxLayout(keyFrame); - keyLayout->setObjectName(QStringLiteral("keyLayout")); - - QLabel* keyLabel = new QLabel(keyFrame); - keyLabel->setObjectName(QStringLiteral("keyLabel")); - keyLabel->setText(QApplication::translate("MultisigDialog", strprintf("Key %i: ", (ui->keyList->count()+1)).c_str(), 0)); - keyLayout->addWidget(keyLabel); - - QLineEdit* key = new QLineEdit(keyFrame); - key->setObjectName(QStringLiteral("key")); - key->setEchoMode(QLineEdit::Password); - keyLayout->addWidget(key); - - QPushButton* keyDeleteButton = new QPushButton(keyFrame); - keyDeleteButton->setObjectName(QStringLiteral("keyDeleteButton")); - QIcon icon; - icon.addFile(QStringLiteral(":/icons/remove"), QSize(), QIcon::Normal, QIcon::Off); - keyDeleteButton->setIcon(icon); - keyDeleteButton->setAutoDefault(false); - connect(keyDeleteButton, SIGNAL(clicked()), this, SLOT(deleteFrame())); - keyLayout->addWidget(keyDeleteButton); - - ui->keyList->addWidget(keyFrame); -} - diff --git a/src/qt/multisigdialog.h b/src/qt/multisigdialog.h deleted file mode 100644 index 12a6cb39b4..0000000000 --- a/src/qt/multisigdialog.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_QT_MULTISIGDIALOG_H -#define BITCOIN_QT_MULTISIGDIALOG_H - -#include -#include -#include -#include -#include "script/script.h" -#include "primitives/transaction.h" -#include "coins.h" -#include "coincontrol.h" -#include "walletmodel.h" -#include "coincontroldialog.h" - -namespace Ui -{ -class MultisigDialog; -} - -class MultisigDialog : public QDialog -{ - Q_OBJECT - -public: - explicit MultisigDialog(QWidget* parent); - ~MultisigDialog(); - void setModel(WalletModel* model); - void updateCoinControl(CAmount nAmount, unsigned int nQuantity); - -public Q_SLOTS: - void showTab(int index); - -private: - Ui::MultisigDialog* ui; - WalletModel* model; - CCoinControl* coinControl; - bool isFirstPrivKey; - bool isFirstRawTx; - CMutableTransaction multisigTx; - - QFrame* createAddress(int labelNumber); - QFrame* createInput(int labelNumber); - CCoinsViewCache getInputsCoinsViewCache(const std::vector& vin); - QString buildMultisigTxStatusString(bool fComplete, const CMutableTransaction& tx); - bool createRedeemScript(int m, std::vector keys, CScript& redeemRet, std::string& errorRet); - bool createMultisigTransaction(std::vector vUserIn, std::vector vUserOut, string& feeStringRet, string& errorRet); - bool signMultisigTx(CMutableTransaction& txToSign, std::string& errorMessageRet, QVBoxLayout* keyList = nullptr); - bool addMultisig(int m, std::vector keys); - bool isFullyVerified(CMutableTransaction& txToVerify); - -private Q_SLOTS: - void deleteFrame(); - void pasteText(); - void commitMultisigTx(); - void addressBookButtonReceiving(); - void on_addAddressButton_clicked(); - void on_addMultisigButton_clicked(); - void on_addDestinationButton_clicked(); - void on_createButton_clicked(); - void on_addInputButton_clicked(); - void on_addPrivKeyButton_clicked(); - void on_signButton_clicked(); - void on_pushButtonCoinControl_clicked(); - void on_importAddressButton_clicked(); -}; - -#endif // BITCOIN_QT_MULTISIGDIALOG_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 4dc1ad480d..b276ae952e 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -154,14 +154,6 @@ void WalletFrame::gotoMultiSendDialog() walletView->gotoMultiSendDialog(); } -void WalletFrame::gotoMultisigDialog(int index) -{ - WalletView* walletView = currentWalletView(); - if(walletView){ - walletView->gotoMultisigDialog(index); - } -} - void WalletFrame::encryptWallet(bool status) { WalletView* walletView = currentWalletView(); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index aa7ca841ea..6e0f2febf8 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -61,8 +61,6 @@ public Q_SLOTS: void gotoBlockExplorerPage(); /** Show MultiSend Dialog **/ void gotoMultiSendDialog(); - /** show a multisig tab **/ - void gotoMultisigDialog(int index); /** Encrypt the wallet */ void encryptWallet(bool status); /** Backup the wallet */ diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 5c78b1000c..958df8f3ca 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -13,7 +13,6 @@ #include "historypage.h" #include "masternodeconfig.h" #include "multisenddialog.h" -#include "multisigdialog.h" #include "optionsmodel.h" #include "overviewpage.h" #include "optionspage.h" @@ -234,13 +233,6 @@ void WalletView::gotoMultiSendDialog() multiSendDialog->show(); } -void WalletView::gotoMultisigDialog(int index) -{ - MultisigDialog* multisig = new MultisigDialog(this); - multisig->setModel(walletModel); - multisig->showTab(index); -} - void WalletView::showSyncStatus(bool fShow) { overviewPage->showBlockSync(fShow); diff --git a/src/qt/walletview.h b/src/qt/walletview.h index f8b8be94d4..cb92a7585c 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -92,8 +92,6 @@ public Q_SLOTS: void gotoSendCoinsPage(QString addr = ""); /** Show MultiSend Dialog */ void gotoMultiSendDialog(); - /** Show a multisig tab **/ - void gotoMultisigDialog(int index); /** Show incoming transaction notification for new transactions. From 8f3369c962996d1071bb18379fe5cd74087b6000 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 20 May 2020 13:23:53 -0400 Subject: [PATCH 0362/1888] Restore fValid assertion --- src/key.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/key.cpp b/src/key.cpp index d3d0e7eceb..8adb383725 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -79,7 +79,7 @@ CPrivKey CKey::GetPrivKey() const CPubKey CKey::GetPubKey() const { - //assert(fValid); + assert(fValid); CPubKey result; int clen = 65; int ret = secp256k1_ec_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed); From 2193ace1296464dd041dc2f963f098ca1ec912e0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 21 May 2020 17:10:14 -0400 Subject: [PATCH 0363/1888] Add testnet seed --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 82c315d7ce..ffc288c5b1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -383,7 +383,7 @@ class CTestNetParams : public CMainParams vFixedSeeds.clear(); vSeeds.clear(); // nodes with support for servicebits filtering should be at the top - vSeeds.push_back(CDNSSeedData("192.168.2.202", "192.168.2.202")); + vSeeds.push_back(CDNSSeedData("testnet.dapscoin-seeds.com", "testnet.dapscoin-seeds.com")); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 139); // Testnet dapscoin addresses start with 'x' or 'y' base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 19); // Testnet dapscoin script addresses start with '8' or '9' From 41b2f10421caad54f13f8cdb2a9ff9e642212a9f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 21 May 2020 21:43:01 -0400 Subject: [PATCH 0364/1888] Update for testnet --- src/chainparams.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ffc288c5b1..416ef371ed 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -345,10 +345,10 @@ class CTestNetParams : public CMainParams nBlockEnforceInvalidUTXO = 9902850; //Start enforcing the invalid UTXO's //! Modify the testnet genesis block so the timestamp is valid for a later start. - genesis.nTime = 1569319143; - genesis.nNonce = 14995439; + genesis.nTime = 1590109816; + genesis.nNonce = 16517940; - if(genesis.GetHash()!=uint256("0000061003c91526e4ecb49305e5bc8f5e880e7542ca4d4b3b1057688aa9aba4")) + if(genesis.GetHash()!=uint256("00000bbcb4a383121aba2a64bc37241b91ea0be6c7584e869d3ca1c05b03a793")) { printf("Searchingforgenesisblock...\n"); uint256 hashTarget=uint256().SetCompact(genesis.nBits); @@ -378,7 +378,7 @@ class CTestNetParams : public CMainParams } hashGenesisBlock = genesis.GetHash(); - assert(hashGenesisBlock == uint256("0000061003c91526e4ecb49305e5bc8f5e880e7542ca4d4b3b1057688aa9aba4")); + assert(hashGenesisBlock == uint256("00000bbcb4a383121aba2a64bc37241b91ea0be6c7584e869d3ca1c05b03a793")); vFixedSeeds.clear(); vSeeds.clear(); From 51a9e3e2c8ef27da8685e208e2d2e03c1e9aadd0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 26 May 2020 22:16:13 -0400 Subject: [PATCH 0365/1888] Bump version to v1.0.6.6 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a8ac27a03c..2003958359 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 5) +define(_CLIENT_VERSION_BUILD, 6) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From 59feba41869174a81e5720b3ff8209a14a17799c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 25 May 2020 21:35:00 -0400 Subject: [PATCH 0366/1888] Fix to CheckBlock to prevent crash Co-Authored-By: akirapham --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 7136d1b6a3..5eb492d43b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4193,7 +4193,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // but issue an initial reject message. // The case also exists that the sending peer could not have enough data to see // that this block is invalid, so don't issue an outright ban. - if (nHeight != 0 && !IsInitialBlockDownload()) { + if (block.IsProofOfStake() && nHeight != 0 && !IsInitialBlockDownload()) { if (!IsBlockPayeeValid(block, nHeight)) { mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); return state.DoS(0, error("CheckBlock() : Couldn't find masternode/budget payment"), From 2c8334e9258845c8b36befc8be90abeeb2eb0dce Mon Sep 17 00:00:00 2001 From: akira Date: Wed, 27 May 2020 14:59:19 +0700 Subject: [PATCH 0367/1888] speedup generator point generation to speedup starting up wallet --- src/main.cpp | 2 +- .../include/secp256k1_bulletproofs.h | 2 + .../src/modules/bulletproofs/main_impl.h | 355 ++++++++++++++++++ 3 files changed, 358 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 321d4aa9fd..38d3278831 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -342,7 +342,7 @@ secp256k1_scratch_space2* GetScratch() secp256k1_bulletproof_generators* GetGenerator() { static secp256k1_bulletproof_generators* generator; - if (!generator) generator = secp256k1_bulletproof_generators_create(GetContext(), &secp256k1_generator_const_g, 64 * 1024); + if (!generator) generator = secp256k1_bulletproof_generators_create_with_pregenerated(GetContext()); return generator; } diff --git a/src/secp256k1-mw/include/secp256k1_bulletproofs.h b/src/secp256k1-mw/include/secp256k1_bulletproofs.h index acff053e15..4a505245da 100644 --- a/src/secp256k1-mw/include/secp256k1_bulletproofs.h +++ b/src/secp256k1-mw/include/secp256k1_bulletproofs.h @@ -42,6 +42,8 @@ SECP256K1_API secp256k1_bulletproof_generators *secp256k1_bulletproof_generators size_t n ) SECP256K1_ARG_NONNULL(1); +SECP256K1_API secp256k1_bulletproof_generators *secp256k1_bulletproof_generators_create_with_pregenerated(const secp256k1_context2 *ctx) SECP256K1_ARG_NONNULL(1); + /** Destroys a list of NUMS generators, freeing allocated memory * Args: ctx: pointer to a context object (cannot be NULL) * gen: pointer to the generator set to be destroyed diff --git a/src/secp256k1-mw/src/modules/bulletproofs/main_impl.h b/src/secp256k1-mw/src/modules/bulletproofs/main_impl.h index 1141c3ce85..2d3067bf76 100644 --- a/src/secp256k1-mw/src/modules/bulletproofs/main_impl.h +++ b/src/secp256k1-mw/src/modules/bulletproofs/main_impl.h @@ -69,6 +69,361 @@ struct secp256k1_bulletproof_generators { #include "modules/bulletproofs/rangeproof_impl.h" #include "modules/bulletproofs/util.h" +secp256k1_bulletproof_generators *secp256k1_bulletproof_generators_create_with_pregenerated(const secp256k1_context2 *ctx) +{ + secp256k1_generator secp256k1_generator_pregenerateds[] = { + {0xB3, 0x4D, 0x5F, 0xA6, 0xB8, 0xF3, 0xD1, 0x38, 0x49, 0xCE, 0x51, 0x91, 0xB7, 0xF6, 0x76, 0x18, 0xFE, 0x5B, 0xD1, 0x2A, 0x88, 0xB2, 0x0E, 0xAC, 0x33, 0x89, 0x45, 0x66, 0x7F, 0xB3, 0x30, 0x56, 0x45, 0x76, 0x4C, 0x51, 0x27, 0xBA, 0xDE, 0xE8, 0xBE, 0x74, 0xC8, 0x8F, 0x9B, 0x55, 0xFC, 0xDD, 0x46, 0x69, 0x47, 0x21, 0x7F, 0x99, 0x85, 0xA8, 0x9E, 0x33, 0xD4, 0x92, 0xD3, 0x31, 0x02, 0x6E}, + {0x62, 0x86, 0x15, 0x16, 0x92, 0x42, 0x10, 0x9E, 0x9E, 0x64, 0xD4, 0xCB, 0x28, 0x81, 0x60, 0x9C, 0x24, 0xB9, 0x89, 0x51, 0x2A, 0xD9, 0x01, 0xAE, 0xFF, 0x75, 0x64, 0x9C, 0x37, 0x5D, 0xBD, 0x79, 0xA2, 0xA4, 0xAB, 0x84, 0xFC, 0x9F, 0xC5, 0x17, 0x2A, 0x9D, 0x8B, 0xD6, 0x8D, 0x1F, 0x01, 0x30, 0x4D, 0x01, 0x93, 0xBF, 0xC1, 0xF4, 0xF1, 0x01, 0xF6, 0x50, 0xDC, 0xC6, 0x74, 0x60, 0xE6, 0x10}, + {0xED, 0xE0, 0x6E, 0x07, 0x5E, 0x79, 0xD0, 0xF7, 0x7B, 0x03, 0x3E, 0xB9, 0xA9, 0x21, 0xA4, 0x5B, 0x99, 0xF3, 0x9B, 0xEE, 0xFE, 0xA0, 0x37, 0xA2, 0x1F, 0xE9, 0xD7, 0x4F, 0x95, 0x8B, 0x10, 0xE2, 0xB6, 0xBC, 0xA1, 0x87, 0xE8, 0x38, 0xBA, 0xD2, 0x78, 0x3B, 0xB9, 0x77, 0xC1, 0xEB, 0x18, 0x44, 0x63, 0xB1, 0x4A, 0x5C, 0xAB, 0x7A, 0x58, 0x8D, 0xC4, 0x5A, 0xBE, 0x4D, 0x98, 0xBA, 0x40, 0xE4}, + {0xC6, 0xEA, 0xFD, 0xCD, 0xBE, 0x7E, 0x16, 0xD9, 0x50, 0x1A, 0x09, 0x16, 0x66, 0xBA, 0xCD, 0x5E, 0x18, 0x40, 0x88, 0x87, 0x14, 0x7F, 0x17, 0x67, 0x89, 0xAA, 0x73, 0xBC, 0xC0, 0x1D, 0x2D, 0x8F, 0xCA, 0x71, 0xB6, 0x4B, 0x56, 0x42, 0xA3, 0xD8, 0x94, 0xC9, 0xA0, 0x50, 0x1E, 0x49, 0x8A, 0xA9, 0xF3, 0x93, 0x78, 0x2C, 0x90, 0xF4, 0x24, 0xB8, 0x29, 0x9C, 0x9E, 0xBA, 0xF9, 0x67, 0x71, 0xE1}, + {0x02, 0x1A, 0xC0, 0x16, 0xD4, 0xEE, 0x11, 0x5F, 0xDA, 0x3C, 0x91, 0xE4, 0x12, 0x3D, 0x55, 0xCE, 0xDA, 0xCB, 0xA7, 0xF6, 0x21, 0x0E, 0xF2, 0xFD, 0x76, 0x92, 0x3A, 0x3C, 0x86, 0x8C, 0x23, 0x3A, 0x9B, 0x4C, 0xC0, 0x56, 0xEB, 0x96, 0x5A, 0xDF, 0xE5, 0x0D, 0x0B, 0xCE, 0x78, 0xD5, 0x90, 0x57, 0xAC, 0x5C, 0x43, 0x5B, 0x36, 0x4E, 0x35, 0x48, 0x35, 0x12, 0xA1, 0x28, 0x1E, 0x03, 0x97, 0xA2}, + {0xB8, 0xB8, 0x0D, 0xE3, 0x6A, 0xDC, 0xB4, 0x13, 0x1F, 0x3F, 0x46, 0x41, 0x21, 0x0B, 0x5A, 0x07, 0x22, 0xE9, 0x4C, 0xF4, 0x6E, 0x29, 0x40, 0x5C, 0xDC, 0x80, 0x5A, 0x40, 0xF9, 0x36, 0x64, 0x0D, 0x46, 0x0A, 0x05, 0xA5, 0xBD, 0x30, 0x9D, 0x13, 0xE7, 0x8F, 0x3A, 0x44, 0x9B, 0xE4, 0x6E, 0x2C, 0xE8, 0x38, 0xA1, 0x8F, 0xC8, 0xB0, 0xFA, 0x5E, 0xA4, 0x67, 0x71, 0x5D, 0x69, 0xB5, 0x31, 0x4A}, + {0x46, 0x6F, 0xEA, 0xB8, 0x3D, 0x73, 0xF9, 0x87, 0x8F, 0x34, 0x6F, 0xCC, 0x77, 0x19, 0x6F, 0xF6, 0x44, 0xA5, 0xA0, 0x17, 0xBD, 0x14, 0x3B, 0xCC, 0x5F, 0xE3, 0xE4, 0x33, 0xBA, 0x36, 0x04, 0x0C, 0xCF, 0xC6, 0x78, 0x5C, 0xC6, 0x0C, 0xA4, 0x30, 0x85, 0x0E, 0x71, 0x45, 0xD1, 0xCB, 0xDE, 0xEF, 0x33, 0xC0, 0x82, 0xB4, 0x26, 0x29, 0x13, 0x0F, 0x95, 0xF9, 0x25, 0x7D, 0xA7, 0x3F, 0x0C, 0xE9}, + {0x26, 0xD9, 0x05, 0xD0, 0x03, 0x19, 0x81, 0x59, 0x40, 0xC7, 0x6C, 0x60, 0x7F, 0xF0, 0x42, 0x79, 0x3A, 0x45, 0xF0, 0x19, 0xF6, 0x92, 0xBE, 0xAC, 0xCB, 0xC2, 0xAF, 0x3F, 0x17, 0x58, 0x31, 0x96, 0xDA, 0xA7, 0x86, 0x2F, 0x51, 0x60, 0xB5, 0xF0, 0xDE, 0x96, 0x80, 0x9D, 0xBF, 0x82, 0xAF, 0x6A, 0x9E, 0x89, 0x04, 0xCC, 0x69, 0x64, 0xBD, 0x41, 0x3F, 0x51, 0x96, 0x88, 0x5B, 0x5E, 0x12, 0x6A}, + {0x46, 0x50, 0xEE, 0x17, 0xF6, 0x0D, 0x02, 0x7E, 0xA1, 0x60, 0x48, 0xB0, 0xA2, 0x61, 0x8D, 0x45, 0x8B, 0x2C, 0xA4, 0xC9, 0x88, 0x5E, 0x62, 0x5E, 0x74, 0xA2, 0xA0, 0x8E, 0x68, 0x66, 0xC4, 0x87, 0x8D, 0x67, 0xB6, 0x00, 0x5A, 0xC6, 0x12, 0x8D, 0x12, 0xCE, 0xE5, 0x8B, 0xC6, 0x9F, 0xF6, 0x56, 0x40, 0xF7, 0xEC, 0x8F, 0xFE, 0x54, 0xFC, 0xDD, 0xD7, 0x08, 0x39, 0xE7, 0x90, 0xCD, 0xD3, 0x3C}, + {0x09, 0x14, 0x7C, 0x3D, 0xDA, 0x51, 0xDA, 0xFE, 0x93, 0xE5, 0xB3, 0x65, 0xCD, 0xBB, 0xD1, 0x00, 0x34, 0xC8, 0x4C, 0x73, 0x72, 0x38, 0x93, 0xE1, 0xF8, 0x77, 0x6F, 0x88, 0x53, 0x96, 0xB9, 0xCB, 0xB7, 0xDC, 0x6B, 0x22, 0x13, 0xD4, 0x32, 0xE0, 0x34, 0xC6, 0xE0, 0xA0, 0x98, 0x52, 0x67, 0x4E, 0x57, 0xC4, 0xCB, 0x06, 0x86, 0xF0, 0x76, 0xC8, 0xE5, 0x97, 0x68, 0x3B, 0x4E, 0x7E, 0xD2, 0x49}, + {0x96, 0xDE, 0x73, 0xB7, 0x29, 0xFA, 0x9F, 0xE9, 0x00, 0x6B, 0x15, 0xA8, 0x20, 0x13, 0xC0, 0x5D, 0x5D, 0x63, 0xA2, 0xCA, 0xE8, 0x21, 0x20, 0x28, 0x3A, 0x11, 0x68, 0xDA, 0x35, 0xF1, 0x1C, 0xBF, 0x53, 0x25, 0x03, 0x25, 0x26, 0xEA, 0x40, 0x1B, 0x5F, 0xCF, 0xC9, 0xE7, 0xA0, 0x9C, 0x68, 0x75, 0xB1, 0xD0, 0x6E, 0x18, 0x4D, 0xC2, 0xC2, 0xD7, 0xE6, 0xA6, 0x41, 0x7B, 0x99, 0xAF, 0xF7, 0x1B}, + {0x92, 0xA4, 0xA5, 0xFD, 0xC9, 0x22, 0xF5, 0xD8, 0x95, 0x20, 0x14, 0x62, 0xCC, 0x76, 0x5D, 0xA9, 0x9E, 0x99, 0x5A, 0x88, 0x80, 0xA8, 0x82, 0x71, 0xA8, 0xA4, 0xCB, 0xD6, 0x1D, 0xB5, 0x4B, 0x8B, 0xAB, 0x0D, 0x11, 0x8F, 0x13, 0x67, 0xB8, 0xB5, 0xE9, 0x65, 0x95, 0x7B, 0xE3, 0xA2, 0x64, 0x79, 0xC3, 0x53, 0xF2, 0xD7, 0xD5, 0x93, 0x6C, 0x59, 0xDB, 0x8B, 0xEF, 0xE7, 0x41, 0xB5, 0xF1, 0x44}, + {0xEA, 0x9D, 0x7F, 0x54, 0x6A, 0x9B, 0x7B, 0x8D, 0xE0, 0xAB, 0x20, 0xDB, 0x6E, 0xCA, 0x57, 0x04, 0xDE, 0x7B, 0x14, 0x6E, 0xA5, 0x3B, 0xFB, 0xE1, 0x2A, 0xBA, 0x3E, 0x0A, 0x97, 0x19, 0x26, 0x79, 0x95, 0x24, 0x80, 0xB8, 0x7C, 0x2C, 0x86, 0x01, 0x6A, 0xD6, 0xCC, 0xBA, 0x69, 0x40, 0xA9, 0xFC, 0x76, 0xC1, 0x80, 0xF3, 0x3E, 0xAC, 0x74, 0x89, 0x88, 0x5C, 0x73, 0xA4, 0x79, 0x38, 0xD5, 0x66}, + {0xC3, 0x86, 0xA3, 0x47, 0xBA, 0x86, 0x48, 0xCA, 0xEA, 0x2A, 0x0E, 0x2C, 0xD5, 0x7D, 0x5B, 0x82, 0x25, 0x30, 0x95, 0xDF, 0x5B, 0xB7, 0x87, 0x5A, 0xB4, 0x89, 0x54, 0xF1, 0xC3, 0xAF, 0x20, 0xDA, 0x52, 0x80, 0x3F, 0x32, 0x2E, 0x4A, 0x9C, 0x38, 0xFA, 0x21, 0x5A, 0x1B, 0x71, 0x63, 0xF2, 0xF6, 0x7C, 0x41, 0xE1, 0x97, 0xE9, 0x9B, 0x54, 0x0F, 0xF2, 0xC1, 0x6D, 0x2F, 0x06, 0xB7, 0x00, 0x61}, + {0xFC, 0x2E, 0xF9, 0x18, 0x3B, 0xDE, 0x7F, 0x86, 0x67, 0xB6, 0xF7, 0x15, 0x13, 0x40, 0x11, 0xDC, 0x16, 0x38, 0xB6, 0x9A, 0x08, 0x67, 0x0C, 0x56, 0x8E, 0x7B, 0x7B, 0x3A, 0x84, 0x44, 0xFD, 0x2B, 0x92, 0x99, 0xF6, 0xDD, 0x2F, 0x37, 0xF0, 0x60, 0x48, 0xFE, 0x7A, 0x41, 0xA5, 0x92, 0x55, 0x48, 0x7B, 0x5F, 0x95, 0x90, 0xEA, 0x16, 0x09, 0x44, 0x8A, 0x24, 0xBF, 0x2F, 0xCE, 0x00, 0xBA, 0xFD}, + {0x62, 0xEB, 0x70, 0x55, 0x64, 0x41, 0x32, 0xAD, 0xBB, 0x51, 0x41, 0x3D, 0x06, 0xC3, 0xD9, 0xEE, 0x8A, 0xFB, 0x67, 0xD9, 0x29, 0x05, 0x71, 0xC8, 0x78, 0x54, 0xC5, 0x8E, 0x1A, 0xEF, 0x6A, 0xB0, 0x06, 0xE4, 0x8A, 0xAB, 0xFC, 0xAE, 0xBA, 0xD7, 0xB5, 0x44, 0x18, 0x9F, 0xBE, 0x38, 0x56, 0x15, 0x27, 0xE5, 0x3C, 0x60, 0xCE, 0xDD, 0x72, 0xF9, 0xF1, 0x37, 0xD3, 0x19, 0xAA, 0x45, 0x13, 0xCA}, + {0xE5, 0x44, 0xD5, 0xA4, 0x90, 0x93, 0xB1, 0xB1, 0xB3, 0x9C, 0xFE, 0xD5, 0xF2, 0xED, 0x3B, 0x05, 0x4F, 0x79, 0x46, 0x70, 0xF8, 0xA3, 0x9C, 0xFC, 0xCE, 0x10, 0x3A, 0x62, 0xAB, 0xB7, 0x10, 0x26, 0xAE, 0x0D, 0xF6, 0x75, 0xB9, 0xAE, 0x44, 0x7B, 0x02, 0x9D, 0x75, 0xB9, 0x5A, 0x8D, 0x23, 0xEE, 0xEC, 0x89, 0x57, 0x87, 0x2E, 0x25, 0xF8, 0xE1, 0x51, 0x6B, 0x5B, 0x06, 0x07, 0x50, 0xC9, 0x83}, + {0x1E, 0x95, 0xA0, 0x8B, 0x43, 0xF9, 0x35, 0xA1, 0x74, 0x3F, 0x43, 0xD2, 0xCC, 0x9F, 0x7F, 0x41, 0xBF, 0x6E, 0xCB, 0xA7, 0x08, 0x84, 0x0B, 0xF1, 0x40, 0xD1, 0x57, 0x8E, 0x0C, 0xE1, 0x44, 0x4E, 0x42, 0xA9, 0x80, 0x45, 0x36, 0x4E, 0xAF, 0x18, 0x38, 0x5E, 0x8E, 0x54, 0x8F, 0x12, 0xEF, 0xE8, 0x37, 0x69, 0x15, 0x4D, 0x19, 0xA6, 0xF7, 0x0E, 0xFC, 0x41, 0x05, 0xB6, 0xC7, 0x6D, 0xF9, 0x52}, + {0x75, 0x36, 0x54, 0x10, 0x86, 0x26, 0x40, 0x25, 0x9D, 0x5D, 0x08, 0x19, 0x9E, 0x90, 0x16, 0xAD, 0xAD, 0x69, 0x0E, 0x38, 0x18, 0x61, 0xB2, 0x88, 0x9D, 0x5C, 0x68, 0xB3, 0x30, 0x3C, 0x96, 0x4B, 0x1E, 0xA2, 0xEC, 0x53, 0xBA, 0x8C, 0xDA, 0x05, 0xB9, 0xF5, 0x01, 0x28, 0xC0, 0xB4, 0x88, 0xB5, 0xC8, 0x7C, 0x8F, 0xF5, 0x1E, 0x71, 0xC5, 0xB4, 0x75, 0x8B, 0x86, 0xBF, 0x60, 0x53, 0xA7, 0x1F}, + {0xCE, 0x34, 0xAC, 0x56, 0x01, 0x37, 0x44, 0xF3, 0xB1, 0x83, 0xB2, 0xE1, 0x2C, 0x8C, 0xB2, 0x06, 0x01, 0x69, 0xFE, 0xA1, 0xD9, 0x3B, 0x37, 0xB9, 0x0E, 0xC9, 0x9B, 0x52, 0xDB, 0xD7, 0x65, 0xE7, 0xD3, 0xD4, 0x0D, 0xBB, 0x49, 0x3F, 0x95, 0xD5, 0xC4, 0x0C, 0x3D, 0x05, 0xE7, 0x8D, 0xE3, 0x91, 0x78, 0x79, 0x51, 0xDF, 0x5A, 0x4F, 0x44, 0x87, 0x46, 0xB3, 0x51, 0x5E, 0x1B, 0x19, 0x60, 0x08}, + {0xFE, 0xE8, 0x1D, 0xB7, 0x5A, 0x10, 0x36, 0x02, 0xB7, 0x07, 0x51, 0xE0, 0xBF, 0xF7, 0xFA, 0x58, 0xBA, 0x16, 0xD9, 0x83, 0xFB, 0x45, 0x45, 0xEC, 0xD6, 0x3A, 0x8D, 0xF8, 0x92, 0x16, 0x54, 0x5D, 0xF6, 0xB0, 0xE7, 0xEE, 0x11, 0xFC, 0xB3, 0x75, 0x7F, 0x8E, 0xC5, 0x9F, 0x7C, 0x10, 0x4C, 0x24, 0xB4, 0x1C, 0x6E, 0xB7, 0x99, 0x40, 0x73, 0x29, 0x1F, 0x76, 0xA9, 0xE3, 0xB9, 0xCC, 0xFF, 0x21}, + {0x77, 0x4D, 0x87, 0x10, 0xCC, 0xD5, 0x27, 0x73, 0xF2, 0xE4, 0x57, 0x7A, 0xAB, 0x1A, 0x32, 0xBE, 0x2C, 0x86, 0x21, 0xD8, 0xFD, 0xD8, 0x59, 0x44, 0xAD, 0xA1, 0xDD, 0x80, 0xB4, 0x82, 0xC9, 0x72, 0xCB, 0x70, 0x91, 0x0F, 0x24, 0x5C, 0x7A, 0x0B, 0xC7, 0xCB, 0xF8, 0x89, 0xA8, 0xFC, 0xE6, 0xAF, 0x3E, 0x3B, 0x31, 0x3C, 0xA7, 0x49, 0xC6, 0x0A, 0xAB, 0xD3, 0x19, 0x5D, 0x25, 0x26, 0xD1, 0x9C}, + {0xD8, 0x83, 0x1D, 0x17, 0x31, 0x4D, 0x67, 0xF9, 0x91, 0xD2, 0x37, 0xE8, 0x33, 0x78, 0x19, 0x9D, 0x9F, 0x04, 0x01, 0xA4, 0x45, 0xC7, 0xB1, 0x33, 0x89, 0xC4, 0x31, 0x01, 0x93, 0xAB, 0x5F, 0xA9, 0x98, 0xE8, 0xC7, 0x9F, 0x8A, 0x91, 0x84, 0x8D, 0x85, 0xDE, 0x2D, 0xFE, 0x05, 0xD0, 0x4A, 0xEB, 0x5A, 0x51, 0x94, 0x40, 0x64, 0x2D, 0xFC, 0x74, 0x33, 0xCE, 0x51, 0x20, 0x53, 0xAD, 0xA7, 0xF2}, + {0x68, 0xA1, 0x0F, 0xA1, 0x47, 0x72, 0x46, 0x24, 0x8D, 0x01, 0x00, 0x53, 0x6B, 0x11, 0xE3, 0xD1, 0xAB, 0xCF, 0xB9, 0x03, 0x6E, 0x8F, 0xC7, 0xED, 0x5A, 0xAC, 0x74, 0xF5, 0x6D, 0x06, 0xA6, 0xC9, 0xFD, 0x34, 0x75, 0xB5, 0x09, 0xBF, 0xBC, 0x20, 0x1B, 0xF9, 0x51, 0x6F, 0xDF, 0xB8, 0x9B, 0x84, 0x19, 0xE0, 0x58, 0x4F, 0xD0, 0xB6, 0x45, 0xFF, 0x31, 0xF1, 0x1E, 0xC4, 0xC8, 0xDF, 0xDB, 0x6C}, + {0x36, 0x24, 0x77, 0xCA, 0x7F, 0x3B, 0x4D, 0x01, 0x22, 0x70, 0xF9, 0x4F, 0x6D, 0x7A, 0xEE, 0x04, 0x20, 0x68, 0xF5, 0x80, 0x22, 0xCD, 0xD0, 0x4A, 0x06, 0xC5, 0x4C, 0x65, 0x4B, 0x9C, 0x9A, 0x53, 0xEA, 0x3E, 0xD8, 0xC4, 0xD3, 0x10, 0x9C, 0xDE, 0xAC, 0xEC, 0xB3, 0x0F, 0x09, 0xDA, 0xA3, 0xD8, 0xED, 0x3C, 0x4C, 0x2D, 0x59, 0xBB, 0x1D, 0xEB, 0x30, 0x2B, 0xC2, 0x07, 0x31, 0xBE, 0xE9, 0x06}, + {0xA7, 0xD7, 0x90, 0x06, 0x2C, 0xF5, 0xF6, 0x03, 0x4A, 0xD7, 0x21, 0x53, 0xBF, 0xC0, 0x8B, 0x47, 0x99, 0xA4, 0xCD, 0x19, 0x76, 0xE1, 0xEA, 0xE9, 0xA8, 0x1E, 0x5D, 0x98, 0x61, 0xD4, 0xB5, 0x93, 0xEA, 0xFB, 0x30, 0xCD, 0xF2, 0x99, 0x3F, 0xD6, 0xB7, 0x8A, 0xC4, 0x58, 0xF6, 0x88, 0xE1, 0xBE, 0xCD, 0xC3, 0x9E, 0xAE, 0xD3, 0xAE, 0x0D, 0x99, 0x7C, 0x42, 0xCB, 0x23, 0xF2, 0x15, 0x1B, 0x17}, + {0x10, 0xEA, 0xF9, 0x7C, 0xBE, 0xA8, 0x2F, 0x7C, 0x00, 0x79, 0x1B, 0xAE, 0x4B, 0xB1, 0xEB, 0xFF, 0xD6, 0xFA, 0xB5, 0xD4, 0xE3, 0x98, 0x4A, 0xC4, 0x0C, 0xB9, 0xCB, 0xFB, 0xE4, 0x14, 0xF8, 0xE8, 0x8E, 0x3E, 0x59, 0xF3, 0xEC, 0xBF, 0xD3, 0x55, 0xC4, 0x50, 0x1A, 0x9F, 0x4C, 0x68, 0xE8, 0xFE, 0xCD, 0x98, 0x8F, 0xDC, 0xD4, 0x07, 0x5F, 0x80, 0xD0, 0xE9, 0x4C, 0xFD, 0xD0, 0x88, 0x81, 0xC4}, + {0x0D, 0x65, 0x83, 0x1F, 0x33, 0x04, 0x04, 0x5F, 0x1D, 0x49, 0x93, 0xD6, 0xF7, 0xB6, 0x78, 0xD6, 0xF4, 0xDD, 0x48, 0xB6, 0x68, 0x2A, 0x3A, 0x7D, 0xAE, 0xA6, 0x62, 0xFB, 0xD9, 0x17, 0x22, 0x81, 0xA2, 0xFF, 0x31, 0xC7, 0x2A, 0x3C, 0x88, 0xA7, 0x48, 0x54, 0x31, 0xB8, 0x65, 0x11, 0x3E, 0x66, 0x55, 0x45, 0x01, 0x28, 0xD8, 0xA6, 0x25, 0xB1, 0xC2, 0xEF, 0x46, 0x28, 0x60, 0x1D, 0xA0, 0xC3}, + {0x41, 0x1D, 0x6F, 0xB2, 0x90, 0xFF, 0xED, 0x92, 0xA4, 0xA9, 0x10, 0xBA, 0x5F, 0x7D, 0x36, 0xD7, 0x51, 0xE0, 0x0A, 0x42, 0x4B, 0x8F, 0x3F, 0x1C, 0x9C, 0xE3, 0xBE, 0xF6, 0xF0, 0x3F, 0xCB, 0x84, 0x77, 0xE4, 0xE2, 0xEB, 0xAE, 0xC8, 0x97, 0xD5, 0x82, 0x56, 0xD1, 0xC9, 0x83, 0x8A, 0xFF, 0xFF, 0xEE, 0xF9, 0x5B, 0x65, 0x12, 0xB4, 0x35, 0x64, 0x24, 0x1D, 0x95, 0x09, 0x0C, 0xE2, 0x67, 0x93}, + {0xD6, 0x15, 0x47, 0x54, 0x83, 0x0F, 0x31, 0x09, 0xE1, 0xC4, 0xF9, 0x51, 0xEB, 0x00, 0xC0, 0x22, 0x3E, 0xE1, 0x25, 0xF8, 0xA2, 0x85, 0xD8, 0x70, 0x16, 0xB8, 0x7D, 0xFD, 0xFD, 0x9E, 0x16, 0xBC, 0x94, 0x64, 0x72, 0x98, 0x11, 0xF0, 0x33, 0x81, 0x3B, 0x36, 0xD3, 0x27, 0xD1, 0xC1, 0xFF, 0xB2, 0x81, 0x7A, 0x8B, 0xCB, 0xA4, 0x79, 0x9D, 0x36, 0x94, 0xE0, 0xB4, 0x01, 0x31, 0x18, 0x11, 0xF2}, + {0x22, 0x8C, 0xA6, 0x13, 0x4B, 0x34, 0x95, 0x03, 0x13, 0xC1, 0xC0, 0x4D, 0x9D, 0x3C, 0xFC, 0x97, 0xD3, 0xE9, 0x01, 0x89, 0x81, 0x51, 0x89, 0xBE, 0x01, 0x51, 0x8D, 0xD3, 0xF9, 0x50, 0x80, 0xA8, 0x2D, 0xEC, 0x15, 0x74, 0x14, 0x9F, 0x2E, 0xB1, 0xA0, 0x0D, 0x1C, 0xDC, 0x40, 0xF9, 0xE7, 0x77, 0xC8, 0x6E, 0xB3, 0x9E, 0xAF, 0x2E, 0x3B, 0x8A, 0x4A, 0x12, 0x65, 0xEB, 0xC2, 0x67, 0x90, 0x46}, + {0x85, 0xF5, 0x7A, 0x5E, 0xE9, 0xF9, 0xAA, 0xCF, 0x5A, 0x20, 0x50, 0x8F, 0x6D, 0xC4, 0x93, 0x31, 0x4C, 0xFC, 0xC2, 0x97, 0xFB, 0xD6, 0x0F, 0xE7, 0xEF, 0x7B, 0x2F, 0x2E, 0x2E, 0xE6, 0x5B, 0xA4, 0x23, 0x8E, 0x86, 0x90, 0x01, 0xB8, 0x50, 0x3C, 0x91, 0x64, 0x5F, 0xDC, 0x64, 0xFF, 0x06, 0x9C, 0x92, 0xA4, 0x62, 0x91, 0x81, 0x26, 0xC1, 0xE3, 0x8A, 0xF6, 0x4E, 0x65, 0x30, 0xBB, 0xF4, 0xAD}, + {0xEF, 0x31, 0xE3, 0x74, 0x99, 0xA0, 0x03, 0xC1, 0x72, 0x3E, 0x14, 0x34, 0xF3, 0x9C, 0xDE, 0xCF, 0xD7, 0x26, 0x8D, 0xBE, 0x69, 0x32, 0x90, 0x41, 0xD5, 0x5A, 0x79, 0xA0, 0x3A, 0xBA, 0x0A, 0x11, 0xE8, 0x70, 0xE5, 0x5B, 0xC3, 0x57, 0xC9, 0x83, 0x4C, 0x14, 0x37, 0x7D, 0x11, 0x53, 0xCE, 0xDE, 0x81, 0xFC, 0x6F, 0x9A, 0xB6, 0xD0, 0x93, 0x9C, 0x0E, 0xFA, 0x7A, 0x36, 0xD0, 0x31, 0xF9, 0xA0}, + {0x51, 0xFC, 0x14, 0x3E, 0x9E, 0xA7, 0x1B, 0x27, 0x6F, 0x11, 0x47, 0xDA, 0x89, 0xF8, 0x04, 0xCD, 0x66, 0x70, 0x7F, 0x49, 0xFD, 0x69, 0xD9, 0xEC, 0xB4, 0xAA, 0x9C, 0xAE, 0x1B, 0xF3, 0xF0, 0x62, 0x0E, 0x1D, 0x36, 0xB3, 0x05, 0x37, 0xA3, 0xE6, 0x9F, 0x31, 0xF9, 0x66, 0x26, 0xE5, 0xF6, 0x19, 0xF1, 0xE0, 0xC5, 0x83, 0x3F, 0xA8, 0x9A, 0x11, 0xF9, 0xF6, 0x0F, 0x7C, 0x61, 0xFC, 0x46, 0x76}, + {0x8B, 0x46, 0x9A, 0x83, 0xBF, 0x19, 0xEA, 0xEC, 0x60, 0x86, 0xD2, 0x46, 0x4D, 0xEB, 0x89, 0xD3, 0x3D, 0xDD, 0x3C, 0xB9, 0x04, 0xF0, 0xFD, 0x2F, 0x50, 0x83, 0xBC, 0x61, 0x25, 0x99, 0x41, 0x09, 0x86, 0x84, 0x7A, 0x3D, 0x4F, 0x1B, 0xCE, 0xD1, 0xD7, 0x14, 0x8B, 0xE7, 0x45, 0xB8, 0xB2, 0x97, 0x14, 0x89, 0x91, 0x91, 0xEA, 0x7D, 0x8E, 0x7E, 0xF2, 0xAE, 0x4C, 0x2E, 0xF0, 0xF4, 0x4A, 0x96}, + {0x77, 0x20, 0xA7, 0xEC, 0x47, 0x9E, 0xD3, 0x73, 0xAD, 0xFE, 0x04, 0xBA, 0x47, 0x0D, 0x9D, 0x99, 0xFF, 0xA4, 0x8F, 0x24, 0x55, 0xD9, 0xE6, 0x1E, 0xBA, 0xDA, 0x84, 0x4D, 0x5F, 0xBC, 0xBF, 0x58, 0xCE, 0x2C, 0x51, 0x85, 0xBC, 0x82, 0x44, 0xE7, 0x90, 0xE8, 0xDC, 0x0A, 0xBB, 0xA4, 0xDE, 0xB5, 0xAC, 0x93, 0x32, 0x59, 0x9C, 0xAB, 0xAA, 0x0F, 0xBA, 0xE6, 0x7C, 0x55, 0xDF, 0x70, 0x32, 0x0C}, + {0xA7, 0x8D, 0xEA, 0x8C, 0xAD, 0xDB, 0x41, 0x65, 0xAF, 0x5E, 0x80, 0xD7, 0x04, 0x2D, 0x22, 0x2E, 0xEB, 0x1C, 0x67, 0x19, 0xDB, 0xC4, 0x25, 0x9C, 0xDB, 0xB3, 0x82, 0xB1, 0xF9, 0xEF, 0x84, 0x04, 0xAE, 0x1E, 0xEA, 0x56, 0xA6, 0x8E, 0x75, 0x37, 0xDB, 0xFC, 0xDE, 0x3D, 0x64, 0x21, 0xCF, 0x49, 0xD6, 0x8E, 0x8D, 0x60, 0x85, 0x24, 0xC3, 0x33, 0x02, 0x43, 0x50, 0x60, 0xAF, 0x57, 0x37, 0x85}, + {0x1F, 0x94, 0x10, 0xE2, 0x50, 0x35, 0x77, 0x1B, 0x10, 0x9B, 0xAF, 0x7D, 0x1D, 0x38, 0x32, 0x8B, 0xC5, 0x82, 0xA0, 0xA1, 0x5D, 0x28, 0x2A, 0xA1, 0x60, 0xF3, 0x8C, 0x1C, 0x41, 0x43, 0x5C, 0x76, 0x6A, 0xF3, 0xB0, 0xE4, 0x16, 0x70, 0x68, 0xFF, 0xC2, 0x15, 0x27, 0x7D, 0x42, 0x3B, 0xD7, 0xF4, 0x6A, 0x8F, 0xD1, 0xE5, 0x1B, 0x6D, 0xA0, 0xC4, 0xB2, 0xCA, 0x15, 0x90, 0x0F, 0x19, 0x0F, 0x97}, + {0xEC, 0xFD, 0xBF, 0x1E, 0x7E, 0x7F, 0x42, 0xC1, 0x35, 0x03, 0xE3, 0x65, 0xC9, 0x5E, 0xAC, 0x5C, 0x7D, 0x86, 0x7C, 0x91, 0x54, 0x6C, 0xF0, 0xAB, 0xAA, 0x8C, 0x1F, 0x8E, 0xA2, 0x21, 0xCF, 0x05, 0x2B, 0xE3, 0xA8, 0x4D, 0xF1, 0x37, 0x00, 0xC7, 0xBF, 0xD5, 0x2C, 0xB2, 0x91, 0x90, 0x3C, 0x84, 0xA2, 0x6E, 0xC9, 0x58, 0x46, 0x80, 0xA2, 0x45, 0x41, 0xE4, 0xB3, 0xCA, 0xC3, 0xAF, 0x31, 0xE6}, + {0x33, 0xD9, 0x13, 0x56, 0x2B, 0xF1, 0x82, 0x55, 0x49, 0xF7, 0xFD, 0x67, 0x1E, 0x90, 0x3F, 0x11, 0x05, 0xE0, 0x8B, 0x83, 0x53, 0x39, 0x9C, 0xE8, 0xFB, 0x02, 0x93, 0xA0, 0xEF, 0x0A, 0x94, 0x2D, 0x06, 0x03, 0xF1, 0xF7, 0x81, 0xD1, 0x4E, 0x9A, 0x47, 0x2B, 0xAE, 0x94, 0xE0, 0x2C, 0xB4, 0xD7, 0xD9, 0x11, 0x59, 0xF7, 0x33, 0xF0, 0x62, 0x5C, 0xBA, 0x4E, 0x79, 0xCB, 0x68, 0xC2, 0x40, 0xFA}, + {0x2D, 0x78, 0xE0, 0xA9, 0x20, 0x78, 0x97, 0xB7, 0x35, 0x2C, 0xC3, 0xD9, 0x23, 0x89, 0xD8, 0x54, 0xD2, 0x1D, 0x97, 0x83, 0x67, 0x16, 0x9D, 0x9A, 0x9B, 0xE2, 0x61, 0x38, 0xF7, 0xBF, 0x4B, 0xC9, 0x51, 0x75, 0xF2, 0x17, 0x8E, 0xC6, 0xAA, 0xE0, 0x66, 0x0A, 0xDB, 0x1E, 0xE4, 0x27, 0xCD, 0xFE, 0x4A, 0xB5, 0x4C, 0x04, 0xAD, 0x33, 0xE3, 0xB7, 0xB2, 0x03, 0xFD, 0x89, 0x2D, 0x64, 0xA8, 0xDD}, + {0x99, 0xC8, 0x87, 0xC2, 0xF3, 0x6C, 0x93, 0xAC, 0xA7, 0x04, 0xE0, 0x87, 0x41, 0x73, 0x0D, 0x5A, 0x23, 0x5C, 0x84, 0xC8, 0xBC, 0x6C, 0x84, 0xF9, 0xD5, 0xE0, 0x2C, 0x09, 0x91, 0xF0, 0x73, 0xB2, 0x0A, 0xDC, 0xFC, 0xBD, 0x94, 0x01, 0x97, 0x84, 0x73, 0xC7, 0x0C, 0x32, 0x17, 0x18, 0x09, 0x42, 0x6A, 0xF6, 0xFB, 0xB7, 0xBE, 0x82, 0x4E, 0xB6, 0xEE, 0x3B, 0x94, 0x99, 0xE7, 0xBA, 0xE5, 0x8C}, + {0x6D, 0x95, 0xDF, 0x67, 0xC7, 0xBD, 0x45, 0xB9, 0xB7, 0xB4, 0x66, 0x73, 0xF9, 0x53, 0x2B, 0xC3, 0xD1, 0xEC, 0x70, 0x8D, 0xD4, 0x8B, 0x33, 0x6B, 0xEF, 0x85, 0xAC, 0xE0, 0x53, 0x09, 0x34, 0x3C, 0x14, 0xA8, 0x3C, 0xFC, 0x48, 0x7F, 0x24, 0x0F, 0xA4, 0x3E, 0x2D, 0x85, 0x97, 0x4E, 0xA5, 0x34, 0xCF, 0x2A, 0x8D, 0x49, 0xA5, 0x4C, 0xB9, 0x21, 0x88, 0x68, 0xA8, 0x51, 0x82, 0xF8, 0xF3, 0x76}, + {0xD7, 0xDE, 0x5A, 0x06, 0x22, 0x57, 0x7F, 0x92, 0x89, 0x00, 0xBB, 0x4D, 0x0F, 0x9D, 0xCD, 0xC9, 0xA1, 0x54, 0x92, 0x81, 0x6B, 0x15, 0x69, 0xD6, 0x46, 0xEF, 0x90, 0xE7, 0x02, 0xCC, 0xC8, 0x8A, 0x20, 0xF1, 0x26, 0x1C, 0x97, 0x3B, 0x4D, 0x3B, 0xF8, 0x31, 0x9D, 0xF4, 0xD4, 0xF3, 0x62, 0x2D, 0x5E, 0x57, 0xB9, 0x5D, 0xA9, 0x0E, 0xF7, 0xA5, 0x06, 0x69, 0x90, 0x49, 0x46, 0x58, 0x17, 0x9C}, + {0xE6, 0x76, 0xB6, 0xF9, 0xA3, 0xE9, 0xD4, 0x7A, 0xB2, 0xA5, 0x58, 0x05, 0x48, 0x41, 0x5E, 0x48, 0xEA, 0x17, 0x0F, 0xDE, 0xA0, 0xC9, 0x75, 0xCE, 0xBD, 0x46, 0x5F, 0xAC, 0xF1, 0x99, 0xA4, 0xE2, 0x3A, 0x07, 0x4E, 0xEB, 0xD1, 0x01, 0x15, 0xEE, 0x39, 0x28, 0x88, 0x30, 0x72, 0x55, 0xDC, 0xAB, 0xFF, 0x11, 0x63, 0x31, 0x31, 0xB8, 0xA1, 0x9C, 0xA1, 0xD1, 0x09, 0x3E, 0x69, 0xE6, 0x8C, 0x79}, + {0xFF, 0x20, 0x69, 0x78, 0xB0, 0xB9, 0xFA, 0x8F, 0x39, 0xC3, 0x5A, 0xD2, 0xC6, 0x17, 0x83, 0x41, 0x89, 0xAF, 0xBB, 0x45, 0x6C, 0x3B, 0x59, 0x64, 0x41, 0x74, 0x58, 0x11, 0x90, 0x4B, 0xDC, 0xEA, 0xF8, 0x2E, 0xA8, 0x89, 0xF2, 0x77, 0xBE, 0xCE, 0x1E, 0x83, 0x9D, 0x3E, 0x48, 0x80, 0x23, 0xF2, 0x16, 0x43, 0x1F, 0x9E, 0x9C, 0x6D, 0x0B, 0x40, 0x60, 0x83, 0xE3, 0x44, 0x79, 0x34, 0xA3, 0x45}, + {0x8B, 0x9B, 0xCD, 0x31, 0xB9, 0x73, 0xCD, 0x74, 0x87, 0x5D, 0x2E, 0x76, 0x34, 0xD9, 0x36, 0x2A, 0x65, 0x85, 0xA8, 0x9F, 0xCF, 0x14, 0x9B, 0x6B, 0x4D, 0x9E, 0xBF, 0x03, 0x60, 0x76, 0x95, 0xB4, 0xB7, 0xEF, 0x9D, 0xF0, 0x03, 0xC8, 0x7D, 0x3A, 0x6A, 0x78, 0x34, 0x0F, 0x6C, 0xC6, 0x1B, 0x0D, 0xFF, 0xD2, 0x7F, 0xE7, 0x0C, 0x5A, 0x18, 0x04, 0x03, 0xD1, 0xB0, 0x1B, 0x85, 0x7A, 0xEF, 0xA3}, + {0xE0, 0x02, 0x44, 0x37, 0xCD, 0xB5, 0xD4, 0x33, 0xBB, 0x93, 0xE3, 0x7E, 0x0E, 0xFE, 0xA6, 0xC8, 0x96, 0xD2, 0x24, 0x3D, 0xD9, 0x24, 0xAF, 0x8B, 0xD8, 0xE9, 0xEA, 0x48, 0x20, 0x00, 0xEC, 0x11, 0xAA, 0x15, 0xFB, 0x57, 0x1C, 0xCF, 0x8F, 0xB2, 0x90, 0xA3, 0x36, 0xBF, 0xDE, 0x56, 0x2E, 0x3E, 0xBE, 0x27, 0x4F, 0x2C, 0xCC, 0xDA, 0x91, 0xF0, 0xD9, 0xF4, 0x23, 0x67, 0xAA, 0xEA, 0xA9, 0x44}, + {0xAC, 0x96, 0x87, 0x6F, 0x24, 0x36, 0xE6, 0x01, 0xF3, 0xB8, 0xFE, 0x6A, 0x24, 0xE4, 0xAD, 0x64, 0x19, 0x3B, 0x0A, 0x9D, 0x83, 0x77, 0x7A, 0x1F, 0xCD, 0x8A, 0x86, 0x78, 0x22, 0xF2, 0x69, 0xA3, 0x91, 0x87, 0x10, 0xD3, 0xB8, 0x9B, 0x94, 0x73, 0x6F, 0x32, 0x0D, 0x66, 0x15, 0x92, 0x4B, 0x4A, 0x0C, 0x49, 0x75, 0x27, 0x83, 0x7C, 0xA0, 0x8B, 0xD8, 0x68, 0xFC, 0xDE, 0xFD, 0x2F, 0xFD, 0xC7}, + {0x20, 0xBD, 0x80, 0x92, 0xC5, 0x5A, 0x6B, 0xCC, 0x33, 0x63, 0xAF, 0x25, 0x20, 0x5A, 0xEF, 0x61, 0x72, 0x18, 0x1B, 0xEA, 0x9D, 0x87, 0xC5, 0x11, 0xDC, 0x47, 0xA5, 0xEB, 0xDE, 0x66, 0x7F, 0x1A, 0xF7, 0xF2, 0xDE, 0x65, 0x29, 0x81, 0xC7, 0x74, 0x45, 0x74, 0x3D, 0xAA, 0xC2, 0x3B, 0x8F, 0x69, 0x5C, 0x48, 0xA9, 0x5C, 0xE4, 0x5C, 0x58, 0x42, 0x2B, 0xAF, 0x00, 0x8E, 0x7C, 0x32, 0x91, 0x56}, + {0x8A, 0x5C, 0x18, 0x6B, 0x4F, 0xD6, 0x5C, 0xC6, 0xB2, 0xA1, 0x7A, 0x76, 0x7D, 0x7D, 0x07, 0x7E, 0x92, 0x94, 0xE8, 0x63, 0x8C, 0xFB, 0x54, 0xDE, 0x20, 0xAB, 0x08, 0x4C, 0xD7, 0x73, 0xD0, 0x94, 0x18, 0x0C, 0x4D, 0x3F, 0xAD, 0x5C, 0xC5, 0x88, 0xFC, 0x3A, 0xDB, 0x39, 0xD1, 0x4A, 0xB0, 0x1F, 0x3A, 0xD8, 0xFF, 0xDB, 0x1B, 0x1A, 0xDF, 0x1E, 0xC1, 0x94, 0x7C, 0x90, 0x0A, 0x39, 0x08, 0xCF}, + {0x56, 0xA1, 0x78, 0xB8, 0x0D, 0x00, 0x3D, 0x34, 0x24, 0x21, 0x0F, 0x39, 0x37, 0xA1, 0x67, 0x22, 0x69, 0x2D, 0x7F, 0x4E, 0x5D, 0xC1, 0xDE, 0x87, 0xD7, 0xCB, 0xF3, 0x64, 0xCC, 0x59, 0xAD, 0x72, 0xE1, 0x39, 0xA6, 0x32, 0x2C, 0x3A, 0xA3, 0x58, 0xA8, 0xF6, 0x56, 0xEA, 0xC4, 0x80, 0x1E, 0x52, 0xD6, 0x95, 0x37, 0x4C, 0xEA, 0x25, 0x56, 0xE7, 0x47, 0x7F, 0x80, 0x69, 0xD5, 0x7D, 0x26, 0xB1}, + {0x09, 0xBE, 0x36, 0x59, 0x85, 0x8B, 0x02, 0x39, 0xA5, 0xFA, 0x9C, 0x96, 0xB1, 0x98, 0x4A, 0x29, 0x7A, 0x18, 0xC8, 0x6E, 0x04, 0x89, 0x69, 0x36, 0xEB, 0x00, 0xF6, 0xC4, 0x37, 0xFB, 0xA3, 0x08, 0xE9, 0x89, 0x73, 0x6E, 0x1B, 0x6C, 0x32, 0x5B, 0xA8, 0xA3, 0x1B, 0x3E, 0xC7, 0x65, 0x13, 0x09, 0x6F, 0x6B, 0x5E, 0xD4, 0x2C, 0x4F, 0xA6, 0x27, 0x4A, 0xAF, 0xF7, 0xD9, 0x67, 0xE8, 0x77, 0xBC}, + {0x27, 0x40, 0xF4, 0x8A, 0x89, 0xCB, 0x1D, 0x15, 0x76, 0x97, 0xBC, 0xA7, 0x28, 0x23, 0x9D, 0x82, 0xCC, 0xF8, 0xB6, 0xB9, 0x4C, 0xE7, 0xC2, 0xE4, 0x5C, 0x3C, 0x31, 0xA3, 0x28, 0xAF, 0xBD, 0xFE, 0x5B, 0xE9, 0xF7, 0x5B, 0x3B, 0xBF, 0x2A, 0x10, 0xF0, 0x4E, 0x21, 0x61, 0x2B, 0xD3, 0x40, 0xEB, 0x4A, 0x1E, 0x5E, 0xBE, 0x44, 0x73, 0x06, 0xE9, 0x26, 0xCC, 0xF4, 0xA8, 0x33, 0x9E, 0x33, 0xC5}, + {0xB6, 0x44, 0x03, 0x9D, 0x77, 0xE7, 0x90, 0x5F, 0x4A, 0xDF, 0xD5, 0x6C, 0xBF, 0xF1, 0xEF, 0x8F, 0xC2, 0x5C, 0x90, 0xFA, 0x88, 0x74, 0x00, 0xEA, 0xE5, 0x5C, 0xDE, 0x96, 0x49, 0xA8, 0xF4, 0x8D, 0x70, 0xFD, 0x17, 0x11, 0xD0, 0x07, 0xCE, 0xBF, 0x3C, 0x90, 0x25, 0xC1, 0x86, 0x23, 0xC7, 0xD1, 0x78, 0xE9, 0x61, 0x5F, 0x1C, 0xAF, 0xA3, 0x86, 0x85, 0x99, 0xCE, 0x31, 0x25, 0x6C, 0x4D, 0x72}, + {0xAA, 0xE1, 0xB9, 0xDF, 0x99, 0x13, 0x99, 0xDD, 0x0A, 0xFA, 0x50, 0x02, 0xDE, 0x31, 0x70, 0xBB, 0x32, 0x56, 0x41, 0x0D, 0x06, 0x14, 0xA9, 0x88, 0x07, 0xA9, 0xF5, 0xB4, 0xA4, 0xEF, 0xB1, 0x0B, 0xB6, 0xBB, 0x5A, 0x5B, 0x84, 0xD8, 0xCA, 0xF3, 0xC4, 0x56, 0x7D, 0xB4, 0xE7, 0x46, 0x05, 0x7E, 0x88, 0xB4, 0x80, 0x59, 0xB9, 0x7D, 0x99, 0x5E, 0x76, 0x8B, 0x71, 0xD4, 0xB3, 0x55, 0xD7, 0x54}, + {0x30, 0x38, 0xA2, 0x17, 0xE8, 0xCD, 0xAB, 0x7C, 0x4F, 0xF4, 0x44, 0x8B, 0xF0, 0x00, 0xE4, 0xBD, 0x69, 0x92, 0x28, 0xA5, 0x44, 0x2B, 0x4E, 0xEE, 0x28, 0x73, 0x2A, 0x68, 0x6E, 0x6D, 0x3E, 0x85, 0xB7, 0x19, 0xFF, 0x13, 0xDB, 0x65, 0xFE, 0xB2, 0x93, 0x37, 0xF9, 0xCD, 0x35, 0x73, 0x0A, 0x6D, 0xEA, 0xA5, 0x09, 0x30, 0x8C, 0x87, 0x93, 0xDA, 0x90, 0xF0, 0xB0, 0xE4, 0x2D, 0xAF, 0x0A, 0xD3}, + {0x51, 0xD2, 0x76, 0xD5, 0x0A, 0xD9, 0x51, 0xCD, 0x90, 0xBC, 0x27, 0x48, 0x8C, 0x53, 0x1D, 0x09, 0x74, 0x99, 0x0E, 0x7D, 0x5B, 0x21, 0x20, 0xC8, 0xF7, 0xAA, 0x3B, 0xDE, 0xF9, 0xEC, 0x7D, 0x6D, 0x2D, 0x71, 0x82, 0xBA, 0x89, 0x0D, 0x9B, 0xA8, 0x83, 0x46, 0xD0, 0x33, 0x4E, 0xF6, 0x46, 0x2A, 0xDC, 0x97, 0xD0, 0x62, 0x10, 0x07, 0x8E, 0x93, 0x1B, 0x64, 0xFB, 0x8C, 0x51, 0xD7, 0x74, 0x6E}, + {0xED, 0x02, 0x1B, 0xB9, 0x61, 0xD6, 0x65, 0x44, 0xE8, 0x1F, 0x43, 0x64, 0xF3, 0xA8, 0x29, 0x01, 0xA2, 0x1E, 0x0D, 0x47, 0xDD, 0x05, 0xE8, 0x6B, 0xE6, 0x66, 0x02, 0x27, 0x54, 0x1C, 0xCE, 0xE2, 0x27, 0xF9, 0x7D, 0x1C, 0x8A, 0x28, 0x1E, 0x81, 0xCD, 0x52, 0x32, 0x1B, 0x15, 0xD0, 0x5F, 0xDA, 0x66, 0x6D, 0x5A, 0x99, 0x87, 0x0D, 0x45, 0x1F, 0x59, 0xAB, 0xAE, 0x8C, 0x7C, 0x6C, 0x12, 0x67}, + {0xDA, 0xF8, 0x26, 0x22, 0x6C, 0xE7, 0x73, 0x64, 0x5C, 0xC8, 0xF2, 0x61, 0xBD, 0x2E, 0x3F, 0x35, 0x31, 0x00, 0x26, 0xD1, 0x44, 0x63, 0xC7, 0x5F, 0x48, 0x25, 0x31, 0x45, 0xAB, 0x88, 0xDB, 0x1D, 0x80, 0x83, 0xD7, 0x4D, 0x36, 0xA2, 0x07, 0xB0, 0xFD, 0x07, 0x0C, 0x65, 0x26, 0xE2, 0x68, 0xB2, 0x5E, 0xA4, 0xDD, 0xCB, 0xEA, 0x3C, 0xD9, 0x98, 0x7B, 0x0E, 0x19, 0x4E, 0xA4, 0x7D, 0x9F, 0x6A}, + {0xA9, 0xAC, 0xB6, 0xED, 0xA3, 0x02, 0xFD, 0xD8, 0xB6, 0x09, 0x46, 0x36, 0x6A, 0x56, 0x62, 0x2C, 0xBE, 0xC0, 0xD0, 0x07, 0xFF, 0x17, 0x23, 0x9A, 0x48, 0xE9, 0x67, 0xFC, 0xB8, 0x0E, 0x0A, 0x49, 0x5B, 0x54, 0x94, 0x91, 0x94, 0x27, 0xB2, 0xF9, 0x6F, 0x04, 0x73, 0x94, 0xC9, 0xFA, 0x5D, 0x1A, 0x24, 0x4E, 0x24, 0x98, 0x2F, 0x1A, 0x0A, 0x66, 0x4D, 0xD6, 0x78, 0x48, 0x8F, 0x12, 0x2C, 0x43}, + {0x0D, 0x0B, 0x0A, 0xE9, 0x1B, 0x71, 0xB4, 0xDC, 0x0A, 0x56, 0x66, 0xB5, 0xB6, 0x00, 0x6F, 0xA3, 0x3D, 0x6A, 0x0A, 0x0F, 0x05, 0x59, 0xE1, 0xB0, 0xE0, 0xF1, 0xB3, 0x4E, 0x8D, 0xE6, 0xE3, 0xBE, 0x98, 0x32, 0x7D, 0x30, 0x0A, 0x00, 0xD6, 0x33, 0xC2, 0xFD, 0xAA, 0xD0, 0x95, 0x15, 0xF4, 0x4D, 0x29, 0xC9, 0xAD, 0x1E, 0xAC, 0xB1, 0x5F, 0x79, 0xC2, 0x78, 0x38, 0xA6, 0x02, 0xB2, 0x1A, 0x31}, + {0xC9, 0x50, 0x0F, 0x0F, 0xD7, 0x04, 0x63, 0x8E, 0xC6, 0x18, 0x49, 0xD3, 0xB2, 0x94, 0x91, 0xB1, 0xB8, 0x8E, 0x43, 0xAD, 0x30, 0x09, 0x93, 0x3D, 0xE5, 0xB8, 0x82, 0x0C, 0x7F, 0x27, 0x03, 0x2B, 0x2D, 0x72, 0x84, 0xAC, 0x44, 0xFA, 0xB7, 0xAA, 0x63, 0x03, 0x9E, 0x93, 0xE9, 0xA1, 0x15, 0x85, 0xAD, 0x57, 0x96, 0x07, 0x56, 0xF9, 0x86, 0x05, 0x86, 0xC9, 0x44, 0x33, 0x6B, 0x95, 0xF1, 0xA7}, + {0xB8, 0x02, 0x05, 0x90, 0x9A, 0x98, 0x9C, 0x87, 0x9F, 0x9C, 0xA3, 0x7E, 0x01, 0xA0, 0xE4, 0x2D, 0xEE, 0x26, 0x30, 0xDF, 0xB5, 0x84, 0x03, 0x17, 0x05, 0xDD, 0x24, 0xFB, 0x31, 0x70, 0xF7, 0x90, 0x12, 0x5C, 0x27, 0xD0, 0x38, 0x9B, 0xC2, 0x83, 0x7F, 0xD2, 0x9D, 0xC0, 0x27, 0xCE, 0xBC, 0x3D, 0x2A, 0x07, 0xC5, 0x25, 0x1A, 0xAE, 0x9C, 0x40, 0xAE, 0xC0, 0x11, 0x5A, 0x15, 0xF6, 0x6A, 0x56}, + {0xD2, 0x3F, 0xD9, 0xB9, 0xC9, 0xE0, 0x80, 0xB5, 0x91, 0xD1, 0xE7, 0x39, 0x97, 0x07, 0xEA, 0x13, 0xBB, 0x16, 0x99, 0x2A, 0x8B, 0x96, 0x83, 0xD7, 0x19, 0xB3, 0x6B, 0x56, 0xAA, 0x0A, 0xE7, 0xDD, 0x6B, 0x76, 0xE2, 0xC2, 0xD1, 0x58, 0x44, 0xB6, 0x67, 0x6F, 0x36, 0xCE, 0x47, 0x7E, 0x9C, 0xBD, 0xC8, 0x22, 0xD3, 0x3C, 0x1E, 0x79, 0xC4, 0xA4, 0xF2, 0xD8, 0xDF, 0x57, 0x53, 0xBC, 0x85, 0x91}, + {0xE9, 0xA2, 0x61, 0xDB, 0x89, 0xD1, 0x58, 0x81, 0xF3, 0x73, 0xC5, 0x31, 0x93, 0x3A, 0x3E, 0xA4, 0x01, 0x75, 0xA6, 0xBC, 0x44, 0xB5, 0x27, 0x50, 0x38, 0x9E, 0x97, 0xA1, 0xF8, 0x36, 0x3E, 0x1B, 0x31, 0x6B, 0xA2, 0x41, 0xF0, 0xC4, 0x93, 0x69, 0x14, 0xC3, 0x06, 0x1C, 0x66, 0x23, 0xE6, 0x67, 0x56, 0x93, 0x30, 0x14, 0xB9, 0xE4, 0xE7, 0x7E, 0xED, 0x21, 0x28, 0xE3, 0xB6, 0xD4, 0xE9, 0x43}, + {0xDB, 0x95, 0xF1, 0xDC, 0xC1, 0xF3, 0xE8, 0xA8, 0x1B, 0x12, 0xA1, 0x5B, 0x9D, 0xC2, 0x9C, 0xA1, 0x71, 0xD0, 0x13, 0xC0, 0x72, 0x66, 0x5A, 0x40, 0xC8, 0x4E, 0xBE, 0x93, 0xEA, 0x03, 0xA7, 0xA7, 0x1A, 0x2B, 0x68, 0x7A, 0xD4, 0x93, 0xF0, 0x70, 0xE6, 0x7B, 0xF4, 0x54, 0x5A, 0xDD, 0xF0, 0x39, 0x90, 0x6E, 0xF0, 0x72, 0xDC, 0xE9, 0xA3, 0xD4, 0x8D, 0xEF, 0x1C, 0x4D, 0x77, 0x4F, 0x4F, 0xAD}, + {0x67, 0x22, 0x60, 0x06, 0x1E, 0x44, 0x6C, 0x67, 0x64, 0x05, 0x2A, 0xDE, 0x9B, 0x87, 0xC9, 0x6A, 0xDD, 0xFF, 0x33, 0x9D, 0x76, 0x7B, 0x4C, 0x0E, 0xE1, 0xF0, 0x32, 0x22, 0x43, 0x1E, 0xC6, 0x61, 0x72, 0x8C, 0x4F, 0x13, 0xDC, 0xF3, 0xFD, 0x50, 0xB2, 0xE3, 0xE3, 0x73, 0x4F, 0x66, 0x08, 0xFC, 0x24, 0xE3, 0x65, 0xB3, 0xC0, 0x3F, 0xE7, 0x7A, 0xCF, 0x01, 0x6E, 0x5E, 0x2C, 0x42, 0xB5, 0x98}, + {0x06, 0xF5, 0x1F, 0x18, 0xC3, 0x02, 0x5B, 0x83, 0x83, 0x5C, 0xBD, 0xAD, 0x73, 0x1E, 0xFE, 0x96, 0xEA, 0xBF, 0x73, 0x90, 0x3F, 0xF8, 0xA5, 0x12, 0xA8, 0x69, 0x83, 0xDE, 0xC7, 0xB9, 0x07, 0xB3, 0x80, 0xF5, 0xBF, 0x38, 0x8F, 0x1D, 0xC5, 0xB3, 0x3F, 0x02, 0x96, 0x38, 0x53, 0x28, 0x60, 0x45, 0x89, 0x84, 0x39, 0x46, 0xE6, 0xDF, 0xC6, 0xB9, 0xCE, 0x89, 0x95, 0xC2, 0x5F, 0x36, 0x51, 0x80}, + {0x90, 0xEE, 0x6D, 0xCD, 0xD4, 0x47, 0x22, 0x49, 0xAB, 0x48, 0x5C, 0x04, 0x99, 0x0B, 0x65, 0x54, 0xE2, 0xEA, 0x3D, 0xE5, 0x9A, 0x35, 0x6E, 0xCB, 0x38, 0x9C, 0xFE, 0xB5, 0x66, 0x0D, 0xAD, 0xE1, 0xCC, 0x56, 0xCA, 0x21, 0x78, 0xF9, 0x08, 0x39, 0xA2, 0x43, 0x00, 0xD1, 0xF0, 0x20, 0xE1, 0xC2, 0x49, 0x4E, 0x97, 0x62, 0xEF, 0x5C, 0x05, 0x1D, 0x22, 0xD1, 0x50, 0x58, 0x67, 0x45, 0x71, 0x26}, + {0x69, 0xF0, 0x6D, 0x86, 0xB7, 0x52, 0x19, 0x96, 0x43, 0x02, 0xB6, 0x5A, 0x2A, 0xE5, 0xF1, 0x9E, 0x75, 0x53, 0x39, 0x79, 0x8A, 0xFE, 0xDD, 0x6A, 0xDA, 0x1E, 0x1C, 0xE0, 0x02, 0x01, 0x50, 0xF5, 0xBD, 0x0B, 0x6D, 0x62, 0x9B, 0xC4, 0x67, 0x58, 0x55, 0x70, 0xA1, 0x50, 0xC6, 0xAD, 0xF4, 0x1D, 0xBD, 0xC2, 0xD8, 0x38, 0x43, 0x74, 0x91, 0x03, 0x69, 0x3A, 0x1B, 0x1C, 0x3D, 0x47, 0x59, 0xF7}, + {0x70, 0xE6, 0xB6, 0x0A, 0x9B, 0x64, 0x38, 0x58, 0xA3, 0xA7, 0x6C, 0x78, 0xFC, 0x68, 0xC1, 0x98, 0x10, 0x55, 0x3E, 0x94, 0x15, 0x2B, 0x2A, 0x92, 0x70, 0xDA, 0x2D, 0x43, 0x4A, 0x85, 0x03, 0x56, 0x98, 0x97, 0x32, 0xA2, 0x93, 0x55, 0xCD, 0x9C, 0x33, 0x17, 0x7C, 0x33, 0xA7, 0xAA, 0x40, 0x1B, 0x05, 0xA9, 0xB8, 0xE2, 0x6C, 0xF3, 0xBF, 0xAA, 0x68, 0xF0, 0x6E, 0x4E, 0x79, 0xC1, 0x38, 0xD2}, + {0xEC, 0x21, 0x24, 0xFA, 0x10, 0x67, 0x21, 0xE1, 0x1D, 0xC0, 0x84, 0x9E, 0x1F, 0x33, 0x68, 0xA4, 0x2F, 0x4D, 0x89, 0xE5, 0x0D, 0xB5, 0x93, 0x83, 0xE5, 0x02, 0x9A, 0xF2, 0x23, 0x9A, 0x99, 0xA9, 0x55, 0x5A, 0x5B, 0xDC, 0xA7, 0xB8, 0x76, 0x7A, 0x0E, 0x56, 0x5F, 0x4F, 0x13, 0xD2, 0xBE, 0xB0, 0x97, 0xE1, 0xBF, 0x8B, 0x4C, 0x42, 0x79, 0x1E, 0xF3, 0x0B, 0xF1, 0x18, 0x06, 0x41, 0xF6, 0xAF}, + {0x58, 0xAA, 0xBD, 0x89, 0x7E, 0x19, 0xB5, 0x1A, 0x04, 0x99, 0x0B, 0xF4, 0xE9, 0xFD, 0x26, 0x8E, 0x2F, 0x48, 0x52, 0x06, 0x33, 0x34, 0xCB, 0x8C, 0x03, 0x1D, 0x61, 0xF9, 0xDC, 0xF5, 0xC7, 0x92, 0xF4, 0xDE, 0x27, 0xA5, 0x1D, 0x86, 0xA9, 0xE4, 0x0D, 0xB0, 0x83, 0xA1, 0x20, 0x19, 0xEC, 0x2F, 0x2A, 0x3D, 0x89, 0xE1, 0x23, 0x55, 0x62, 0xF7, 0x37, 0x2D, 0x5F, 0x1C, 0xBF, 0x37, 0x3F, 0xF3}, + {0xEA, 0xEF, 0xC4, 0x9A, 0x39, 0xCF, 0x89, 0x18, 0x5E, 0x22, 0x76, 0x26, 0x47, 0xC1, 0x67, 0x06, 0x67, 0x8C, 0x1E, 0x54, 0x6C, 0x5E, 0x8C, 0x53, 0x2D, 0x11, 0x1E, 0x2F, 0x1C, 0x4F, 0x29, 0xFE, 0x65, 0xFB, 0x5F, 0x52, 0xAC, 0x7B, 0xE2, 0xE8, 0xFD, 0x77, 0x1F, 0x1F, 0x17, 0xB9, 0x53, 0x78, 0xB3, 0xBA, 0x47, 0x19, 0xBB, 0x38, 0xD3, 0xFC, 0x54, 0xF9, 0x50, 0x96, 0xB0, 0x6F, 0xC7, 0x83}, + {0x3A, 0xF3, 0x72, 0x6E, 0x89, 0xAB, 0x7F, 0xFD, 0xEA, 0x23, 0xC8, 0x3E, 0x50, 0x5C, 0xB2, 0xA4, 0x12, 0x9F, 0xDC, 0xD0, 0xE1, 0x20, 0x26, 0x21, 0xCC, 0x65, 0x51, 0xC5, 0xC0, 0x11, 0x48, 0x8D, 0xB6, 0x02, 0x39, 0xC6, 0xF1, 0xA5, 0x07, 0x1A, 0x77, 0xD7, 0x63, 0x66, 0x90, 0x9A, 0x0F, 0x89, 0xEA, 0xEE, 0xB7, 0x21, 0xBA, 0x73, 0xE9, 0x2D, 0xBC, 0x03, 0x57, 0x34, 0xCD, 0x1B, 0xA7, 0xBF}, + {0x78, 0xEF, 0xA0, 0x8C, 0x29, 0xDA, 0x18, 0xEC, 0x42, 0xB4, 0x18, 0x55, 0xAE, 0xF2, 0xC2, 0x7C, 0x7C, 0xB3, 0xB9, 0xF8, 0xB0, 0xF2, 0xEF, 0xE8, 0x05, 0x36, 0xAF, 0x01, 0xE3, 0x42, 0x3C, 0x9E, 0x8B, 0xD7, 0xA4, 0x7A, 0xB0, 0x2A, 0xFD, 0xF8, 0x80, 0x99, 0x24, 0xD7, 0xB6, 0xA5, 0x58, 0x66, 0xA1, 0x71, 0xC5, 0xE2, 0xDF, 0x6E, 0x86, 0x73, 0x32, 0xCF, 0xAD, 0x9C, 0xFA, 0x88, 0x47, 0xBC}, + {0x18, 0xD9, 0x86, 0xA2, 0x49, 0xA4, 0xF8, 0x1A, 0xA8, 0x9B, 0x12, 0xEF, 0xBD, 0x22, 0xCF, 0xD7, 0xBF, 0xC4, 0x04, 0x45, 0x87, 0x36, 0xA8, 0x95, 0x8D, 0x0C, 0xF4, 0x9B, 0xD4, 0xE3, 0xCC, 0x68, 0xED, 0xE2, 0x18, 0x6D, 0x40, 0xE2, 0x3C, 0xE5, 0xF5, 0x84, 0xBE, 0x16, 0xAF, 0x6B, 0xD6, 0x86, 0xF8, 0x3C, 0x87, 0x09, 0x62, 0x76, 0x5E, 0x76, 0xE2, 0x85, 0xFE, 0x8E, 0xE8, 0xAB, 0x9F, 0xF6}, + {0x77, 0xED, 0xF2, 0x6A, 0x92, 0x2E, 0x96, 0xA1, 0xC8, 0x52, 0x8C, 0x96, 0xD8, 0x56, 0x81, 0x57, 0xEE, 0xA5, 0x87, 0x12, 0xAF, 0xC8, 0x98, 0xD1, 0x62, 0x1B, 0x96, 0xBF, 0xA8, 0x19, 0x50, 0x14, 0x55, 0x07, 0xFD, 0xA0, 0xB6, 0x49, 0x4A, 0x46, 0x52, 0x9C, 0xDD, 0x1F, 0x98, 0xF3, 0x4C, 0x8A, 0xAF, 0x29, 0x6B, 0x2F, 0xAE, 0xBB, 0x29, 0x92, 0x01, 0x91, 0xC9, 0x04, 0x48, 0x5C, 0x2A, 0xF8}, + {0x10, 0x02, 0xA9, 0xF7, 0x49, 0xB1, 0xA6, 0x0F, 0x67, 0xED, 0x6F, 0x8F, 0x08, 0xE7, 0xA1, 0xA9, 0x52, 0xD5, 0xE4, 0xC7, 0x1B, 0x35, 0xD4, 0x75, 0xAE, 0x0C, 0xB0, 0x31, 0x59, 0x62, 0x19, 0xB1, 0x2F, 0x29, 0x92, 0x72, 0xFB, 0xB0, 0xAE, 0x46, 0x8D, 0xF5, 0x13, 0xBA, 0x82, 0xBF, 0x6B, 0xBA, 0x91, 0x96, 0x1C, 0x3A, 0xA1, 0x55, 0x93, 0xC0, 0x43, 0x52, 0xE9, 0x73, 0xBE, 0x1E, 0x18, 0x03}, + {0xB2, 0xC6, 0x2A, 0xD5, 0x17, 0xE3, 0x9F, 0x41, 0xF9, 0x92, 0x44, 0x2B, 0xF0, 0xD8, 0x4B, 0x45, 0xCA, 0xBC, 0x7A, 0x1D, 0xD8, 0xCD, 0x34, 0xA8, 0x1F, 0x33, 0xAF, 0x28, 0xFF, 0x57, 0x84, 0xB5, 0xAB, 0x08, 0xE9, 0x6B, 0x5B, 0x96, 0xDE, 0x56, 0x04, 0x3F, 0xAE, 0xEA, 0x2B, 0x6F, 0x5D, 0x92, 0x08, 0x6A, 0x9C, 0xCD, 0x79, 0xA2, 0x12, 0x22, 0x39, 0x34, 0x1A, 0x30, 0x70, 0x9A, 0xDC, 0xED}, + {0x4B, 0x52, 0xFA, 0xC1, 0xC2, 0xA0, 0x84, 0x7B, 0xBD, 0xFE, 0x9B, 0x82, 0x83, 0x9C, 0x56, 0x18, 0x19, 0x8F, 0x0C, 0x56, 0x54, 0x0D, 0x74, 0x37, 0x2B, 0xCD, 0x5A, 0xEE, 0xB7, 0x90, 0xB2, 0x1C, 0x73, 0xB5, 0x3D, 0xBA, 0x5D, 0xC4, 0x13, 0x95, 0x79, 0xAA, 0xAF, 0xF8, 0x97, 0xC0, 0x36, 0x0F, 0xB7, 0xC0, 0x27, 0x6D, 0x0F, 0xEE, 0x55, 0x46, 0x36, 0x09, 0x00, 0x5E, 0xC7, 0x79, 0x15, 0xAD}, + {0x96, 0x84, 0xD7, 0x60, 0xE4, 0x2A, 0x37, 0x01, 0x46, 0xA0, 0x25, 0xBA, 0xAD, 0x15, 0xE0, 0x26, 0x48, 0x7C, 0x28, 0x94, 0x65, 0x7C, 0xA9, 0xAB, 0x6F, 0x6E, 0x28, 0xE8, 0x43, 0xC7, 0xF6, 0x65, 0x7A, 0xCE, 0x54, 0x1D, 0xC0, 0x88, 0xFE, 0xED, 0xAB, 0xA3, 0xE0, 0x66, 0xE9, 0x80, 0x2E, 0x76, 0x96, 0x17, 0xF0, 0x14, 0xAE, 0x38, 0x08, 0x7C, 0x84, 0x7D, 0xC0, 0xE8, 0x19, 0xDE, 0xB8, 0x36}, + {0x1C, 0xF3, 0x0C, 0xF1, 0x57, 0x55, 0xF2, 0x98, 0x88, 0x22, 0x07, 0x6A, 0x99, 0x84, 0x8C, 0x2C, 0x40, 0xBA, 0xE3, 0x4C, 0xAE, 0xB3, 0x0E, 0x15, 0x29, 0x06, 0x24, 0xF9, 0xCC, 0xF8, 0x04, 0x90, 0xD7, 0xF5, 0xC3, 0x87, 0x11, 0x51, 0x4F, 0x9B, 0xD9, 0x38, 0x61, 0x93, 0x69, 0xA8, 0x9E, 0xC7, 0x8C, 0xAE, 0x0A, 0x71, 0x56, 0x28, 0xFB, 0x01, 0x58, 0x09, 0xD6, 0xFC, 0x95, 0x3D, 0xFA, 0xEB}, + {0xB5, 0xDA, 0x03, 0x59, 0x61, 0xB5, 0x8F, 0xCC, 0x6C, 0x2C, 0x02, 0x0F, 0x97, 0x51, 0x4E, 0x79, 0x0D, 0x61, 0x4F, 0xB7, 0x11, 0xC0, 0x04, 0xFD, 0x0F, 0x36, 0xB4, 0x3D, 0x2C, 0x01, 0xFA, 0x78, 0x4B, 0x5E, 0x37, 0x26, 0xAA, 0x6A, 0xA8, 0x45, 0x26, 0x6A, 0xD1, 0x14, 0x07, 0x17, 0x7A, 0x17, 0x95, 0xE4, 0x62, 0xD6, 0x98, 0x01, 0x6D, 0x6B, 0x71, 0x58, 0xD9, 0x41, 0x6E, 0x4C, 0xDF, 0x92}, + {0xB8, 0x29, 0xE6, 0xE0, 0x69, 0x7A, 0x6B, 0xE2, 0x7C, 0xAD, 0x9A, 0xB3, 0x9D, 0xAA, 0xB6, 0x82, 0x72, 0x6C, 0x26, 0x56, 0x76, 0xDC, 0xC3, 0x8B, 0x7F, 0xA3, 0x35, 0x4D, 0xE1, 0x6C, 0xAB, 0x27, 0x97, 0xF5, 0x70, 0xC7, 0xB7, 0x57, 0xBF, 0x34, 0xE7, 0x20, 0xC6, 0xEC, 0xC0, 0x02, 0x74, 0x01, 0x87, 0xD9, 0x40, 0xD6, 0x0A, 0xE7, 0x25, 0xB6, 0xDB, 0x91, 0x04, 0x3C, 0xBD, 0x09, 0xDF, 0x9C}, + {0xBC, 0x85, 0x9F, 0x24, 0x96, 0x50, 0x81, 0xB6, 0xCE, 0x9E, 0xC8, 0xC5, 0x1F, 0x85, 0x25, 0x53, 0xBD, 0x37, 0xCE, 0x47, 0x57, 0x72, 0xAF, 0x08, 0x95, 0x3B, 0xA4, 0x0E, 0xEC, 0x6E, 0x95, 0xF6, 0x61, 0x90, 0xF4, 0xA6, 0x77, 0x28, 0x26, 0xAB, 0x7F, 0xAC, 0xEB, 0xEC, 0x53, 0x9E, 0x2D, 0x34, 0xD6, 0x18, 0x7C, 0x47, 0x5C, 0x94, 0xB4, 0xD6, 0x50, 0xB9, 0xDD, 0x4F, 0x62, 0x63, 0xFB, 0xF1}, + {0xE6, 0xFC, 0x5E, 0x8E, 0xD0, 0x84, 0x22, 0xD6, 0xEF, 0xC6, 0x8E, 0xDC, 0xC4, 0x3D, 0xF3, 0x06, 0x8A, 0x49, 0x93, 0x2E, 0x48, 0x5B, 0x00, 0x99, 0x7D, 0xC5, 0x7C, 0x23, 0x30, 0x5E, 0xE7, 0x22, 0xC3, 0xE2, 0xF2, 0x91, 0xF2, 0x76, 0x79, 0x57, 0xCD, 0x04, 0xAC, 0xE9, 0xB3, 0xC7, 0x79, 0xF3, 0x0D, 0xC0, 0xD7, 0xB4, 0x01, 0xAF, 0x29, 0xCF, 0xF5, 0x34, 0xCB, 0x80, 0xAB, 0x25, 0x65, 0xA5}, + {0x6E, 0x80, 0x88, 0x76, 0x97, 0x97, 0xE9, 0x8E, 0x21, 0xD6, 0x71, 0xFA, 0xD0, 0xC0, 0x97, 0x4D, 0x39, 0xCA, 0x7D, 0x49, 0x38, 0x26, 0x30, 0xBA, 0x61, 0xDD, 0x73, 0xF5, 0xAA, 0xC3, 0x0E, 0x9C, 0x3C, 0x12, 0xE9, 0x39, 0x00, 0x59, 0xB0, 0x10, 0x33, 0xC6, 0xFF, 0x8C, 0x21, 0xC4, 0x1A, 0x24, 0x72, 0xE2, 0xE7, 0x6E, 0xD8, 0x3C, 0xDE, 0x35, 0xE4, 0x2F, 0x13, 0xFC, 0xAD, 0xFB, 0x24, 0x6B}, + {0x49, 0x42, 0x32, 0xA2, 0xD6, 0xB8, 0x4D, 0x7C, 0xD4, 0x14, 0xA9, 0x86, 0x07, 0xC3, 0x88, 0x16, 0x1E, 0xD1, 0x77, 0xF7, 0xB6, 0xBF, 0x1F, 0x5F, 0x1E, 0xFF, 0xCC, 0x43, 0x37, 0xB6, 0x1A, 0xA8, 0x1B, 0xCD, 0x87, 0x12, 0xD5, 0xA0, 0x6C, 0x6D, 0x19, 0xB3, 0x77, 0x84, 0x13, 0xF6, 0xD9, 0x67, 0x24, 0x62, 0xF9, 0xC6, 0xEC, 0x72, 0x76, 0x5D, 0x89, 0x96, 0xAB, 0x0A, 0x96, 0xAC, 0x75, 0xEE}, + {0x08, 0x8D, 0x25, 0xB4, 0xB8, 0x1B, 0x24, 0x16, 0x32, 0xC0, 0x22, 0xCC, 0xCB, 0xAF, 0xB0, 0x19, 0xD5, 0x4C, 0x83, 0x54, 0x74, 0xCF, 0x35, 0x84, 0x2B, 0x0C, 0x02, 0xE2, 0x50, 0x9B, 0x3E, 0xCB, 0x5B, 0xD2, 0x21, 0x88, 0xC6, 0x86, 0xE0, 0x22, 0x84, 0x36, 0x73, 0xCC, 0x7C, 0x4B, 0x23, 0x7A, 0xD1, 0x8C, 0xE2, 0x3F, 0xF5, 0x4F, 0xA6, 0xD5, 0xDF, 0xCB, 0x74, 0x0D, 0xB9, 0x53, 0x89, 0xFB}, + {0xA6, 0x98, 0xD5, 0x56, 0x03, 0x70, 0x5D, 0xB1, 0xC9, 0x81, 0x4F, 0xCB, 0x63, 0xB5, 0x8B, 0x62, 0x85, 0x7B, 0xFC, 0xE1, 0xA5, 0xB7, 0xAB, 0x81, 0xDC, 0x00, 0x2A, 0xB8, 0xC0, 0xA2, 0xBE, 0xBC, 0x71, 0x07, 0xD2, 0x85, 0x9E, 0xEA, 0xEB, 0xC8, 0xC4, 0x32, 0x53, 0x06, 0x97, 0x75, 0xA8, 0x87, 0x47, 0x7E, 0xB5, 0x17, 0xFB, 0xA7, 0x77, 0x8A, 0xA3, 0x70, 0x89, 0x01, 0x5F, 0x50, 0x2A, 0x9C}, + {0xDD, 0x28, 0x11, 0xBA, 0x4D, 0x71, 0x44, 0xE4, 0xFB, 0x15, 0x4E, 0x4A, 0xD0, 0x14, 0x36, 0x6F, 0xE6, 0xE3, 0xDA, 0xBF, 0x18, 0x47, 0xF0, 0xC5, 0x4A, 0xDB, 0x21, 0xC3, 0x1A, 0x41, 0xF5, 0x92, 0xA3, 0x96, 0x0A, 0xAA, 0xC5, 0xF9, 0x26, 0x90, 0x8D, 0x61, 0x7F, 0x16, 0x7E, 0xDB, 0x2C, 0x65, 0x05, 0x5F, 0x75, 0xAC, 0xF8, 0x0A, 0x82, 0xE4, 0x9D, 0x8F, 0x9F, 0xE1, 0x7A, 0xF6, 0xB7, 0x22}, + {0xF4, 0xC2, 0xFE, 0x3C, 0x6F, 0x88, 0x8D, 0xC2, 0x34, 0xF9, 0x11, 0xE0, 0x04, 0xD6, 0x4A, 0xBF, 0xC2, 0x56, 0xC1, 0xD0, 0x4A, 0xB8, 0xFC, 0x9C, 0x97, 0xE2, 0x20, 0x2E, 0x72, 0x80, 0x05, 0x0A, 0x4C, 0xE5, 0x24, 0x1D, 0x18, 0x8D, 0x76, 0x5D, 0x61, 0x7F, 0x76, 0xE9, 0x8D, 0xBE, 0xE6, 0x2C, 0xCE, 0xFD, 0x87, 0x48, 0x76, 0x21, 0xE3, 0x98, 0xEC, 0xBE, 0x8D, 0xAE, 0x8B, 0x37, 0x3E, 0x4C}, + {0xC6, 0x8F, 0x84, 0x82, 0xDA, 0xCC, 0x5D, 0x1C, 0x94, 0xD7, 0x7E, 0x65, 0xF7, 0xF0, 0xAA, 0x1B, 0x15, 0x0B, 0x41, 0xB5, 0x35, 0xCF, 0xE0, 0xEA, 0x39, 0x59, 0xCF, 0xD2, 0x14, 0xE6, 0x19, 0x20, 0x43, 0x21, 0x17, 0x97, 0xB9, 0x56, 0x75, 0xB1, 0xBE, 0xA7, 0x99, 0x06, 0xE6, 0xD8, 0x15, 0x73, 0x1D, 0x36, 0x4D, 0x19, 0xA2, 0xF5, 0xE6, 0xAB, 0x45, 0x1C, 0x35, 0x5F, 0x44, 0xE7, 0xDC, 0x32}, + {0x47, 0x24, 0x94, 0xEE, 0x48, 0x4C, 0x1D, 0xE2, 0x67, 0x13, 0xE3, 0xFB, 0xE5, 0x61, 0xEA, 0x4A, 0x43, 0x86, 0x23, 0xE1, 0x94, 0xF6, 0x33, 0xC7, 0x0E, 0xB5, 0x15, 0x79, 0xE3, 0x92, 0x15, 0xE7, 0x8C, 0x51, 0x53, 0x5C, 0x2E, 0x06, 0x8F, 0xB4, 0xA8, 0x2B, 0x21, 0x62, 0x2E, 0x34, 0x2C, 0x36, 0x7C, 0xA4, 0x52, 0xF5, 0x90, 0x3D, 0xC0, 0xC8, 0x7B, 0x01, 0x74, 0x21, 0xAB, 0x3B, 0x40, 0xB8}, + {0x4C, 0x25, 0xDE, 0x3D, 0x15, 0x40, 0x79, 0xE7, 0x20, 0xAA, 0x80, 0x9A, 0x6F, 0xBC, 0xC7, 0x76, 0x5A, 0x66, 0x99, 0x2E, 0x4B, 0x47, 0x2C, 0x68, 0xE9, 0xEE, 0x53, 0x35, 0x40, 0x90, 0x1D, 0x22, 0x66, 0x93, 0x45, 0x9A, 0x9C, 0x8F, 0x95, 0x83, 0x8D, 0x72, 0x8A, 0x16, 0x15, 0x6F, 0x27, 0x6F, 0x1F, 0x39, 0x1E, 0x5E, 0x6F, 0x51, 0x87, 0x53, 0x5A, 0xEF, 0x57, 0x5A, 0x0B, 0x79, 0xAF, 0xC9}, + {0x42, 0x51, 0x2E, 0x31, 0x30, 0x3B, 0x62, 0x2A, 0xC2, 0xC3, 0x29, 0x2B, 0xB9, 0x14, 0x59, 0x04, 0x78, 0x9F, 0x83, 0x46, 0x35, 0xCD, 0xF6, 0xB2, 0x7F, 0x9C, 0x90, 0x85, 0xBA, 0x98, 0xC6, 0x7E, 0x10, 0x7B, 0x02, 0x96, 0x3F, 0xEE, 0x97, 0xA4, 0xDE, 0x29, 0x0D, 0xDC, 0x6B, 0xFF, 0xDF, 0x4A, 0x6A, 0x0C, 0x96, 0xEA, 0xCB, 0xE2, 0x8A, 0x7C, 0x8A, 0x72, 0x30, 0x99, 0x0C, 0x25, 0xAF, 0x85}, + {0x2E, 0x01, 0x02, 0xBA, 0xF9, 0x01, 0x07, 0x80, 0xC3, 0xC9, 0xEF, 0xAF, 0x31, 0xA1, 0x06, 0xA7, 0x7B, 0xA4, 0xC2, 0x7B, 0x22, 0x05, 0x17, 0x4E, 0x63, 0x16, 0x00, 0xAB, 0x3F, 0x23, 0xA4, 0x18, 0x13, 0x1D, 0x16, 0x62, 0xEB, 0xA8, 0x93, 0xC1, 0x43, 0x7C, 0x84, 0xEF, 0x42, 0x0B, 0x56, 0xBA, 0x06, 0x69, 0xA3, 0x9B, 0xAA, 0x37, 0x79, 0x99, 0xA8, 0x69, 0x68, 0xAE, 0x91, 0x5F, 0xB0, 0x96}, + {0xD2, 0x67, 0xDA, 0xBD, 0xDF, 0xC5, 0x91, 0xA5, 0x8D, 0xF2, 0x96, 0xC4, 0x9B, 0x04, 0xD8, 0xF9, 0x35, 0x54, 0x5A, 0x2A, 0xCB, 0x98, 0x3F, 0x52, 0x4F, 0x00, 0xC3, 0x76, 0x93, 0x5C, 0x1B, 0xCE, 0x40, 0xF8, 0x24, 0xC6, 0xEF, 0x5E, 0x40, 0x48, 0x62, 0x24, 0x46, 0xA9, 0x1A, 0xB2, 0x47, 0x1B, 0xFB, 0x93, 0x18, 0x4A, 0xAE, 0x30, 0x89, 0x4D, 0xCA, 0x85, 0xFA, 0x61, 0xAF, 0x47, 0x23, 0x95}, + {0x96, 0x6E, 0x47, 0x3F, 0xB9, 0xEB, 0x34, 0x93, 0xCD, 0x16, 0xAC, 0xB4, 0x0D, 0x46, 0x2F, 0xCF, 0x68, 0xFB, 0xFF, 0xDF, 0xAE, 0xCB, 0xCB, 0x23, 0xFC, 0x19, 0xED, 0x39, 0xA5, 0x73, 0xA0, 0x90, 0x1F, 0x6E, 0x57, 0xBC, 0x58, 0x9D, 0x98, 0x48, 0xD2, 0x0F, 0xAA, 0x31, 0x05, 0xD0, 0xBC, 0xE5, 0x41, 0x3B, 0x9F, 0xB0, 0xAC, 0xAE, 0xAA, 0x98, 0xD1, 0x2F, 0xAE, 0x85, 0xB0, 0x5C, 0x1E, 0x05}, + {0xB9, 0xEC, 0x5D, 0x92, 0x1F, 0xA4, 0x38, 0x81, 0xC1, 0xA8, 0x52, 0x21, 0x7E, 0x5F, 0x81, 0x4E, 0xD1, 0x76, 0x1A, 0x2C, 0x02, 0xC6, 0xC2, 0x77, 0x28, 0x57, 0x97, 0x9A, 0x4F, 0x30, 0xA1, 0x58, 0x9F, 0x6E, 0x1C, 0x23, 0x22, 0xFB, 0x3F, 0x28, 0x21, 0x74, 0x88, 0xFB, 0xBB, 0x50, 0xD1, 0xD0, 0x6E, 0x3E, 0x90, 0x62, 0x64, 0x67, 0x8B, 0x59, 0xDD, 0xF0, 0x14, 0x9E, 0x74, 0x34, 0xD0, 0x7B}, + {0xB3, 0x23, 0x75, 0xB5, 0xD0, 0xD2, 0x18, 0xB2, 0x36, 0x62, 0x1E, 0x3C, 0xC8, 0x7C, 0x35, 0x72, 0xC0, 0x94, 0xCA, 0xD2, 0x48, 0x3A, 0xC8, 0x5E, 0x93, 0xD4, 0xEC, 0x13, 0xF2, 0xDC, 0x51, 0xBF, 0x4B, 0x5F, 0xD8, 0x7E, 0xA0, 0xB4, 0x22, 0x69, 0x7E, 0x1F, 0xCC, 0xE9, 0xC1, 0xBD, 0xF5, 0xBB, 0xC1, 0x2D, 0x17, 0x2D, 0x80, 0x45, 0xD4, 0x31, 0x0F, 0xB5, 0x21, 0xBB, 0xBE, 0x02, 0x81, 0x4D}, + {0x00, 0x06, 0x8C, 0x3D, 0x87, 0xB2, 0xDD, 0x30, 0x5B, 0xD2, 0xD3, 0x83, 0x82, 0x94, 0x48, 0x3C, 0x50, 0x53, 0x2F, 0xAB, 0x1C, 0x86, 0x1F, 0x4B, 0x66, 0x87, 0x23, 0x06, 0xE3, 0xA0, 0xDE, 0xBD, 0xFE, 0x56, 0xE7, 0x38, 0x87, 0x30, 0xE5, 0x52, 0x9A, 0xC1, 0xA8, 0x16, 0xEA, 0x1D, 0x54, 0x38, 0xC7, 0x59, 0x32, 0x06, 0xD4, 0xBE, 0xB3, 0x73, 0x23, 0x9C, 0x25, 0x16, 0xA2, 0x13, 0xEF, 0x90}, + {0xF4, 0x38, 0x88, 0xC5, 0x0C, 0xE3, 0x64, 0x5C, 0x6F, 0xB4, 0xA3, 0xA2, 0x5C, 0x31, 0x27, 0x84, 0xDF, 0x42, 0x6C, 0x0A, 0x37, 0x43, 0xC9, 0x63, 0xAA, 0x92, 0xED, 0xCE, 0x82, 0x6B, 0x83, 0x9A, 0xCB, 0xC5, 0x03, 0xD9, 0x57, 0x53, 0xD6, 0x30, 0xFB, 0x9A, 0x93, 0x23, 0xB2, 0x4B, 0x99, 0x97, 0xBB, 0x9B, 0x7C, 0x02, 0xB0, 0x4F, 0xA8, 0x47, 0xCA, 0x87, 0xC0, 0x6F, 0x81, 0x29, 0x19, 0xEF}, + {0x27, 0x60, 0x20, 0x31, 0x01, 0x92, 0x69, 0x44, 0x64, 0xFD, 0x1B, 0x02, 0x89, 0x59, 0xF3, 0x82, 0x44, 0xB0, 0xB1, 0x24, 0xD8, 0x42, 0xF2, 0xD3, 0xDB, 0xA1, 0x6C, 0xA8, 0xA1, 0x30, 0x96, 0x42, 0x89, 0xD4, 0x8B, 0xC1, 0x5D, 0x43, 0xBB, 0x8C, 0x1D, 0x92, 0xCA, 0x04, 0x4A, 0x75, 0x4B, 0xE2, 0xEF, 0xFC, 0x5D, 0xDE, 0x2E, 0x80, 0xB0, 0x92, 0x1A, 0x61, 0x57, 0x0E, 0x5C, 0x93, 0xC0, 0xD3}, + {0x1D, 0x2F, 0x4D, 0xD1, 0x88, 0x90, 0xAF, 0x6D, 0x67, 0x22, 0xCA, 0xFB, 0x4C, 0x78, 0xB8, 0xB7, 0xAC, 0x99, 0x39, 0x4E, 0x45, 0x53, 0x81, 0xAD, 0x8B, 0xBE, 0x5A, 0xC2, 0x6C, 0x5F, 0xDE, 0x96, 0x36, 0x38, 0x25, 0xF8, 0xA6, 0x2E, 0x20, 0x9A, 0x89, 0xF8, 0x30, 0xD7, 0xDA, 0xD6, 0xA3, 0x72, 0xC1, 0x00, 0x41, 0xCE, 0xA1, 0x32, 0xCC, 0x77, 0xCE, 0xA6, 0xE6, 0x70, 0x34, 0x97, 0x34, 0x51}, + {0x24, 0xEA, 0xDC, 0x43, 0x47, 0x4D, 0x99, 0x4C, 0x61, 0x2C, 0x32, 0xFC, 0x27, 0xE5, 0x82, 0x23, 0x81, 0x5E, 0xE7, 0x95, 0x3E, 0x99, 0x8B, 0x62, 0x1C, 0x60, 0x9D, 0x1A, 0xD4, 0x67, 0x26, 0x56, 0x06, 0xC2, 0x59, 0x79, 0xA0, 0x09, 0xF4, 0xBB, 0x5E, 0x8B, 0x71, 0x58, 0x94, 0x73, 0x1E, 0x0F, 0xFE, 0x1C, 0xA8, 0x69, 0x07, 0x24, 0xD8, 0xC2, 0xAB, 0x3E, 0xF8, 0xC7, 0x62, 0xD3, 0x04, 0xA5}, + {0x53, 0x9E, 0x53, 0x47, 0x71, 0x26, 0xDA, 0x3E, 0x6C, 0x2D, 0xC4, 0x07, 0x95, 0x1B, 0xB0, 0x18, 0x95, 0xE6, 0xA1, 0xB0, 0xA0, 0xBB, 0x31, 0x22, 0xC4, 0x57, 0x7D, 0x0A, 0xCB, 0x0E, 0xFB, 0xB5, 0x53, 0xCB, 0xAD, 0x0D, 0xD4, 0x05, 0x7E, 0xA3, 0x3A, 0x58, 0x94, 0x65, 0xB5, 0xC1, 0x08, 0x97, 0xE3, 0xDC, 0xA1, 0x0A, 0x0C, 0x91, 0x74, 0x0F, 0x80, 0x75, 0xE2, 0x8B, 0x41, 0xA1, 0xB7, 0xBA}, + {0x47, 0x3F, 0x28, 0x75, 0x5F, 0x1A, 0xB6, 0x56, 0xDE, 0xED, 0x11, 0xF3, 0x01, 0xC2, 0x4B, 0xFC, 0x92, 0x94, 0x0E, 0x41, 0xB7, 0x91, 0x7F, 0xE5, 0x95, 0x98, 0xB7, 0x04, 0xD7, 0x50, 0xB2, 0xF1, 0x5E, 0x26, 0x9F, 0xF1, 0xB1, 0x0C, 0x9E, 0x50, 0x43, 0x95, 0x85, 0xEE, 0xA8, 0xF6, 0x9E, 0xEA, 0x0D, 0x95, 0x2B, 0x9B, 0x0A, 0x63, 0x4B, 0xDE, 0x27, 0x44, 0x04, 0xBF, 0x4A, 0x77, 0x07, 0x94}, + {0x29, 0x88, 0xDD, 0x1C, 0x44, 0x64, 0xA7, 0xA6, 0xB7, 0x6E, 0x50, 0x08, 0x30, 0x12, 0x51, 0x85, 0x65, 0xAA, 0x4C, 0xBE, 0x32, 0xA8, 0xD9, 0xEE, 0xB5, 0x8D, 0x2A, 0x89, 0x70, 0xCF, 0x78, 0x32, 0x63, 0xE4, 0x72, 0xDA, 0xB2, 0x9B, 0x42, 0xB3, 0x5A, 0xFF, 0x59, 0x0B, 0x8F, 0x8B, 0x55, 0x61, 0xA8, 0xD9, 0x49, 0x82, 0x0F, 0x2F, 0x4F, 0x80, 0x9A, 0x73, 0x63, 0xC5, 0xA7, 0xD1, 0x5E, 0x1E}, + {0xD5, 0x3C, 0x11, 0x19, 0x6C, 0x58, 0xE8, 0xB8, 0xD7, 0xE3, 0x98, 0x37, 0x63, 0x59, 0x41, 0x06, 0xB5, 0xDB, 0x1E, 0xE7, 0x62, 0x7E, 0x73, 0x17, 0xF1, 0x3A, 0x9D, 0x7D, 0xA0, 0x36, 0x7C, 0xB5, 0x10, 0xBE, 0x95, 0xDA, 0x34, 0xE2, 0x9F, 0x18, 0xA4, 0x32, 0xE4, 0x47, 0xB5, 0x05, 0x71, 0x52, 0x0D, 0xEF, 0xDE, 0x86, 0xC2, 0xB6, 0x0A, 0xD7, 0xD9, 0x64, 0x4B, 0xFD, 0xF4, 0xF8, 0x82, 0x52}, + {0xA1, 0x1C, 0xD7, 0x85, 0x85, 0x86, 0xC1, 0x41, 0x32, 0x0B, 0x64, 0x96, 0x98, 0x41, 0x0A, 0x04, 0xF1, 0x04, 0xBD, 0xB2, 0xD6, 0x60, 0x3A, 0x22, 0xBD, 0xF9, 0x43, 0x18, 0x3A, 0xCF, 0xAC, 0x73, 0x92, 0xE4, 0x68, 0x08, 0xD2, 0xEE, 0x0E, 0x37, 0xC3, 0x8B, 0x9D, 0x56, 0x00, 0x78, 0xA1, 0x89, 0x4F, 0xB6, 0xAA, 0xBE, 0x01, 0x0B, 0x43, 0xC3, 0x9B, 0x7F, 0xAD, 0xE4, 0xD4, 0x24, 0xF7, 0x3A}, + {0x90, 0x12, 0x90, 0x10, 0x76, 0xB2, 0xB3, 0xF4, 0x21, 0xF6, 0xD3, 0x7A, 0xF2, 0x36, 0x14, 0x8F, 0xF0, 0x9D, 0x65, 0xAD, 0x75, 0x34, 0x48, 0xA6, 0x1D, 0x11, 0x31, 0x04, 0x17, 0xCF, 0x9D, 0xE6, 0x65, 0xC5, 0x25, 0x6A, 0x6E, 0x0C, 0x13, 0x19, 0xB5, 0xE2, 0x14, 0xD0, 0xD5, 0x5A, 0x66, 0xE0, 0x4D, 0x2A, 0x3E, 0xF6, 0x76, 0xDA, 0x3F, 0x5B, 0x33, 0xFA, 0x1B, 0x65, 0x07, 0xA6, 0x55, 0xCF}, + {0x50, 0x09, 0x3E, 0x8E, 0xC0, 0x35, 0xC4, 0x26, 0x6C, 0x36, 0x79, 0x28, 0x6A, 0x7D, 0xA3, 0xE6, 0x11, 0xD9, 0xD8, 0xBA, 0x4C, 0xB9, 0x32, 0x9F, 0xF4, 0xAB, 0x98, 0x97, 0x33, 0x3E, 0x5F, 0x9E, 0x51, 0x4B, 0x0C, 0x35, 0xEB, 0xD2, 0x03, 0x9F, 0x51, 0x5C, 0xC1, 0xE9, 0x46, 0x76, 0x72, 0x1B, 0x06, 0x24, 0x50, 0x35, 0x58, 0xDD, 0xE9, 0x08, 0x36, 0xE1, 0xCA, 0x99, 0x1D, 0xC7, 0x8A, 0xD7}, + {0x61, 0x96, 0x76, 0x0D, 0x9B, 0xDC, 0x2D, 0xEB, 0x93, 0x26, 0xCD, 0xEF, 0x1A, 0xE3, 0xCC, 0x7A, 0x47, 0xDE, 0x95, 0xDD, 0x36, 0x86, 0xD0, 0x67, 0xAE, 0x27, 0x29, 0x32, 0x14, 0x35, 0x38, 0xAB, 0xB3, 0x27, 0x7E, 0xC0, 0x5A, 0x4F, 0x43, 0x89, 0x21, 0x9E, 0x45, 0xEF, 0xF1, 0x10, 0xCF, 0x53, 0xFB, 0xEF, 0xD6, 0x37, 0xDF, 0x68, 0xEA, 0xD7, 0x2C, 0xFB, 0xF2, 0x56, 0xCC, 0x42, 0x3B, 0xA2}, + {0x6A, 0xCB, 0xEA, 0x6C, 0x70, 0x1F, 0x0D, 0xD9, 0xFF, 0x49, 0xC2, 0x22, 0xCA, 0x28, 0xAA, 0xA5, 0x77, 0xB2, 0x79, 0x49, 0x32, 0xF0, 0xBF, 0x4E, 0xEC, 0x7B, 0x99, 0x3F, 0x8B, 0xB3, 0xA1, 0xDE, 0x22, 0xDE, 0xD9, 0x6F, 0xC0, 0x8D, 0x45, 0x42, 0x66, 0x11, 0xA5, 0x8E, 0x62, 0xAA, 0x75, 0x83, 0x6D, 0x6B, 0x47, 0x5F, 0x78, 0x74, 0xE4, 0x0B, 0x65, 0x75, 0x63, 0xA5, 0xF3, 0xDF, 0x9A, 0x27}, + {0x5A, 0x40, 0x29, 0x69, 0x73, 0xB0, 0xB0, 0xEE, 0xE1, 0x92, 0x9A, 0x65, 0xFF, 0x9E, 0x9F, 0xC9, 0xCE, 0x0D, 0x5D, 0x0E, 0x49, 0x6B, 0xFD, 0xF6, 0x7D, 0xAF, 0x58, 0xA5, 0x71, 0xA8, 0x51, 0xF9, 0x7C, 0xFE, 0xD8, 0x8C, 0x3E, 0x2B, 0xB8, 0xCA, 0x1C, 0xF2, 0x97, 0xC6, 0x85, 0x24, 0xB8, 0x09, 0xE7, 0x52, 0xC9, 0x43, 0x77, 0x4A, 0x68, 0x66, 0xC4, 0x91, 0x1A, 0xCD, 0x31, 0x29, 0x0D, 0x93}, + {0x18, 0xA5, 0xB9, 0xF6, 0x9A, 0xF5, 0xAF, 0x93, 0xD8, 0xC7, 0xCC, 0x18, 0xD4, 0x60, 0x9D, 0x78, 0x3E, 0x5D, 0x63, 0xEB, 0x7E, 0x3D, 0x85, 0xBA, 0xC7, 0xC3, 0x3A, 0x1A, 0x2A, 0xB8, 0x18, 0xE9, 0x6E, 0xAF, 0xCD, 0xC8, 0x28, 0x58, 0xFC, 0xBF, 0xAE, 0xC5, 0xB1, 0x3A, 0x79, 0x5F, 0x60, 0xFF, 0xBD, 0xB4, 0x3F, 0x79, 0x27, 0x24, 0x52, 0x44, 0xB8, 0xE9, 0xCF, 0xD1, 0x4D, 0x52, 0x61, 0x79}, + {0x9A, 0x31, 0x8C, 0xB8, 0x2D, 0xBC, 0x99, 0x3C, 0x2D, 0x9B, 0x2A, 0x69, 0x05, 0x4B, 0xD9, 0x65, 0x37, 0x97, 0x39, 0x12, 0x66, 0x72, 0xAB, 0x55, 0xB0, 0x3E, 0x36, 0xA4, 0x57, 0x31, 0x0A, 0xFF, 0x2D, 0xA4, 0x5C, 0xCA, 0x0D, 0x72, 0x8B, 0xD9, 0x06, 0x66, 0xDD, 0xCB, 0x6D, 0x63, 0xE0, 0xEC, 0xD9, 0x2C, 0xE6, 0x0E, 0x06, 0x29, 0x97, 0xB4, 0x6B, 0xA2, 0x80, 0x28, 0xD6, 0xFB, 0xDC, 0xA5}, + {0x16, 0x90, 0xED, 0x13, 0xBA, 0x44, 0xCA, 0x51, 0x94, 0x4A, 0x63, 0x8B, 0x6E, 0xFD, 0xA0, 0x58, 0x45, 0x3F, 0x39, 0x99, 0x64, 0x4A, 0x70, 0xDE, 0x7C, 0xF4, 0x78, 0xD4, 0xA4, 0x73, 0xE4, 0x10, 0xEE, 0x07, 0xA9, 0x34, 0x3C, 0x43, 0xA4, 0x56, 0x12, 0x0B, 0x1C, 0xFC, 0xBD, 0x74, 0x45, 0xF5, 0x81, 0x89, 0xE6, 0x46, 0xF5, 0xC2, 0x97, 0x64, 0x89, 0xD1, 0x60, 0x67, 0xB8, 0x36, 0xA1, 0xF6}, + {0x1E, 0x39, 0xD6, 0xD3, 0x87, 0x42, 0x4A, 0xB0, 0xDD, 0x38, 0xBE, 0x7D, 0x91, 0x5D, 0x86, 0x0A, 0x7E, 0xC3, 0x8E, 0x74, 0xFC, 0x96, 0x1A, 0x22, 0x21, 0xB5, 0x0F, 0xB9, 0x93, 0x3F, 0xFA, 0xF2, 0xE1, 0x84, 0x7B, 0x2A, 0x6B, 0x26, 0xA4, 0xAC, 0xD8, 0xF8, 0xD6, 0x69, 0x55, 0x28, 0x00, 0x36, 0xD2, 0x1F, 0x51, 0x43, 0xA1, 0xF6, 0x07, 0x7E, 0x00, 0x5E, 0xF4, 0x4C, 0x9C, 0xDC, 0xF8, 0x94}, + {0xBC, 0x12, 0x4D, 0x53, 0xA4, 0x30, 0x6C, 0xEA, 0x84, 0x01, 0xE9, 0xBD, 0x3E, 0x30, 0x31, 0x99, 0xF3, 0xDD, 0x43, 0x2B, 0xBA, 0x1D, 0x00, 0xC1, 0x50, 0x10, 0x90, 0xDE, 0xA4, 0x74, 0xE2, 0xDE, 0x10, 0xD9, 0x75, 0x16, 0xBD, 0x9C, 0x4F, 0x0C, 0x38, 0x0A, 0x2C, 0xA7, 0x47, 0x94, 0x2C, 0x87, 0x70, 0x8E, 0xCC, 0x3B, 0x3E, 0xB7, 0x07, 0x89, 0x94, 0x80, 0x26, 0x46, 0xBF, 0x42, 0x41, 0x48}, + {0xC0, 0x24, 0x1C, 0x7C, 0x55, 0x4C, 0x4D, 0x05, 0x24, 0x14, 0x4D, 0xE5, 0x7D, 0x26, 0x40, 0x5B, 0xE7, 0x33, 0x66, 0x11, 0xF9, 0x6C, 0x6D, 0x30, 0x9F, 0x20, 0x00, 0xE2, 0xF5, 0xB0, 0x96, 0x0D, 0x22, 0xBE, 0x72, 0xD3, 0x8F, 0xB8, 0x7C, 0x95, 0xFF, 0xA9, 0x1A, 0xB3, 0xAB, 0xEE, 0xB5, 0x69, 0x8E, 0xAD, 0x06, 0xEB, 0xB5, 0x10, 0xD5, 0xF4, 0xD0, 0x69, 0x31, 0x20, 0x20, 0xC8, 0xB7, 0x73}, + {0xA1, 0xB3, 0x97, 0x39, 0x37, 0x9F, 0xF9, 0x98, 0xCE, 0x3F, 0x7E, 0xA7, 0x48, 0x55, 0xF1, 0x0F, 0x28, 0xE5, 0x3D, 0xA8, 0xDF, 0x19, 0x48, 0xDE, 0xF7, 0xFD, 0x45, 0x5E, 0xAD, 0x5E, 0xBA, 0xD2, 0x32, 0x7F, 0x54, 0xAB, 0x41, 0xF3, 0xA0, 0x69, 0xFD, 0x7A, 0xE1, 0x32, 0x72, 0x87, 0xD5, 0x11, 0xDE, 0x94, 0x33, 0xB1, 0xC9, 0x8D, 0x17, 0xB3, 0x69, 0x2A, 0x32, 0xBA, 0xA1, 0x0A, 0xC9, 0xC3}, + {0xFD, 0x47, 0x0F, 0xF6, 0x29, 0x89, 0x3D, 0x51, 0x81, 0x3D, 0x23, 0x9F, 0xA5, 0xC3, 0xE5, 0x0B, 0x1B, 0xA9, 0xBA, 0xAF, 0xC6, 0xE6, 0x71, 0x93, 0x8F, 0x3D, 0xB4, 0x67, 0x5D, 0xC6, 0xB8, 0x54, 0x1A, 0xD9, 0xF0, 0x59, 0x4A, 0xFD, 0x5B, 0x19, 0x63, 0xB4, 0x3D, 0x5F, 0x91, 0xDD, 0x6C, 0x67, 0xD8, 0x89, 0x16, 0x50, 0x63, 0xDB, 0x78, 0x4E, 0xBC, 0x02, 0x7A, 0xD2, 0xCB, 0xAA, 0x99, 0xB5}, + {0xA1, 0xD2, 0x38, 0x40, 0x84, 0x7E, 0xF5, 0xB4, 0x77, 0x5E, 0x3A, 0xDF, 0x84, 0x2E, 0x3A, 0x78, 0x01, 0xF2, 0xBE, 0x72, 0x0B, 0xFB, 0x33, 0xCF, 0x22, 0x53, 0xFD, 0x24, 0x34, 0x2D, 0xF3, 0x7D, 0xCB, 0x75, 0x30, 0xE3, 0xC9, 0x2B, 0x45, 0x87, 0xD8, 0x7E, 0xAF, 0x64, 0x7B, 0x93, 0x53, 0x52, 0xE0, 0x7F, 0x73, 0x39, 0xA3, 0x3E, 0xB9, 0xE6, 0xA6, 0x63, 0x91, 0xE2, 0xA7, 0xDC, 0x33, 0x18}, + {0x8F, 0x49, 0x11, 0x8F, 0x06, 0x7E, 0x86, 0x36, 0x30, 0x97, 0x08, 0xEA, 0x03, 0x4C, 0x24, 0x26, 0x9D, 0xAE, 0x46, 0x92, 0x64, 0x1C, 0xC0, 0xCA, 0x3C, 0xB9, 0xB6, 0x92, 0xF7, 0xCE, 0xC8, 0xCB, 0x0C, 0x29, 0x5B, 0x87, 0x12, 0x1C, 0xA5, 0x23, 0x1E, 0x48, 0x96, 0x07, 0xB2, 0x47, 0x05, 0x41, 0x63, 0x13, 0xD2, 0x2C, 0x5F, 0x3E, 0x63, 0x64, 0xDA, 0x33, 0x90, 0xD3, 0x66, 0x71, 0xA7, 0xB5}, + {0x22, 0x24, 0x02, 0x7A, 0xAE, 0xED, 0x03, 0x5C, 0xDC, 0xD5, 0xDE, 0xB0, 0xB9, 0x05, 0xE2, 0x16, 0x81, 0x47, 0x13, 0x3A, 0x29, 0x1D, 0x59, 0xEA, 0x43, 0xE8, 0x3F, 0x01, 0xB8, 0x6D, 0xE4, 0x5A, 0x2A, 0x09, 0x1F, 0x5C, 0x8B, 0xAA, 0xBF, 0xE5, 0xE7, 0xA3, 0x58, 0xB1, 0x42, 0x4D, 0x8E, 0x5F, 0x3E, 0x65, 0x30, 0xA2, 0x89, 0x0A, 0x01, 0x26, 0x49, 0xCD, 0x24, 0xD5, 0x93, 0xAA, 0x1A, 0xB3}, + {0x05, 0xB6, 0x90, 0x04, 0xBA, 0x4C, 0xBA, 0x10, 0xB1, 0x01, 0xC6, 0xE0, 0x21, 0x54, 0x83, 0x25, 0x1B, 0x97, 0xEE, 0xE6, 0x64, 0xED, 0x37, 0x9E, 0x4C, 0x95, 0x67, 0x10, 0x17, 0x7D, 0x33, 0x80, 0x16, 0x04, 0x22, 0xE2, 0x9F, 0xFF, 0x5C, 0xE9, 0xAF, 0xB6, 0x12, 0x86, 0x14, 0x06, 0x25, 0x92, 0x9F, 0x37, 0x0F, 0x72, 0x2A, 0x47, 0x51, 0x83, 0x6A, 0x10, 0x29, 0x10, 0xF7, 0x4A, 0xAE, 0x85}, + {0xD4, 0x11, 0x7A, 0x88, 0xF2, 0x95, 0xE6, 0x92, 0x78, 0x2E, 0x91, 0xD3, 0x61, 0x1F, 0x6B, 0xAB, 0xC7, 0xBE, 0x13, 0x2B, 0xD2, 0xF2, 0x2D, 0xF7, 0x33, 0x37, 0x22, 0x1A, 0xDC, 0xF0, 0x5F, 0xA0, 0x8E, 0x22, 0x96, 0x81, 0xB9, 0xE4, 0x25, 0x99, 0x36, 0x85, 0x77, 0x33, 0x7B, 0x2C, 0xB7, 0x60, 0x3E, 0x00, 0x3D, 0xBF, 0x77, 0x63, 0xCB, 0xEC, 0xFA, 0x5D, 0x83, 0x55, 0x9E, 0xB0, 0x6D, 0xC2}, + {0x68, 0xD5, 0x1F, 0xA9, 0xEB, 0x73, 0xC6, 0x87, 0x68, 0x09, 0x58, 0xCD, 0x9C, 0x66, 0xF7, 0x7A, 0x11, 0x46, 0x24, 0xEC, 0xD3, 0x88, 0x46, 0xD0, 0xEB, 0x44, 0x2E, 0x75, 0x58, 0x9B, 0x68, 0x98, 0x03, 0x36, 0xFD, 0x98, 0xAB, 0x29, 0x1F, 0xC0, 0xBA, 0xCD, 0xFF, 0xE9, 0x38, 0x92, 0x2E, 0x44, 0x54, 0xCA, 0x32, 0x10, 0xB6, 0xAD, 0x04, 0x2F, 0xDB, 0x91, 0x5F, 0x37, 0x3A, 0xF9, 0x12, 0xBA}, + {0x21, 0x1C, 0x0B, 0xFC, 0x13, 0xE0, 0x6C, 0x22, 0x86, 0x7B, 0x48, 0x82, 0x89, 0x9A, 0xA6, 0x47, 0x87, 0x74, 0x27, 0x09, 0xC5, 0x4C, 0xCD, 0x4D, 0x69, 0xA8, 0x9D, 0x42, 0x77, 0x52, 0x6F, 0x3A, 0x3B, 0xB0, 0x5D, 0x5B, 0x76, 0x1C, 0x43, 0x4F, 0x9F, 0x4F, 0x36, 0x11, 0xFC, 0x5D, 0xC1, 0xBC, 0xBC, 0xE1, 0x31, 0xB3, 0x5B, 0x9C, 0x02, 0x82, 0x38, 0xCD, 0x5D, 0x34, 0x6A, 0x8B, 0x79, 0x42}, + {0x8B, 0xD8, 0x8C, 0x3F, 0x49, 0x46, 0xDE, 0x7F, 0x0F, 0x8E, 0xDB, 0x70, 0x48, 0xBF, 0x9D, 0x6F, 0x53, 0x78, 0xCE, 0x00, 0x9B, 0xA9, 0x26, 0xE2, 0xFB, 0x2D, 0xA6, 0xEE, 0x63, 0x2E, 0x0F, 0x5A, 0x08, 0x9B, 0x78, 0xB3, 0xA2, 0x28, 0x9C, 0x99, 0x9F, 0x30, 0x22, 0x1C, 0xFC, 0xC3, 0xFF, 0x06, 0x5F, 0x73, 0x1D, 0xC4, 0x65, 0x60, 0x3F, 0x66, 0xBF, 0x99, 0x09, 0x65, 0x97, 0x0D, 0x3D, 0xDF}, + {0x21, 0xC5, 0x8B, 0x75, 0xDE, 0x16, 0xAC, 0x71, 0x2F, 0x28, 0x2D, 0xF0, 0x60, 0x39, 0x08, 0x32, 0x9C, 0xE9, 0x7B, 0x40, 0xE5, 0xF2, 0xFF, 0xC0, 0x1F, 0x79, 0x7F, 0x24, 0xB2, 0xD3, 0xF1, 0x7D, 0x3A, 0x50, 0xCE, 0xE9, 0xB5, 0x49, 0x73, 0x82, 0x83, 0x6B, 0x5A, 0x9F, 0x3B, 0xE1, 0x3A, 0xBB, 0xE5, 0x66, 0x42, 0xD3, 0xF5, 0x02, 0x29, 0x2B, 0xF9, 0x1E, 0x91, 0x0A, 0x39, 0x30, 0x17, 0x1D}, + {0x03, 0x52, 0xA3, 0x85, 0x45, 0xB3, 0xBA, 0x64, 0x4A, 0xF3, 0x78, 0x1E, 0xBB, 0x3D, 0x08, 0x8C, 0x69, 0x84, 0x31, 0xA7, 0xAB, 0x13, 0x78, 0xB5, 0x59, 0xD2, 0x42, 0x2A, 0xB8, 0xD6, 0x4A, 0xE9, 0x99, 0x63, 0x6A, 0xBE, 0x17, 0x4A, 0x72, 0x91, 0xD4, 0x09, 0xCA, 0x6E, 0x6A, 0x2F, 0xD8, 0xD6, 0x4B, 0x5C, 0x29, 0x4A, 0x77, 0x84, 0x06, 0x2B, 0x2D, 0xEB, 0x1B, 0xA0, 0xB6, 0xD1, 0x0B, 0x0A}, + {0xDF, 0x08, 0x25, 0x47, 0x4F, 0x8B, 0x74, 0x64, 0xF6, 0x7F, 0x43, 0x32, 0x8F, 0x76, 0x76, 0x0F, 0x1D, 0x36, 0x1F, 0x38, 0x8B, 0xF3, 0xC4, 0x0C, 0x1A, 0x22, 0xB8, 0x6D, 0x24, 0x57, 0xB2, 0x81, 0x3B, 0xA8, 0xE7, 0x67, 0xE5, 0x8E, 0x37, 0xCE, 0xDC, 0xFC, 0x76, 0xC8, 0x63, 0x41, 0x35, 0x64, 0x9F, 0xB9, 0x12, 0x5A, 0x06, 0xB7, 0xDB, 0xED, 0xB2, 0xEB, 0x4E, 0xA1, 0x4E, 0x1F, 0x48, 0x9D}, + {0xD7, 0x4A, 0x3F, 0x36, 0x81, 0x6E, 0xEA, 0x58, 0x35, 0x50, 0xAE, 0x37, 0x44, 0x94, 0xFE, 0x7E, 0x9E, 0x6B, 0x2E, 0xB9, 0xDE, 0x0E, 0x11, 0xB3, 0x32, 0xAA, 0xEE, 0x69, 0x2A, 0x24, 0x36, 0x76, 0x8F, 0xD1, 0xE9, 0xF3, 0xBF, 0xB5, 0x20, 0x57, 0xBB, 0xD3, 0xA8, 0x22, 0x35, 0x18, 0x2D, 0xD6, 0xBA, 0x4F, 0x7F, 0xFC, 0x41, 0x8A, 0x30, 0xF6, 0xDC, 0x12, 0x6E, 0xDC, 0xE3, 0x2D, 0x96, 0xFC}, + {0x01, 0x24, 0x8D, 0x42, 0xD3, 0x2A, 0x60, 0x1E, 0xA2, 0xEE, 0x2C, 0xB7, 0xFF, 0x5C, 0x24, 0xCA, 0x99, 0xF2, 0x25, 0x62, 0xDE, 0x2F, 0x86, 0xF3, 0xD3, 0xCA, 0x99, 0xEA, 0xEA, 0x43, 0x68, 0xF8, 0x76, 0x90, 0xB8, 0xCA, 0xE3, 0x21, 0x65, 0xE3, 0x39, 0x61, 0xFD, 0x8D, 0xEE, 0xF2, 0xC1, 0x2E, 0xBE, 0x3B, 0x01, 0x08, 0xCB, 0xB6, 0xDD, 0x7C, 0xF1, 0x86, 0x31, 0x75, 0x2D, 0xD9, 0x99, 0xB4}, + {0xAD, 0x78, 0xFC, 0xAF, 0xE8, 0xCC, 0x72, 0x70, 0x9C, 0xF8, 0xAB, 0x0A, 0x61, 0x9B, 0xE0, 0x4A, 0xD1, 0x0C, 0xD6, 0x71, 0xDF, 0x0A, 0x4D, 0xFB, 0x24, 0x16, 0xCC, 0x74, 0xAF, 0x62, 0x77, 0xB2, 0x55, 0x21, 0x25, 0xC7, 0x21, 0x91, 0xBD, 0x88, 0xA3, 0x0A, 0x0C, 0x7D, 0x06, 0x5C, 0x55, 0x9B, 0x30, 0x43, 0xE8, 0x6B, 0x13, 0x15, 0xB3, 0x85, 0x90, 0xBD, 0xC9, 0xBD, 0xFC, 0xAB, 0x86, 0x79}, + {0xF5, 0xBF, 0x99, 0x0D, 0x77, 0x97, 0xAA, 0x76, 0x23, 0xC1, 0x0F, 0xBD, 0xB4, 0x47, 0xC5, 0x38, 0x7F, 0x55, 0xAF, 0x7F, 0xFE, 0x73, 0xEA, 0x84, 0x21, 0xF0, 0xD3, 0x4B, 0xB8, 0x17, 0xAA, 0x87, 0x9D, 0xB6, 0xE9, 0xA6, 0xBD, 0x95, 0x4E, 0x31, 0x21, 0xB6, 0xA7, 0x1D, 0x3A, 0x79, 0x60, 0xF5, 0x09, 0x61, 0x37, 0x1D, 0xA1, 0x95, 0xED, 0x2E, 0x25, 0x44, 0x86, 0xF7, 0x8E, 0xA9, 0xF1, 0x01}, + {0xA9, 0x9A, 0xCC, 0x54, 0x6F, 0x29, 0xAB, 0xC3, 0xCB, 0xA2, 0xFB, 0xC0, 0x53, 0xD4, 0xF8, 0xBC, 0x4A, 0x3A, 0x3C, 0x03, 0x60, 0xA3, 0x5A, 0x79, 0xE0, 0xF6, 0x49, 0x6D, 0xAA, 0x41, 0xCD, 0x0D, 0x0D, 0x97, 0x27, 0xFA, 0x9F, 0x2A, 0xBF, 0x19, 0x89, 0x33, 0xDA, 0xB0, 0xED, 0xB9, 0xB7, 0x56, 0x5B, 0xF2, 0xFB, 0xCA, 0x23, 0xBD, 0x98, 0x94, 0xA0, 0x50, 0x02, 0x62, 0xB1, 0x76, 0x9A, 0x69}, + {0x76, 0xD1, 0x86, 0xC8, 0x8F, 0xD5, 0x23, 0x03, 0x74, 0x9B, 0xF4, 0x60, 0xAF, 0xAC, 0x32, 0x9E, 0x41, 0x14, 0xE9, 0xE2, 0xEC, 0xEB, 0x1D, 0x04, 0x06, 0xBD, 0xC8, 0xB4, 0x76, 0xE1, 0xB0, 0xE7, 0x5E, 0xBF, 0xD5, 0x8C, 0xB9, 0x42, 0x2A, 0x63, 0x57, 0x91, 0x7E, 0x98, 0x95, 0xA8, 0xDE, 0xCB, 0xBD, 0x26, 0x4C, 0x26, 0xC5, 0x77, 0x52, 0xB7, 0xA9, 0x3B, 0x85, 0xFE, 0xDF, 0x62, 0x5C, 0x1E}, + {0x21, 0xF9, 0x7F, 0xF7, 0x8D, 0xC7, 0x1F, 0x28, 0xAC, 0x7C, 0x6A, 0xCA, 0x32, 0xCB, 0x99, 0x56, 0x71, 0x37, 0x98, 0xF2, 0x5D, 0x0C, 0x4C, 0xC2, 0xA5, 0x4D, 0x2A, 0x83, 0x51, 0x47, 0x7D, 0xBA, 0x4E, 0x0D, 0x85, 0x65, 0x25, 0xC9, 0x2C, 0x8A, 0x41, 0xA4, 0x41, 0x3B, 0x07, 0x8C, 0x80, 0x57, 0x21, 0x71, 0x50, 0x03, 0x6D, 0x72, 0x3F, 0x61, 0x24, 0x5A, 0x4D, 0xB7, 0x19, 0x96, 0x81, 0x10}, + {0xD4, 0x24, 0xB9, 0xB5, 0x39, 0x2B, 0xB4, 0x8C, 0xB6, 0xE8, 0x94, 0xE7, 0x9B, 0x8F, 0x34, 0x84, 0x48, 0xE4, 0xE4, 0x5C, 0x65, 0xF3, 0x27, 0xA3, 0x57, 0x06, 0x31, 0x63, 0x3F, 0x83, 0x53, 0x15, 0x99, 0xC7, 0x99, 0x94, 0x6F, 0x3D, 0x68, 0x68, 0xB3, 0x89, 0xE2, 0x32, 0x3C, 0xD9, 0x4C, 0x1D, 0x11, 0x4D, 0x3F, 0x0C, 0xF3, 0x2E, 0x2E, 0xD9, 0x23, 0x23, 0xC6, 0x8D, 0x73, 0xF6, 0xF1, 0xB4}, + {0x6A, 0xEC, 0x78, 0x5F, 0xF3, 0xD1, 0xAB, 0xD8, 0xAF, 0x17, 0x71, 0x9D, 0x8E, 0x10, 0xD1, 0xD8, 0x01, 0xD3, 0x16, 0xDD, 0xBF, 0x27, 0x3D, 0x2D, 0x72, 0x68, 0xAA, 0x2A, 0x7C, 0x31, 0x6A, 0xD2, 0xEE, 0x32, 0x54, 0xB9, 0xD2, 0x74, 0x21, 0x2E, 0x2A, 0x05, 0x03, 0x30, 0xE7, 0xA9, 0xA1, 0xB1, 0x06, 0xC9, 0xD2, 0x66, 0xB1, 0xD7, 0x53, 0x3F, 0x93, 0x08, 0x16, 0x2C, 0xD8, 0xC5, 0x63, 0x68}, + {0xCD, 0xE8, 0xEE, 0xDD, 0x8D, 0x8E, 0x01, 0x25, 0x6E, 0xD0, 0x62, 0xAD, 0x76, 0x23, 0x7C, 0x4D, 0xF1, 0xE9, 0xC7, 0x17, 0xA3, 0x43, 0x8F, 0x47, 0xFE, 0x1B, 0xDA, 0xAE, 0xB9, 0xD5, 0x89, 0x79, 0x8D, 0x76, 0xE9, 0x69, 0x64, 0xF8, 0x2C, 0x00, 0x0D, 0x49, 0xF2, 0x4E, 0x9F, 0x1A, 0x50, 0xCF, 0xD6, 0xBB, 0x5C, 0xA4, 0xE6, 0xFC, 0x3C, 0xB8, 0x0A, 0x41, 0x8D, 0x0C, 0x23, 0x77, 0x5C, 0x2F}, + {0x0C, 0x0D, 0xC8, 0x87, 0x4B, 0xA8, 0x8B, 0x28, 0x99, 0xCD, 0x33, 0xC3, 0xEA, 0xCE, 0x82, 0x87, 0x70, 0x96, 0x09, 0xEA, 0x82, 0x8D, 0xE4, 0x35, 0x70, 0xFD, 0x2C, 0x4B, 0x07, 0xFD, 0x5A, 0xE2, 0x27, 0x15, 0x91, 0x32, 0x4A, 0x92, 0xD2, 0x0B, 0x94, 0x80, 0x0D, 0x5B, 0x8F, 0x75, 0xCF, 0x9E, 0xB9, 0x90, 0xB9, 0x97, 0x26, 0xEB, 0x19, 0xF7, 0xAE, 0xFC, 0xE1, 0x7F, 0x21, 0x66, 0x76, 0x9C}, + {0x94, 0xA8, 0x81, 0xF1, 0x7F, 0x7A, 0x24, 0x30, 0xA9, 0x59, 0x06, 0x16, 0x6A, 0xD1, 0x81, 0xF5, 0x99, 0x87, 0x00, 0x04, 0x75, 0xFE, 0x43, 0xB6, 0x27, 0x5B, 0x0E, 0xA8, 0x44, 0x35, 0xEE, 0xC8, 0x26, 0xA2, 0x4B, 0xBB, 0x16, 0x34, 0xDC, 0xE5, 0xE8, 0x85, 0xAA, 0x5C, 0x16, 0xE1, 0x9E, 0xCE, 0x01, 0xDC, 0xBA, 0xD7, 0x31, 0x53, 0xC5, 0x81, 0x13, 0x91, 0xAE, 0x6F, 0xF0, 0xFE, 0x4A, 0xF2}, + {0x78, 0x22, 0x2A, 0x9E, 0x07, 0x79, 0x3F, 0x46, 0x77, 0xC9, 0xD8, 0x84, 0x4E, 0xB4, 0xDE, 0x51, 0xEA, 0xD5, 0x43, 0xD6, 0x09, 0x53, 0x42, 0x4B, 0xDE, 0xE1, 0xAA, 0x6B, 0x39, 0xA4, 0x2E, 0x54, 0xFA, 0x31, 0x46, 0xEF, 0xAA, 0x7B, 0x92, 0xE2, 0xF1, 0xE0, 0x2E, 0x77, 0xEE, 0xBF, 0xAD, 0x65, 0x4A, 0xDB, 0x4F, 0x14, 0xDC, 0xFA, 0x71, 0x36, 0xF8, 0x03, 0x75, 0x74, 0xA1, 0x78, 0x5B, 0x36}, + {0x3E, 0x6F, 0xD1, 0x4A, 0x24, 0x5B, 0x1E, 0x0E, 0xB6, 0xE7, 0xF8, 0x5F, 0x46, 0x9B, 0x5B, 0x90, 0xD4, 0x33, 0xD6, 0xFA, 0xF4, 0xE5, 0x5A, 0x24, 0xDA, 0xAF, 0xCB, 0x77, 0x07, 0x7B, 0xCC, 0x34, 0xF8, 0xB9, 0x92, 0xA9, 0xD3, 0xC7, 0x28, 0x1E, 0x4A, 0x03, 0x2A, 0xF3, 0x8C, 0xFE, 0x38, 0x1E, 0x02, 0x4B, 0xCA, 0xDA, 0x3B, 0x8A, 0xB8, 0x11, 0x02, 0xBB, 0x69, 0x4E, 0x7E, 0xBF, 0x9D, 0x96}, + {0x11, 0x14, 0x87, 0x3A, 0x77, 0xA2, 0xA5, 0x79, 0xB7, 0x4E, 0xA8, 0xA7, 0x79, 0x08, 0x06, 0xF9, 0xF1, 0x3A, 0x2C, 0xF9, 0xD3, 0xFF, 0x5F, 0x9F, 0x69, 0x03, 0xC0, 0x53, 0x82, 0xD1, 0xD4, 0xD7, 0xF0, 0xBD, 0xA6, 0x57, 0x19, 0xD0, 0x3C, 0x38, 0xFA, 0x81, 0x0C, 0x17, 0x8A, 0xBF, 0xE7, 0x3B, 0x38, 0x87, 0x9C, 0x44, 0x93, 0xE2, 0x8B, 0x3E, 0xE1, 0xCA, 0x61, 0xB8, 0xE8, 0x57, 0x5F, 0x93}, + {0xC4, 0x6B, 0x55, 0x26, 0x1D, 0x19, 0xD9, 0x41, 0xFA, 0x76, 0xC9, 0xA7, 0x90, 0xD1, 0x02, 0x4F, 0xE5, 0xCF, 0x98, 0x9C, 0x7A, 0xD9, 0x28, 0xD9, 0x79, 0x7E, 0xF5, 0x19, 0xDA, 0xFC, 0xC5, 0x36, 0xE4, 0xD4, 0x4C, 0x70, 0x7B, 0xBB, 0xA1, 0x29, 0xD2, 0x6B, 0xA4, 0xAE, 0xD7, 0x74, 0xC1, 0xC2, 0xA2, 0x30, 0xC2, 0x47, 0xF4, 0xBC, 0x28, 0xFD, 0x2E, 0xD1, 0x54, 0x2F, 0x8B, 0x93, 0xB4, 0x5F}, + {0xA6, 0x33, 0xBC, 0xF3, 0x70, 0x95, 0x23, 0x82, 0xB0, 0xA9, 0x69, 0x58, 0xA9, 0xF6, 0xE2, 0xD3, 0x31, 0xAF, 0xC6, 0x76, 0xB7, 0xFA, 0x7E, 0x8B, 0x32, 0xD1, 0xA5, 0x2E, 0xAE, 0x34, 0xB4, 0x25, 0x9E, 0xBC, 0xBD, 0x7B, 0xDF, 0x89, 0x06, 0xFE, 0xDD, 0xED, 0x8C, 0x78, 0xF5, 0xD1, 0xD3, 0x05, 0xF0, 0x60, 0x7A, 0xB6, 0xEB, 0x1B, 0xDE, 0xE4, 0xC2, 0x52, 0xFB, 0x0C, 0x18, 0xC3, 0xCB, 0x13}, + {0x78, 0xC0, 0x43, 0xBD, 0xB3, 0xC1, 0xE5, 0x64, 0xEB, 0x0E, 0xB0, 0x47, 0x11, 0xC7, 0xE6, 0xA6, 0x5B, 0x72, 0x33, 0x19, 0xE3, 0xDD, 0x52, 0xAB, 0x35, 0x50, 0x47, 0xB9, 0x94, 0xD3, 0x03, 0xED, 0x8A, 0xEB, 0x92, 0xAE, 0x86, 0xAE, 0x18, 0x36, 0x63, 0x2E, 0xCF, 0x81, 0x19, 0x58, 0x47, 0x65, 0x81, 0x9D, 0xED, 0xF7, 0xF5, 0x5A, 0x10, 0xBC, 0x89, 0x89, 0x65, 0xAA, 0x42, 0xCE, 0x07, 0x84}, + {0xB0, 0xF3, 0x19, 0x5E, 0xA9, 0xD9, 0xE3, 0x62, 0x9C, 0x1A, 0xCF, 0x94, 0xBC, 0xBF, 0x0E, 0x71, 0x34, 0x63, 0x3A, 0xC7, 0xE2, 0x38, 0x3F, 0x15, 0xBD, 0xB0, 0x13, 0xA2, 0xE2, 0xAD, 0x47, 0xC4, 0x8B, 0xC0, 0x17, 0x40, 0xD6, 0xA4, 0xBB, 0xD9, 0x8F, 0x31, 0x4D, 0xF9, 0xB6, 0x1A, 0x1F, 0xA7, 0x9B, 0xE0, 0x9C, 0x4F, 0xB9, 0x3F, 0x8F, 0x78, 0x6E, 0x9E, 0x88, 0x4F, 0x5D, 0x4C, 0xD8, 0xD3}, + {0x5D, 0xAB, 0x56, 0x02, 0xED, 0x43, 0x01, 0xC4, 0xFE, 0xFF, 0x42, 0xC7, 0x06, 0x82, 0xB6, 0xC2, 0x04, 0x2B, 0x98, 0x9E, 0x06, 0xB5, 0x35, 0xC5, 0xC4, 0x46, 0x39, 0x3E, 0xDE, 0x51, 0x4F, 0x93, 0x8A, 0x1D, 0x99, 0x26, 0x89, 0xF6, 0x8C, 0xBC, 0x8E, 0xD4, 0x88, 0x97, 0x74, 0xFF, 0xFC, 0xBA, 0x00, 0x77, 0xE6, 0xC8, 0x1B, 0xD2, 0xC2, 0x94, 0xD0, 0xDB, 0x94, 0x13, 0xB0, 0xB9, 0xDB, 0xC3}, + {0x7E, 0x14, 0xF9, 0x6A, 0x3E, 0x51, 0x2C, 0x20, 0x9A, 0xD1, 0xC7, 0xF6, 0xF5, 0x58, 0xCC, 0x36, 0x8A, 0xFD, 0x25, 0x7D, 0x5F, 0x3D, 0x30, 0xC4, 0xCB, 0xBC, 0x4D, 0xF1, 0x65, 0xA9, 0xCA, 0xA3, 0x49, 0x5C, 0x7D, 0xCE, 0x36, 0x8E, 0x5D, 0x46, 0x28, 0x10, 0x72, 0xD5, 0xB0, 0xCD, 0xE2, 0x4A, 0x68, 0x5C, 0xFD, 0x0B, 0xEB, 0xD1, 0x24, 0xAA, 0xBA, 0x84, 0x12, 0x9D, 0x2C, 0x5B, 0x2C, 0x81}, + {0x38, 0x4F, 0x56, 0x74, 0xB6, 0x42, 0x3B, 0xAB, 0x5C, 0xAB, 0x38, 0x1D, 0xF1, 0xA9, 0x70, 0x71, 0xF1, 0xC1, 0x61, 0x59, 0x86, 0xD1, 0xB4, 0x7F, 0x6F, 0xBD, 0x23, 0x04, 0xD0, 0x0D, 0xC5, 0xC3, 0xAB, 0xF4, 0x22, 0xB8, 0xDA, 0xBF, 0x48, 0xEA, 0x3E, 0xD7, 0x9A, 0x16, 0x72, 0x34, 0xCA, 0x83, 0x5A, 0x7D, 0x38, 0xC9, 0xB5, 0xA7, 0x3F, 0x07, 0xE6, 0x5C, 0xC5, 0x89, 0x1A, 0x9D, 0xB5, 0x7C}, + {0x40, 0x07, 0xC8, 0xF9, 0x1D, 0x52, 0x34, 0xCA, 0x76, 0x98, 0xA5, 0xB9, 0x36, 0xBF, 0xCD, 0x13, 0x15, 0x81, 0xB6, 0xAA, 0x18, 0x2F, 0x4B, 0xA4, 0x3A, 0xAF, 0x90, 0x21, 0xFD, 0x69, 0xE3, 0xE7, 0xAC, 0x94, 0x42, 0xC3, 0x4F, 0xCA, 0xBB, 0x15, 0xD5, 0x76, 0xDF, 0x67, 0xF1, 0x4B, 0xA0, 0x5D, 0x5F, 0xA8, 0xDC, 0x33, 0xE4, 0x7E, 0x66, 0xDF, 0xA8, 0x7C, 0x49, 0x90, 0x18, 0x44, 0x4E, 0x1F}, + {0xFD, 0x26, 0x1F, 0x82, 0xA6, 0xA9, 0xB6, 0xDF, 0x50, 0x41, 0x1B, 0x7D, 0xA7, 0x39, 0xE1, 0xD2, 0xB6, 0x12, 0x88, 0x97, 0x62, 0x62, 0xE4, 0x38, 0x59, 0xE8, 0x93, 0xF7, 0xFA, 0xE9, 0xBF, 0x1D, 0x8F, 0x67, 0x8D, 0xA9, 0xF2, 0xA4, 0x76, 0xCF, 0x1A, 0xA7, 0x3C, 0x96, 0xA2, 0xEB, 0xA1, 0x35, 0x7D, 0x9B, 0xE3, 0xC9, 0x45, 0x7D, 0xAA, 0xB7, 0x35, 0x65, 0x60, 0xBF, 0x38, 0x2F, 0x96, 0x7C}, + {0xF6, 0xDF, 0xF4, 0xA2, 0x59, 0xE8, 0x54, 0x5F, 0x6D, 0xC1, 0x13, 0xEC, 0xF5, 0x68, 0x51, 0x56, 0xFC, 0xA0, 0x10, 0x3D, 0x98, 0x95, 0xE1, 0x22, 0xDB, 0x2F, 0x62, 0x82, 0x26, 0x71, 0xFD, 0xC6, 0x3B, 0xC5, 0xF3, 0xAA, 0xAA, 0x02, 0x86, 0x13, 0xB9, 0x0C, 0x83, 0xEF, 0x31, 0xED, 0xEC, 0xFD, 0xFB, 0x35, 0xA5, 0x7A, 0x3B, 0x82, 0x8F, 0x6D, 0xD6, 0x25, 0x69, 0x13, 0x50, 0xF9, 0xE2, 0x04}, + {0x9B, 0x5C, 0xDD, 0x94, 0x1A, 0xC5, 0x06, 0x98, 0x6A, 0x0E, 0xF4, 0xC5, 0x3C, 0x2C, 0x39, 0x6B, 0x07, 0x8A, 0xE6, 0xF8, 0x62, 0xE2, 0x5C, 0x23, 0x96, 0xCE, 0xEB, 0x19, 0xE1, 0x3D, 0x39, 0x01, 0x5F, 0xB2, 0xE3, 0x39, 0xC6, 0x9B, 0x69, 0x5C, 0xC8, 0x58, 0xCC, 0x0B, 0x3B, 0x65, 0xFF, 0x2F, 0xD9, 0x69, 0xCB, 0x24, 0xE6, 0x3A, 0xCB, 0x74, 0x73, 0xB2, 0x5A, 0xAE, 0x84, 0x16, 0x17, 0x49}, + {0xCF, 0x07, 0x40, 0xEE, 0x08, 0xCC, 0xEF, 0x8B, 0x31, 0xFE, 0xD9, 0xC5, 0x6D, 0xD3, 0x67, 0xE3, 0x89, 0xF1, 0x68, 0x38, 0x62, 0x9C, 0x08, 0x3F, 0xEA, 0xFE, 0x06, 0xBB, 0x17, 0x7D, 0x96, 0xDA, 0x6E, 0xBD, 0x24, 0x77, 0xEF, 0x97, 0x10, 0xDF, 0x97, 0x53, 0x3C, 0xD7, 0x0E, 0xF1, 0xA1, 0x8D, 0x45, 0x23, 0x4D, 0x9A, 0x2D, 0x0F, 0x8E, 0xD8, 0xA6, 0x10, 0x71, 0x85, 0x09, 0x50, 0x37, 0xBB}, + {0x44, 0x3B, 0x0D, 0xF1, 0xE9, 0x63, 0xEF, 0x55, 0x27, 0xE8, 0x09, 0x2F, 0x50, 0x77, 0x9C, 0x1C, 0x36, 0x61, 0xE0, 0x44, 0x88, 0x45, 0xD2, 0x22, 0x76, 0x74, 0xA2, 0x6A, 0x58, 0xEA, 0x0A, 0x6D, 0xFE, 0x1B, 0x62, 0x2F, 0xC2, 0x20, 0xAE, 0x78, 0x96, 0xFC, 0xDB, 0xED, 0x47, 0x56, 0x94, 0x7D, 0x70, 0x1D, 0xC2, 0x83, 0x47, 0x4A, 0xE5, 0xA7, 0x50, 0x2D, 0x07, 0x7F, 0x90, 0x16, 0xE0, 0xE1}, + {0xA9, 0xA8, 0xD5, 0x20, 0xDB, 0x30, 0x74, 0xE4, 0x32, 0xF0, 0x60, 0x0D, 0xE4, 0x2A, 0xB1, 0x79, 0xF6, 0xE0, 0xB5, 0x3E, 0x88, 0x97, 0x8D, 0x0B, 0xB0, 0xD8, 0x80, 0x34, 0xE5, 0x96, 0x3B, 0x3F, 0x0D, 0xB8, 0x43, 0x75, 0x84, 0x48, 0xC3, 0xD5, 0x1E, 0x8B, 0xF1, 0xEE, 0x41, 0x2B, 0x82, 0x86, 0x0B, 0x5D, 0x85, 0x40, 0x52, 0x68, 0x90, 0x63, 0xB1, 0x51, 0xA5, 0x7E, 0x1B, 0x7E, 0xBF, 0x4C}, + {0xF0, 0x6B, 0x12, 0x12, 0xD1, 0x30, 0x4F, 0x19, 0xD1, 0x52, 0xE1, 0x91, 0xFE, 0xF4, 0xA0, 0x8A, 0xA2, 0xDC, 0x0D, 0xA0, 0xD6, 0x95, 0x68, 0xA7, 0x55, 0xBE, 0x1E, 0x9B, 0xA7, 0xBC, 0xE3, 0xC1, 0xF3, 0xE1, 0x04, 0xB6, 0x98, 0xC1, 0x5C, 0xEC, 0x82, 0xCE, 0x3C, 0x79, 0x10, 0x83, 0x69, 0xAB, 0x71, 0xBD, 0x6B, 0x05, 0x7D, 0x00, 0x37, 0x0A, 0xD4, 0xD2, 0x2D, 0x60, 0x21, 0xE5, 0x81, 0xD4}, + {0xCD, 0xDA, 0x88, 0x5F, 0xE1, 0x89, 0xF3, 0xB9, 0xCE, 0x8E, 0x0C, 0xD1, 0xDB, 0x4A, 0x79, 0x03, 0xD0, 0x34, 0x7A, 0x0B, 0xEE, 0xDA, 0xC6, 0xFC, 0xA4, 0x50, 0x7D, 0xEF, 0x0F, 0x0E, 0xA0, 0x8E, 0x55, 0xF6, 0x54, 0x64, 0xFA, 0x43, 0xA2, 0xB1, 0xEA, 0x8F, 0x7F, 0x8E, 0xE7, 0xDB, 0xBF, 0x6C, 0x0C, 0x91, 0x17, 0x0A, 0x5A, 0x2B, 0x50, 0x8C, 0x72, 0x5C, 0x16, 0x49, 0x0B, 0x19, 0xF9, 0x0D}, + {0xF0, 0x2F, 0x03, 0xB2, 0x86, 0x6B, 0xDC, 0x0F, 0xD8, 0x9D, 0xAA, 0x44, 0xA8, 0xDB, 0x0A, 0x72, 0xE4, 0x25, 0x4F, 0x82, 0x15, 0x70, 0x19, 0xA7, 0x31, 0x4A, 0x6E, 0x0A, 0xBE, 0x35, 0x74, 0x19, 0xD1, 0xAE, 0x43, 0xCA, 0x92, 0xF0, 0x24, 0xC3, 0x89, 0xA8, 0xBE, 0x7F, 0xB0, 0x47, 0x3D, 0x44, 0xD2, 0x24, 0x1B, 0x4A, 0x05, 0x66, 0xA6, 0x5B, 0xE4, 0x4D, 0xFB, 0x51, 0x97, 0x05, 0x3E, 0xC2}, + {0x19, 0x2C, 0xDC, 0xDF, 0xDB, 0xAF, 0x99, 0x77, 0x8B, 0x3B, 0x77, 0x89, 0x3B, 0x69, 0xFD, 0xB9, 0xCB, 0xFF, 0x3C, 0xE7, 0xCF, 0x5A, 0x92, 0x04, 0x6C, 0x74, 0x42, 0x86, 0x26, 0x51, 0x9A, 0x63, 0x94, 0x3C, 0xE7, 0x7C, 0xF2, 0x30, 0x42, 0x33, 0xAA, 0x79, 0xF9, 0x0E, 0x9D, 0x78, 0x10, 0x2A, 0x01, 0x95, 0x2F, 0x4C, 0x0C, 0x5D, 0xEF, 0xD5, 0xA7, 0x35, 0xBA, 0x57, 0xBE, 0xF4, 0x02, 0xF0}, + {0x3E, 0x31, 0x6D, 0xEA, 0x77, 0xB4, 0x56, 0x8D, 0xA0, 0x1E, 0xE6, 0xCF, 0x49, 0x5C, 0xF3, 0x6C, 0x67, 0xA7, 0x34, 0x65, 0x5F, 0x77, 0xB1, 0xAA, 0xF4, 0x1B, 0x20, 0x0B, 0x23, 0x8C, 0x9E, 0x5C, 0xDE, 0xC8, 0xB1, 0xCC, 0x46, 0x18, 0x3A, 0xED, 0x7A, 0xE4, 0x85, 0xFF, 0xD0, 0xBD, 0x5D, 0x96, 0xB3, 0x5C, 0x6F, 0xD9, 0x11, 0xC2, 0xD1, 0x7E, 0xA6, 0xE8, 0x7F, 0xB8, 0x9B, 0xC7, 0x04, 0x59}, + {0xF0, 0x4F, 0x90, 0x07, 0xC4, 0xC9, 0xF4, 0x32, 0x0F, 0x67, 0x12, 0xAF, 0x79, 0x24, 0x57, 0x35, 0xD0, 0x1A, 0x5B, 0x8E, 0x5C, 0xAC, 0xE5, 0x05, 0x1D, 0x6E, 0x4C, 0x7D, 0x9E, 0x80, 0x42, 0x54, 0x88, 0xF5, 0x22, 0xF0, 0x69, 0x11, 0xEE, 0xF5, 0xA1, 0x6D, 0x6E, 0xCD, 0xAA, 0xC8, 0xD5, 0x9D, 0x14, 0xAD, 0x74, 0x44, 0xAF, 0xB7, 0xE8, 0x35, 0x20, 0x66, 0x20, 0x9C, 0xF2, 0x83, 0x83, 0x9D}, + {0x77, 0xA9, 0x7D, 0xFD, 0xA1, 0x02, 0xE9, 0x0B, 0x62, 0xA0, 0x0F, 0x10, 0x7F, 0x01, 0x8E, 0x87, 0x21, 0x24, 0xD7, 0x33, 0xB7, 0x68, 0xB7, 0x46, 0xB2, 0xD0, 0x64, 0x80, 0x61, 0xD8, 0x5A, 0x01, 0x53, 0x95, 0xCF, 0x87, 0x4C, 0xE0, 0x48, 0x02, 0x91, 0xE8, 0x6B, 0x94, 0x08, 0xEB, 0x45, 0x37, 0xB5, 0x94, 0xB3, 0x14, 0x6F, 0x43, 0xDE, 0x06, 0x7C, 0xB6, 0x0D, 0x9C, 0x36, 0x6C, 0x35, 0xA1}, + {0xB9, 0x63, 0xAF, 0x3B, 0xBB, 0xCE, 0x3F, 0xBB, 0x00, 0x54, 0xBE, 0xFD, 0xDA, 0x2E, 0x07, 0x98, 0x1A, 0xD5, 0x1A, 0x31, 0xF2, 0xF6, 0x95, 0xA8, 0xA5, 0xAA, 0x26, 0x7C, 0xD4, 0x31, 0x8A, 0x4A, 0x1C, 0xAA, 0x7E, 0x53, 0x3D, 0x10, 0xE7, 0xD0, 0xEC, 0xFB, 0xF5, 0x9E, 0x84, 0xA8, 0xDD, 0xA0, 0x62, 0x95, 0x03, 0x1A, 0xC4, 0xA7, 0x3C, 0xCE, 0x4A, 0x73, 0x05, 0x79, 0xED, 0xEA, 0x2C, 0x10}, + {0xA0, 0x39, 0x44, 0xD0, 0xE4, 0xFE, 0x4B, 0xEF, 0x38, 0xD7, 0x38, 0x7F, 0x91, 0x51, 0x1A, 0xE0, 0x91, 0x50, 0xBC, 0xF9, 0x04, 0x02, 0x17, 0xB2, 0x92, 0xCB, 0xBE, 0x8E, 0xE1, 0xA3, 0x4B, 0x3A, 0x83, 0x14, 0xB6, 0xC1, 0x87, 0x38, 0x1B, 0x4A, 0x21, 0xD2, 0x46, 0x62, 0x68, 0xCD, 0x05, 0x93, 0x68, 0x6B, 0xAD, 0x06, 0x4B, 0x7E, 0x69, 0xDA, 0xB7, 0x79, 0x9A, 0x87, 0x2E, 0x3D, 0xA5, 0x3E}, + {0xAC, 0xA1, 0xBE, 0x3B, 0xDE, 0xB2, 0xA6, 0xE2, 0xA2, 0x6F, 0x96, 0x90, 0x3D, 0x49, 0x01, 0x64, 0x52, 0xF8, 0xBF, 0x7C, 0x1B, 0x1E, 0x71, 0x1E, 0x7D, 0x1F, 0x2D, 0xE6, 0x7F, 0xF3, 0x48, 0x91, 0xF1, 0xA2, 0xFC, 0x2F, 0x78, 0x5F, 0xD3, 0x5C, 0x84, 0xF8, 0x2A, 0x49, 0x0C, 0x21, 0xE1, 0xE6, 0xFA, 0xE6, 0x10, 0x03, 0x34, 0x26, 0x62, 0xD9, 0xF2, 0x07, 0xE1, 0x57, 0xDD, 0x04, 0x62, 0x48}, + {0x7E, 0x35, 0xC0, 0x40, 0xBA, 0x4E, 0xCE, 0x46, 0x98, 0x58, 0xD1, 0xAF, 0xD8, 0x1E, 0xDA, 0x4A, 0xC3, 0xFD, 0x33, 0x69, 0x45, 0xC4, 0xBA, 0xDC, 0x87, 0x43, 0xE0, 0xD2, 0x96, 0xB7, 0x29, 0xAC, 0x28, 0x30, 0xB1, 0x60, 0x5F, 0xD3, 0x98, 0xC9, 0xE2, 0x52, 0x89, 0x93, 0xAA, 0x89, 0x77, 0x42, 0xC6, 0xD4, 0xCB, 0xF2, 0x91, 0xD2, 0x57, 0xFD, 0x56, 0x1B, 0x99, 0x57, 0x15, 0x26, 0xF6, 0xF8}, + {0xA3, 0x2F, 0x30, 0x91, 0xF9, 0x23, 0xCB, 0x43, 0xC8, 0x1B, 0x5A, 0x32, 0x1E, 0xDD, 0x07, 0xE2, 0xC5, 0xFB, 0x64, 0xBA, 0x43, 0x11, 0x77, 0xC2, 0x47, 0xB6, 0xFF, 0xB7, 0x33, 0x13, 0xBE, 0xAF, 0xE7, 0x6C, 0xC5, 0x67, 0x42, 0x48, 0xAA, 0x63, 0xBA, 0xD4, 0xAB, 0x51, 0x1E, 0x67, 0xFF, 0x65, 0xD1, 0x70, 0x21, 0x4E, 0xF1, 0x11, 0xCA, 0xAD, 0xB2, 0x90, 0x2D, 0xF3, 0x01, 0xCF, 0x0B, 0xFF}, + {0xF5, 0xF3, 0x9D, 0xE9, 0xC6, 0xDE, 0xF5, 0xF8, 0x98, 0x6E, 0x1B, 0xC6, 0x80, 0x6E, 0x9B, 0xC2, 0x3E, 0x89, 0xC3, 0xAE, 0x2C, 0xDF, 0x1A, 0x86, 0xB8, 0xFD, 0xE5, 0x1B, 0x83, 0x24, 0x62, 0x17, 0xC6, 0x0C, 0x6C, 0xF6, 0x29, 0x20, 0x55, 0x28, 0xB4, 0x68, 0x86, 0xEF, 0x13, 0x7D, 0x90, 0xC0, 0xCB, 0x4A, 0x4C, 0x7B, 0x98, 0xFB, 0x25, 0x95, 0x5F, 0x92, 0x06, 0x3D, 0x0C, 0x14, 0x72, 0x76}, + {0xAF, 0x10, 0x44, 0x9F, 0x0B, 0x94, 0x00, 0xD1, 0x24, 0x64, 0xCF, 0x15, 0x0E, 0x03, 0xF5, 0xC7, 0x77, 0x44, 0xDC, 0xE8, 0x25, 0x99, 0xB2, 0x7A, 0x4E, 0xB4, 0xD9, 0xC4, 0x5B, 0xF7, 0x79, 0x0C, 0x0D, 0x03, 0x4F, 0x3D, 0x72, 0xB4, 0xF5, 0x8B, 0xE2, 0x7C, 0x8E, 0x8F, 0xA0, 0x45, 0xC6, 0x04, 0x5B, 0x01, 0x9C, 0xF0, 0xA7, 0x0E, 0xD5, 0xF8, 0x3E, 0xC5, 0xAC, 0x04, 0x0E, 0xD8, 0x32, 0xEC}, + {0x02, 0xA4, 0x71, 0xDB, 0x40, 0x46, 0x28, 0xE0, 0xB4, 0x19, 0xD6, 0x6C, 0x07, 0xF4, 0x12, 0xA2, 0xB5, 0xDF, 0x75, 0x69, 0xA8, 0xD8, 0x83, 0xE4, 0x8B, 0x9C, 0x23, 0xD8, 0x44, 0x36, 0x4F, 0xD5, 0xCA, 0x5A, 0x0F, 0xD7, 0x6F, 0x89, 0x2F, 0xD4, 0xC9, 0x62, 0x44, 0x56, 0x29, 0xD6, 0x8B, 0x9F, 0xE9, 0xB8, 0x1D, 0xDB, 0x5F, 0x82, 0xF8, 0x0E, 0x63, 0x4C, 0xEB, 0xBE, 0xC9, 0x42, 0x99, 0xA8}, + {0x81, 0x59, 0x5D, 0xA3, 0x8A, 0x52, 0xF3, 0x40, 0x4D, 0xF9, 0x3F, 0x6C, 0x06, 0xE4, 0x8E, 0xD3, 0x1C, 0x2C, 0x1A, 0xDC, 0x50, 0x27, 0xED, 0xEF, 0x5C, 0x5D, 0x98, 0xBD, 0x72, 0x49, 0x5D, 0x0C, 0x73, 0xE5, 0x2F, 0xB2, 0x7C, 0x34, 0x50, 0x1D, 0xC1, 0x1C, 0x1D, 0xC1, 0xC8, 0x82, 0xAA, 0x17, 0x92, 0xB4, 0x63, 0x1B, 0xBE, 0x6D, 0x2D, 0xE2, 0x24, 0xC6, 0x55, 0x99, 0x8C, 0xDF, 0x79, 0x70}, + {0x73, 0x1C, 0xA6, 0x3D, 0x56, 0xC5, 0xDF, 0xA7, 0x72, 0xB2, 0xA7, 0xCF, 0x61, 0x1B, 0xCC, 0x23, 0x99, 0x24, 0x81, 0x38, 0x0E, 0xFF, 0xE7, 0x81, 0x5D, 0x48, 0x04, 0xE8, 0xBE, 0xBF, 0xE2, 0xED, 0x42, 0xAE, 0xDB, 0x14, 0x8A, 0xF3, 0xFF, 0x3F, 0x60, 0x91, 0x93, 0x61, 0xDB, 0x24, 0xC3, 0x37, 0xDC, 0xA7, 0xED, 0xDE, 0xEA, 0x2E, 0x56, 0xC8, 0xA9, 0x14, 0xA1, 0xEA, 0x3C, 0x53, 0x2E, 0x39}, + {0x18, 0xBF, 0x9C, 0xF3, 0x70, 0x73, 0x31, 0x76, 0xFC, 0x78, 0x65, 0xC5, 0x93, 0x16, 0x01, 0x80, 0x90, 0xFC, 0x48, 0x5D, 0x51, 0x36, 0x41, 0x61, 0xC2, 0x12, 0xEE, 0x2E, 0x9C, 0x79, 0x6E, 0xE6, 0xD8, 0xF2, 0x0D, 0xD5, 0x4B, 0x8F, 0x3A, 0xC1, 0x5C, 0x99, 0x0B, 0x08, 0x4B, 0x3F, 0x05, 0xFB, 0x2C, 0xD9, 0xD3, 0xB4, 0x91, 0x32, 0x5C, 0xB9, 0x52, 0xED, 0xB7, 0xDB, 0xDD, 0xB0, 0x98, 0x11}, + {0x46, 0x7B, 0xAD, 0xBF, 0xD3, 0xFD, 0x3A, 0xF6, 0xB9, 0xF8, 0xE5, 0x57, 0xD3, 0xE8, 0x60, 0x4B, 0x3C, 0x72, 0x58, 0xED, 0x1C, 0x8F, 0xAA, 0xCC, 0xE9, 0x24, 0x81, 0x67, 0xD8, 0x8C, 0xE6, 0xCB, 0xC1, 0xAA, 0xEA, 0x6E, 0x03, 0x5F, 0xAC, 0x24, 0xEC, 0xC3, 0x91, 0xC1, 0x40, 0x47, 0xDC, 0xF9, 0xC6, 0xE8, 0xE3, 0xDB, 0x37, 0x15, 0x8C, 0xAA, 0xA0, 0x3E, 0xE5, 0x45, 0x6C, 0x7D, 0x52, 0x6D}, + {0xBD, 0x03, 0x81, 0x89, 0x7A, 0x72, 0x5F, 0x93, 0xD3, 0xC9, 0xDD, 0x0C, 0x4C, 0x41, 0x05, 0x72, 0xD3, 0x3E, 0xDB, 0x26, 0x06, 0x2C, 0xDB, 0x23, 0xBA, 0xD0, 0x71, 0x3D, 0x84, 0xC6, 0x40, 0x37, 0x34, 0xB3, 0x5D, 0x7B, 0xFF, 0x60, 0x89, 0xE2, 0xA8, 0x79, 0x09, 0x99, 0x1C, 0x14, 0xE3, 0x41, 0xB5, 0xFC, 0xF6, 0x94, 0x85, 0x82, 0x82, 0xDB, 0xEC, 0x15, 0x5C, 0x05, 0x29, 0xE1, 0x7C, 0x58}, + {0x07, 0x9C, 0x79, 0x67, 0x12, 0xDD, 0xAD, 0xD7, 0x1E, 0xBA, 0xA8, 0x03, 0x59, 0xDF, 0x21, 0x86, 0x13, 0xEE, 0xC8, 0x30, 0xCA, 0x6A, 0x18, 0xD7, 0x4B, 0xEF, 0x67, 0xE4, 0x5B, 0x03, 0xBE, 0x1F, 0x25, 0xA6, 0x49, 0xE4, 0x92, 0xB5, 0xDA, 0xE7, 0x72, 0xFB, 0x07, 0x3C, 0x57, 0x5E, 0x93, 0xD2, 0x79, 0x44, 0x08, 0xC1, 0x22, 0x91, 0x46, 0xCC, 0x91, 0x4E, 0xA4, 0xBC, 0x62, 0x3B, 0x8F, 0x7D}, + {0x58, 0x37, 0x51, 0xE9, 0x1D, 0x02, 0x14, 0xC3, 0xC4, 0xDA, 0x08, 0x34, 0xBE, 0x76, 0x73, 0x27, 0xF5, 0x4C, 0x11, 0x3F, 0x4D, 0x2E, 0xF9, 0x84, 0x82, 0x75, 0x8B, 0x34, 0x73, 0xFA, 0x33, 0x27, 0xBB, 0x61, 0xFC, 0x3F, 0x2B, 0xB8, 0x0B, 0xF6, 0x7D, 0xA7, 0x8D, 0x8C, 0xC7, 0xA6, 0x50, 0x5B, 0x78, 0x77, 0xFE, 0xCD, 0x61, 0x9C, 0x0A, 0x12, 0x61, 0xE8, 0xEA, 0x4C, 0xC4, 0xA6, 0x23, 0x8A}, + {0x1E, 0x39, 0x08, 0xD1, 0xE7, 0x54, 0x00, 0xE7, 0xDA, 0xF5, 0xAD, 0xA3, 0xEA, 0x1A, 0x5E, 0xC9, 0xBF, 0xB2, 0xEB, 0xC2, 0x6A, 0x27, 0x89, 0x20, 0x51, 0xA9, 0x1D, 0xF4, 0x2D, 0xDD, 0xE9, 0x93, 0xA1, 0xDB, 0x59, 0x7F, 0x39, 0xF0, 0xA1, 0xD6, 0x73, 0x64, 0x30, 0xA7, 0xB2, 0xDF, 0xDB, 0x0A, 0x38, 0xF2, 0xA2, 0x8F, 0x9D, 0xAA, 0xD6, 0x6A, 0x25, 0x2E, 0xDD, 0xE7, 0xCE, 0xA9, 0x27, 0x53}, + {0xA7, 0x06, 0x70, 0x2E, 0xAC, 0x30, 0x05, 0x10, 0x35, 0xF9, 0x6C, 0x90, 0x51, 0x46, 0xD9, 0x61, 0x06, 0x5D, 0xB0, 0xC5, 0xD4, 0x40, 0xB9, 0xD9, 0x5B, 0x4C, 0x7E, 0xF1, 0xFA, 0x31, 0x60, 0xF4, 0xAA, 0x6B, 0xA3, 0x87, 0x60, 0xF9, 0xFD, 0x42, 0x91, 0x51, 0x74, 0x17, 0x4C, 0x17, 0xBA, 0xF0, 0x3C, 0xFC, 0x06, 0xDE, 0x66, 0x3C, 0x73, 0x51, 0x0B, 0xE6, 0xAD, 0x42, 0x67, 0x23, 0x62, 0xDE}, + {0xD1, 0x13, 0xE4, 0x63, 0x9C, 0xD0, 0x5A, 0xC2, 0xA6, 0x43, 0x23, 0xA1, 0xA6, 0x58, 0x21, 0xAF, 0xBB, 0xFB, 0x7E, 0x38, 0x7F, 0xED, 0x19, 0xE4, 0x0E, 0x11, 0x58, 0xDB, 0x46, 0x19, 0x1F, 0xA0, 0x4A, 0x37, 0x09, 0xA5, 0x2C, 0xA5, 0x07, 0x8F, 0x25, 0xB2, 0x81, 0xBB, 0x7C, 0x98, 0xBB, 0xE4, 0x14, 0x55, 0x3B, 0x84, 0x1D, 0x7F, 0x96, 0xFE, 0x7A, 0xBF, 0x14, 0xF7, 0x4B, 0x2C, 0x0E, 0xDA}, + {0xDF, 0x38, 0x0E, 0x46, 0x75, 0xDE, 0x90, 0xD1, 0x22, 0x64, 0xE3, 0x1A, 0xD5, 0xB1, 0xC6, 0xFE, 0xBF, 0x97, 0x94, 0x74, 0x08, 0xBF, 0x24, 0xA2, 0x79, 0xAB, 0x62, 0x3D, 0x64, 0xFE, 0xA4, 0x2C, 0xFE, 0x2A, 0x7D, 0xA5, 0xE6, 0x20, 0xB3, 0x7F, 0xD7, 0x51, 0xC0, 0x41, 0x88, 0x51, 0x2A, 0xBF, 0x90, 0x31, 0xEB, 0x2D, 0x2C, 0x6D, 0x3D, 0xE4, 0x4E, 0xAC, 0x62, 0x93, 0x6E, 0x90, 0xEF, 0x9E}, + {0xB7, 0xA4, 0xEF, 0xB7, 0x06, 0xDD, 0x0D, 0x71, 0x3C, 0x60, 0xE2, 0x99, 0x96, 0xF0, 0x13, 0x88, 0xF6, 0x55, 0x99, 0xFB, 0xEE, 0x0B, 0x07, 0x6E, 0x0D, 0xE7, 0xD9, 0x81, 0x64, 0xBE, 0x82, 0x2D, 0x39, 0x17, 0x62, 0x49, 0x40, 0xE0, 0x1B, 0xDC, 0xC8, 0xCF, 0x2E, 0x13, 0xF3, 0xBA, 0x91, 0x8B, 0x3F, 0x9B, 0x7F, 0x92, 0x74, 0xA8, 0x81, 0x84, 0xB6, 0x31, 0x47, 0xF3, 0x0C, 0x69, 0x03, 0x23}, + {0x80, 0x2E, 0x46, 0x08, 0x38, 0xF8, 0x13, 0x7C, 0x1B, 0x0E, 0xAF, 0xBB, 0x24, 0x0D, 0xDC, 0x1F, 0x4A, 0x20, 0x22, 0xD4, 0x57, 0xB9, 0xF5, 0x66, 0x93, 0x2E, 0x39, 0x28, 0x95, 0x8F, 0xDA, 0x9C, 0xC9, 0xE5, 0xD1, 0xEE, 0xAD, 0x63, 0xAF, 0xA2, 0x7B, 0xDD, 0x37, 0x19, 0x34, 0x71, 0xA7, 0x33, 0xB1, 0x13, 0x2D, 0x91, 0x7E, 0x79, 0xF6, 0xAE, 0x5A, 0x5C, 0xE1, 0xD5, 0xD0, 0x8B, 0xE9, 0xBC}, + {0x64, 0xE8, 0xD9, 0x77, 0xAD, 0x92, 0x02, 0xD7, 0x66, 0xC5, 0x47, 0xA8, 0x24, 0x07, 0x72, 0x99, 0x5C, 0x7D, 0x45, 0xEB, 0x8D, 0x43, 0xE7, 0x6A, 0x7E, 0xFF, 0xC3, 0x2F, 0x6B, 0x93, 0xCF, 0xE5, 0x93, 0xEF, 0x8A, 0x9B, 0x6E, 0x0B, 0x01, 0xC0, 0x56, 0xD0, 0x2A, 0x62, 0xFF, 0xB9, 0x19, 0x07, 0xF3, 0x7D, 0x2E, 0xD9, 0x9D, 0x8F, 0x1B, 0xE5, 0x71, 0x96, 0xB0, 0x23, 0x3D, 0xA9, 0x38, 0xA9}, + {0x71, 0x28, 0xE3, 0x35, 0x7B, 0xDA, 0x6F, 0xEB, 0x63, 0xEE, 0x1F, 0x46, 0x91, 0x2E, 0x95, 0x29, 0x7A, 0xDB, 0xE5, 0x6A, 0xFD, 0x40, 0xC4, 0x8D, 0x0D, 0x83, 0x93, 0x7B, 0xE3, 0x7B, 0x7B, 0xBC, 0x4A, 0x12, 0x21, 0xF0, 0xF0, 0xB2, 0xB3, 0x8B, 0xF6, 0x7A, 0x80, 0xC6, 0x01, 0xF4, 0xA9, 0xDF, 0xF3, 0xBA, 0x85, 0x80, 0x26, 0xDC, 0x48, 0xCB, 0xB7, 0xAB, 0xA7, 0xAF, 0x4D, 0xFE, 0xC2, 0xCD}, + {0x2B, 0x88, 0x2D, 0x33, 0x4F, 0xE1, 0x83, 0xE4, 0x2D, 0x4E, 0xD5, 0x84, 0xEB, 0x8C, 0x83, 0x68, 0xFC, 0x37, 0xAF, 0xB9, 0x2A, 0x11, 0xF4, 0xD8, 0x62, 0xF0, 0x7A, 0x5E, 0x6B, 0x6B, 0x2E, 0x8D, 0x80, 0x0E, 0x3E, 0x9D, 0x4F, 0x31, 0x27, 0x70, 0x7B, 0xA0, 0xE0, 0xA0, 0x6B, 0x8D, 0x0B, 0x3F, 0x11, 0x1D, 0xEF, 0x16, 0x72, 0xCD, 0xEF, 0xA0, 0xB8, 0x1F, 0x5D, 0x85, 0xE6, 0x4D, 0x63, 0xCE}, + {0x35, 0xF3, 0xB3, 0x3B, 0x33, 0x52, 0xAD, 0x22, 0xB2, 0x87, 0x87, 0x86, 0x63, 0x90, 0x4A, 0x4D, 0xEA, 0x9A, 0xE8, 0x5B, 0x66, 0x52, 0x71, 0x68, 0xDD, 0x6C, 0x4B, 0x9E, 0x85, 0x37, 0x5B, 0x59, 0x1F, 0xD2, 0xD1, 0xAC, 0xE4, 0x97, 0xCA, 0xAF, 0x5F, 0xD8, 0x5B, 0x97, 0xD0, 0xFF, 0xF0, 0xBB, 0x3F, 0xFD, 0x9F, 0x5D, 0x75, 0x90, 0xFC, 0x64, 0xFB, 0xF0, 0xF0, 0x78, 0x10, 0x27, 0xE0, 0x64}, + {0x26, 0xA8, 0x9E, 0x0B, 0xBA, 0x8D, 0x98, 0x76, 0x9E, 0x68, 0x8D, 0x2B, 0x44, 0x58, 0x90, 0x1C, 0x5B, 0x22, 0xCF, 0x91, 0x64, 0x24, 0xD0, 0xF6, 0xB7, 0x78, 0xE0, 0xF0, 0xB7, 0xCA, 0x77, 0x8E, 0xA4, 0x7B, 0x71, 0x9F, 0x75, 0x31, 0x2E, 0xAF, 0xB0, 0x97, 0xD7, 0x4F, 0x8E, 0xD3, 0xA1, 0x29, 0xDA, 0xD0, 0xDB, 0x2B, 0x94, 0xEB, 0x8F, 0x6F, 0xE3, 0x13, 0x4F, 0xD0, 0x1B, 0x0E, 0x70, 0xFD}, + {0x46, 0x2F, 0x62, 0x8B, 0xDB, 0xF5, 0xDB, 0xAF, 0x5D, 0xF6, 0x43, 0xEC, 0xC6, 0x30, 0xB0, 0x97, 0xE4, 0xA6, 0x70, 0x27, 0xE9, 0x53, 0x98, 0x29, 0xFE, 0xF2, 0xB9, 0x71, 0x7F, 0x2F, 0x10, 0x9E, 0x96, 0xC4, 0x03, 0xDE, 0x9D, 0x63, 0x31, 0x1B, 0xAA, 0xAC, 0x81, 0xA7, 0x00, 0x1F, 0x6C, 0xA5, 0xDC, 0x4B, 0xF4, 0x72, 0x58, 0xBC, 0x93, 0xE5, 0x99, 0x91, 0x06, 0x33, 0x72, 0x25, 0x5E, 0x45}, + {0x27, 0xCB, 0xE1, 0x59, 0xB9, 0xD2, 0x9F, 0xF8, 0x67, 0xB5, 0x04, 0x04, 0xEB, 0x3D, 0xC3, 0x43, 0x52, 0xDD, 0x49, 0xD2, 0xE2, 0x09, 0x79, 0x08, 0xCB, 0x62, 0xD5, 0xD5, 0xAD, 0x8F, 0x26, 0x9A, 0xDB, 0x7E, 0x51, 0xC7, 0xB4, 0x5D, 0x72, 0xCD, 0xCD, 0xC9, 0xE7, 0x6A, 0x5D, 0xD5, 0x28, 0x2B, 0x3A, 0xDD, 0x13, 0x4A, 0x2A, 0x10, 0x99, 0xB8, 0x0F, 0xC8, 0x3E, 0x5D, 0x84, 0xC8, 0x4E, 0x81}, + {0xE9, 0xCD, 0x56, 0x9E, 0x3D, 0xDF, 0x81, 0xF7, 0xA8, 0x78, 0x36, 0x28, 0xDE, 0x41, 0x29, 0xFF, 0xF4, 0xE2, 0x4F, 0xC4, 0xD4, 0x1F, 0xE9, 0xCB, 0x35, 0xB4, 0x40, 0xAC, 0x30, 0x5D, 0x84, 0x44, 0xD1, 0x6D, 0xD3, 0x91, 0xED, 0xA5, 0x02, 0x19, 0xA0, 0xD1, 0xAF, 0x4C, 0xC1, 0x29, 0x79, 0x86, 0xD9, 0xBE, 0x09, 0xA3, 0xD7, 0xB9, 0xA0, 0x2D, 0x2B, 0x5B, 0xFF, 0x7B, 0x24, 0x40, 0xAD, 0xB4}, + {0xB4, 0xAA, 0x16, 0x90, 0xDF, 0x99, 0x27, 0x58, 0xFB, 0xA0, 0x12, 0x66, 0xB1, 0xB3, 0xCA, 0x96, 0xB6, 0xC7, 0xB5, 0xFC, 0x6A, 0x7B, 0x21, 0xA8, 0x22, 0xEF, 0x78, 0xDB, 0xEC, 0xD5, 0xC0, 0x7B, 0x7B, 0xF6, 0xD6, 0x2B, 0x09, 0xD8, 0x87, 0x81, 0xA3, 0xD9, 0x47, 0x53, 0x0F, 0x1D, 0x15, 0x9F, 0xF6, 0x3D, 0x3C, 0x95, 0x02, 0x39, 0x63, 0x5A, 0x09, 0x6D, 0xE3, 0xCA, 0xDA, 0x31, 0xE3, 0xAD}, + {0x60, 0x48, 0x0C, 0x1B, 0x7D, 0x8D, 0xF7, 0xFC, 0x48, 0xE1, 0xE1, 0x11, 0x33, 0xEE, 0xDE, 0x03, 0x41, 0x9E, 0xDD, 0x8E, 0x6C, 0x73, 0x8E, 0xD1, 0x27, 0x39, 0x57, 0xE2, 0xA4, 0xA1, 0x6D, 0x53, 0xB6, 0xD6, 0xC4, 0x60, 0x9B, 0x3C, 0x92, 0x28, 0x3D, 0xA1, 0x89, 0x4F, 0x20, 0xC3, 0x93, 0x8C, 0x30, 0x0E, 0x80, 0x97, 0x4D, 0x42, 0x8E, 0x0A, 0x7E, 0x79, 0x73, 0x39, 0xC2, 0x23, 0x14, 0x45}, + {0x40, 0xC4, 0xEC, 0x99, 0xBE, 0x13, 0xD8, 0x85, 0xAD, 0xE8, 0xED, 0x8E, 0x8F, 0x30, 0x14, 0x22, 0x44, 0xB2, 0x03, 0xD3, 0x31, 0x1D, 0x05, 0x9C, 0x0E, 0x98, 0xF5, 0x00, 0x40, 0x41, 0xC8, 0x35, 0x42, 0x6B, 0xC9, 0x4A, 0xDE, 0x68, 0xD2, 0x55, 0xC0, 0x9C, 0x01, 0xCA, 0x48, 0x9F, 0xD0, 0x2A, 0x5C, 0x16, 0x5E, 0xAD, 0x10, 0xD9, 0xC2, 0x52, 0xDF, 0x0E, 0x26, 0x4A, 0x03, 0x23, 0xAA, 0x47}, + {0x63, 0xDF, 0xE5, 0x02, 0x0F, 0x54, 0x2D, 0x74, 0x14, 0xD2, 0x11, 0x0F, 0x0D, 0xD5, 0x81, 0x09, 0xC3, 0x2F, 0xAA, 0x73, 0xA8, 0xF3, 0xB1, 0xB9, 0xB1, 0xA0, 0x3A, 0xBD, 0x27, 0x7A, 0x07, 0x7B, 0x21, 0x62, 0x26, 0x46, 0x3B, 0x5A, 0x3B, 0xC3, 0x38, 0x26, 0x45, 0x2E, 0x8C, 0xCB, 0x78, 0x9C, 0xEE, 0x5C, 0x43, 0xA8, 0xE2, 0xD3, 0x58, 0x88, 0x50, 0x3A, 0xF2, 0xE5, 0xFE, 0x5D, 0x7A, 0x3A}, + {0x3E, 0x32, 0x60, 0x40, 0x1C, 0x26, 0x18, 0x91, 0x6F, 0x12, 0xE6, 0xDA, 0xE1, 0x5F, 0x5C, 0xCC, 0xAE, 0xE7, 0x1C, 0x78, 0xAA, 0x4C, 0xB6, 0xE0, 0xC5, 0x93, 0x19, 0x91, 0x8B, 0x7B, 0x75, 0xA6, 0x01, 0xC9, 0xC5, 0xF4, 0x5C, 0xDE, 0xBA, 0x8D, 0x20, 0x10, 0xEA, 0xAC, 0xBB, 0x27, 0x42, 0x66, 0xDA, 0xE7, 0xFB, 0x01, 0x95, 0xF6, 0x68, 0x8C, 0x0D, 0x3A, 0xEC, 0x36, 0xF9, 0xAC, 0x82, 0xE0}, + {0xD4, 0x13, 0x5D, 0x70, 0x3C, 0xBA, 0x42, 0x7D, 0x21, 0xB4, 0x86, 0x43, 0xD8, 0xB3, 0x3D, 0xD1, 0x72, 0xD0, 0x81, 0xFC, 0xED, 0x21, 0x11, 0xA0, 0x4C, 0xD7, 0x29, 0xA0, 0xAD, 0xD9, 0xBA, 0xC5, 0xE1, 0xA4, 0x50, 0x80, 0x51, 0x3F, 0xDA, 0x77, 0x77, 0x2F, 0x6F, 0x7A, 0x2E, 0x1D, 0x70, 0x9A, 0x0E, 0x89, 0xF0, 0x4B, 0xC3, 0xAB, 0xEE, 0x67, 0x5A, 0x26, 0x34, 0x9A, 0x40, 0x5C, 0x82, 0xB3}, + {0x2C, 0x52, 0x13, 0x30, 0x3D, 0xEC, 0xB6, 0x1A, 0x5B, 0x5A, 0x6E, 0x85, 0xA3, 0x46, 0xA5, 0x86, 0x6F, 0x0D, 0x59, 0x01, 0x2C, 0x63, 0x45, 0x1A, 0xB9, 0xAD, 0xF6, 0x82, 0xF0, 0x09, 0x4F, 0x6D, 0xE8, 0x9F, 0x79, 0xC6, 0x43, 0x6E, 0x19, 0x22, 0x0A, 0x38, 0x89, 0x35, 0x20, 0x66, 0x24, 0x84, 0xD3, 0xAC, 0x66, 0xCF, 0xFB, 0x5B, 0x92, 0x31, 0x0F, 0xDF, 0x0D, 0xF4, 0x3D, 0x7D, 0x15, 0xC6}, + {0x13, 0xA9, 0xCE, 0x77, 0xB4, 0xAA, 0x8F, 0x4D, 0xD2, 0x8F, 0x37, 0x4B, 0xEF, 0x4A, 0x2F, 0xDB, 0x20, 0xE7, 0xF2, 0xB5, 0x61, 0xFE, 0x9C, 0x82, 0x5C, 0x21, 0xA7, 0xE6, 0xC7, 0x33, 0xDB, 0xDE, 0xC2, 0xC1, 0xB9, 0xB9, 0x2F, 0xC1, 0x2A, 0xEA, 0x30, 0x77, 0x6D, 0x21, 0xC0, 0xF9, 0x0A, 0xB0, 0x65, 0x3C, 0xCD, 0xC9, 0x76, 0xF8, 0x59, 0x0B, 0xF4, 0xFB, 0x10, 0x69, 0xD5, 0xD9, 0xA7, 0xF0}, + {0xFB, 0xF2, 0xDF, 0x0A, 0xC7, 0xA5, 0x35, 0xE9, 0x3C, 0x62, 0xDA, 0x6F, 0x5A, 0x3F, 0x4B, 0x4E, 0x48, 0x07, 0x43, 0x6E, 0xC4, 0x1C, 0xED, 0x9C, 0x75, 0x3D, 0xC3, 0x02, 0x99, 0x59, 0x38, 0xE7, 0x7D, 0xE8, 0x85, 0xDA, 0x7A, 0x1F, 0x5D, 0xD0, 0xBE, 0x69, 0x1B, 0x4C, 0x44, 0xDF, 0x87, 0xC9, 0xE3, 0x8F, 0xF4, 0x27, 0xCD, 0xBB, 0xDB, 0x6D, 0x1C, 0xAE, 0x5A, 0xAB, 0x9C, 0xCD, 0x55, 0xD1}, + {0x5D, 0xCE, 0x58, 0x6B, 0xA2, 0x99, 0x9C, 0xD7, 0x7F, 0x16, 0xB4, 0x16, 0xAB, 0x24, 0x1D, 0x53, 0xF9, 0xB2, 0xE2, 0x0E, 0x84, 0xC0, 0x0B, 0x16, 0xE2, 0x36, 0x0A, 0x1F, 0x10, 0x66, 0xB1, 0xD8, 0x9E, 0xFA, 0x9A, 0x84, 0xAE, 0x5D, 0xC5, 0x96, 0xE3, 0x63, 0x8B, 0x63, 0x50, 0xF6, 0xF1, 0xAB, 0x5D, 0x07, 0xB4, 0xDD, 0x84, 0xBC, 0x74, 0x48, 0xA5, 0x5A, 0x4A, 0xA9, 0x52, 0x5D, 0xAE, 0x41}, + {0xA6, 0x90, 0x55, 0x0B, 0x2A, 0x2F, 0x3E, 0x55, 0x7B, 0xAB, 0x45, 0x7F, 0x85, 0xE1, 0x69, 0xA6, 0xFF, 0x83, 0xE6, 0xD8, 0x0E, 0x10, 0x60, 0xC3, 0x9D, 0xE0, 0x80, 0x4B, 0xF9, 0x1B, 0x41, 0xB5, 0xB9, 0x66, 0x25, 0xC2, 0xE2, 0x70, 0x08, 0x7B, 0x42, 0x0A, 0x2B, 0x4E, 0x40, 0xBD, 0x44, 0x5E, 0x80, 0x19, 0x42, 0xDD, 0xF7, 0x9A, 0xD1, 0xE2, 0x01, 0xA6, 0xD7, 0x9B, 0x98, 0x1B, 0xFD, 0x02}, + {0xE1, 0xF9, 0x63, 0xAD, 0x4E, 0xB8, 0x76, 0x28, 0x0F, 0x3C, 0x3E, 0x5E, 0x56, 0xDA, 0x50, 0x34, 0x02, 0x76, 0x21, 0x32, 0x77, 0xAA, 0x9D, 0xF1, 0xD2, 0x12, 0xD5, 0xF5, 0xB3, 0xDB, 0x7B, 0x1A, 0x1A, 0x67, 0x3A, 0x89, 0xC8, 0x33, 0x1F, 0xF6, 0xF2, 0x87, 0xDD, 0xF1, 0xDF, 0x15, 0x62, 0xD0, 0x62, 0xB2, 0x32, 0xF7, 0x4D, 0x07, 0x68, 0x4C, 0xA0, 0x0B, 0x0F, 0xBB, 0xA6, 0xD8, 0xEC, 0xF6}, + {0x09, 0x6E, 0x3C, 0xA9, 0xF5, 0x87, 0x9C, 0xD9, 0x9C, 0x9C, 0x0E, 0xDC, 0x11, 0x2C, 0xD7, 0x0B, 0xCA, 0xB7, 0x25, 0x1C, 0x09, 0x6E, 0x3D, 0x85, 0x70, 0xBB, 0xAF, 0xF3, 0x25, 0xE0, 0xB0, 0x46, 0xAB, 0x62, 0x9D, 0x46, 0x2F, 0x62, 0x7E, 0x71, 0x89, 0x12, 0x8A, 0x58, 0xAB, 0x72, 0x84, 0x81, 0x0A, 0x2B, 0x18, 0x8E, 0x9A, 0xAC, 0xBE, 0xF5, 0xB3, 0xA2, 0x72, 0xB3, 0x26, 0x5A, 0x7D, 0x11}, + {0xE2, 0xF8, 0xED, 0x94, 0x12, 0x15, 0x94, 0x9B, 0x4E, 0xB9, 0xE9, 0xD8, 0x3F, 0x4F, 0x31, 0x8A, 0x23, 0xC5, 0xA4, 0x91, 0x82, 0x25, 0x67, 0xD9, 0xF8, 0x38, 0x65, 0x35, 0xBB, 0xBA, 0x3F, 0xDC, 0xDE, 0x70, 0xD2, 0x61, 0x21, 0x6F, 0xB5, 0xEC, 0x5C, 0x72, 0x65, 0x21, 0xA5, 0xD9, 0xE4, 0x63, 0x16, 0x47, 0xBF, 0xBD, 0x82, 0xC2, 0x2A, 0xDC, 0x05, 0xF9, 0x73, 0x27, 0x45, 0xF1, 0x24, 0x14}, + {0xF3, 0xD9, 0x4D, 0x2C, 0xF4, 0x2D, 0x8F, 0xFC, 0x3D, 0xB5, 0x71, 0xCC, 0x0D, 0xD2, 0x70, 0x4D, 0x1F, 0x69, 0x4A, 0x01, 0xA8, 0xD4, 0x9E, 0x51, 0x39, 0xC3, 0xE9, 0x44, 0x9B, 0x8B, 0xEE, 0x60, 0xC5, 0x35, 0xEC, 0xA4, 0x7F, 0x00, 0xD5, 0x13, 0xAC, 0xB0, 0x8B, 0x45, 0x2F, 0x5D, 0x02, 0x20, 0x93, 0xE8, 0x16, 0xFC, 0x13, 0xE6, 0xAD, 0x74, 0xDB, 0x1B, 0x67, 0x5B, 0x31, 0xB6, 0x61, 0xBD}, + {0xE4, 0x60, 0xD1, 0x6D, 0xBB, 0xB3, 0xFF, 0xFF, 0x93, 0x5E, 0xF9, 0xFD, 0x75, 0x65, 0x6E, 0x02, 0xF5, 0xB1, 0xC7, 0xB6, 0x29, 0xCC, 0x8B, 0x3A, 0xF2, 0xD2, 0x2C, 0x26, 0xAB, 0xF6, 0x88, 0x5A, 0xD7, 0xF6, 0x45, 0x01, 0x95, 0x2E, 0x5B, 0xCE, 0x8A, 0xC1, 0x8C, 0xDC, 0x4A, 0xD3, 0x8F, 0x45, 0x2B, 0x67, 0xE7, 0x19, 0xBE, 0xCD, 0x23, 0x93, 0x47, 0xDD, 0x37, 0x86, 0xE1, 0xC8, 0xA3, 0x1D}, + {0x0E, 0xF7, 0x6E, 0x95, 0xB9, 0x35, 0x0D, 0x3D, 0xFD, 0x13, 0xD0, 0xDD, 0x80, 0x35, 0x01, 0x39, 0x6B, 0x31, 0xF4, 0xE8, 0xCB, 0x67, 0x09, 0xC8, 0xF3, 0xA2, 0x58, 0xE0, 0xC6, 0x2A, 0xA5, 0x35, 0x1C, 0xD4, 0xAF, 0x13, 0x90, 0x18, 0x2D, 0xEC, 0x01, 0x05, 0x49, 0x5E, 0xF6, 0xCF, 0xCB, 0xD2, 0x7B, 0x29, 0x65, 0xE6, 0xEA, 0x4F, 0x3D, 0xB8, 0x20, 0x34, 0x03, 0x32, 0x3A, 0x94, 0x61, 0xEE}, + {0x40, 0xB0, 0x19, 0xBF, 0xCD, 0x3B, 0xD2, 0xD4, 0x08, 0x9B, 0x14, 0x51, 0x90, 0xD1, 0x40, 0x9D, 0xA0, 0x25, 0x34, 0xF6, 0x06, 0x6E, 0xCE, 0x6C, 0x66, 0xEB, 0xAC, 0x46, 0x19, 0x20, 0x74, 0x54, 0xD5, 0x9B, 0x27, 0xF0, 0x7D, 0xD8, 0x8B, 0x79, 0x88, 0x65, 0x0E, 0x6B, 0xA1, 0xDC, 0xE7, 0x18, 0x8B, 0x21, 0x0C, 0x6F, 0x13, 0x4F, 0x5D, 0x21, 0x11, 0x55, 0xE3, 0x68, 0xE3, 0x67, 0x86, 0x1D}, + {0xA9, 0xE7, 0x96, 0x14, 0x34, 0xC2, 0x1E, 0xC4, 0xC7, 0xF5, 0x33, 0x41, 0x36, 0x05, 0x5B, 0xFB, 0x43, 0x34, 0xC3, 0x90, 0x75, 0xCB, 0xF6, 0x9B, 0x18, 0xF7, 0xDE, 0xC8, 0x00, 0xC5, 0x75, 0x70, 0x0D, 0xCD, 0x59, 0xB6, 0xB7, 0x5B, 0x14, 0xBB, 0xEC, 0x4D, 0x35, 0x21, 0x78, 0xB9, 0x6D, 0xD7, 0x6B, 0xD1, 0xE2, 0x09, 0x16, 0x7A, 0xD0, 0x73, 0x7E, 0x35, 0xE2, 0x3B, 0xF2, 0x4D, 0x08, 0x73}, + {0xE3, 0x5E, 0xE0, 0x45, 0xC8, 0xBE, 0xFB, 0x8E, 0x11, 0x2A, 0x5B, 0x2C, 0x57, 0xE1, 0x46, 0xEB, 0xB1, 0xC5, 0x6D, 0x42, 0xC9, 0x33, 0x9B, 0xF1, 0x1A, 0xBD, 0x65, 0xF9, 0x92, 0xB4, 0x4C, 0x50, 0x43, 0xA2, 0x3B, 0xD2, 0xC8, 0xAB, 0x84, 0x6B, 0x8E, 0x81, 0x41, 0x8F, 0x84, 0xEA, 0x46, 0x26, 0xDE, 0xAA, 0xFB, 0x05, 0x7A, 0x62, 0x25, 0x7A, 0x20, 0xDC, 0xE4, 0x49, 0x53, 0x9F, 0xB3, 0x7C}, + {0x89, 0xBA, 0xDA, 0x49, 0x8E, 0x19, 0x20, 0x69, 0x50, 0x4F, 0x9E, 0xFA, 0xB4, 0x1A, 0x1D, 0xB9, 0xCE, 0x3F, 0xF7, 0x63, 0x10, 0x8A, 0xE6, 0x87, 0x34, 0xD4, 0x18, 0x70, 0xE0, 0x70, 0xD7, 0x93, 0xA4, 0x09, 0xC8, 0xDB, 0x0C, 0xCC, 0xAC, 0x5C, 0x38, 0xCA, 0x8D, 0x67, 0x81, 0x43, 0xEB, 0xC8, 0x56, 0x40, 0x4D, 0x13, 0x2D, 0x24, 0xFA, 0x0F, 0x2A, 0x9D, 0x40, 0xAB, 0x60, 0xA8, 0x7D, 0x80}, + {0x02, 0x0C, 0x3A, 0xEC, 0xD9, 0x5E, 0x35, 0x42, 0x7D, 0x93, 0xEA, 0x1E, 0x29, 0xE1, 0x04, 0x98, 0x4E, 0x78, 0x12, 0xC6, 0x9C, 0x9E, 0xD7, 0x7B, 0x7A, 0xCF, 0xB7, 0xA1, 0x94, 0x57, 0x33, 0xAA, 0x88, 0x5F, 0x35, 0x70, 0x50, 0x4F, 0x21, 0xE6, 0xE6, 0xDE, 0x44, 0x54, 0x0E, 0xED, 0x16, 0xBB, 0xA8, 0x5F, 0x03, 0x6B, 0xD0, 0x36, 0xBF, 0xED, 0xE1, 0x03, 0x3A, 0xCA, 0x3C, 0x6E, 0x80, 0xE9}, + {0xB1, 0xEF, 0x9F, 0x91, 0x34, 0xB2, 0x6C, 0xDA, 0xB9, 0x5A, 0x25, 0x57, 0xF2, 0xCB, 0x13, 0xE0, 0x72, 0x75, 0xD7, 0xAD, 0x66, 0xBD, 0xFB, 0x17, 0xF0, 0xCD, 0xC1, 0x79, 0x74, 0x65, 0x5C, 0xEB, 0x79, 0x39, 0xC2, 0x3E, 0x7F, 0x6F, 0xF1, 0x9F, 0x3C, 0x6D, 0xC6, 0x08, 0x1B, 0xE9, 0xFC, 0xAF, 0x02, 0xEF, 0x1A, 0xD4, 0xF2, 0x55, 0x6C, 0xC8, 0x4F, 0x37, 0x9D, 0xD6, 0x06, 0x01, 0xD8, 0xFF}, + {0xBF, 0xBE, 0x53, 0x2F, 0xA5, 0x85, 0x65, 0x6F, 0xE2, 0x00, 0x18, 0xC8, 0xF3, 0x34, 0x73, 0xF2, 0x95, 0x50, 0x98, 0x03, 0xC5, 0x92, 0x00, 0xE3, 0xBD, 0xB3, 0xF6, 0x0D, 0x02, 0xE2, 0x97, 0xD9, 0x89, 0x5E, 0x65, 0x26, 0x24, 0x3F, 0x38, 0xD8, 0x74, 0x72, 0xE0, 0x61, 0x09, 0x66, 0x03, 0xFA, 0xF4, 0x9B, 0x1B, 0x90, 0xAC, 0x0C, 0xC2, 0x2C, 0xCF, 0x46, 0x8F, 0xFF, 0x79, 0x7B, 0x1E, 0x08}, + {0x1B, 0x97, 0x65, 0x89, 0x0D, 0xCF, 0xE2, 0xAB, 0x04, 0xCB, 0x85, 0x9B, 0x73, 0xEB, 0xCC, 0x4C, 0x98, 0x98, 0xE6, 0x47, 0xE1, 0xBB, 0x21, 0xD1, 0x5A, 0xBE, 0x9C, 0x4F, 0x02, 0x2A, 0xE8, 0x5D, 0x43, 0xB8, 0xE7, 0x06, 0xB8, 0x63, 0xFB, 0xEB, 0x15, 0x47, 0xF3, 0x41, 0xA2, 0x64, 0x01, 0x32, 0x0B, 0x55, 0x60, 0x46, 0x4E, 0x92, 0x5E, 0xB7, 0xD4, 0x9F, 0x9E, 0xFE, 0x0E, 0xF8, 0x9B, 0x11}, + {0xAE, 0xCA, 0x07, 0xD7, 0x1A, 0x66, 0x0C, 0x30, 0x10, 0x9D, 0x94, 0x24, 0x35, 0x8A, 0x6A, 0x39, 0x56, 0xF5, 0xC4, 0x01, 0x54, 0x68, 0xED, 0x8F, 0x67, 0xF0, 0x3E, 0x14, 0x0B, 0x67, 0xD7, 0x30, 0xE6, 0xB3, 0x4B, 0xE7, 0x8E, 0x1C, 0x56, 0xC0, 0xC0, 0xDE, 0x01, 0xAF, 0xF8, 0xA9, 0x1C, 0x96, 0x47, 0x71, 0x2C, 0x9C, 0xDF, 0x3D, 0x41, 0xE7, 0x18, 0x00, 0x19, 0x08, 0x6E, 0x1C, 0x2B, 0x38}, + {0x1D, 0xEE, 0xD3, 0xA2, 0xDA, 0x9D, 0xBB, 0x25, 0x1E, 0xD0, 0x63, 0x99, 0xB7, 0x6A, 0x19, 0x16, 0xE3, 0x0B, 0xB5, 0x76, 0x9D, 0x34, 0x03, 0xCA, 0x69, 0x53, 0x17, 0x97, 0x12, 0xE0, 0x76, 0x60, 0x0F, 0x57, 0x17, 0xA1, 0x6C, 0x05, 0x2D, 0x91, 0x66, 0xAC, 0xED, 0x24, 0x2E, 0x77, 0x1F, 0xE7, 0x30, 0xBC, 0xC4, 0xE2, 0x19, 0x0B, 0x0F, 0xEC, 0xA0, 0x10, 0x7C, 0x85, 0x51, 0x03, 0xAC, 0xE8}, + {0x6E, 0x7C, 0x2B, 0x20, 0xC4, 0x8F, 0x33, 0x33, 0xC0, 0x55, 0xB2, 0xB7, 0xB8, 0xFE, 0x05, 0x80, 0x05, 0x70, 0x5C, 0x4F, 0x31, 0xB8, 0xFE, 0x23, 0x74, 0x86, 0xB5, 0xAC, 0xC0, 0xBB, 0x1A, 0x3A, 0x5A, 0xF3, 0xFE, 0x5A, 0x8D, 0x8D, 0x09, 0xE3, 0x88, 0x1E, 0xAB, 0x8D, 0x27, 0x82, 0x2A, 0x46, 0xC9, 0xC0, 0x63, 0x86, 0x59, 0x32, 0x2D, 0xE6, 0xA6, 0x68, 0x5B, 0xC1, 0x89, 0x3E, 0xDD, 0x70}, + {0x8C, 0xC3, 0xFC, 0xAF, 0x7E, 0x59, 0xFB, 0x5F, 0xB7, 0x4C, 0xD0, 0x3B, 0xCD, 0xEE, 0xA1, 0xF5, 0x20, 0x77, 0x2F, 0x7A, 0x38, 0x78, 0xDF, 0x4B, 0xE8, 0xD6, 0x89, 0xAB, 0x32, 0xB2, 0xC4, 0x34, 0x95, 0x4F, 0x91, 0xEE, 0xDC, 0x24, 0x44, 0x7A, 0xA7, 0x72, 0xB2, 0x51, 0xA0, 0xD2, 0x7A, 0x2C, 0xCF, 0x46, 0xCE, 0x2C, 0x10, 0x20, 0x5D, 0xE5, 0xF1, 0xBB, 0x95, 0x5F, 0xF9, 0x62, 0x65, 0x0C}, + {0xCA, 0x12, 0xBB, 0x8A, 0x3E, 0x3C, 0x81, 0x6B, 0x0D, 0x14, 0x53, 0x66, 0x35, 0xAA, 0x47, 0x94, 0x04, 0xC7, 0x6F, 0xB6, 0x1C, 0xF8, 0xEA, 0xE3, 0x4B, 0x35, 0x96, 0xD6, 0x9B, 0x20, 0x4C, 0xA5, 0x22, 0x65, 0xCC, 0x67, 0x82, 0xDB, 0x85, 0xE8, 0x84, 0x3B, 0x72, 0x11, 0xFE, 0xBB, 0xA1, 0xD5, 0x43, 0x7D, 0x76, 0xCC, 0x4E, 0x8E, 0x9D, 0x40, 0xCA, 0x53, 0xE8, 0xC2, 0xC8, 0xFE, 0x29, 0x18}, + {0x57, 0x74, 0x4D, 0x8B, 0x8E, 0x34, 0xB0, 0x55, 0x9E, 0x87, 0x89, 0xC0, 0xDF, 0x35, 0xBA, 0xC7, 0x6E, 0x66, 0x2E, 0x2A, 0x3B, 0x0E, 0xAF, 0x0A, 0x97, 0x5D, 0xC8, 0x2C, 0x28, 0x6B, 0x1C, 0xCC, 0x7F, 0xBA, 0x8F, 0x79, 0xB0, 0x39, 0x7B, 0x76, 0x16, 0x0E, 0x06, 0xC2, 0xC1, 0xFF, 0x85, 0xD6, 0x27, 0xD2, 0x77, 0x00, 0xE5, 0x95, 0xA6, 0x3E, 0x0C, 0x55, 0xC2, 0x63, 0x83, 0x97, 0xBE, 0xDF}, + {0x66, 0x8A, 0x23, 0x28, 0xA0, 0xEB, 0x7C, 0x73, 0x1A, 0x1E, 0xFE, 0x6A, 0x65, 0xEA, 0xF8, 0x5D, 0xC4, 0xCC, 0x74, 0xDA, 0xFD, 0xE8, 0xB6, 0x54, 0xC4, 0xB1, 0x4E, 0x6E, 0xB6, 0x54, 0x52, 0x0C, 0x98, 0x0E, 0x9B, 0x2C, 0x34, 0xBE, 0x83, 0xDB, 0x3D, 0x56, 0x9D, 0x1A, 0x5C, 0xD4, 0x7C, 0x1B, 0xE3, 0x67, 0x0E, 0x94, 0xAC, 0xA2, 0x84, 0x3B, 0x4A, 0x0D, 0x3D, 0x17, 0xF1, 0xE6, 0xDA, 0xF4}, + {0x29, 0xA0, 0x0A, 0xB5, 0x09, 0x43, 0xDD, 0xF6, 0x56, 0x20, 0x05, 0xA0, 0x0B, 0xD2, 0xA9, 0xB7, 0x99, 0xB7, 0x4C, 0x99, 0x6D, 0x5A, 0xD9, 0x64, 0xE0, 0x3E, 0xB1, 0x54, 0x04, 0x61, 0x72, 0xF1, 0x86, 0xE4, 0xE4, 0xD2, 0x23, 0x5A, 0xA0, 0xE7, 0x62, 0xA0, 0x93, 0x09, 0xD3, 0xFA, 0x29, 0xF5, 0x8E, 0xE3, 0xE3, 0xA9, 0x92, 0x53, 0x16, 0xD0, 0xEE, 0x8B, 0x33, 0x32, 0xC6, 0xD0, 0x9F, 0x87}, + {0x56, 0x6F, 0x18, 0x3F, 0x39, 0x74, 0x5D, 0x5D, 0xB2, 0xDB, 0x30, 0x9A, 0xDA, 0x3A, 0xBD, 0x8A, 0x6D, 0x0C, 0x2C, 0xDD, 0xFC, 0x74, 0xDB, 0xED, 0x15, 0x18, 0x08, 0x41, 0xDC, 0xA8, 0x10, 0x2A, 0x32, 0x86, 0x6F, 0x68, 0x25, 0xDE, 0x29, 0x13, 0xDF, 0xBA, 0x0C, 0x36, 0xCB, 0xE4, 0x30, 0x85, 0xF1, 0xBA, 0xC4, 0xBC, 0xAD, 0x9E, 0xA8, 0xDD, 0x21, 0x52, 0xC5, 0xD3, 0x68, 0xE5, 0xDB, 0x7E}, + {0x81, 0x4F, 0xE3, 0x6F, 0xA8, 0xD6, 0x2B, 0x35, 0xBF, 0xA8, 0xEE, 0x55, 0xCD, 0x14, 0xE5, 0x67, 0x37, 0x9F, 0xFC, 0x61, 0x9B, 0xFB, 0x4B, 0x61, 0x3F, 0x89, 0xDD, 0xCE, 0x6F, 0xDE, 0x4C, 0xA9, 0x1D, 0x7C, 0x36, 0xB8, 0x30, 0x59, 0xF6, 0xE0, 0xDD, 0xC8, 0xE3, 0x9C, 0x71, 0xC7, 0x23, 0xE5, 0x85, 0xE3, 0xF2, 0xC1, 0xFA, 0x1D, 0x7B, 0xD9, 0x82, 0x4E, 0xF6, 0x8F, 0xBA, 0x1F, 0x7A, 0x3A}, + {0x4E, 0x0C, 0xBA, 0xC4, 0xD1, 0xD5, 0x17, 0xA9, 0x3B, 0x58, 0xC8, 0x8B, 0x15, 0x46, 0x3B, 0xA2, 0x73, 0x84, 0xF8, 0xA2, 0xA5, 0xCD, 0xA2, 0xE8, 0x28, 0xA4, 0x22, 0xA5, 0x05, 0xCE, 0x75, 0x4E, 0x40, 0x8F, 0x1F, 0x3A, 0x2D, 0x3F, 0x39, 0xE1, 0xAE, 0xA4, 0x6B, 0xFB, 0x3A, 0xB5, 0x17, 0x74, 0xE0, 0xAB, 0xB9, 0xD0, 0x4D, 0xEB, 0x45, 0x62, 0xA0, 0x82, 0x46, 0x64, 0x38, 0xAD, 0x44, 0x7A}, + {0xAB, 0x3A, 0x75, 0xB7, 0x6F, 0xC4, 0x48, 0x4D, 0x37, 0x9F, 0x6D, 0x5D, 0xE6, 0xE9, 0xAB, 0x2E, 0xF8, 0xB9, 0xDC, 0xEE, 0xF6, 0x36, 0x27, 0x42, 0x4C, 0x6F, 0x4F, 0xEA, 0xA3, 0x6E, 0xF5, 0xB2, 0xE9, 0xBA, 0xC5, 0x99, 0x58, 0xBE, 0x46, 0x7A, 0xFA, 0xD6, 0xAD, 0x26, 0x4B, 0xDF, 0xED, 0x1F, 0x78, 0x05, 0xDD, 0xC7, 0x4D, 0x1C, 0x91, 0xC1, 0x11, 0x78, 0x38, 0x23, 0x2C, 0x50, 0x53, 0x88}, + {0xB5, 0x17, 0xB7, 0x38, 0xEC, 0x2C, 0xE1, 0xDC, 0xF1, 0x2E, 0x98, 0xCA, 0x5F, 0xB4, 0x78, 0x7F, 0x94, 0x62, 0x93, 0xA3, 0x5C, 0x44, 0x3B, 0x7B, 0x48, 0xB8, 0x68, 0x79, 0x47, 0x14, 0x04, 0xDE, 0x65, 0x24, 0x98, 0xCA, 0x91, 0x9D, 0xDF, 0x95, 0xF2, 0x35, 0xD9, 0x28, 0xF9, 0xEC, 0x44, 0xCA, 0x58, 0x8B, 0xB8, 0x6D, 0x23, 0x78, 0x20, 0x78, 0x24, 0x07, 0xA8, 0x50, 0x61, 0x9B, 0x1E, 0xAE}, + {0x0E, 0xC5, 0x96, 0xDA, 0x5C, 0x1A, 0x4D, 0xF1, 0x72, 0x5C, 0x6C, 0xC8, 0x13, 0x31, 0xE4, 0xA9, 0x76, 0x4C, 0x86, 0x78, 0xE2, 0x66, 0x37, 0xE0, 0xBF, 0x96, 0xC4, 0x8F, 0x6E, 0xBC, 0x1A, 0x68, 0x8E, 0xB3, 0x1D, 0x2C, 0x86, 0xF6, 0x3F, 0xF7, 0x11, 0xE0, 0x45, 0x83, 0x12, 0x4A, 0x0A, 0xCB, 0xBF, 0x82, 0x8D, 0x82, 0x24, 0xF1, 0x9D, 0xB8, 0x06, 0xFF, 0xDF, 0xE0, 0x21, 0xB9, 0x12, 0xC4}, + {0x1A, 0x3D, 0x00, 0x1E, 0x26, 0xA9, 0x06, 0xAC, 0x50, 0xBF, 0x52, 0x12, 0xA1, 0x20, 0xF3, 0xD5, 0xF9, 0xFB, 0x3D, 0x78, 0x75, 0x88, 0xFE, 0x0E, 0xAF, 0x26, 0x18, 0xFC, 0x9C, 0x20, 0x13, 0xD0, 0x6C, 0x5E, 0x43, 0x6B, 0x73, 0xEC, 0x1D, 0xD1, 0xF8, 0x6A, 0xAB, 0xCD, 0xCC, 0x26, 0x9B, 0xCC, 0x28, 0xF9, 0x50, 0x9B, 0x56, 0x8B, 0x99, 0x6F, 0x9E, 0xFF, 0x4E, 0x6D, 0x60, 0xFB, 0x0D, 0x37}, + {0x5C, 0xA4, 0xB2, 0xA3, 0xE5, 0x03, 0x97, 0x01, 0x5D, 0x8F, 0xAF, 0xE8, 0xE3, 0xD4, 0x76, 0xA3, 0x1C, 0xB9, 0x1D, 0x37, 0x74, 0x41, 0x5D, 0xFD, 0xC2, 0xEC, 0x2A, 0xC1, 0x5D, 0xC9, 0x32, 0x73, 0x34, 0xB3, 0x9F, 0x8A, 0x80, 0xA1, 0x88, 0x08, 0x1F, 0xCD, 0x2A, 0xEF, 0xE5, 0x90, 0x3A, 0x7E, 0xBD, 0xEF, 0x99, 0xB3, 0x7E, 0xB4, 0xF5, 0x96, 0xBD, 0x4D, 0xBF, 0x54, 0x34, 0xD2, 0xA5, 0xE3}, + {0x2F, 0x6D, 0x9E, 0xC1, 0xAE, 0xFD, 0xFE, 0x9F, 0x29, 0x40, 0xE5, 0xD9, 0x91, 0x48, 0xCE, 0x9D, 0x8C, 0x61, 0x94, 0x51, 0xB7, 0xBF, 0x03, 0x07, 0x94, 0xC9, 0xD6, 0x0E, 0x19, 0x66, 0x76, 0xA4, 0x80, 0xAE, 0x71, 0x59, 0x90, 0xE2, 0x8C, 0xF2, 0x45, 0xB0, 0x42, 0x65, 0xAC, 0x2E, 0x77, 0xE8, 0x73, 0x86, 0xDE, 0x17, 0x5C, 0x4F, 0x72, 0x42, 0x37, 0x4F, 0x55, 0xAD, 0x99, 0x02, 0x13, 0x26}, + {0x51, 0x44, 0x30, 0x3B, 0x4E, 0x14, 0xA1, 0xD7, 0xE9, 0xC3, 0xA5, 0xA8, 0xD5, 0x61, 0xE4, 0x4A, 0x1F, 0xE5, 0xF9, 0x65, 0x4D, 0x46, 0x0F, 0xFB, 0xDB, 0x19, 0x50, 0xF9, 0xA4, 0xD2, 0xE5, 0x55, 0xA8, 0x7B, 0x60, 0xEE, 0xBA, 0xCB, 0x21, 0xAA, 0x70, 0x9C, 0x64, 0x8B, 0x2A, 0x34, 0x98, 0x05, 0x56, 0xB1, 0x08, 0x58, 0x74, 0x39, 0x04, 0x86, 0x7F, 0x74, 0xBB, 0xA5, 0x4E, 0x81, 0x11, 0xCF}, + {0xF5, 0xC0, 0xE3, 0xA5, 0xA0, 0x65, 0xDA, 0x3C, 0x6C, 0xCB, 0x6C, 0xD0, 0x11, 0x88, 0x35, 0x99, 0x2E, 0x0D, 0xEE, 0xC1, 0x1A, 0x6F, 0x91, 0xA7, 0x5B, 0x1A, 0xB2, 0x21, 0x0B, 0x2C, 0xC9, 0x54, 0xB0, 0x13, 0x23, 0xB1, 0xD6, 0xFC, 0xAA, 0x5C, 0x45, 0x93, 0xD6, 0x2A, 0x60, 0xFB, 0x74, 0x68, 0xCE, 0x39, 0x0C, 0x4C, 0x9A, 0x25, 0xCF, 0x30, 0x24, 0xCD, 0xEC, 0x66, 0x23, 0x66, 0x7C, 0xAA}, + {0x8F, 0x31, 0xB0, 0x12, 0xE0, 0x11, 0x7D, 0x95, 0xBF, 0xC9, 0x78, 0x05, 0x5E, 0xC5, 0xFF, 0x7D, 0x1F, 0x2A, 0x63, 0x5B, 0x11, 0x72, 0x29, 0xF9, 0x5B, 0x50, 0x82, 0x5D, 0xDF, 0x42, 0x61, 0x92, 0xDA, 0xF3, 0xC2, 0xC0, 0x34, 0x72, 0x6F, 0xB4, 0x67, 0x14, 0x0F, 0x68, 0xC4, 0xFD, 0x64, 0xBF, 0x2C, 0x34, 0x59, 0x71, 0xAD, 0xF4, 0xB0, 0x64, 0xD5, 0xC5, 0xE3, 0x5E, 0x87, 0xD2, 0x33, 0xAB}, + {0xE4, 0xE8, 0xED, 0xFB, 0xF1, 0x95, 0xFD, 0x0A, 0xB0, 0x55, 0x1A, 0xF9, 0x0F, 0x10, 0xDF, 0xC7, 0xD8, 0xC0, 0xC2, 0x63, 0x09, 0x11, 0x7A, 0xC6, 0x90, 0x27, 0x6B, 0x72, 0xE3, 0xFC, 0x3B, 0x81, 0x39, 0x54, 0x9C, 0x95, 0xFA, 0x83, 0x71, 0x57, 0x28, 0xD6, 0x1B, 0x98, 0x8D, 0xA6, 0x90, 0x67, 0x44, 0x5D, 0xE5, 0xE4, 0x70, 0xA9, 0x96, 0x2B, 0x80, 0x06, 0x5F, 0x52, 0xB9, 0x0B, 0x22, 0x2F}, + {0x6F, 0xAF, 0xE6, 0x01, 0x46, 0xB8, 0x5C, 0xB9, 0xB1, 0xC8, 0x1D, 0x9B, 0xEA, 0x29, 0xFE, 0x16, 0x6C, 0x8F, 0x11, 0x2D, 0x74, 0x29, 0xC1, 0x6B, 0x6A, 0x89, 0x51, 0x6F, 0xCA, 0xE0, 0x31, 0x11, 0xC1, 0xF7, 0xA3, 0xE7, 0x02, 0x91, 0x0D, 0x7C, 0xFB, 0x09, 0xFE, 0x5B, 0x95, 0x7D, 0x57, 0xC4, 0x21, 0x96, 0xA8, 0xF1, 0x92, 0x5B, 0x94, 0x97, 0x79, 0x19, 0xBE, 0x82, 0x0D, 0x6E, 0x28, 0xA4}, + {0xAA, 0x14, 0xF6, 0x6F, 0xF4, 0xAA, 0xAC, 0x9D, 0xDB, 0xB6, 0x00, 0x60, 0x2F, 0x0C, 0xA5, 0x43, 0xF7, 0x95, 0x24, 0xB9, 0x7F, 0x3F, 0xFA, 0x84, 0xEA, 0x9B, 0x94, 0x53, 0xA7, 0x76, 0xB1, 0x9C, 0xCD, 0xD3, 0x5E, 0x19, 0x4D, 0x6B, 0x11, 0x69, 0x0B, 0x5E, 0x1A, 0xD7, 0x80, 0x0A, 0xBE, 0x76, 0xEF, 0xEC, 0xB0, 0x33, 0x89, 0x16, 0x91, 0x44, 0x33, 0x5F, 0xFE, 0x20, 0x4C, 0xCA, 0xEF, 0x17}, + {0x3E, 0x34, 0xF3, 0xC5, 0x02, 0x7D, 0x9E, 0x4F, 0x39, 0xF0, 0x0B, 0x6D, 0x3A, 0x4F, 0x7D, 0x90, 0xB6, 0x13, 0x2D, 0x79, 0x7F, 0xEF, 0xE2, 0x1C, 0x09, 0x2F, 0x2A, 0x7A, 0xC2, 0xFD, 0x62, 0x46, 0x76, 0x35, 0xD6, 0xB1, 0xEC, 0x7A, 0xB1, 0x15, 0x09, 0x71, 0xBD, 0x2B, 0x90, 0xD5, 0xD3, 0x2C, 0x15, 0xC9, 0x89, 0xE0, 0x19, 0x7F, 0x47, 0xAD, 0xB4, 0x32, 0xDA, 0xFD, 0x93, 0x4D, 0x67, 0x77}, + {0x45, 0xE9, 0x02, 0xFC, 0xD0, 0x87, 0xC0, 0xDA, 0x65, 0x3C, 0xA3, 0xD0, 0x5C, 0x4E, 0x35, 0x52, 0xEE, 0xE8, 0x85, 0x24, 0xD6, 0xEC, 0xE3, 0x84, 0x53, 0xE3, 0xC9, 0x53, 0xB9, 0x1B, 0x63, 0x77, 0x37, 0x02, 0x70, 0x90, 0x5A, 0x84, 0x74, 0x38, 0xB8, 0xE5, 0x18, 0x23, 0x62, 0xA5, 0x8F, 0x52, 0x26, 0x65, 0xA4, 0xD6, 0x36, 0xF7, 0x5A, 0x1C, 0xF8, 0x45, 0xB8, 0x78, 0x27, 0x15, 0xCF, 0xA4}, + {0xB4, 0xEF, 0x59, 0x0A, 0xC1, 0xCD, 0xBE, 0x3C, 0x07, 0x02, 0xA6, 0x04, 0xB7, 0x46, 0x34, 0x94, 0xE2, 0x7E, 0xD4, 0x97, 0xDA, 0x69, 0xAE, 0x6A, 0x9D, 0xD2, 0xA4, 0x81, 0x50, 0x04, 0x04, 0xFE, 0x65, 0xD7, 0x5B, 0xF3, 0x5E, 0xB8, 0x66, 0x10, 0xAB, 0x32, 0x8B, 0x94, 0x45, 0x93, 0xDC, 0x67, 0xCC, 0xBC, 0x43, 0xF6, 0xAE, 0x9B, 0x92, 0xA1, 0x85, 0xF9, 0x2B, 0x66, 0x4C, 0xC2, 0x96, 0xC0}, + {0x5A, 0x97, 0xEA, 0x4D, 0x96, 0x80, 0x13, 0x2B, 0xB9, 0x47, 0x3A, 0x14, 0x8C, 0xE3, 0x4A, 0xC5, 0x7E, 0xBA, 0xD1, 0x61, 0xCD, 0x8B, 0x9D, 0xAA, 0xB0, 0x79, 0x58, 0x41, 0xE7, 0x5D, 0x4C, 0xC5, 0xA9, 0x98, 0xB5, 0x78, 0x23, 0x62, 0xDD, 0x1B, 0x13, 0xE6, 0xFA, 0x6A, 0x33, 0x49, 0x67, 0xDA, 0xD5, 0x74, 0xB2, 0x6A, 0x7F, 0xCA, 0x50, 0x4B, 0x08, 0x09, 0xEC, 0x28, 0x04, 0x58, 0x69, 0x5B}, + {0xD8, 0x82, 0x09, 0x03, 0xB2, 0x5D, 0x5E, 0xC0, 0x92, 0x6C, 0x08, 0xF0, 0x19, 0xC5, 0xC2, 0xFE, 0x45, 0x0B, 0xE0, 0xE9, 0xEC, 0x36, 0x09, 0xBA, 0x68, 0x0F, 0xF1, 0x33, 0xC9, 0xE1, 0xE3, 0xAF, 0xD8, 0x12, 0x77, 0x1B, 0xD0, 0x1B, 0x41, 0x79, 0x6B, 0xA7, 0x80, 0x01, 0x4B, 0xE6, 0x7A, 0x8D, 0xF6, 0x27, 0x2B, 0x94, 0x84, 0x71, 0x39, 0xB3, 0x7C, 0x19, 0x67, 0xAA, 0x2A, 0x3D, 0x00, 0xDD}, + {0x2E, 0x14, 0x63, 0x45, 0xB3, 0x01, 0xB5, 0xAC, 0xA9, 0x62, 0x6C, 0xAB, 0xDF, 0x57, 0x60, 0xC1, 0x70, 0xB2, 0xDF, 0x7A, 0xA6, 0xBC, 0x91, 0x36, 0x62, 0x68, 0xD7, 0x85, 0xD8, 0x49, 0xCB, 0x5A, 0xD0, 0x0B, 0xDD, 0xBA, 0x7C, 0x24, 0xAC, 0xA2, 0x6A, 0x23, 0x68, 0x43, 0xC9, 0xEB, 0xD0, 0xF7, 0x4C, 0x50, 0xFE, 0xF3, 0x61, 0x09, 0x1C, 0xAC, 0x68, 0xEE, 0xE7, 0x7A, 0x46, 0xC8, 0x8E, 0xC9}, + {0xF5, 0x43, 0x08, 0xCD, 0x7D, 0x35, 0x0B, 0x38, 0x1B, 0xAD, 0x4C, 0xF1, 0x6E, 0x65, 0xCC, 0xBF, 0x68, 0x1F, 0x47, 0x6F, 0x10, 0x1B, 0x9B, 0x25, 0xCC, 0x4F, 0x1C, 0x2C, 0x8F, 0x46, 0xEB, 0x7D, 0x8F, 0x1C, 0x86, 0x8E, 0x36, 0x16, 0x1F, 0x97, 0x76, 0x2B, 0xBC, 0x35, 0xEF, 0x75, 0x79, 0xFD, 0x3B, 0x14, 0xCE, 0x2E, 0x2E, 0x28, 0x66, 0x75, 0x48, 0xF5, 0xE6, 0x5E, 0xAD, 0x56, 0xC4, 0x17}, + {0xE2, 0x18, 0x6D, 0x9A, 0x9F, 0x91, 0x97, 0x20, 0xC9, 0x03, 0x30, 0x85, 0x40, 0x69, 0x4D, 0x9B, 0x13, 0xB0, 0x9E, 0xC5, 0x83, 0x17, 0x5B, 0x36, 0xC4, 0x55, 0x27, 0x4F, 0xBC, 0xEE, 0x3A, 0x22, 0x70, 0x00, 0x2F, 0xD6, 0xE5, 0x24, 0x18, 0x93, 0xE9, 0xA0, 0x78, 0x87, 0x65, 0x74, 0x4B, 0x98, 0x91, 0x66, 0x56, 0xA6, 0x39, 0xFF, 0x89, 0x62, 0xC4, 0xE3, 0x13, 0x28, 0x0E, 0x2A, 0x24, 0x30}, + {0x7C, 0x9F, 0x62, 0xDD, 0xFB, 0x7A, 0x03, 0x31, 0x3E, 0xD9, 0x55, 0x44, 0xAC, 0xCC, 0xD1, 0xB3, 0x5F, 0x94, 0x11, 0x2C, 0x14, 0xF2, 0xBB, 0x8D, 0xD8, 0xFD, 0xF3, 0xC5, 0xDB, 0xA3, 0x3A, 0xE5, 0x3B, 0xC7, 0xBD, 0x2F, 0xFC, 0xEE, 0x50, 0xC3, 0x7A, 0xE3, 0xCA, 0x49, 0x8C, 0x67, 0xF6, 0x1C, 0x3C, 0x15, 0xA2, 0x21, 0x5F, 0x6C, 0x21, 0x88, 0xAC, 0xD3, 0xA5, 0xFC, 0x01, 0x43, 0x18, 0x20}, + {0x36, 0x02, 0x67, 0x7B, 0x52, 0x9F, 0x5D, 0xFB, 0x52, 0x0F, 0x13, 0x83, 0x2F, 0xC4, 0xC0, 0x2C, 0x35, 0xD7, 0x4A, 0x61, 0x63, 0x3A, 0x0F, 0x25, 0x41, 0xD1, 0x06, 0x5A, 0x61, 0xC8, 0xEE, 0xDE, 0xBF, 0xA5, 0x28, 0xA1, 0x3C, 0x01, 0xB4, 0x6C, 0x7A, 0x14, 0x72, 0x92, 0xE9, 0x38, 0x70, 0xEC, 0xC5, 0xA0, 0xE2, 0x8C, 0xBD, 0x7F, 0x2D, 0xCE, 0x55, 0x5C, 0xD0, 0xBB, 0xF3, 0xBA, 0x6F, 0x05}, + {0x90, 0xC4, 0xA8, 0xAA, 0xCF, 0x35, 0xAD, 0xA0, 0x66, 0x01, 0x3C, 0xEA, 0xAE, 0x9B, 0x99, 0xF4, 0x7F, 0xF2, 0x74, 0xBB, 0x0B, 0xC2, 0x52, 0x7A, 0xAB, 0x0E, 0xD5, 0xA6, 0x29, 0x6D, 0x70, 0x2E, 0xAF, 0x65, 0x46, 0x36, 0x04, 0xC0, 0xB7, 0xDC, 0xEF, 0x15, 0x17, 0x7D, 0xF2, 0x7B, 0x0A, 0x95, 0x32, 0x1B, 0x89, 0xED, 0xA5, 0x97, 0xC0, 0xF7, 0xC6, 0x10, 0x34, 0x31, 0xE4, 0x27, 0xEE, 0x92}, + {0xC1, 0x31, 0xE4, 0x62, 0x53, 0xA4, 0x62, 0xFE, 0x9F, 0x94, 0xD3, 0xAB, 0xFF, 0x29, 0x0C, 0xDA, 0xCB, 0x35, 0x67, 0xC8, 0x1A, 0xF3, 0x45, 0x75, 0x2E, 0xE2, 0x84, 0xE8, 0xFC, 0x92, 0x0E, 0x83, 0x0B, 0x06, 0x70, 0xB0, 0xFA, 0xE8, 0xA0, 0x2F, 0x49, 0x04, 0xE7, 0x79, 0x3D, 0x33, 0x38, 0xDA, 0x2E, 0x71, 0xA7, 0xB5, 0x16, 0x3E, 0x9F, 0x7C, 0x84, 0x3B, 0x9C, 0x4C, 0x6F, 0x50, 0x7E, 0xB3}, + {0xA4, 0xB1, 0x69, 0x84, 0x6E, 0x68, 0x76, 0xCD, 0x53, 0xFF, 0x4D, 0x7F, 0xC5, 0xCD, 0x23, 0x7A, 0x74, 0xF7, 0x96, 0x28, 0xCB, 0x2D, 0xE7, 0x5E, 0xE9, 0x2E, 0xD5, 0x9D, 0x83, 0x19, 0x66, 0x76, 0x4B, 0xA3, 0xA0, 0x08, 0xA1, 0xA7, 0x6C, 0xCB, 0x2E, 0x8E, 0xB3, 0xF8, 0x9F, 0x62, 0x19, 0xC2, 0xE4, 0xF9, 0x0C, 0x5A, 0x84, 0x2C, 0x87, 0x45, 0x36, 0x49, 0xDD, 0x34, 0x93, 0x07, 0x6B, 0x9C}, + {0xAE, 0x7B, 0xD1, 0xC9, 0xF6, 0xE5, 0x58, 0x73, 0x5E, 0x41, 0xC2, 0x54, 0x7E, 0xCD, 0xD2, 0x61, 0x9C, 0x24, 0x85, 0xE5, 0xAE, 0xE5, 0x34, 0xD3, 0xA3, 0x3F, 0xBD, 0x9B, 0xB0, 0xB1, 0x4F, 0xAC, 0xD3, 0x42, 0xF3, 0xE2, 0xD8, 0xC0, 0x26, 0x56, 0x6F, 0x1F, 0x3B, 0x16, 0x7E, 0xA0, 0xD6, 0x96, 0x4E, 0xB0, 0xE4, 0x59, 0xE3, 0x2D, 0xE7, 0xF2, 0x86, 0x46, 0x33, 0x07, 0x8E, 0x2D, 0xBF, 0x11}, + {0x86, 0xB9, 0xBA, 0xC2, 0xFA, 0xAB, 0x84, 0xA2, 0x9B, 0x13, 0xE3, 0xD5, 0xA5, 0x9B, 0x1E, 0xF6, 0x8D, 0x3A, 0x48, 0x46, 0x9C, 0x84, 0xB5, 0x06, 0x5D, 0xB6, 0x78, 0xF8, 0xCA, 0x8A, 0xEC, 0x42, 0xE4, 0x06, 0x79, 0x08, 0x29, 0x2A, 0xC6, 0x90, 0xFE, 0x90, 0xD0, 0x62, 0x90, 0xCD, 0x0A, 0xF9, 0x73, 0x8B, 0x6D, 0x7D, 0x6A, 0xD3, 0xE2, 0x0D, 0xD2, 0xE6, 0xF5, 0x9A, 0xE5, 0xC8, 0xC8, 0xA5}, + {0x8C, 0x42, 0x57, 0x6C, 0x60, 0xE4, 0xDB, 0x62, 0xE6, 0xD6, 0x77, 0x16, 0x10, 0xCA, 0x2A, 0x6E, 0x4F, 0xC0, 0xB8, 0x33, 0xFB, 0x87, 0xB9, 0x4D, 0xF7, 0xB4, 0x61, 0x45, 0x9D, 0xD7, 0xB3, 0x5E, 0x8F, 0x3A, 0xFC, 0xBC, 0xD7, 0x99, 0xC6, 0x6D, 0x02, 0xE5, 0xA6, 0xD3, 0x40, 0x46, 0xB0, 0x29, 0x54, 0x31, 0xDB, 0xF9, 0xF0, 0xEF, 0xD9, 0x8D, 0x5D, 0xA1, 0xCA, 0x8C, 0xCF, 0x25, 0x70, 0x4F}, + {0x21, 0x1F, 0xCA, 0xD6, 0xA1, 0x7A, 0x95, 0x31, 0x04, 0x5B, 0x88, 0x03, 0xA0, 0x31, 0x5E, 0x90, 0xE5, 0x1D, 0x4D, 0xEC, 0xC6, 0xC1, 0x5B, 0x6B, 0x6D, 0xEC, 0x4D, 0xB7, 0x19, 0xB5, 0x34, 0x61, 0xA0, 0x04, 0x03, 0x43, 0xE4, 0xBF, 0x81, 0x1B, 0xCE, 0x16, 0x04, 0x31, 0xC7, 0x4B, 0x95, 0x06, 0x0F, 0x19, 0x78, 0x7F, 0xA5, 0x95, 0xA6, 0xCD, 0x30, 0xDF, 0xA6, 0x0C, 0x43, 0x0D, 0xE6, 0xDB}, + {0xC6, 0x05, 0x83, 0x5D, 0x01, 0x33, 0x21, 0x89, 0xAC, 0x95, 0xA7, 0x74, 0x28, 0xAC, 0xD7, 0xF6, 0xEA, 0x21, 0xB1, 0x65, 0xB1, 0x50, 0x22, 0x79, 0xE1, 0x76, 0x8C, 0xDF, 0x56, 0x7E, 0x66, 0x64, 0x01, 0x1E, 0x67, 0x92, 0x10, 0x06, 0xA2, 0x75, 0xC7, 0x91, 0x7A, 0x82, 0x98, 0x38, 0x6B, 0x21, 0x7F, 0xE7, 0xE5, 0xD3, 0x84, 0x8D, 0x4F, 0xB6, 0xDD, 0x06, 0xA9, 0x17, 0x96, 0xB6, 0x78, 0x10}, + {0x8A, 0xCD, 0x34, 0x37, 0x3A, 0x64, 0x8D, 0x73, 0x2F, 0x0F, 0x06, 0xA9, 0xD3, 0xCC, 0x7F, 0x7B, 0xB4, 0x9C, 0xDE, 0xA5, 0x50, 0xBC, 0xC9, 0x0D, 0xE7, 0x8A, 0xF3, 0xF5, 0x3E, 0x95, 0xBC, 0xBF, 0xA8, 0x9E, 0x93, 0x17, 0xC5, 0xC9, 0xA7, 0x37, 0xE4, 0xF6, 0x7E, 0xBA, 0x72, 0x5F, 0x56, 0x20, 0x5F, 0xE7, 0x94, 0x72, 0x3B, 0x25, 0x94, 0x92, 0x19, 0x85, 0x39, 0x12, 0xF5, 0x81, 0xC5, 0x1F}, + {0x9B, 0xCA, 0x98, 0x2A, 0xB3, 0x00, 0x10, 0xE8, 0xBE, 0xA1, 0x90, 0x2A, 0xA2, 0x4D, 0x84, 0xEE, 0xEC, 0x20, 0x9C, 0xEA, 0x63, 0xA2, 0xD0, 0x72, 0xCE, 0xD4, 0x18, 0x7F, 0x58, 0x01, 0x27, 0xAA, 0x43, 0x11, 0x97, 0x98, 0xD2, 0x2F, 0x94, 0xD6, 0x1C, 0x5C, 0x61, 0x90, 0xB2, 0x8F, 0xE9, 0xAD, 0x9A, 0x4D, 0xD6, 0x5D, 0xE3, 0xC7, 0x82, 0x80, 0xD0, 0x91, 0x93, 0xF1, 0x66, 0x1C, 0x8D, 0xD4}, + {0x88, 0x0F, 0x5E, 0x28, 0xCE, 0xA7, 0x88, 0xEC, 0x6C, 0xF9, 0xD2, 0xCB, 0x4C, 0xD5, 0x17, 0x9D, 0xDE, 0xA7, 0xEC, 0x69, 0xE9, 0xB2, 0xE2, 0x9B, 0x58, 0xBA, 0x50, 0x32, 0xF3, 0x67, 0x92, 0x2A, 0x14, 0x5C, 0x32, 0x3B, 0x55, 0x28, 0xF6, 0xB6, 0x46, 0xEF, 0x91, 0xE8, 0x81, 0x41, 0x60, 0x08, 0x76, 0xA9, 0x14, 0xD0, 0x7A, 0x50, 0x7D, 0xF8, 0x04, 0xE1, 0x88, 0xA2, 0x6E, 0x9E, 0x22, 0x04}, + {0x28, 0xCB, 0x93, 0x91, 0x83, 0x21, 0xFA, 0x55, 0x72, 0x77, 0x0F, 0x2A, 0x30, 0xB1, 0xDE, 0xDA, 0x53, 0xF4, 0xD6, 0x5D, 0x8B, 0xA0, 0x5A, 0x79, 0x67, 0x4A, 0x3C, 0x4A, 0x28, 0x1E, 0xDD, 0x2A, 0xAE, 0xB8, 0x06, 0xFD, 0x13, 0xBB, 0x4C, 0x73, 0x52, 0xD0, 0x61, 0xF2, 0xEE, 0xC5, 0x54, 0xF5, 0x69, 0xC1, 0x3C, 0xD5, 0x9E, 0xE2, 0x76, 0x60, 0x52, 0x7E, 0x89, 0x58, 0xB7, 0xAF, 0x21, 0x9C}, + {0xA6, 0x9B, 0x3A, 0xE4, 0xBB, 0x8A, 0x0E, 0x2E, 0xD0, 0x63, 0x5E, 0x66, 0x18, 0xDB, 0x5D, 0x9A, 0x03, 0x59, 0xD2, 0x80, 0x2C, 0x37, 0x5D, 0x20, 0xB6, 0xF4, 0xD7, 0x37, 0xBA, 0xF9, 0x12, 0xDE, 0xC1, 0x19, 0x18, 0xA8, 0x7E, 0x83, 0xAD, 0xC2, 0x0D, 0x51, 0x53, 0xDB, 0x2B, 0x3A, 0x34, 0x0A, 0x0F, 0x2D, 0x30, 0x3F, 0xC1, 0x7D, 0xEF, 0xC3, 0xA8, 0x79, 0xED, 0x0C, 0x30, 0xFD, 0x9B, 0x77}, + {0x87, 0x5D, 0x25, 0x3C, 0x52, 0xB3, 0xB4, 0x5A, 0x7D, 0xEF, 0xB4, 0xD8, 0x86, 0x29, 0x35, 0xFA, 0x1E, 0x3E, 0x06, 0xC5, 0x1F, 0x8A, 0xC8, 0xDE, 0xD7, 0x17, 0xCC, 0xB1, 0xB3, 0x27, 0x37, 0x24, 0x83, 0x0F, 0x29, 0x50, 0xB5, 0x86, 0xB9, 0xDD, 0xDF, 0xF6, 0x71, 0x19, 0xFB, 0x19, 0x44, 0x19, 0xB8, 0xD2, 0x04, 0x32, 0x2A, 0x88, 0xE0, 0x5F, 0xC6, 0x63, 0x0D, 0x59, 0x23, 0xCC, 0xD6, 0xFC}, + {0x90, 0xE4, 0x91, 0xF1, 0xFD, 0x31, 0x8E, 0x46, 0x4D, 0x17, 0x5C, 0x6D, 0x77, 0x93, 0x9E, 0xA5, 0x01, 0xDC, 0x4A, 0x08, 0xBA, 0xDE, 0xFC, 0xE3, 0x0A, 0xCE, 0x64, 0xD1, 0xCD, 0xFB, 0x3B, 0x14, 0x9F, 0x2A, 0xDA, 0x8E, 0x6B, 0xF9, 0x30, 0x9B, 0x0C, 0xF6, 0xF2, 0x2D, 0xF4, 0x46, 0x9D, 0x6F, 0x36, 0xAC, 0xF0, 0xC3, 0xBF, 0x0C, 0x70, 0xE7, 0xB4, 0xED, 0x14, 0x90, 0x1F, 0x82, 0x13, 0xD8}, + {0xBF, 0xC0, 0xEE, 0x1E, 0xB0, 0x6C, 0x37, 0x11, 0x8B, 0x94, 0x53, 0x93, 0xBA, 0xBF, 0x40, 0xF3, 0xC8, 0xCF, 0x15, 0xE9, 0x8F, 0xF1, 0x44, 0xB4, 0xB4, 0x25, 0x76, 0xA4, 0xD3, 0xB3, 0xE5, 0x49, 0xA8, 0x21, 0xAF, 0x95, 0x82, 0x90, 0xDE, 0x7A, 0xFD, 0x4A, 0x65, 0x90, 0xD0, 0x14, 0xEF, 0x68, 0x4E, 0xC4, 0x66, 0x46, 0x9B, 0x57, 0x84, 0x09, 0xBE, 0x72, 0xAF, 0x69, 0x9D, 0xF3, 0xB4, 0x56}, + {0xAB, 0x6C, 0x83, 0x26, 0x35, 0x06, 0xD6, 0x3F, 0xF0, 0x90, 0x18, 0xF2, 0x68, 0x78, 0x55, 0x42, 0xD1, 0x6E, 0xF0, 0x84, 0x14, 0x95, 0x5F, 0x1B, 0xB2, 0xE2, 0x61, 0x4F, 0x12, 0x0A, 0x30, 0x67, 0x81, 0xCA, 0xD3, 0xF2, 0x14, 0x85, 0xDD, 0x19, 0x86, 0x8C, 0x0B, 0xD5, 0xE2, 0x6B, 0x64, 0xCD, 0xCA, 0x28, 0xD8, 0x3C, 0x15, 0x77, 0x13, 0x54, 0x2E, 0xF5, 0x63, 0x60, 0x54, 0xFC, 0x34, 0x36}, + {0x6B, 0xC9, 0xC4, 0x20, 0xF0, 0x2E, 0x49, 0xED, 0x9B, 0x56, 0x39, 0xED, 0x6F, 0x77, 0x66, 0x9C, 0xEF, 0x0D, 0x8C, 0xC8, 0xF8, 0xA9, 0xBB, 0x1D, 0xB5, 0x23, 0xCC, 0x03, 0x52, 0xE0, 0xDB, 0x68, 0x85, 0xF5, 0x71, 0x4C, 0x3C, 0x43, 0xE6, 0xA7, 0xC3, 0x68, 0x24, 0x20, 0x3B, 0x95, 0x12, 0x88, 0x1B, 0x10, 0x7E, 0x32, 0xCF, 0x62, 0xE6, 0x68, 0x05, 0xDD, 0xBD, 0xD3, 0x5C, 0x8A, 0xFE, 0x45}, + {0xAA, 0xCF, 0x31, 0x66, 0xBE, 0x40, 0x87, 0xA1, 0x33, 0x97, 0xFE, 0x00, 0x63, 0x56, 0xA0, 0x3B, 0x9C, 0x91, 0x85, 0xB0, 0xBC, 0x45, 0xB2, 0xC3, 0x5B, 0xFC, 0xF6, 0xBF, 0x0E, 0x7D, 0x45, 0xED, 0x7F, 0x3D, 0xF2, 0xAD, 0xE8, 0x87, 0x4D, 0xA6, 0x0B, 0xC5, 0xDE, 0xE8, 0x42, 0x42, 0x5A, 0x0B, 0x4B, 0xC4, 0x53, 0x06, 0xE3, 0xFD, 0x2E, 0x81, 0xE3, 0x1F, 0x93, 0x59, 0x4B, 0xB3, 0xE9, 0x7F}, + {0xCC, 0x53, 0x39, 0xF3, 0x46, 0x79, 0x35, 0x33, 0x73, 0xF7, 0x78, 0xFA, 0x1A, 0x91, 0xE4, 0xFC, 0x8B, 0x17, 0xFE, 0xA3, 0x19, 0x3C, 0x38, 0x7D, 0x08, 0xE2, 0x4F, 0x11, 0xF9, 0xEC, 0x55, 0x36, 0x4A, 0x4E, 0xBC, 0x13, 0x38, 0x4C, 0x75, 0x1F, 0x95, 0x0E, 0xAE, 0x8A, 0x49, 0xD1, 0x93, 0x14, 0xA4, 0x93, 0xA6, 0x19, 0x59, 0xB9, 0x8A, 0xAE, 0xEB, 0x91, 0x21, 0x72, 0x2C, 0x91, 0x45, 0xD7}, + {0x39, 0x18, 0xD6, 0xEB, 0x9A, 0x66, 0x70, 0xEE, 0xB6, 0x7A, 0xC8, 0x4C, 0xCE, 0x84, 0x9F, 0x37, 0x8E, 0xAE, 0x52, 0xAB, 0x65, 0x56, 0x58, 0x6A, 0xBE, 0x17, 0xFF, 0xB4, 0x95, 0x29, 0x99, 0x48, 0x59, 0xEC, 0x95, 0x01, 0x32, 0x27, 0x9E, 0xF8, 0x8E, 0x9D, 0x21, 0x7F, 0x08, 0x9E, 0x75, 0x49, 0xB6, 0xF6, 0xAA, 0x57, 0xEF, 0x13, 0x48, 0xE7, 0xDB, 0x9B, 0x7A, 0xDF, 0x4B, 0x59, 0xCC, 0xC1}, + {0xCA, 0x9B, 0xCC, 0xE9, 0x69, 0x0E, 0xD1, 0x3C, 0x94, 0x05, 0x6C, 0x29, 0x4F, 0xE6, 0xF5, 0x22, 0xF6, 0xB7, 0x20, 0x15, 0x52, 0xA1, 0x00, 0xA3, 0xB6, 0xC6, 0x03, 0x8D, 0x07, 0x88, 0x54, 0xDF, 0x26, 0xF2, 0xF4, 0x42, 0x98, 0xC0, 0xC6, 0x30, 0xCC, 0x7C, 0x14, 0x4C, 0xE5, 0x27, 0x99, 0xA5, 0x3F, 0xF3, 0xAD, 0x00, 0xA9, 0xBE, 0xAF, 0x48, 0x8E, 0xF0, 0x5B, 0x10, 0xAF, 0xFE, 0x9A, 0x4B}, + {0x65, 0x63, 0x25, 0x07, 0xDB, 0x0B, 0xEF, 0x39, 0x34, 0x14, 0xB2, 0x8B, 0x4E, 0x5D, 0x39, 0x19, 0x1B, 0x4C, 0x96, 0xA1, 0xEC, 0x9C, 0x6E, 0x24, 0x96, 0xEA, 0xBA, 0x0C, 0xB6, 0xA4, 0xA4, 0x9D, 0xB5, 0xEE, 0xE0, 0x24, 0xE6, 0xF8, 0x31, 0x0E, 0x06, 0xE6, 0xF3, 0xA2, 0x62, 0x37, 0x89, 0xE9, 0x81, 0x5F, 0x18, 0x3A, 0x49, 0x07, 0xEE, 0xFD, 0x75, 0xCF, 0x19, 0x2E, 0x68, 0xF2, 0xD8, 0xD1}, + {0x9F, 0x61, 0x21, 0xBC, 0x6A, 0xE3, 0xEA, 0xCD, 0x52, 0x56, 0x1C, 0xA4, 0x65, 0x67, 0xD5, 0x40, 0xCB, 0x25, 0x2A, 0x31, 0x4C, 0xEB, 0xAD, 0x5D, 0x72, 0x12, 0xC6, 0xA4, 0x58, 0xBC, 0x25, 0x5D, 0x25, 0x12, 0x17, 0x64, 0x32, 0x73, 0xC1, 0x5F, 0x22, 0xBE, 0xD8, 0x36, 0xE2, 0xA5, 0xE6, 0x2B, 0xAE, 0xFE, 0xDB, 0x20, 0x2B, 0x08, 0x13, 0x4E, 0x49, 0xF7, 0xBE, 0xBC, 0x2F, 0x42, 0x30, 0xEB}, + {0xE1, 0xF6, 0x0B, 0x62, 0xB4, 0xCA, 0xF3, 0xA3, 0x13, 0x7D, 0xE6, 0xC2, 0x14, 0x1E, 0x71, 0x4C, 0x43, 0x23, 0xEB, 0x09, 0x77, 0xF6, 0xCA, 0xAE, 0xB3, 0xA4, 0x74, 0x0B, 0x6A, 0x9E, 0x4B, 0x8C, 0xDC, 0x00, 0x33, 0x03, 0xDA, 0xEE, 0xAE, 0x29, 0xBA, 0xAA, 0x7E, 0xFF, 0x8C, 0x0D, 0x76, 0x33, 0xD7, 0xD6, 0x69, 0x7E, 0xA5, 0x4E, 0xF3, 0x7D, 0x32, 0x1C, 0xE1, 0xAF, 0x75, 0x9B, 0x40, 0x7D}, + {0xB6, 0x37, 0xB6, 0x9A, 0x8A, 0xC6, 0xEC, 0xC9, 0x63, 0xB9, 0x81, 0x9D, 0x84, 0xE3, 0xDD, 0xA8, 0x2E, 0xC5, 0x82, 0xBF, 0x92, 0xE2, 0xC2, 0x9D, 0xE6, 0xC3, 0xF0, 0x97, 0x96, 0xEB, 0x22, 0x39, 0x22, 0x1E, 0x68, 0xD1, 0x44, 0xED, 0x3E, 0xD3, 0x72, 0x90, 0x79, 0xBE, 0x79, 0x84, 0xE6, 0xAB, 0xB1, 0x74, 0x84, 0x2F, 0x61, 0x8D, 0x75, 0x36, 0x3A, 0x89, 0x95, 0x53, 0xE6, 0xB2, 0x57, 0x56}, + {0xAD, 0x0F, 0xDA, 0x67, 0x1B, 0xAA, 0x61, 0xE4, 0x97, 0x35, 0xD6, 0x13, 0xD4, 0x0F, 0x24, 0x49, 0x10, 0x0C, 0x46, 0x1F, 0x9C, 0xBE, 0xAC, 0x8A, 0xC3, 0xFE, 0x96, 0x36, 0xF1, 0xCD, 0xE6, 0x8F, 0x21, 0x2C, 0x90, 0x25, 0x06, 0x24, 0x0E, 0xF6, 0x82, 0xD2, 0xDA, 0x61, 0x81, 0x6B, 0x9E, 0x3B, 0xE1, 0x85, 0x79, 0x45, 0x15, 0xD2, 0x36, 0xB5, 0x5E, 0x36, 0x3E, 0x60, 0x2C, 0xC0, 0x30, 0x5D}, + {0xD8, 0xED, 0x75, 0x86, 0x1F, 0x10, 0x3D, 0x6B, 0xB2, 0xE5, 0xB5, 0xEC, 0x4A, 0x0E, 0xAB, 0xB2, 0x37, 0xAB, 0x63, 0xD5, 0x17, 0xDD, 0x0C, 0x87, 0x6D, 0xF6, 0x62, 0xEB, 0xD1, 0x12, 0x62, 0x4B, 0x6A, 0xBB, 0xC2, 0x0C, 0xA9, 0x92, 0x92, 0x0A, 0x73, 0x8A, 0x88, 0x16, 0x54, 0x0F, 0x23, 0x66, 0x09, 0x0F, 0x31, 0x74, 0x4E, 0x8B, 0xC4, 0x9C, 0x8B, 0xC6, 0x07, 0x80, 0x6A, 0x0C, 0xEC, 0xD1}, + {0x19, 0x69, 0x10, 0xCC, 0x23, 0xB7, 0xC9, 0x3A, 0x62, 0xD8, 0xE1, 0x7E, 0x89, 0x96, 0xEC, 0xB7, 0x5D, 0x02, 0xA4, 0x68, 0x09, 0xC5, 0x26, 0x5A, 0xA1, 0xF7, 0xD4, 0x86, 0x56, 0xBE, 0x4C, 0xE0, 0x9C, 0x89, 0x2A, 0xBE, 0x08, 0x8E, 0x26, 0x37, 0x70, 0x1F, 0xEA, 0x2F, 0x82, 0x5D, 0x27, 0x13, 0xCA, 0x1C, 0x79, 0x13, 0x78, 0x22, 0xA9, 0xEE, 0xFD, 0x65, 0xA5, 0xB5, 0x8C, 0x58, 0xFB, 0xC1}, + {0x32, 0xDF, 0xA1, 0xA0, 0x8C, 0x24, 0xB2, 0xE3, 0xC4, 0x62, 0xB0, 0x25, 0x6B, 0x51, 0xDB, 0x06, 0xC2, 0x2B, 0x8C, 0x5E, 0x83, 0x90, 0x3F, 0x19, 0xCA, 0x88, 0xA4, 0x91, 0xE1, 0x8C, 0x89, 0x1F, 0xA8, 0x20, 0x6F, 0x7A, 0x85, 0xFC, 0x3E, 0x44, 0xB8, 0x32, 0x33, 0xDC, 0xB3, 0x86, 0x9A, 0x78, 0x52, 0x22, 0xC8, 0xE4, 0x37, 0xC7, 0x2F, 0xCE, 0xE5, 0xFB, 0xF3, 0x2C, 0x2E, 0x87, 0xFD, 0x5E}, + {0x41, 0x49, 0x86, 0x1C, 0x3C, 0x9C, 0x81, 0xE8, 0x9B, 0x60, 0x6E, 0xE4, 0x3D, 0xF9, 0x3B, 0x90, 0x55, 0x71, 0xD1, 0x79, 0x22, 0xAE, 0xA6, 0x45, 0x15, 0x38, 0x84, 0x63, 0x49, 0xF8, 0xF6, 0x36, 0x26, 0x91, 0xA2, 0xF8, 0x97, 0xC1, 0xBA, 0x70, 0x62, 0x6C, 0x87, 0x75, 0x8E, 0xE4, 0xB0, 0x28, 0x10, 0x88, 0xFF, 0x45, 0xB0, 0xBF, 0x9A, 0xDC, 0xC3, 0xDD, 0xC5, 0xBC, 0x66, 0x12, 0x81, 0x6F}, + {0x8F, 0x15, 0x76, 0x94, 0xD8, 0xA3, 0x35, 0xAF, 0x09, 0xA3, 0x7C, 0xB0, 0x1C, 0xBE, 0xFF, 0x46, 0x9D, 0xF8, 0xDF, 0x20, 0x51, 0x82, 0xAD, 0x61, 0x31, 0x78, 0x20, 0xB9, 0x6A, 0xC1, 0xD7, 0xE9, 0xA3, 0xC3, 0x69, 0x77, 0x71, 0xB7, 0x60, 0x91, 0xB4, 0x6E, 0x17, 0x0C, 0xCD, 0x2A, 0xA2, 0x5B, 0x5E, 0xC2, 0xC1, 0xD0, 0x2F, 0xA5, 0x62, 0x37, 0xE4, 0xEA, 0x59, 0x74, 0xF3, 0xF9, 0x5E, 0x85}, + {0xDF, 0x32, 0x0D, 0x5F, 0xF0, 0x98, 0x3E, 0x7A, 0x75, 0x65, 0xB3, 0x2F, 0xF9, 0xEB, 0xC8, 0x48, 0x3C, 0x99, 0xD6, 0x43, 0xEB, 0xDD, 0x5B, 0x9D, 0x82, 0x56, 0x3F, 0x1D, 0x29, 0xA6, 0x49, 0x15, 0x63, 0xC9, 0x26, 0x66, 0xD3, 0x5E, 0x06, 0x95, 0x3F, 0x4D, 0x97, 0x35, 0x0F, 0x52, 0x66, 0xED, 0x8C, 0x29, 0x4A, 0x13, 0x36, 0xEF, 0x70, 0x91, 0x45, 0xB8, 0x38, 0xA3, 0x16, 0x48, 0xE4, 0x88}, + {0x81, 0x9D, 0xCF, 0x22, 0xDF, 0x3A, 0x60, 0xAD, 0x0C, 0x41, 0xA4, 0xFD, 0xBC, 0xCB, 0xA3, 0x4B, 0xD2, 0x4F, 0x7C, 0x0F, 0xDF, 0x82, 0x75, 0x2C, 0xE6, 0xB9, 0xD7, 0xEB, 0xB4, 0xCC, 0x20, 0xD4, 0x37, 0x84, 0x14, 0xE4, 0xDE, 0x39, 0x78, 0x3D, 0x7B, 0x91, 0xC9, 0xD8, 0x87, 0xC9, 0x7F, 0x96, 0xB1, 0x5F, 0xD9, 0xD1, 0xED, 0x67, 0x8E, 0xF7, 0x4C, 0x8F, 0xA8, 0xBD, 0x21, 0x8F, 0xAA, 0x68}, + {0x0E, 0xE4, 0x04, 0x98, 0x7C, 0xF5, 0xD8, 0x83, 0x5B, 0x60, 0xE5, 0xE0, 0x77, 0x3B, 0xC9, 0x78, 0x81, 0x49, 0x85, 0x58, 0x39, 0xA8, 0x2D, 0xCF, 0xB4, 0x73, 0x31, 0xC5, 0xB5, 0xDB, 0xB8, 0x63, 0x17, 0x37, 0x52, 0xC9, 0x85, 0x4C, 0x52, 0x89, 0x88, 0x28, 0xFF, 0x80, 0xAA, 0x9B, 0xEA, 0x0C, 0x6C, 0xEE, 0xF2, 0xB1, 0x4C, 0xA7, 0x95, 0xFE, 0x13, 0xAA, 0xAE, 0xDC, 0xA4, 0xF0, 0x67, 0x82}, + {0xF5, 0x06, 0x83, 0xA6, 0x11, 0xE0, 0x31, 0x9B, 0x98, 0xF4, 0x4D, 0x19, 0xC1, 0x68, 0x83, 0xFB, 0xF2, 0xCC, 0x0A, 0x2A, 0x69, 0xE3, 0xDA, 0x0A, 0xF2, 0x29, 0xFF, 0x4D, 0xB6, 0x1E, 0xD5, 0x17, 0x48, 0xFD, 0xF2, 0x76, 0x54, 0xE4, 0x92, 0x92, 0x4A, 0x26, 0x43, 0xCE, 0xF2, 0xF2, 0xB2, 0x88, 0x6E, 0x71, 0x16, 0xA5, 0xE0, 0x99, 0x18, 0xCB, 0x3D, 0xA3, 0x05, 0xF9, 0x4A, 0xF7, 0x0A, 0xA4}, + {0xEF, 0x4F, 0xCE, 0x4B, 0x22, 0xD0, 0x2E, 0x26, 0x82, 0x90, 0x19, 0x45, 0x58, 0x0C, 0xE4, 0x19, 0x82, 0x6A, 0x66, 0xFE, 0x55, 0xD8, 0x5F, 0x8D, 0xB0, 0x78, 0x2D, 0x9D, 0x9B, 0xA0, 0xE3, 0x75, 0x7D, 0xF6, 0x5E, 0x0B, 0xA3, 0x52, 0xD4, 0x22, 0x11, 0xB9, 0xCA, 0x3A, 0x53, 0x1E, 0x24, 0x2C, 0x16, 0x57, 0xED, 0x9F, 0x09, 0xC7, 0xDF, 0x4F, 0x3D, 0xE7, 0xEB, 0xF2, 0x17, 0xE6, 0xA1, 0xF3}, + {0xCB, 0xF1, 0xAD, 0x79, 0x3E, 0x2E, 0x0B, 0xBB, 0x78, 0x57, 0xB8, 0x44, 0xB7, 0x45, 0x02, 0xDA, 0xB3, 0x15, 0x04, 0x46, 0x0B, 0x8B, 0xFB, 0x3C, 0x7C, 0xF7, 0x0A, 0xEA, 0x32, 0xE2, 0x46, 0xCA, 0x6F, 0xCD, 0xD8, 0xFE, 0x38, 0x89, 0x9E, 0x11, 0x76, 0x45, 0xD4, 0x6B, 0x5A, 0xED, 0x79, 0x93, 0x09, 0xE8, 0x4D, 0x7B, 0x07, 0x56, 0xE3, 0x1D, 0x4B, 0x63, 0xBA, 0x54, 0xA3, 0x00, 0x37, 0x3A}, + {0xC0, 0x6D, 0xC2, 0x46, 0x16, 0xCA, 0xEF, 0x61, 0x8F, 0xE6, 0x6B, 0x37, 0x99, 0xFF, 0x89, 0x5E, 0x2D, 0x27, 0x25, 0xEE, 0x7E, 0x66, 0x57, 0xCA, 0xF6, 0x40, 0xA8, 0xC2, 0xDB, 0xCD, 0x92, 0xC7, 0xB4, 0xBA, 0x85, 0x83, 0x49, 0x87, 0x3E, 0x97, 0xE4, 0xA4, 0xD1, 0x14, 0x57, 0xBD, 0x7F, 0xA8, 0x56, 0xF6, 0x39, 0xB3, 0xD8, 0x52, 0xA8, 0x78, 0x6E, 0x49, 0xBA, 0x8D, 0x36, 0x0E, 0xC0, 0x02}, + {0xD1, 0x9A, 0xF0, 0x70, 0x77, 0xD9, 0xF8, 0xA3, 0x9D, 0xFB, 0xBC, 0xB9, 0x77, 0xC5, 0x3D, 0x88, 0x26, 0xCF, 0x01, 0x41, 0xE7, 0x84, 0x86, 0x36, 0x11, 0xC7, 0xCE, 0xC4, 0x43, 0x1D, 0xF2, 0xF3, 0x64, 0x3B, 0x80, 0x98, 0xBA, 0xB1, 0x85, 0x83, 0xC8, 0xB5, 0xBE, 0x7C, 0x36, 0x4D, 0x8E, 0x8F, 0x65, 0x4C, 0x23, 0xF9, 0x59, 0xCB, 0x0C, 0xA7, 0x46, 0xB1, 0xD3, 0x9A, 0x86, 0x4E, 0x7D, 0x6A}, + {0x9E, 0xBA, 0x84, 0x2D, 0xB4, 0xDB, 0x8C, 0x7A, 0xBB, 0x49, 0x4D, 0xEA, 0x29, 0xF6, 0x9B, 0x78, 0x79, 0x19, 0x04, 0xA5, 0xCB, 0xB2, 0xDC, 0x6C, 0xFF, 0xE4, 0x67, 0x9A, 0x5C, 0x09, 0x4C, 0x42, 0x97, 0xBF, 0xE7, 0x24, 0xE3, 0x8D, 0x62, 0x06, 0x52, 0x26, 0x9E, 0xF1, 0xB9, 0x10, 0x1E, 0xE1, 0x6B, 0x86, 0x7D, 0xF5, 0x86, 0x3B, 0xC8, 0x4D, 0x02, 0xD3, 0xCD, 0x8D, 0x83, 0x17, 0xE2, 0x32}, + {0x28, 0x1F, 0x4B, 0xC6, 0x40, 0x48, 0xF8, 0x58, 0xDF, 0xCD, 0x66, 0xC2, 0x55, 0x37, 0xE0, 0x70, 0xD1, 0x6B, 0x14, 0xC8, 0x8C, 0xBB, 0xE4, 0xE2, 0x30, 0x73, 0x0C, 0xFC, 0x8A, 0x0F, 0x5B, 0xAE, 0xD8, 0x34, 0xE6, 0xF6, 0xA1, 0x28, 0x4D, 0x34, 0xB1, 0xD0, 0x1E, 0x9E, 0x67, 0x36, 0x50, 0x55, 0x09, 0xEB, 0x94, 0x06, 0xEB, 0xF3, 0x73, 0x87, 0x80, 0x47, 0x31, 0x1A, 0x85, 0xD9, 0x07, 0x46}, + {0xCE, 0x54, 0x21, 0x49, 0xF1, 0xCC, 0x38, 0x79, 0x20, 0xB2, 0x27, 0x6B, 0x34, 0x26, 0xCC, 0xF4, 0xFB, 0xEA, 0xD6, 0x41, 0xD4, 0x27, 0x3A, 0xA4, 0xE9, 0x3E, 0xA9, 0xF8, 0x7E, 0x31, 0xB0, 0x07, 0x3A, 0x63, 0xAD, 0x2C, 0xCE, 0xDC, 0xA9, 0x13, 0x14, 0xBC, 0x44, 0x65, 0xC7, 0x92, 0xCB, 0x6F, 0x85, 0xCD, 0xB4, 0x80, 0x2D, 0x0F, 0x96, 0xB4, 0x94, 0xBF, 0xC2, 0xCD, 0xC7, 0x81, 0x25, 0x8B}, + {0xC7, 0xAB, 0x09, 0x9C, 0xF7, 0x75, 0x32, 0x1E, 0x33, 0xEB, 0x5E, 0xE0, 0xC6, 0xD3, 0xA2, 0xFE, 0xF1, 0xE5, 0x4F, 0xD2, 0xAF, 0x69, 0x6D, 0x8F, 0x5C, 0x62, 0x82, 0x3D, 0xB2, 0xAA, 0x5F, 0xEA, 0x18, 0xAB, 0x7A, 0x85, 0x75, 0x4F, 0xF6, 0x94, 0x84, 0x0E, 0x08, 0xDD, 0x8D, 0x92, 0x09, 0x18, 0xA2, 0x78, 0x6D, 0x7A, 0xC8, 0x5E, 0xB0, 0xF6, 0x97, 0x0E, 0x04, 0x78, 0xC2, 0x94, 0x75, 0x73}, + {0x22, 0x11, 0x58, 0xFF, 0x8C, 0x7C, 0xCD, 0x60, 0x67, 0x74, 0xE1, 0x7C, 0x0B, 0x1E, 0x20, 0xAB, 0xB3, 0xA9, 0x13, 0x77, 0xAB, 0x3B, 0x7F, 0x26, 0x07, 0xF9, 0xBE, 0xA7, 0x43, 0x37, 0xB0, 0x84, 0xC2, 0xD8, 0x3B, 0x0E, 0x3C, 0x4D, 0x4B, 0x97, 0xF8, 0x71, 0x7E, 0x4C, 0xA8, 0xE9, 0x70, 0x4B, 0x3F, 0xBD, 0x7B, 0x33, 0x59, 0x8D, 0xD3, 0xE5, 0x65, 0x33, 0xB7, 0x69, 0xE3, 0x49, 0x83, 0x71}, + {0x88, 0x46, 0x54, 0x2A, 0xD8, 0xA4, 0xDC, 0xBE, 0x33, 0xBC, 0x21, 0x71, 0x24, 0x96, 0x8F, 0xBD, 0x65, 0x1E, 0xB4, 0xED, 0x87, 0x49, 0x8E, 0x66, 0x22, 0xF6, 0x6B, 0xB8, 0x06, 0xFB, 0xF6, 0x79, 0x83, 0x6E, 0x12, 0xBD, 0xC1, 0x19, 0x29, 0xD3, 0xCF, 0x8C, 0x61, 0xE0, 0xCD, 0x1B, 0x15, 0x88, 0xCA, 0xB5, 0x37, 0x81, 0xA8, 0x4A, 0x1A, 0x41, 0x44, 0x16, 0xEE, 0x1A, 0xF8, 0x9B, 0xA4, 0x01}, + {0x56, 0x85, 0x59, 0x83, 0x88, 0xAB, 0x31, 0x62, 0x34, 0xD8, 0x63, 0x4E, 0xCD, 0x71, 0x78, 0xE1, 0xF1, 0xCC, 0x7C, 0xB2, 0x4D, 0xBE, 0x0F, 0x20, 0xCB, 0x08, 0xAB, 0x58, 0x14, 0xD3, 0x6A, 0x6E, 0xCF, 0xC3, 0x9C, 0x30, 0x06, 0x8D, 0xD5, 0x6D, 0x95, 0x9F, 0xEC, 0xDF, 0x72, 0x3E, 0x79, 0x85, 0xA1, 0xDE, 0x0F, 0x25, 0xB5, 0x00, 0x6D, 0x79, 0x65, 0x6F, 0x31, 0xE3, 0xDC, 0x6F, 0x06, 0x55}, + {0x12, 0xE9, 0x4C, 0x3B, 0x6F, 0x13, 0x80, 0xDC, 0x4A, 0xCF, 0xE7, 0x2E, 0x0A, 0xDB, 0xEB, 0x23, 0xBE, 0xBC, 0x88, 0xA8, 0xE8, 0xA9, 0xA4, 0x72, 0x79, 0x58, 0x1D, 0x63, 0x3E, 0x1C, 0xAB, 0x2E, 0x92, 0x51, 0x52, 0x1B, 0x37, 0x7B, 0xB6, 0xFD, 0x25, 0xA2, 0xB8, 0x42, 0xF2, 0x25, 0x1A, 0xE7, 0xD1, 0x94, 0x0A, 0x4D, 0x23, 0x0B, 0x7A, 0xA2, 0x94, 0x75, 0xBB, 0x2F, 0xE1, 0x58, 0x87, 0xCB}, + {0x71, 0x72, 0x39, 0x25, 0xC9, 0x07, 0x76, 0x29, 0x21, 0xA2, 0x28, 0x42, 0xAF, 0x5D, 0x69, 0x8E, 0xA2, 0xA4, 0xDA, 0x3E, 0x93, 0xBD, 0x55, 0x2F, 0x1B, 0x9A, 0xD2, 0xFE, 0x7B, 0x67, 0x64, 0xD2, 0xFD, 0x72, 0xF8, 0xD2, 0xC7, 0x2F, 0xC0, 0xBC, 0x4F, 0xBB, 0xC3, 0x7B, 0x92, 0xDB, 0xCA, 0x93, 0xF0, 0x4A, 0x9E, 0xB1, 0xD2, 0xF7, 0x2D, 0xB7, 0x2F, 0x79, 0x4F, 0xCD, 0x81, 0x8B, 0xF9, 0xC1}, + {0xAD, 0x34, 0xCF, 0x56, 0x02, 0xFD, 0x7D, 0x2F, 0xF5, 0xE0, 0x40, 0x0D, 0x74, 0x40, 0x31, 0xBA, 0x0A, 0xDA, 0x35, 0x8E, 0xEB, 0xDD, 0x65, 0xF5, 0x28, 0x42, 0x55, 0x12, 0x06, 0x44, 0x67, 0x33, 0xC9, 0x1F, 0x63, 0xE6, 0x77, 0x72, 0xD9, 0xF4, 0xC1, 0xF4, 0xF5, 0x98, 0x1D, 0xCC, 0xC0, 0xB6, 0x0A, 0xCA, 0x59, 0x68, 0x81, 0x71, 0x99, 0x0B, 0xF4, 0x6C, 0x36, 0x0E, 0xA8, 0x87, 0x96, 0x1B}, + {0x23, 0x60, 0x93, 0xE9, 0x3E, 0x03, 0xA1, 0x16, 0xB6, 0x57, 0xA3, 0xFF, 0x0B, 0xFD, 0x0A, 0x32, 0xED, 0xD9, 0x84, 0x2E, 0x01, 0x59, 0x88, 0x8B, 0x5E, 0x11, 0xE3, 0x0C, 0xBF, 0xB5, 0x33, 0x88, 0x1F, 0x45, 0xAC, 0x69, 0xD8, 0x72, 0x70, 0xEF, 0xDE, 0x15, 0xA6, 0xE2, 0x3A, 0x04, 0x07, 0xC1, 0x81, 0x47, 0xB0, 0xFC, 0x5D, 0xD6, 0x47, 0xA7, 0xBD, 0x85, 0x6F, 0xCC, 0x93, 0x8E, 0x05, 0xEF}, + {0xEF, 0x6F, 0xC2, 0x23, 0xD1, 0xFC, 0x4E, 0x34, 0xBD, 0x0D, 0x13, 0x53, 0x0D, 0xD9, 0x58, 0x26, 0xE9, 0x0B, 0xC6, 0x0E, 0x09, 0x83, 0x1A, 0x1E, 0x36, 0x7A, 0x0F, 0x5A, 0xAD, 0x2D, 0x1E, 0x31, 0xB3, 0x54, 0x15, 0xDA, 0x84, 0x15, 0x0F, 0x36, 0x29, 0x5D, 0x31, 0x59, 0xF6, 0x5B, 0x2B, 0x2A, 0x7F, 0xB5, 0xF1, 0x85, 0x63, 0x01, 0x27, 0x50, 0x6C, 0x05, 0x6D, 0xD0, 0x49, 0x39, 0x68, 0xFD}, + {0xE1, 0x86, 0xB9, 0x10, 0xB8, 0x3D, 0x5D, 0xB4, 0x7A, 0xE6, 0x76, 0x5D, 0x48, 0x22, 0x95, 0xCF, 0x87, 0x99, 0xE9, 0xEA, 0x53, 0x43, 0x93, 0xEB, 0x91, 0x87, 0x4F, 0xD4, 0x3A, 0xDD, 0x3D, 0x17, 0x09, 0xBA, 0xC0, 0x21, 0x6A, 0x8B, 0x64, 0xCC, 0x30, 0x58, 0xB8, 0x90, 0x98, 0x4D, 0x3D, 0x0A, 0x8F, 0x1D, 0x18, 0x97, 0xE9, 0xA4, 0x2F, 0x16, 0x2A, 0x12, 0x78, 0xD3, 0xF5, 0x73, 0xAB, 0xA4}, + {0xE9, 0x86, 0x71, 0xC5, 0xFC, 0x29, 0x1F, 0xF8, 0x59, 0x30, 0xC7, 0xF1, 0xD7, 0xAB, 0x19, 0x4D, 0xBD, 0x20, 0xB0, 0x7B, 0x83, 0x6C, 0x3E, 0x97, 0xFF, 0xA6, 0x87, 0x2D, 0x75, 0x9A, 0x67, 0x4C, 0xBA, 0x06, 0x3C, 0xDD, 0x1F, 0x4E, 0x74, 0x47, 0x05, 0xAF, 0x0B, 0x58, 0xBF, 0x78, 0x2F, 0xE2, 0xBA, 0xE6, 0x3A, 0x63, 0xCB, 0x3F, 0xF8, 0x27, 0x74, 0xD8, 0x68, 0xE3, 0x71, 0x04, 0xCA, 0x22}, + {0x9A, 0x15, 0x60, 0xDA, 0x1D, 0x5A, 0xA3, 0x9A, 0xA2, 0x6F, 0x6C, 0x86, 0xA3, 0x84, 0xB2, 0xA7, 0x89, 0x6B, 0x36, 0x53, 0x3F, 0x24, 0x65, 0x77, 0x8F, 0xF6, 0xC1, 0xD6, 0x99, 0x18, 0x75, 0x46, 0xFB, 0x7A, 0x58, 0x5F, 0xEC, 0x5B, 0x7B, 0xC7, 0x16, 0x7E, 0x0C, 0xF2, 0xF3, 0x39, 0x7E, 0xBC, 0x6C, 0xA3, 0x25, 0x7F, 0xE0, 0xAC, 0x11, 0xFE, 0x39, 0x80, 0xF3, 0xDB, 0xF4, 0x36, 0x18, 0x00}, + {0xE3, 0xE2, 0x7C, 0x99, 0x2A, 0x59, 0xA7, 0xE2, 0x0B, 0x61, 0x7D, 0x05, 0xA3, 0x77, 0x8C, 0x8F, 0x11, 0x21, 0x45, 0x1F, 0x4D, 0xCD, 0x53, 0xF0, 0x78, 0x91, 0xF4, 0x49, 0x0C, 0xB2, 0xAA, 0xAE, 0x35, 0xB2, 0x22, 0x74, 0x9E, 0xA5, 0x18, 0xFA, 0x72, 0x1B, 0x40, 0x94, 0x6C, 0x84, 0x00, 0x77, 0x2C, 0xFC, 0xE6, 0x86, 0xA2, 0xA3, 0x71, 0xE7, 0xCB, 0xA4, 0x7D, 0x88, 0x7C, 0x11, 0x9D, 0x5C}, + {0xAB, 0x44, 0xFD, 0x78, 0x6B, 0xBC, 0x5D, 0x57, 0x3A, 0x50, 0x79, 0x15, 0x51, 0x4D, 0x66, 0x23, 0x1C, 0xA6, 0xF2, 0x46, 0xD6, 0xAB, 0xEF, 0xA5, 0xE0, 0xCC, 0xFC, 0x8D, 0x03, 0x12, 0x9C, 0xE0, 0xCE, 0x47, 0x73, 0xFD, 0x02, 0x5A, 0x35, 0xA1, 0x6A, 0x2F, 0x05, 0xBA, 0xB2, 0x55, 0x1D, 0x58, 0xA4, 0xDB, 0x1D, 0x0A, 0x0F, 0x82, 0xA5, 0xCF, 0xFC, 0xF1, 0x1C, 0xED, 0xEC, 0xFD, 0x58, 0x08}, + {0xD7, 0x4E, 0xE8, 0xC0, 0x7D, 0x75, 0xC8, 0xAB, 0x8C, 0x62, 0xF0, 0xAF, 0x1E, 0x0D, 0xED, 0xC7, 0x58, 0x91, 0xD8, 0x3F, 0xB3, 0xD1, 0xB1, 0xB0, 0x6D, 0xBA, 0xB8, 0x34, 0xF3, 0x68, 0x48, 0xFD, 0xB9, 0x3B, 0xB6, 0x2E, 0xAF, 0x1A, 0xD4, 0xD2, 0x3E, 0xE2, 0x51, 0x69, 0x3A, 0xA7, 0x4C, 0x32, 0x9B, 0x21, 0x79, 0xD3, 0x44, 0xB6, 0xD2, 0x81, 0xAB, 0x12, 0xA4, 0x0E, 0xEE, 0xA0, 0x1C, 0x3B}, + {0x20, 0x5E, 0x88, 0x93, 0x47, 0x4C, 0x59, 0x3B, 0x72, 0xAE, 0x23, 0xCD, 0x5F, 0x49, 0x2D, 0x4F, 0x34, 0x2D, 0x9F, 0x60, 0x19, 0xFC, 0x6B, 0x5C, 0xFC, 0x31, 0x28, 0xB4, 0x0D, 0x82, 0x86, 0x6D, 0x9A, 0x8C, 0xC2, 0xA0, 0x73, 0xB8, 0x8E, 0x00, 0x24, 0x8C, 0x6B, 0xE2, 0x7E, 0x7B, 0x56, 0x70, 0x18, 0x30, 0xE7, 0x01, 0x07, 0x5A, 0xF4, 0x65, 0x7F, 0x3D, 0x5F, 0x4A, 0x64, 0x78, 0x88, 0x6C}, + {0xB9, 0x81, 0x94, 0x82, 0xFD, 0x26, 0xA4, 0x92, 0xDF, 0x00, 0x74, 0xF7, 0x1C, 0xBE, 0x0E, 0xBE, 0xD9, 0x7B, 0x52, 0x40, 0x0C, 0x44, 0xDF, 0x20, 0x53, 0xFA, 0x90, 0x47, 0x11, 0xAA, 0xBA, 0xD1, 0x33, 0x29, 0x4F, 0x63, 0x9D, 0x47, 0x88, 0x23, 0x77, 0xD0, 0xDF, 0x08, 0xAC, 0xF3, 0xAC, 0x17, 0x7A, 0x18, 0x46, 0x70, 0x58, 0x7F, 0x7C, 0x19, 0xE7, 0xC4, 0x69, 0x3A, 0xAC, 0x07, 0xAF, 0x5A}}; + + secp256k1_bulletproof_generators *ret; + size_t i; + size_t n = 320; + + VERIFY_CHECK(ctx != NULL); + + ret = (secp256k1_bulletproof_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret)); + if (ret == NULL) + { + return NULL; + } + ret->gens = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (n + 1) * sizeof(*ret->gens)); + if (ret->gens == NULL) + { + free(ret); + return NULL; + } + ret->blinding_gen = &ret->gens[n]; + ret->n = n; + + for (i = 0; i < n; i++) + { + secp256k1_generator *gen = &(secp256k1_generator_pregenerateds[i]); + secp256k1_generator_load(&ret->gens[i], gen); + } + + secp256k1_generator_load(&ret->blinding_gen[0], &secp256k1_generator_const_g); + + return ret; +} + secp256k1_bulletproof_generators *secp256k1_bulletproof_generators_create(const secp256k1_context2 *ctx, const secp256k1_generator *blinding_gen, size_t n) { secp256k1_bulletproof_generators *ret; secp256k1_rfc6979_hmac_sha256 rng; From 00e4748037307c67c9a1c83f55d5ef309a227dd9 Mon Sep 17 00:00:00 2001 From: akira Date: Thu, 28 May 2020 11:54:06 +0700 Subject: [PATCH 0368/1888] remove unnecessary checks in mempool --- src/main.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 85a722de3a..7ddcfee482 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1686,11 +1686,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa return false; } - // are the actual inputs available? - if (!view.HaveInputs(tx)) - return state.Invalid(error("%s: inputs already spent", - __func__), REJECT_DUPLICATE, "bad-txns-inputs-spent"); - if (!tx.IsCoinStake() && !tx.IsCoinBase() && !tx.IsCoinAudit()) { if (!tx.IsCoinAudit()) { if (!VerifyRingSignatureWithTxFee(tx, chainActive.Tip())) From 8df498cf11721c4c94efe923c141a3d1df787252 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Thu, 28 May 2020 10:50:23 +0200 Subject: [PATCH 0369/1888] Update to 1.0.6.6 --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index a262b0d849..64196f8a09 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.6.5 \ No newline at end of file +1.0.6.6 From f380ec0aa02aa968a354f76c0ac265315476bb80 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 28 May 2020 18:30:07 -0400 Subject: [PATCH 0370/1888] Fix Check For Updates --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 69840d30a0..8bf906ce1f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -936,7 +936,7 @@ void BitcoinGUI::serviceRequestFinished(QNetworkReply* reply) reply->deleteLater(); if(reply->error() == QNetworkReply::NoError) { QByteArray data = reply->readAll(); - if (data != currentVersion) { + if (data.trimmed() != currentVersion) { QMessageBox::StandardButton msgReply; msgReply = QMessageBox::question(this, "Wallet Update Available!", "Wallet update available.\n\nWould you like to go to the GitHub Releases page to download v" + data.trimmed() + "?", QMessageBox::Yes|QMessageBox::No); if (msgReply == QMessageBox::Yes) { From d8fa92ad2c167dd6793ab4084991fc68807208b9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 2 Jun 2020 08:14:09 -0400 Subject: [PATCH 0371/1888] Fix incorrect check in AcceptableInputs Co-Authored-By: akirapham --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7ddcfee482..4ff2518a18 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1904,9 +1904,9 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // are the actual inputs available? - if (!view.HaveInputs(tx)) - return state.Invalid(error("%s : inputs already spent", - __func__), REJECT_DUPLICATE, "bad-txns-inputs-spent"); + if (!CheckHaveInputs(view, tx)) + return state.Invalid(error("AcceptableInputs : inputs already spent"), + REJECT_DUPLICATE, "bad-txns-inputs-spent"); // Bring the best block into scope view.GetBestBlock(); From 5f5ad310a8f860a9e5e7280a714aad820d45ccfc Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 4 Jun 2020 13:38:51 -0400 Subject: [PATCH 0372/1888] Change btc/pivx to DAPS in help texts --- src/rpc/blockchain.cpp | 4 ++-- src/rpc/rawtransaction.cpp | 8 ++++---- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index dd5326be87..a83504f638 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -406,7 +406,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) "{ (json object)\n" " \"transactionid\" : { (json object)\n" " \"size\" : n, (numeric) transaction size in bytes\n" - " \"fee\" : n, (numeric) transaction fee in pivx\n" + " \"fee\" : n, (numeric) transaction fee in DAPS\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"height\" : n, (numeric) block height when transaction entered pool\n" " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" @@ -617,7 +617,7 @@ UniValue gettxout(const UniValue& params, bool fHelp) "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" - " \"value\" : x.xxx, (numeric) The transaction value in btc\n" + " \"value\" : x.xxx, (numeric) The transaction value in DAPS\n" " \"scriptPubKey\" : { (json object)\n" " \"asm\" : \"code\", (string) \n" " \"hex\" : \"hex\", (string) \n" diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 64c142308d..598e78876a 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -280,7 +280,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " ],\n" " \"vout\" : [ (array of json objects)\n" " {\n" - " \"value\" : x.xxx, (numeric) The value in btc\n" + " \"value\" : x.xxx, (numeric) The value in DAPS\n" " \"n\" : n, (numeric) index\n" " \"scriptPubKey\" : { (json object)\n" " \"asm\" : \"asm\", (string) the asm\n" @@ -353,7 +353,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) " \"address\" : \"address\", (string) the dapscoin address\n" " \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" - " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" + " \"amount\" : x.xxx, (numeric) the transaction amount in DAPS\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" " \"spendable\" : true|false (boolean) Whether we have the private keys to spend this output\n" " }\n" @@ -457,7 +457,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ]\n" "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" " {\n" - " \"address\": x.xxx (numeric, required) The key is the pivx address, the value is the btc amount\n" + " \"address\": x.xxx (numeric, required) The key is the DAPS address, the value is the DAPS amount\n" " ,...\n" " }\n" @@ -542,7 +542,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) " ],\n" " \"vout\" : [ (array of json objects)\n" " {\n" - " \"value\" : x.xxx, (numeric) The value in btc\n" + " \"value\" : x.xxx, (numeric) The value in DAPS\n" " \"n\" : n, (numeric) index\n" " \"scriptPubKey\" : { (json object)\n" " \"asm\" : \"asm\", (string) the asm\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2fabd47a7d..838778cb36 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2768,7 +2768,7 @@ UniValue sendtostealthaddress(const UniValue& params, bool fHelp) HelpRequiringPassphrase() + "\nArguments:\n" "1. \"dapsstealthaddress\" (string, required) The dapscoin stealth address to send to.\n" - "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n" + "2. \"amount\" (numeric, required) The amount in DAPS to send. eg 0.1\n" "\nResult:\n" "\"transactionid\" (string) The transaction id.\n" "\nExamples:\n" + From e6ac1b241a5f5e1f5ce457bb52b048ffc9e64423 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 4 Jun 2020 17:26:14 -0400 Subject: [PATCH 0373/1888] [Cleanup] Remove obsolete multisig code --- src/keystore.cpp | 26 -------------------------- src/keystore.h | 11 ----------- src/qt/coincontroldialog.cpp | 21 +-------------------- src/qt/coincontroldialog.h | 3 +-- src/qt/walletmodel.cpp | 15 --------------- src/qt/walletmodel.h | 6 ------ src/wallet/wallet.cpp | 32 -------------------------------- src/wallet/wallet.h | 9 --------- src/wallet/wallet_ismine.cpp | 6 ------ src/wallet/wallet_ismine.h | 2 -- src/wallet/walletdb.cpp | 11 ----------- 11 files changed, 2 insertions(+), 140 deletions(-) diff --git a/src/keystore.cpp b/src/keystore.cpp index 9dd672c50c..988b6a2498 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -84,29 +84,3 @@ bool CBasicKeyStore::HaveWatchOnly() const LOCK(cs_KeyStore); return (!setWatchOnly.empty()); } - -bool CBasicKeyStore::AddMultiSig(const CScript& dest) -{ - LOCK(cs_KeyStore); - setMultiSig.insert(dest); - return true; -} - -bool CBasicKeyStore::RemoveMultiSig(const CScript& dest) -{ - LOCK(cs_KeyStore); - setMultiSig.erase(dest); - return true; -} - -bool CBasicKeyStore::HaveMultiSig(const CScript& dest) const -{ - LOCK(cs_KeyStore); - return setMultiSig.count(dest) > 0; -} - -bool CBasicKeyStore::HaveMultiSig() const -{ - LOCK(cs_KeyStore); - return (!setMultiSig.empty()); -} diff --git a/src/keystore.h b/src/keystore.h index 38cd8aedf3..27720ae653 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -46,12 +46,6 @@ class CKeyStore virtual bool RemoveWatchOnly(const CScript& dest) = 0; virtual bool HaveWatchOnly(const CScript& dest) const = 0; virtual bool HaveWatchOnly() const = 0; - - //! Support for MultiSig addresses - virtual bool AddMultiSig(const CScript& dest) = 0; - virtual bool RemoveMultiSig(const CScript& dest) = 0; - virtual bool HaveMultiSig(const CScript& dest) const = 0; - virtual bool HaveMultiSig() const = 0; }; typedef std::map KeyMap; @@ -112,11 +106,6 @@ class CBasicKeyStore : public CKeyStore virtual bool RemoveWatchOnly(const CScript& dest); virtual bool HaveWatchOnly(const CScript& dest) const; virtual bool HaveWatchOnly() const; - - virtual bool AddMultiSig(const CScript& dest); - virtual bool RemoveMultiSig(const CScript& dest); - virtual bool HaveMultiSig(const CScript& dest) const; - virtual bool HaveMultiSig() const; }; typedef std::vector > CKeyingMaterial; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 733abea839..abbed8b751 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -44,12 +44,11 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { return QTreeWidgetItem::operator<(other); } -CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), +CoinControlDialog::CoinControlDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::CoinControlDialog), model(0) { ui->setupUi(this); - this->fMultisigEnabled = fMultisigEnabled; /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); @@ -764,10 +763,6 @@ void CoinControlDialog::updateView() int nInputSum = 0; for(const COutput& out: coins.second) { isminetype mine = pwalletMain->IsMine(out.tx->vout[out.i]); - bool fMultiSigUTXO = (mine & ISMINE_MULTISIG); - // when multisig is enabled, it will only display outputs from multisig addresses - if (fMultisigEnabled && !fMultiSigUTXO) - continue; int nInputSize = 0; nSum += model->getCWallet()->getCTxOutValue(*out.tx, out.tx->vout[out.i]); nChildren++; @@ -780,20 +775,6 @@ void CoinControlDialog::updateView() itemOutput->setFlags(flgCheckbox); itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - //MultiSig - if (fMultiSigUTXO) { - itemOutput->setText(COLUMN_TYPE, "MultiSig"); - - if (!fMultisigEnabled) { - COutPoint outpt(out.tx->GetHash(), out.i); - coinControl->UnSelect(outpt); // just to be sure - itemOutput->setDisabled(true); - itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); - } - } else { - itemOutput->setText(COLUMN_TYPE, "Personal"); - } - // address CTxDestination outputAddress; QString sAddress = ""; diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 90a30cf3b2..36aa19db62 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -41,7 +41,7 @@ class CoinControlDialog : public QDialog Q_OBJECT public: - explicit CoinControlDialog(QWidget* parent = nullptr, bool fMultisigEnabled = false); + explicit CoinControlDialog(QWidget* parent = nullptr); ~CoinControlDialog(); void setModel(WalletModel* model); @@ -61,7 +61,6 @@ class CoinControlDialog : public QDialog WalletModel* model; int sortColumn; Qt::SortOrder sortOrder; - bool fMultisigEnabled; bool fSelectAllToggled{true}; // false when pushButtonSelectAll text is "Unselect All" QMenu* contextMenu; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index d707c0a8f1..691a8d0526 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -49,7 +49,6 @@ WalletModel::WalletModel(CWallet* wallet, OptionsModel* optionsModel, QObject* p { fHaveWatchOnly = wallet->HaveWatchOnly(); - fHaveMultiSig = wallet->HaveMultiSig(); fForceCheckBalanceChanged = false; addressTableModel = new AddressTableModel(wallet, this); @@ -258,12 +257,6 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) Q_EMIT notifyWatchonlyChanged(fHaveWatchonly); } -void WalletModel::updateMultiSigFlag(bool fHaveMultiSig) -{ - this->fHaveMultiSig = fHaveMultiSig; - Q_EMIT notifyMultiSigChanged(fHaveMultiSig); -} - bool WalletModel::validateAddress(const QString& address) { CBitcoinAddress addressParsed(address.toStdString()); @@ -516,12 +509,6 @@ static void NotifyWatchonlyChanged(WalletModel* walletmodel, bool fHaveWatchonly Q_ARG(bool, fHaveWatchonly)); } -static void NotifyMultiSigChanged(WalletModel* walletmodel, bool fHaveMultiSig) -{ - QMetaObject::invokeMethod(walletmodel, "updateMultiSigFlag", Qt::QueuedConnection, - Q_ARG(bool, fHaveMultiSig)); -} - void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet @@ -530,7 +517,6 @@ void WalletModel::subscribeToCoreSignals() wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1)); - wallet->NotifyMultiSigChanged.connect(boost::bind(NotifyMultiSigChanged, this, _1)); } void WalletModel::unsubscribeFromCoreSignals() @@ -541,7 +527,6 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1)); - wallet->NotifyMultiSigChanged.disconnect(boost::bind(NotifyMultiSigChanged, this, _1)); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 9c5838d9b0..c580974536 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -229,7 +229,6 @@ class WalletModel : public QObject private: CWallet* wallet; bool fHaveWatchOnly; - bool fHaveMultiSig; bool fForceCheckBalanceChanged; // Wallet has an options model for wallet-specific options @@ -282,9 +281,6 @@ class WalletModel : public QObject // Watch-only address added void notifyWatchonlyChanged(bool fHaveWatchonly); - // MultiSig address added - void notifyMultiSigChanged(bool fHaveMultiSig); - void RefreshRecent(); void WalletUnlocked(); @@ -298,8 +294,6 @@ public Q_SLOTS: void updateAddressBook(const QString& pubCoin, const QString& isUsed, int status); /* Watch-only added */ void updateWatchOnlyFlag(bool fHaveWatchonly); - /* MultiSig added */ - void updateMultiSigFlag(bool fHaveMultiSig); /* Current, immature or unconfirmed balance might have changed - Q_EMIT 'balanceChanged' if so */ void pollBalanceChanged(); }; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5bf347f9c8..24773547dc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -473,36 +473,6 @@ bool CWallet::LoadWatchOnly(const CScript& dest) return CCryptoKeyStore::AddWatchOnly(dest); } -bool CWallet::AddMultiSig(const CScript& dest) -{ - if (!CCryptoKeyStore::AddMultiSig(dest)) - return false; - nTimeFirstKey = 1; // No birthday information - NotifyMultiSigChanged(true); - if (!fFileBacked) - return true; - return CWalletDB(strWalletFile).WriteMultiSig(dest); -} - -bool CWallet::RemoveMultiSig(const CScript& dest) -{ - AssertLockHeld(cs_wallet); - if (!CCryptoKeyStore::RemoveMultiSig(dest)) - return false; - if (!HaveMultiSig()) - NotifyMultiSigChanged(false); - if (fFileBacked) - if (!CWalletDB(strWalletFile).EraseMultiSig(dest)) - return false; - - return true; -} - -bool CWallet::LoadMultiSig(const CScript& dest) -{ - return CCryptoKeyStore::AddMultiSig(dest); -} - bool CWallet::RescanAfterUnlock(int fromHeight) { if (IsLocked()) { @@ -2026,8 +1996,6 @@ bool CWallet::AvailableCoins(const uint256 wtxid, const CWalletTx* pcoin, vector bool fIsSpendable = false; if ((mine & ISMINE_SPENDABLE) != ISMINE_NO) fIsSpendable = true; - if ((mine & ISMINE_MULTISIG) != ISMINE_NO) - fIsSpendable = true; if (IsSpent(wtxid, i)) { cannotSpend++; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9fd4112321..dd37e212c4 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -439,12 +439,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) bool LoadWatchOnly(const CScript& dest); - //! Adds a MultiSig address to the store, and saves it to disk. - bool AddMultiSig(const CScript& dest); - bool RemoveMultiSig(const CScript& dest); - //! Adds a MultiSig address to the store, without saving it to disk (used by LoadWallet) - bool LoadMultiSig(const CScript& dest); - bool Unlock(const SecureString& strWalletPassphrase, bool anonimizeOnly = false); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); @@ -599,9 +593,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /** Watch-only address added */ boost::signals2::signal NotifyWatchonlyChanged; - /** MultiSig address added */ - boost::signals2::signal NotifyMultiSigChanged; - bool ComputeStealthPublicAddress(const std::string& accountName, std::string& pubAddress); bool ComputeIntegratedPublicAddress(const uint64_t paymentID, const std::string& accountName, std::string& pubAddress); bool EncodeStealthPublicAddress(const std::vector& pubViewKey, const std::vector& pubSpendKey, std::string& pubAddr); diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index b76c21e23e..9213d6918c 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -38,16 +38,12 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) { if(keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; - if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; vector vSolutions; txnouttype whichType; if(!Solver(scriptPubKey, whichType, vSolutions)) { if(keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; - if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; return ISMINE_NO; } @@ -93,8 +89,6 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) if(keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; - if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; return ISMINE_NO; } diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h index 32e7b2dce7..c76b4c5e7c 100644 --- a/src/wallet/wallet_ismine.h +++ b/src/wallet/wallet_ismine.h @@ -17,8 +17,6 @@ enum isminetype { ISMINE_NO = 0, //! Indicates that we dont know how to create a scriptSig that would solve this if we were given the appropriate private keys ISMINE_WATCH_ONLY = 1, - //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys - ISMINE_MULTISIG = 2, ISMINE_SPENDABLE = 4, ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE }; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 090871376d..2e91b6cca0 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -596,17 +596,6 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW // Watch-only addresses have no birthday information for now, // so set the wallet birthday to the beginning of time. pwallet->nTimeFirstKey = 1; - } else if (strType == "multisig") { - CScript script; - ssKey >> script; - char fYes; - ssValue >> fYes; - if (fYes == '1') - pwallet->LoadMultiSig(script); - - // MultiSig addresses have no birthday information for now, - // so set the wallet birthday to the beginning of time. - pwallet->nTimeFirstKey = 1; } else if (strType == "key" || strType == "wkey") { CPubKey vchPubKey; ssKey >> vchPubKey; From 991e1b3ad757b9c9299ae9e7007899ea5903cd19 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 28 May 2020 16:59:54 -0400 Subject: [PATCH 0374/1888] Ban v1.0.4.6 wallets --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4ff2518a18..c2426a7789 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5722,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } - if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/") { + if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/" || pfrom->strSubVer == "/DAPS:1.0.4.6/") { // disconnect from peers other than these sub versions LogPrintf("partner %s using obsolete version %s; banning and disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); state->fShouldBan = true; From a6c97a61b07dec61017405741d47ec5b51532c39 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 10 Jun 2020 17:38:59 -0400 Subject: [PATCH 0375/1888] gui: update Qt base translations for macOS release These haven't been updated since their addition, so this updates the list that controls which qt base translations are bundled with the macOS binary, to all the languages that are available with qt 5.9.8. This could probably be improved in some way, however qt updates are infrequent, and I didn't want to spend any more time looking at this. Also given that no-one seems to have noticed and/or reported this it wouldn't seem high-priority. Could be backported to 0.20.1. --- Makefile.am | 2 +- depends/packages/qt.mk | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 414c5e90ff..4c5cd4b932 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,7 @@ OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed -OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW +OSX_QT_TRANSLATIONS = ar,bg,ca,cs,da,de,es,fa,fi,fr,gd,gl,he,hu,it,ja,ko,lt,lv,pl,pt,ru,sk,sl,sv,uk,zh_CN,zh_TW DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index ae1ea38dd8..2ba2656385 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -10,6 +10,7 @@ $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch +# Update OSX_QT_TRANSLATIONS when this is updated $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=f7474f260a1382549720081bf2359a3d425ec3bf7d31976c512834303d30d73b From 61f867ae8f5698e6dbf20b9708d9e7b7ab4e71d9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Apr 2020 18:08:17 -0400 Subject: [PATCH 0376/1888] [Trivial] Remove CMasternode::SliceHash Removes un-used function SliceHash (which is also buggy and overflowing, trying to copy 64 bytes to a destination buffer having only 8 bytes). --- src/masternode.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/masternode.h b/src/masternode.h index 5013bca067..9941db1e10 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -223,13 +223,6 @@ class CMasternode bool UpdateFromNewBroadcast(CMasternodeBroadcast& mnb); - inline uint64_t SliceHash(uint256& hash, int slice) - { - uint64_t n = 0; - memcpy(&n, &hash + slice * 64, 64); - return n; - } - void Check(bool forceCheck = false); bool IsBroadcastedWithin(int seconds) From 108855419399df403b16963d4784fb93f6d02c4a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 10 Jun 2020 19:10:55 -0400 Subject: [PATCH 0377/1888] Add checkpoint for block 458733 --- src/chainparams.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 416ef371ed..c776726607 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -134,6 +134,7 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (290000, uint256("49c13c93d22f4de36dd8cab41ef8fb879e657198d8b16dd97c4225d199126169")) (295000, uint256("e6742077e1d536bdbd4d4e1f440371be5045b604b21bbe5ab9cf5bed30747e46")) (300000, uint256("28fe81715aa6450890103e65fbfa3e9d0b4bac3baf86a480ce0c630e82a32e62")) + (458733, uint256("51d7f917147f3bec3f2e6767fd70c14730a0b0773a7b967e827336e936cf50e2")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, From ee911e9d4c80094221d1798de4dc1ec95ba3a1fc Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 10 Jun 2020 19:13:38 -0400 Subject: [PATCH 0378/1888] Add checkpoint for block 458734 --- src/chainparams.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c776726607..63bc09be7a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -135,6 +135,7 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (295000, uint256("e6742077e1d536bdbd4d4e1f440371be5045b604b21bbe5ab9cf5bed30747e46")) (300000, uint256("28fe81715aa6450890103e65fbfa3e9d0b4bac3baf86a480ce0c630e82a32e62")) (458733, uint256("51d7f917147f3bec3f2e6767fd70c14730a0b0773a7b967e827336e936cf50e2")) + (458734, uint256("35ff8e3884036187ed56e7d4a4adda3e0f75eac5655afd4cef8605954b28362f")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, From 81b0d4eed5568c7c6625308a4ce98144e68b15fc Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 15 Jun 2020 21:38:53 -0400 Subject: [PATCH 0379/1888] Add error MsgBox when attempting to send a tx before synced --- src/qt/sendcoinsdialog.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 36c7858936..8cc966b37b 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -14,6 +14,7 @@ #include "coincontroldialog.h" #include "guiutil.h" #include "optionsmodel.h" +#include "masternode-sync.h" #include "sendcoinsentry.h" #include "walletmodel.h" @@ -133,6 +134,15 @@ SendCoinsDialog::~SendCoinsDialog(){ } void SendCoinsDialog::on_sendButton_clicked(){ + if (!masternodeSync.IsBlockchainSynced()) { + QMessageBox msgBox; + msgBox.setWindowTitle("Send Disabled - Syncing"); + msgBox.setText("Sending DAPS is disabled when you are still syncing the wallet. Please allow the wallet to fully sync before attempting to send a transaction."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } if (!ui->entries->count()) return; From 9f40b4093ec643d7d3eef2c26da94cae94fd379c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 9 May 2020 15:24:36 -0400 Subject: [PATCH 0380/1888] Update "Transaction Size Too Large" msgbox --- src/qt/sendcoinsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 36c7858936..6c82587bda 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -275,7 +275,7 @@ void SendCoinsDialog::sendTx() { std::string errMes(err.what()); if (errMes.find("You have attempted to send more than 50 UTXOs in a single transaction") != std::string::npos) { QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Transaction Size Too Large", QString(err.what()) + QString("\n Do you want to combine small UTXOs into a larger one?"), QMessageBox::Yes|QMessageBox::No); + reply = QMessageBox::question(this, "Transaction Size Too Large", QString(err.what()) + QString("\n\nDo you want to combine small UTXOs into a larger one?"), QMessageBox::Yes|QMessageBox::No); if (reply == QMessageBox::Yes) { CAmount backupReserve = nReserveBalance; try { @@ -299,7 +299,7 @@ void SendCoinsDialog::sendTx() { QMessageBox msgBox; LogPrintf("ERROR:%s: %s\n", __func__, err1.what()); msgBox.setWindowTitle("Sweeping Transaction Creation Error"); - msgBox.setText(QString("Sweeping transaction failed due to an internal error! Please try again later!")); + msgBox.setText(QString("Sweeping transaction creation failed due to an internal error. Please try again later.")); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.setIcon(QMessageBox::Critical); msgBox.exec(); From 48e3839978af860848a6902c78ce8593695f22f3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 9 May 2020 15:25:02 -0400 Subject: [PATCH 0381/1888] Add additional error msgbox as the one in catch was not displaying --- src/qt/sendcoinsdialog.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 6c82587bda..52db060a9c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -293,6 +293,13 @@ void SendCoinsDialog::sendTx() { msgBox.setText(msg); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.exec(); + } else { + QMessageBox msgBox; + msgBox.setWindowTitle("Sweeping Transaction Creation Error"); + msgBox.setText(QString("Sweeping transaction creation failed due to an internal error. Please try again later.")); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.setIcon(QMessageBox::Critical); + msgBox.exec(); } } catch (const std::exception& err1) { nReserveBalance = backupReserve; From 6a2916780d237446b999d8764e5609e6d26055f0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 8 Jun 2020 20:17:05 -0400 Subject: [PATCH 0382/1888] Update text for work around UTXO limit msgbox --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 24773547dc..48d81b1a64 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2773,7 +2773,7 @@ bool CWallet::CreateTransactionBulletProof(const CKey& txPrivDes, const CPubKey& strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); } else if (setCoins.size() > MAX_TX_INPUTS) { //max inputs - strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount."); + strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. To work around this limitation, please either lower the total amount of the transaction or send two separate transactions with 50% of your total desired amount."); } else { //other strFailReason = _("Error in CreateTransactionBulletProof. Please try again."); From 53b477423dbbc50eaad776ce37bce9d39bd7cae9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 8 Jun 2020 20:18:05 -0400 Subject: [PATCH 0383/1888] Updated logging for sweeping transactions --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 48d81b1a64..02abf59954 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5088,6 +5088,7 @@ bool CWallet::CreateSweepingTransaction(CAmount target, CAmount threshold, uint3 if (GetSpendableBalance() < 5 * COIN) { return false; } + LogPrintf("Attempting to create a sweeping transaction\n"); CAmount total = 0; std::vector vCoins; COutput lowestLarger(NULL, 0, 0, false); @@ -5360,7 +5361,6 @@ void CWallet::AutoCombineDust() } return; } - LogPrintf("Creating a sweeping transaction\n"); CreateSweepingTransaction(nAutoCombineThreshold, nAutoCombineThreshold, GetAdjustedTime()); } From 90609d1802d200107151e835a569450bb9a28917 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 15 Jun 2020 22:29:14 -0400 Subject: [PATCH 0384/1888] Bump version to v1.0.7.0 --- configure.ac | 4 ++-- version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 2003958359..d97ef654a4 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 6) +define(_CLIENT_VERSION_REVISION, 7) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index a262b0d849..561cfa022e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.6.5 \ No newline at end of file +1.0.7.0 \ No newline at end of file From 1be2390c7fca0a9af45b7bc73029fad8f2035499 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 16 Jun 2020 17:35:37 -0400 Subject: [PATCH 0385/1888] Avoid counting failed connect attempts when probably offline. If a node is offline failed outbound connection attempts will crank up the addrman counter and effectively blow away our state. This change reduces the problem by only counting attempts made while the node believes it has outbound connections to at least two netgroups. Connect and addnode connections are also not counted, as there is no reason to unequally penalize them for their more frequent connections -- though there should be no real effect from this unless their addnode configureation is later removed. Wasteful repeated connection attempts while only a few connections are up are avoided via nLastTry. This is still somewhat incomplete protection because our outbound peers could be down but not timed out or might all be on 'local' networks (although the requirement for multiple netgroups helps). --- src/activemasternode.cpp | 2 +- src/addrman.cpp | 4 ++-- src/addrman.h | 6 +++--- src/net.cpp | 26 +++++++++++++------------- src/net.h | 4 ++-- src/obfuscation-relay.cpp | 2 +- src/rpc/masternode.cpp | 2 +- src/rpc/net.cpp | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index f70230e1f5..012dec4762 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -73,7 +73,7 @@ void CActiveMasternode::ManageStatus() LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString()); - CNode* pnode = ConnectNode((CAddress)service, NULL, false); + CNode* pnode = ConnectNode((CAddress)service, NULL, false, true); if (!pnode) { notCapableReason = "Could not connect to " + service.ToString(); LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); diff --git a/src/addrman.cpp b/src/addrman.cpp index 79f8031450..19d9b8731a 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -317,7 +317,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP return fNew; } -void CAddrMan::Attempt_(const CService& addr, int64_t nTime) +void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) { CAddrInfo* pinfo = Find(addr); @@ -333,7 +333,7 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) // update info info.nLastTry = nTime; - info.nAttempts++; + if (fCountFailure) info.nAttempts++; } CAddrInfo CAddrMan::Select_() diff --git a/src/addrman.h b/src/addrman.h index 3769090dc8..fc37eed848 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -226,7 +226,7 @@ class CAddrMan bool Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty); //! Mark an entry as attempted to connect. - void Attempt_(const CService& addr, int64_t nTime); + void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime); //! Select an address to connect to. //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) @@ -518,12 +518,12 @@ class CAddrMan } //! Mark an entry as connection attempted to. - void Attempt(const CService& addr, int64_t nTime = GetAdjustedTime()) + void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()) { { LOCK(cs); Check(); - Attempt_(addr, nTime); + Attempt_(addr, fCountFailure, nTime); Check(); } } diff --git a/src/net.cpp b/src/net.cpp index 922c68175b..1799de05b4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -368,7 +368,7 @@ CNode *FindNode(const CService &addr) { return NULL; } -CNode *ConnectNode(CAddress addrConnect, const char *pszDest, bool obfuScationMaster) { +CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool obfuScationMaster, bool fCountFailure) { if (pszDest == NULL) { // we clean masternode connections in CMasternodeMan::ProcessMasternodeConnections() // so should be safe to skip this and connect to local Hot MN on CActiveMasternode::ManageStatus() @@ -402,7 +402,7 @@ CNode *ConnectNode(CAddress addrConnect, const char *pszDest, bool obfuScationMa return NULL; } - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); // Add node CNode *pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); @@ -420,7 +420,7 @@ CNode *ConnectNode(CAddress addrConnect, const char *pszDest, bool obfuScationMa } else if (!proxyConnectionFailed) { // If connecting to the node failed, and failure is not caused by a problem connecting to // the proxy, mark this as an attempt. - addrman.Attempt(addrConnect); + addrman.Attempt(addrConnect, fCountFailure); } return NULL; @@ -1274,7 +1274,7 @@ void static ProcessOneShot() { CAddress addr; CSemaphoreGrant grant(*semOutbound, true); if (grant) { - OpenNetworkConnection(addr, &grant, strDest.c_str(), true); + OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true); } } @@ -1285,7 +1285,7 @@ void ThreadOpenConnections() { ProcessOneShot(); for (string strAddr : mapMultiArgs["-connect"]) { CAddress addr; - OpenNetworkConnection(addr, NULL, strAddr.c_str()); + OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { MilliSleep(500); } @@ -1367,7 +1367,7 @@ void ThreadOpenConnections() { } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, &grant); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= min(nMaxConnections - 1, 2), &grant); } } @@ -1389,7 +1389,7 @@ void ThreadOpenAddedConnections() { { CAddress addr; CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(addr, &grant, strAddNode.c_str()); + OpenNetworkConnection(addr, false, &grant, strAddNode.c_str()); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1435,7 +1435,7 @@ void ThreadOpenAddedConnections() { for (vector < CService > &vserv : lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1443,7 +1443,7 @@ void ThreadOpenAddedConnections() { } // if successful, this moves the passed grant to the constructed node -void OpenNetworkConnection(const CAddress &addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) { +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* pszDest, bool fOneShot) { // // Initiate outbound network connection // @@ -1452,15 +1452,15 @@ void OpenNetworkConnection(const CAddress &addrConnect, CSemaphoreGrant *grantOu if (IsLocal(addrConnect) || FindNode((CNetAddr) addrConnect) || CNode::IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) - return; + return false; } else if (FindNode(pszDest)) - return; + return false; - CNode *pnode = ConnectNode(addrConnect, pszDest); + CNode* pnode = ConnectNode(addrConnect, pszDest, false, fCountFailure); boost::this_thread::interruption_point(); if (!pnode) - return; + return false; if (grantOutbound) grantOutbound->MoveTo(pnode->grantOutbound); pnode->fNetworkNode = true; diff --git a/src/net.h b/src/net.h index 983781c421..8843f5683c 100644 --- a/src/net.h +++ b/src/net.h @@ -78,8 +78,8 @@ CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); -CNode* ConnectNode(CAddress addrConnect, const char* pszDest = NULL, bool obfuScationMaster = false); -void OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant* grantOutbound = NULL, const char* strDest = NULL, bool fOneShot = false); +CNode* ConnectNode(CAddress addrConnect, const char* pszDest = NULL, bool obfuScationMaster = false, bool fCountFailure = false); +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound = NULL, const char* strDest = NULL, bool fOneShot = false); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService& bindAddr, std::string& strError, bool fWhitelisted = false); diff --git a/src/obfuscation-relay.cpp b/src/obfuscation-relay.cpp index 15474c52d3..decc44af4e 100644 --- a/src/obfuscation-relay.cpp +++ b/src/obfuscation-relay.cpp @@ -101,7 +101,7 @@ void CObfuScationRelay::RelayThroughNode(int nRank) CMasternode* pmn = mnodeman.GetMasternodeByRank(nRank, nBlockHeight, ActiveProtocol()); if (pmn != NULL) { - CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, false); + CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, false, true); if (pnode) { pnode->PushMessage("dsr", (*this)); pnode->Release(); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index f032bb235b..f33bd816a6 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -288,7 +288,7 @@ UniValue masternodeconnect(const UniValue& params, bool fHelp) CService addr = CService(strAddress); - CNode* pnode = ConnectNode((CAddress)addr, NULL, false); + CNode* pnode = ConnectNode((CAddress)addr, NULL, false, true); if (pnode) { pnode->Release(); return NullUniValue; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index cc9e9efe0e..df5a6cbd64 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -179,7 +179,7 @@ UniValue addnode(const UniValue& params, bool fHelp) if (strCommand == "onetry") { CAddress addr; - OpenNetworkConnection(addr, NULL, strNode.c_str()); + OpenNetworkConnection(addr, false, NULL, strNode.c_str()); return NullUniValue; } From 102ffa4d4d700d22fdd2ec8868d2b1f5b41d7a49 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 16 Jun 2020 17:39:00 -0400 Subject: [PATCH 0386/1888] Do not increment nAttempts by more than one for every Good connection. This slows the increase of the nAttempts in addrman while partitioned, even if the node hasn't yet noticed the partitioning. --- src/addrman.cpp | 8 +++++++- src/addrman.h | 8 ++++++++ src/net.cpp | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index 19d9b8731a..f18e5716f6 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -198,6 +198,9 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) void CAddrMan::Good_(const CService& addr, int64_t nTime) { int nId; + + nLastGood = nTime; + CAddrInfo* pinfo = Find(addr, &nId); // if not found, bail out @@ -333,7 +336,10 @@ void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) // update info info.nLastTry = nTime; - if (fCountFailure) info.nAttempts++; + if (fCountFailure && info.nLastCountAttempt < nLastGood) { + info.nLastCountAttempt = nTime; + info.nAttempts++; + } } CAddrInfo CAddrMan::Select_() diff --git a/src/addrman.h b/src/addrman.h index fc37eed848..7a5f54b01f 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -26,6 +26,9 @@ class CAddrInfo : public CAddress //! last try whatsoever by us (memory only) int64_t nLastTry; + //! last counted attempt (memory only) + int64_t nLastCountAttempt; + private: //! where knowledge about this address first came from CNetAddr source; @@ -63,6 +66,7 @@ class CAddrInfo : public CAddress { nLastSuccess = 0; nLastTry = 0; + nLastCountAttempt = 0; nAttempts = 0; nRefCount = 0; fInTried = false; @@ -199,6 +203,9 @@ class CAddrMan //! list of "new" buckets int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; + //! last time Good was called (memory only) + int64_t nLastGood; + protected: //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL); @@ -444,6 +451,7 @@ class CAddrMan nIdCount = 0; nTried = 0; nNew = 0; + nLastGood = 1; //Initially at 1 so that "never" is strictly worse. } CAddrMan() diff --git a/src/net.cpp b/src/net.cpp index 1799de05b4..5e210abfa7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1367,7 +1367,7 @@ void ThreadOpenConnections() { } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= min(nMaxConnections - 1, 2), &grant); + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); } } From 3d3a2617f45b2a50994b723f8f24af14e3ec37f0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 18 Jun 2020 22:48:55 -0400 Subject: [PATCH 0387/1888] Add getsupply --- src/rpc/blockchain.cpp | 15 +++++++++++++++ src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + 3 files changed, 17 insertions(+) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a83504f638..6ca8d67a80 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -160,6 +160,21 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx return result; } +UniValue getsupply(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getsupply\n" + "\nReturns the current supply.\n" + "\nResult:\n" + "n (numeric) The current supply\n" + "\nExamples:\n" + + HelpExampleCli("getsupply", "") + HelpExampleRpc("getsupply", "")); + + LOCK(cs_main); + return ValueFromAmount(chainActive.Tip()->nMoneySupply); +} + UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index cd712e29a8..391d3d9b4e 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -285,6 +285,7 @@ static const CRPCCommand vRPCCommands[] = {"network", "clearbanned", &clearbanned, true, false, false}, /* Block chain and UTXO */ + {"blockchain", "getsupply", &getsupply, true, false, false}, {"blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false}, {"blockchain", "getbestblockhash", &getbestblockhash, true, false, false}, {"blockchain", "getblockcount", &getblockcount, true, false, false}, diff --git a/src/rpc/server.h b/src/rpc/server.h index faadde7579..406b90cd34 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -279,6 +279,7 @@ extern UniValue decodescript(const UniValue& params, bool fHelp); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); +extern UniValue getsupply(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue waitfornewblock(const UniValue& params, bool fHelp); From 1009be9d54d3352e394a5d8dd79b56de34fad861 Mon Sep 17 00:00:00 2001 From: akira Date: Fri, 19 Jun 2020 14:40:23 +0700 Subject: [PATCH 0388/1888] reconsider a Poa block if it was rejected before due to sync between nodes --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c2426a7789..8854657639 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4423,8 +4423,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, 0, "bad-prevblk"); pindexPrev = (*mi).second; if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { - //If this "invalid" block is an exact match from the checkpoints, then reconsider it - if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true)) { + //If this "invalid" block is an exact match from the checkpoints or if it is a PoA block rejected previously due not synced with other nodes before, then reconsider it + if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true) || (block.IsPoABlockByVersion() && block.posBlocksAudited.size() > 0)) { LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); CValidationState statePrev; From 43c79e9375292f3417fccf51e96f19b05d0cad14 Mon Sep 17 00:00:00 2001 From: akira Date: Fri, 19 Jun 2020 14:55:42 +0700 Subject: [PATCH 0389/1888] reconsider a Poa block if it was rejected before due to sync between nodes --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 8854657639..acc661c31f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4424,7 +4424,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, pindexPrev = (*mi).second; if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { //If this "invalid" block is an exact match from the checkpoints or if it is a PoA block rejected previously due not synced with other nodes before, then reconsider it - if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true) || (block.IsPoABlockByVersion() && block.posBlocksAudited.size() > 0)) { + if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true) || (pindexPrev->IsProofOfAudit())) { LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); CValidationState statePrev; From ac1d994ceba1c46d375c21ec837cadb0a3ca5adb Mon Sep 17 00:00:00 2001 From: akira Date: Fri, 19 Jun 2020 15:16:36 +0700 Subject: [PATCH 0390/1888] reconsider a Poa block if it was rejected before due to sync between nodes --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index acc661c31f..f9eacc9fee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4424,7 +4424,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, pindexPrev = (*mi).second; if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { //If this "invalid" block is an exact match from the checkpoints or if it is a PoA block rejected previously due not synced with other nodes before, then reconsider it - if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true) || (pindexPrev->IsProofOfAudit())) { + if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true) || (pindexPrev->IsProofOfAudit() && chainActive.Height() - pindexPrev->nHeight < Params().MaxReorganizationDepth())) { LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); CValidationState statePrev; From edf04e74ad9baf9ce0f7a475fe787b4ddeb34af9 Mon Sep 17 00:00:00 2001 From: akira Date: Mon, 22 Jun 2020 15:28:34 +0700 Subject: [PATCH 0391/1888] add debug log --- src/poa.cpp | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/poa.cpp b/src/poa.cpp index 9b0c0ff293..c43216bfca 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -222,16 +222,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) CBlockIndex* piterator = mapBlockIndex[lastAuditedPoSHash]->pnext; uint32_t idxOfPoSInfo = 0; if (!piterator) { - //check whether chainActive has - if (mapBlockIndex[lastAuditedPoSHash]->nHeight + 1 > chainActive.Height()) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } - piterator = chainActive[mapBlockIndex[lastAuditedPoSHash]->nHeight + 1]; - if (!piterator) - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != lastAuditedPoSHash) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } + return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); } while (piterator->nHeight <= (uint32_t)currentTip->nHeight && idxOfPoSInfo < block.posBlocksAudited.size()) { if (!piterator->GetBlockHeader().IsPoABlockByVersion() && piterator->nHeight > Params().LAST_POW_BLOCK()) { @@ -242,6 +233,9 @@ bool CheckPoAContainRecentHash(const CBlock& block) } else { //The PoA block is not satisfied the constraint ret = false; + LogPrintf("%s: Error: audited block height=%d, hash=%s, time=%d, actual block height=%d, hash=%s, time=%d\n", + __func__, pos.height, pos.hash.GetHex(), pos.nTime, + posAudited->nHeight, posAudited->phashBlock->GetHex(), posAudited->GetBlockTime()); break; } @@ -250,6 +244,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) if (!auditResult) { if (pos.nTime) { ret = false; + LogPrintf("%s: Failed to reverify block %s\n", __func__, pos.hash.GetHex()); break; } } @@ -258,20 +253,13 @@ bool CheckPoAContainRecentHash(const CBlock& block) piterator = piterator->pnext; if (!piterator) { - if (mapBlockIndex[h]->nHeight + 1 > chainActive.Height()) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } - piterator = chainActive[mapBlockIndex[h]->nHeight + 1]; - if (!piterator) - return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); - if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != h) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); - } + return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); } } if (idxOfPoSInfo != block.posBlocksAudited.size()) { //Not all PoS Blocks in PoA block have been checked, not satisfied + LogPrintf("%s: the number of audited blocks not valid with the chain\n", __func__); ret = false; } } else { From 49f2dea33481c5bdf804f9ba529b26e79b35b3c0 Mon Sep 17 00:00:00 2001 From: akira Date: Mon, 22 Jun 2020 16:00:21 +0700 Subject: [PATCH 0392/1888] skip poa block check at initialization --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index f9eacc9fee..34013bd5e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2914,7 +2914,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin /** * @Audit ConnectBlock */ - if (block.IsProofOfAudit()) { + if (!fVerifyingBlocks && block.IsProofOfAudit()) { //Check PoA consensus rules if (!CheckPoAContainRecentHash(block)) { return state.DoS(100, error("ConnectBlock(): PoA block should contain only non-audited recent PoS blocks")); From bee9e60e5fd31089143fa2d919a9b24773e51247 Mon Sep 17 00:00:00 2001 From: akira Date: Mon, 22 Jun 2020 17:09:27 +0700 Subject: [PATCH 0393/1888] re-implement CheckPoAContainRecentHash to re-audit blocks backwardly --- src/poa.cpp | 93 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/src/poa.cpp b/src/poa.cpp index c43216bfca..0087cad7a2 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -168,6 +168,11 @@ uint256 GetBlockProof(const CBlockIndex& block) return (~bnTarget / (bnTarget + 1)) + 1; } +CBlockIndex* FindPrevPoSBlock(CBlockIndex* p) { + if (!p || !p->pprev) return NULL; + return p->pprev->IsProofOfStake()?p->pprev:FindPrevPoSBlock(p->pprev); +} + //If blockheight = -1, the to-be-checked block is not included yet in the chain, otherwise, that is the height of the poa block bool CheckPoAContainRecentHash(const CBlock& block) { @@ -219,48 +224,64 @@ bool CheckPoAContainRecentHash(const CBlock& block) if (mapBlockIndex.count(lastAuditedPoSHash) < 1) { return error("CheckPoAContainRecentHash() : Audited blocks not found"); } - CBlockIndex* piterator = mapBlockIndex[lastAuditedPoSHash]->pnext; - uint32_t idxOfPoSInfo = 0; - if (!piterator) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); + + uint256 currentFirstPoSAuditedHash = block.posBlocksAudited[0].hash; + uint256 currentLastPoSAuditedHash = block.posBlocksAudited.back().hash; + if (mapBlockIndex.count(currentFirstPoSAuditedHash) < 1 || mapBlockIndex.count(currentLastPoSAuditedHash) < 1) { + return error("CheckPoAContainRecentHash() : Being audited blocks not found"); + } + CBlockIndex* pCurrentFirstPoSAuditedIndex = mapBlockIndex[currentFirstPoSAuditedHash]; + CBlockIndex* pCurrentLastPoSAuditedIndex = mapBlockIndex[currentLastPoSAuditedHash]; + + //check lastAuditedPoSHash and currentFirstPoSAuditedHash must be on the same fork + //that lastAuditedPoSHash must be parent block of currentFirstPoSAuditedHash + if (pCurrentFirstPoSAuditedIndex->GetAncestor(lastAuditedPoSBlockInfo.height)->GetBlockHash() != lastAuditedPoSHash) { + return error("CheckPoAContainRecentHash() : PoA block is not on the same fork with the previous poa block"); } - while (piterator->nHeight <= (uint32_t)currentTip->nHeight && idxOfPoSInfo < block.posBlocksAudited.size()) { - if (!piterator->GetBlockHeader().IsPoABlockByVersion() && piterator->nHeight > Params().LAST_POW_BLOCK()) { - PoSBlockSummary pos = block.posBlocksAudited[idxOfPoSInfo]; - CBlockIndex* posAudited = piterator; - if (pos.hash == *(posAudited->phashBlock) && pos.height == (uint32_t)posAudited->nHeight && pos.nTime == posAudited->GetBlockTime()) { - idxOfPoSInfo++; - } else { - //The PoA block is not satisfied the constraint + + //check there is no pos block between lastAuditedPoSHash and currentFirstPoSAuditedHash + CBlockIndex* pIndexLoop = pCurrentFirstPoSAuditedIndex->pprev; + while(pIndexLoop && !pIndexLoop->IsProofOfStake()) { + pIndexLoop = pIndexLoop->pprev; + } + if (!pIndexLoop || pIndexLoop->GetBlockHash() != lastAuditedPoSHash) { + return error("CheckPoAContainRecentHash() : Some PoS block between %s and %s is not audited\n", lastAuditedPoSHash.GetHex(), currentFirstPoSAuditedHash.GetHex()); + } + + //alright, check all pos blocks audited in the block is conseutive in the chain + for(size_t i = block.posBlocksAudited.size() - 1; i > 0; i--) { + uint256 thisPoSAduditedHash = block.posBlocksAudited[i].hash; + if (mapBlockIndex.count(thisPoSAduditedHash) < 1) { + return error("CheckPoAContainRecentHash() : PoS block %s not found\n", thisPoSAduditedHash.GetHex()); + } + CBlockIndex* thisPoSAuditedIndex = mapBlockIndex[thisPoSAduditedHash]; + CBlockIndex* previousPoSIndex = FindPrevPoSBlock(thisPoSAuditedIndex); + if (!previousPoSIndex) { + return error("CheckPoAContainRecentHash() : Failed to find previous PoS block for block %s\n", thisPoSAduditedHash.GetHex()); + } + PoSBlockSummary previousSummary = block.posBlocksAudited[i - 1]; + if (previousPoSIndex->GetBlockHash() != previousSummary.hash || + (uint32_t)previousPoSIndex->nHeight != previousSummary.height || + previousPoSIndex->GetBlockTime() != previousSummary.nTime) { + return error("CheckPoAContainRecentHash() : PoS block info not matched for %s\n", thisPoSAduditedHash.GetHex()); + } + bool auditResult = ReVerifyPoSBlock(thisPoSAuditedIndex); + if (!auditResult) { + if (previousSummary.nTime) { ret = false; - LogPrintf("%s: Error: audited block height=%d, hash=%s, time=%d, actual block height=%d, hash=%s, time=%d\n", - __func__, pos.height, pos.hash.GetHex(), pos.nTime, - posAudited->nHeight, posAudited->phashBlock->GetHex(), posAudited->GetBlockTime()); + LogPrintf("%s: Failed to reverify block %s\n", __func__, previousSummary.hash.GetHex()); break; } - - CBlockIndex* p = mapBlockIndex[pos.hash]; - bool auditResult = ReVerifyPoSBlock(p); - if (!auditResult) { - if (pos.nTime) { - ret = false; - LogPrintf("%s: Failed to reverify block %s\n", __func__, pos.hash.GetHex()); - break; - } - } - } - uint256 h = piterator->GetBlockHash(); - piterator = piterator->pnext; - - if (!piterator) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); } } - - if (idxOfPoSInfo != block.posBlocksAudited.size()) { - //Not all PoS Blocks in PoA block have been checked, not satisfied - LogPrintf("%s: the number of audited blocks not valid with the chain\n", __func__); - ret = false; + if (ret) { + bool auditResult = ReVerifyPoSBlock(pCurrentFirstPoSAuditedIndex); + if (!auditResult) { + if (block.posBlocksAudited[0].nTime) { + ret = false; + LogPrintf("%s: Failed to reverify block %s\n", __func__, block.posBlocksAudited[0].hash.GetHex()); + } + } } } else { ret = block.hashPrevPoABlock.IsNull(); From e47ae72bcfafd88eda6c1e5023eaff62cee34aa1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 23 Jun 2020 13:47:28 -0400 Subject: [PATCH 0394/1888] depends: xproto is only directly needed by libXau --- depends/packages/libxcb.mk | 2 +- depends/packages/qt.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index ab2e89dfbe..961cb86c95 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -3,7 +3,7 @@ $(package)_version=1.10 $(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 -$(package)_dependencies=xcb_proto libXau xproto +$(package)_dependencies=xcb_proto libXau define $(package)_set_vars $(package)_config_opts=--disable-static diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 2ba2656385..f5d85aa807 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -5,7 +5,7 @@ $(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) $(package)_sha256_hash=d5a97381b9339c0fbaf13f0c05d599a5c999dcf94145044058198987183fed65 $(package)_dependencies=openssl zlib -$(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext +$(package)_linux_dependencies=freetype fontconfig libxcb libX11 libXext $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch From 2c88040b1583904b92ecaeae98ac60bd1f4eac6a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 23 Jun 2020 13:48:14 -0400 Subject: [PATCH 0395/1888] depends: qt: Explicitly stop using Xlib/libX11 Previously, in 683b7d7 and 0e75263, we accidentally broke QT's ability to pick up Xlib thru the config.gui.tests.xlib configuration test, which also means that config.gui.libraries.xcb_xlib wasn't run. This resulted in a QT build that was implicitly -no-xcb-lib and -no-feature-xlib. This is actually a desired behaviour, as it means less required shared objects for our final bitcoin-qt binary. Specifically, it eliminated the libX11-xcb.so.1 and libX11.so.6 requirements. In this commit, we explicitly build without Xlib. We should continue to track upstream ticket https://bugreports.qt.io/browse/QTBUG-61452 which talks about adding a -no-xlib (non-hidden) flag instead of the -no-feature-xlib (hidden) flag. --- depends/packages/qt.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index f5d85aa807..048cd22299 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -100,6 +100,8 @@ endif $(package)_config_opts_linux = -qt-xkbcommon-x11 $(package)_config_opts_linux += -qt-xcb +$(package)_config_opts_linux += -no-xcb-xlib +$(package)_config_opts_linux += -no-feature-xlib $(package)_config_opts_linux += -system-freetype $(package)_config_opts_linux += -no-feature-sessionmanager $(package)_config_opts_linux += -fontconfig From d5b417004dce199581cc7686781b8d77b07d0f7e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 24 Jun 2020 08:10:56 -0400 Subject: [PATCH 0396/1888] Undo Addrman offline attempts PR#187 This was causing a crash on Mac, will be revisited later --- src/activemasternode.cpp | 2 +- src/addrman.cpp | 10 ++-------- src/addrman.h | 14 +++----------- src/net.cpp | 26 +++++++++++++------------- src/net.h | 4 ++-- src/obfuscation-relay.cpp | 2 +- src/rpc/masternode.cpp | 2 +- src/rpc/net.cpp | 2 +- 8 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 012dec4762..f70230e1f5 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -73,7 +73,7 @@ void CActiveMasternode::ManageStatus() LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString()); - CNode* pnode = ConnectNode((CAddress)service, NULL, false, true); + CNode* pnode = ConnectNode((CAddress)service, NULL, false); if (!pnode) { notCapableReason = "Could not connect to " + service.ToString(); LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); diff --git a/src/addrman.cpp b/src/addrman.cpp index f18e5716f6..79f8031450 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -198,9 +198,6 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId) void CAddrMan::Good_(const CService& addr, int64_t nTime) { int nId; - - nLastGood = nTime; - CAddrInfo* pinfo = Find(addr, &nId); // if not found, bail out @@ -320,7 +317,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP return fNew; } -void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) +void CAddrMan::Attempt_(const CService& addr, int64_t nTime) { CAddrInfo* pinfo = Find(addr); @@ -336,10 +333,7 @@ void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) // update info info.nLastTry = nTime; - if (fCountFailure && info.nLastCountAttempt < nLastGood) { - info.nLastCountAttempt = nTime; - info.nAttempts++; - } + info.nAttempts++; } CAddrInfo CAddrMan::Select_() diff --git a/src/addrman.h b/src/addrman.h index 7a5f54b01f..3769090dc8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -26,9 +26,6 @@ class CAddrInfo : public CAddress //! last try whatsoever by us (memory only) int64_t nLastTry; - //! last counted attempt (memory only) - int64_t nLastCountAttempt; - private: //! where knowledge about this address first came from CNetAddr source; @@ -66,7 +63,6 @@ class CAddrInfo : public CAddress { nLastSuccess = 0; nLastTry = 0; - nLastCountAttempt = 0; nAttempts = 0; nRefCount = 0; fInTried = false; @@ -203,9 +199,6 @@ class CAddrMan //! list of "new" buckets int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; - //! last time Good was called (memory only) - int64_t nLastGood; - protected: //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL); @@ -233,7 +226,7 @@ class CAddrMan bool Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty); //! Mark an entry as attempted to connect. - void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime); + void Attempt_(const CService& addr, int64_t nTime); //! Select an address to connect to. //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) @@ -451,7 +444,6 @@ class CAddrMan nIdCount = 0; nTried = 0; nNew = 0; - nLastGood = 1; //Initially at 1 so that "never" is strictly worse. } CAddrMan() @@ -526,12 +518,12 @@ class CAddrMan } //! Mark an entry as connection attempted to. - void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()) + void Attempt(const CService& addr, int64_t nTime = GetAdjustedTime()) { { LOCK(cs); Check(); - Attempt_(addr, fCountFailure, nTime); + Attempt_(addr, nTime); Check(); } } diff --git a/src/net.cpp b/src/net.cpp index 5e210abfa7..922c68175b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -368,7 +368,7 @@ CNode *FindNode(const CService &addr) { return NULL; } -CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool obfuScationMaster, bool fCountFailure) { +CNode *ConnectNode(CAddress addrConnect, const char *pszDest, bool obfuScationMaster) { if (pszDest == NULL) { // we clean masternode connections in CMasternodeMan::ProcessMasternodeConnections() // so should be safe to skip this and connect to local Hot MN on CActiveMasternode::ManageStatus() @@ -402,7 +402,7 @@ CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool obfuScationMa return NULL; } - addrman.Attempt(addrConnect, fCountFailure); + addrman.Attempt(addrConnect); // Add node CNode *pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); @@ -420,7 +420,7 @@ CNode* ConnectNode(CAddress addrConnect, const char* pszDest, bool obfuScationMa } else if (!proxyConnectionFailed) { // If connecting to the node failed, and failure is not caused by a problem connecting to // the proxy, mark this as an attempt. - addrman.Attempt(addrConnect, fCountFailure); + addrman.Attempt(addrConnect); } return NULL; @@ -1274,7 +1274,7 @@ void static ProcessOneShot() { CAddress addr; CSemaphoreGrant grant(*semOutbound, true); if (grant) { - OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true); + OpenNetworkConnection(addr, &grant, strDest.c_str(), true); } } @@ -1285,7 +1285,7 @@ void ThreadOpenConnections() { ProcessOneShot(); for (string strAddr : mapMultiArgs["-connect"]) { CAddress addr; - OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); + OpenNetworkConnection(addr, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { MilliSleep(500); } @@ -1367,7 +1367,7 @@ void ThreadOpenConnections() { } if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); + OpenNetworkConnection(addrConnect, &grant); } } @@ -1389,7 +1389,7 @@ void ThreadOpenAddedConnections() { { CAddress addr; CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(addr, false, &grant, strAddNode.c_str()); + OpenNetworkConnection(addr, &grant, strAddNode.c_str()); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1435,7 +1435,7 @@ void ThreadOpenAddedConnections() { for (vector < CService > &vserv : lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); - OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), false, &grant); + OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); MilliSleep(500); } MilliSleep(120000); // Retry every 2 minutes @@ -1443,7 +1443,7 @@ void ThreadOpenAddedConnections() { } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* pszDest, bool fOneShot) { +void OpenNetworkConnection(const CAddress &addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) { // // Initiate outbound network connection // @@ -1452,15 +1452,15 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem if (IsLocal(addrConnect) || FindNode((CNetAddr) addrConnect) || CNode::IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) - return false; + return; } else if (FindNode(pszDest)) - return false; + return; - CNode* pnode = ConnectNode(addrConnect, pszDest, false, fCountFailure); + CNode *pnode = ConnectNode(addrConnect, pszDest); boost::this_thread::interruption_point(); if (!pnode) - return false; + return; if (grantOutbound) grantOutbound->MoveTo(pnode->grantOutbound); pnode->fNetworkNode = true; diff --git a/src/net.h b/src/net.h index 8843f5683c..983781c421 100644 --- a/src/net.h +++ b/src/net.h @@ -78,8 +78,8 @@ CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); -CNode* ConnectNode(CAddress addrConnect, const char* pszDest = NULL, bool obfuScationMaster = false, bool fCountFailure = false); -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound = NULL, const char* strDest = NULL, bool fOneShot = false); +CNode* ConnectNode(CAddress addrConnect, const char* pszDest = NULL, bool obfuScationMaster = false); +void OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant* grantOutbound = NULL, const char* strDest = NULL, bool fOneShot = false); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService& bindAddr, std::string& strError, bool fWhitelisted = false); diff --git a/src/obfuscation-relay.cpp b/src/obfuscation-relay.cpp index decc44af4e..15474c52d3 100644 --- a/src/obfuscation-relay.cpp +++ b/src/obfuscation-relay.cpp @@ -101,7 +101,7 @@ void CObfuScationRelay::RelayThroughNode(int nRank) CMasternode* pmn = mnodeman.GetMasternodeByRank(nRank, nBlockHeight, ActiveProtocol()); if (pmn != NULL) { - CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, false, true); + CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, false); if (pnode) { pnode->PushMessage("dsr", (*this)); pnode->Release(); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index f33bd816a6..f032bb235b 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -288,7 +288,7 @@ UniValue masternodeconnect(const UniValue& params, bool fHelp) CService addr = CService(strAddress); - CNode* pnode = ConnectNode((CAddress)addr, NULL, false, true); + CNode* pnode = ConnectNode((CAddress)addr, NULL, false); if (pnode) { pnode->Release(); return NullUniValue; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index df5a6cbd64..cc9e9efe0e 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -179,7 +179,7 @@ UniValue addnode(const UniValue& params, bool fHelp) if (strCommand == "onetry") { CAddress addr; - OpenNetworkConnection(addr, false, NULL, strNode.c_str()); + OpenNetworkConnection(addr, NULL, strNode.c_str()); return NullUniValue; } From 96fb149251ab9990b9de17733b1da26a642fdf5b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 24 Jun 2020 08:11:59 -0400 Subject: [PATCH 0397/1888] Bump version to v1.0.7.1 --- configure.ac | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d97ef654a4..72971a5040 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 7) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index 561cfa022e..97244d8e52 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.7.0 \ No newline at end of file +1.0.7.1 \ No newline at end of file From 311f09fe83a0ec9e98e4f48121a414d69994f5d0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 22:55:19 -0400 Subject: [PATCH 0398/1888] depends: libX11: Make package headers-only We're no longer building QT with libX11/XLib, however, libX11/XLib headers are still required for parts of QT. In this commit we add a minimal configure.ac for libX11/XLib that is headers-only. This change allows us to remove all of libX11/XLib's dependencies. --- depends/packages/libX11.mk | 17 +++++------------ depends/packages/packages.mk | 2 +- depends/packages/xextproto.mk | 25 ------------------------- depends/packages/xtrans.mk | 26 -------------------------- depends/patches/libX11/configure.ac | 6 ++++++ 5 files changed, 12 insertions(+), 64 deletions(-) delete mode 100644 depends/packages/xextproto.mk delete mode 100644 depends/packages/xtrans.mk create mode 100644 depends/patches/libX11/configure.ac diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk index a013da5192..abf21963e7 100644 --- a/depends/packages/libX11.mk +++ b/depends/packages/libX11.mk @@ -3,25 +3,18 @@ $(package)_version=1.6.2 $(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 -$(package)_dependencies=libxcb xtrans xextproto xproto - -define $(package)_set_vars -$(package)_config_opts=--disable-xkb --disable-static -$(package)_config_opts_linux=--with-pic -endef +$(package)_patches=configure.ac define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . && \ + cp -f $($(package)_patch_dir)/configure.ac . endef define $(package)_config_cmds + autoreconf --install --force --verbose && \ $($(package)_autoconf) endef -define $(package)_build_cmds - $(MAKE) -endef - define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install + $(MAKE) -C include DESTDIR=$($(package)_staging_dir) install-x11includeHEADERS endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index c760a63a1f..a2ffac9ecb 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -5,7 +5,7 @@ qt_packages = protobuf zlib qrencode_packages = qrencode -qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 libXext qt_android_packages=qt qt_darwin_packages=qt diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk deleted file mode 100644 index 157b76edf6..0000000000 --- a/depends/packages/xextproto.mk +++ /dev/null @@ -1,25 +0,0 @@ -package=xextproto -$(package)_version=7.3.0 -$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0 - -define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . -endef - -define $(package)_set_vars -$(package)_config_opts=--disable-shared -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk deleted file mode 100644 index 6201d1d270..0000000000 --- a/depends/packages/xtrans.mk +++ /dev/null @@ -1,26 +0,0 @@ -package=xtrans -$(package)_version=1.3.4 -$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a -$(package)_dependencies= - -define $(package)_set_vars - $(package)_config_opts_linux=--disable-docs --without-xmlto --without-fop --without-xsltproc -endef - -define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef diff --git a/depends/patches/libX11/configure.ac b/depends/patches/libX11/configure.ac new file mode 100644 index 0000000000..1c3bd41b3f --- /dev/null +++ b/depends/patches/libX11/configure.ac @@ -0,0 +1,6 @@ +AC_PREREQ([2.60]) +AC_INIT([libX11], [1.6.2], + [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], [libX11]) +AM_INIT_AUTOMAKE([foreign]) +AC_CONFIG_FILES([include/Makefile]) +AC_OUTPUT From 1ce84e10a835ad162579b71859d835230b0db85b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 22:57:05 -0400 Subject: [PATCH 0399/1888] build-aux: Remove check for x11-xcb We're no longer building QT with libX11/XLib, so it doesn't make sense to check for the x11-xcb package --- build-aux/m4/bitcoin_qt.m4 | 1 - 1 file changed, 1 deletion(-) diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index d918aa6db0..d2fdb303db 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -381,7 +381,6 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ PKG_CHECK_MODULES([QTFB], [Qt5FbSupport], [QT_LIBS="-lQt5FbSupport $QT_LIBS"]) fi if test "x$TARGET_OS" = xlinux; then - PKG_CHECK_MODULES([X11XCB], [x11-xcb], [QT_LIBS="$X11XCB_LIBS $QT_LIBS"]) if ${PKG_CONFIG} --exists "Qt5Core >= 5.5" 2>/dev/null; then PKG_CHECK_MODULES([QTXCBQPA], [Qt5XcbQpa], [QT_LIBS="$QTXCBQPA_LIBS $QT_LIBS"]) fi From 5d2f1cf1324ef8e7101bcb46be8587f0a30b9b08 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 23:02:18 -0400 Subject: [PATCH 0400/1888] depends: libXext isn't needed by anyone libXext was only needed (as a library) by QT when it was using XLib/libX11 (as a library), now that we're building QT without XLib/libX11, we can safely remove libXext. --- depends/packages/libXext.mk | 26 -------------------------- depends/packages/packages.mk | 2 +- depends/packages/qt.mk | 2 +- 3 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 depends/packages/libXext.mk diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk deleted file mode 100644 index d94f49f3be..0000000000 --- a/depends/packages/libXext.mk +++ /dev/null @@ -1,26 +0,0 @@ -package=libXext -$(package)_version=1.3.2 -$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0 -$(package)_dependencies=xproto xextproto libX11 libXau - -define $(package)_set_vars - $(package)_config_opts=--disable-shared -endef - -define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -endef - -define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) install -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index a2ffac9ecb..79b74373a2 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -5,7 +5,7 @@ qt_packages = protobuf zlib qrencode_packages = qrencode -qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 libXext +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 qt_android_packages=qt qt_darwin_packages=qt diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 048cd22299..706da71e1e 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -5,7 +5,7 @@ $(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) $(package)_sha256_hash=d5a97381b9339c0fbaf13f0c05d599a5c999dcf94145044058198987183fed65 $(package)_dependencies=openssl zlib -$(package)_linux_dependencies=freetype fontconfig libxcb libX11 libXext +$(package)_linux_dependencies=freetype fontconfig libxcb libX11 $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch From 61d51485f597bdb254b6d40a36d7939ee2bf3233 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 23:02:35 -0400 Subject: [PATCH 0401/1888] symbol-check: Disallow libX11-*.so.* shared libraries They should no longer be needed as we build QT without libX11/XLib libraries now. --- contrib/devtools/symbol-check.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index ea8bcb5608..cad26b78f5 100644 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -63,8 +63,6 @@ b'ld-linux-x86-64.so.2', # 64-bit dynamic linker b'ld-linux.so.2', # 32-bit dynamic linker # bitcoin-qt only -b'libX11-xcb.so.1', # part of X11 -b'libX11.so.6', # part of X11 b'libxcb.so.1', # part of X11 b'libfontconfig.so.1', # font support b'libfreetype.so.6', # font parsing From be153268cfcd2ae0723d841b4d7188142d98c10b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 23:05:03 -0400 Subject: [PATCH 0402/1888] gitignore: Actually pay attention to depends patches There was a previous attempt to achieve this, and it was bad. This works. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2d2d19ae71..aa4fca1689 100644 --- a/.gitignore +++ b/.gitignore @@ -138,7 +138,7 @@ qa/pull-tester/test.*/* !src/leveldb*/Makefile !depends/Makefile -!depends/patches/*/*.patch +!depends/patches/**/*.patch .cproject .project From 2d86919647f2dc7d44f125a3dab8b79b57f1e0c8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 25 Jun 2020 23:10:12 -0400 Subject: [PATCH 0403/1888] depends: qt: Patch to remove dep on libX11 We can actually patch QT to remove its dependency on libX11's headers. It turns it this wasn't that hard. --- depends/packages/libX11.mk | 20 --------- depends/packages/packages.mk | 2 +- depends/packages/qt.mk | 5 ++- depends/patches/libX11/configure.ac | 6 --- depends/patches/qt/no-xlib.patch | 69 +++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 29 deletions(-) delete mode 100644 depends/packages/libX11.mk delete mode 100644 depends/patches/libX11/configure.ac create mode 100644 depends/patches/qt/no-xlib.patch diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk deleted file mode 100644 index abf21963e7..0000000000 --- a/depends/packages/libX11.mk +++ /dev/null @@ -1,20 +0,0 @@ -package=libX11 -$(package)_version=1.6.2 -$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 -$(package)_patches=configure.ac - -define $(package)_preprocess_cmds - cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . && \ - cp -f $($(package)_patch_dir)/configure.ac . -endef - -define $(package)_config_cmds - autoreconf --install --force --verbose && \ - $($(package)_autoconf) -endef - -define $(package)_stage_cmds - $(MAKE) -C include DESTDIR=$($(package)_staging_dir) install-x11includeHEADERS -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 79b74373a2..9922bbe3b0 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -5,7 +5,7 @@ qt_packages = protobuf zlib qrencode_packages = qrencode -qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libX11 +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig qt_android_packages=qt qt_darwin_packages=qt diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 706da71e1e..2a048b88b9 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -5,10 +5,10 @@ $(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) $(package)_sha256_hash=d5a97381b9339c0fbaf13f0c05d599a5c999dcf94145044058198987183fed65 $(package)_dependencies=openssl zlib -$(package)_linux_dependencies=freetype fontconfig libxcb libX11 +$(package)_linux_dependencies=freetype fontconfig libxcb $(package)_build_subdir=qtbase $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent -$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch fix_android_qmake_conf.patch fix_android_jni_static.patch no-xlib.patch # Update OSX_QT_TRANSLATIONS when this is updated $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) @@ -198,6 +198,7 @@ define $(package)_preprocess_cmds echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch &&\ patch -p1 -i $($(package)_patch_dir)/fix_s390x_powerpc_mips_mipsel_architectures.patch &&\ + patch -p1 -i $($(package)_patch_dir)/no-xlib.patch &&\ echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ diff --git a/depends/patches/libX11/configure.ac b/depends/patches/libX11/configure.ac deleted file mode 100644 index 1c3bd41b3f..0000000000 --- a/depends/patches/libX11/configure.ac +++ /dev/null @@ -1,6 +0,0 @@ -AC_PREREQ([2.60]) -AC_INIT([libX11], [1.6.2], - [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], [libX11]) -AM_INIT_AUTOMAKE([foreign]) -AC_CONFIG_FILES([include/Makefile]) -AC_OUTPUT diff --git a/depends/patches/qt/no-xlib.patch b/depends/patches/qt/no-xlib.patch new file mode 100644 index 0000000000..fe82c2c73c --- /dev/null +++ b/depends/patches/qt/no-xlib.patch @@ -0,0 +1,69 @@ +From 9563cef873ae82e06f60708d706d054717e801ce Mon Sep 17 00:00:00 2001 +From: Carl Dong +Date: Thu, 18 Jul 2019 17:22:05 -0400 +Subject: [PATCH] Wrap xlib related code blocks in #if's + +They are not necessary to compile QT. +--- + qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +index 7c62c2e2b3..c05c6c0a07 100644 +--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp ++++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +@@ -49,7 +49,9 @@ + #include + #include + #include ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + #include ++#endif + #include + #include + +@@ -384,6 +386,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget) + w->setCursor(c, isBitmapCursor); + } + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + static int cursorIdForShape(int cshape) + { + int cursorId = 0; +@@ -437,6 +440,7 @@ static int cursorIdForShape(int cshape) + } + return cursorId; + } ++#endif + + xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) + { +@@ -558,7 +562,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) + xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + { + xcb_connection_t *conn = xcb_connection(); ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + int cursorId = cursorIdForShape(cshape); ++#endif + xcb_cursor_t cursor = XCB_NONE; + + // Try Xcursor first +@@ -589,6 +595,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + // Non-standard X11 cursors are created from bitmaps + cursor = createNonStandardCursor(cshape); + ++#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) + // Create a glpyh cursor if everything else failed + if (!cursor && cursorId) { + cursor = xcb_generate_id(conn); +@@ -596,6 +603,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) + cursorId, cursorId + 1, + 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); + } ++#endif + + if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) { + const char *name = cursorNames[cshape]; +-- +2.22.0 + From 5acd65825a144325f70ce8a91e9df32f53111f09 Mon Sep 17 00:00:00 2001 From: ALEEF02 Date: Tue, 25 Aug 2020 09:52:29 -0700 Subject: [PATCH 0404/1888] Change TOTP from 6 to 8 digits --- src/qt/2faconfirmdialog.cpp | 32 +++++++++++++++-- src/qt/2fadialog.cpp | 32 +++++++++++++++-- src/qt/2faqrdialog.cpp | 2 +- src/qt/forms/2faconfirmdialog.ui | 58 +++++++++++++++++++++++++++++- src/qt/forms/2fadialog.ui | 60 ++++++++++++++++++++++++++++++-- 5 files changed, 176 insertions(+), 8 deletions(-) diff --git a/src/qt/2faconfirmdialog.cpp b/src/qt/2faconfirmdialog.cpp index 3cf9bec89e..bbc63faaa6 100644 --- a/src/qt/2faconfirmdialog.cpp +++ b/src/qt/2faconfirmdialog.cpp @@ -41,6 +41,16 @@ TwoFAConfirmDialog::TwoFAConfirmDialog(QWidget *parent) : intVal_6->setLocale(QLocale::C); ui->txtcode_6->setValidator(intVal_6); ui->txtcode_6->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); + intVal_7->setLocale(QLocale::C); + ui->txtcode_7->setValidator(intVal_7); + ui->txtcode_7->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); + intVal_8->setLocale(QLocale::C); + ui->txtcode_8->setValidator(intVal_8); + ui->txtcode_8->setAlignment(Qt::AlignCenter); connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_acceptCode())); connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); @@ -50,6 +60,8 @@ TwoFAConfirmDialog::TwoFAConfirmDialog(QWidget *parent) : connect(ui->txtcode_4, &QLineEdit::textChanged, this, &TwoFAConfirmDialog::codeChanged); connect(ui->txtcode_5, &QLineEdit::textChanged, this, &TwoFAConfirmDialog::codeChanged); connect(ui->txtcode_6, &QLineEdit::textChanged, this, &TwoFAConfirmDialog::codeChanged); + connect(ui->txtcode_7, &QLineEdit::textChanged, this, &TwoFAConfirmDialog::codeChanged); + connect(ui->txtcode_8, &QLineEdit::textChanged, this, &TwoFAConfirmDialog::codeChanged); } @@ -61,7 +73,7 @@ TwoFAConfirmDialog::~TwoFAConfirmDialog() void TwoFAConfirmDialog::on_acceptCode() { QString code; - char code1, code2, code3, code4, code5, code6; + char code1, code2, code3, code4, code5, code6, code7, code8; QString input; char* chrlist; QRegExp re("\\d*"); // a digit (\d), zero or more times (*) @@ -112,8 +124,24 @@ void TwoFAConfirmDialog::on_acceptCode() return; chrlist = input.toUtf8().data(); code6 = chrlist[0]; + + input = ui->txtcode_7->text(); + if (input.length() > 1) + return; + if (!re.exactMatch(input)) + return; + chrlist = input.toUtf8().data(); + code7 = chrlist[0]; + + input = ui->txtcode_8->text(); + if (input.length() > 1) + return; + if (!re.exactMatch(input)) + return; + chrlist = input.toUtf8().data(); + code8 = chrlist[0]; - code.sprintf("%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6); + code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); QString result = ""; QString secret = QString::fromStdString(pwalletMain->Read2FASecret()); diff --git a/src/qt/2fadialog.cpp b/src/qt/2fadialog.cpp index b8c0cc50b7..9019248fdd 100644 --- a/src/qt/2fadialog.cpp +++ b/src/qt/2fadialog.cpp @@ -40,6 +40,16 @@ TwoFADialog::TwoFADialog(QWidget *parent) : intVal_6->setLocale(QLocale::C); ui->txtcode_6->setValidator(intVal_6); ui->txtcode_6->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); + intVal_7->setLocale(QLocale::C); + ui->txtcode_7->setValidator(intVal_7); + ui->txtcode_7->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); + intVal_8->setLocale(QLocale::C); + ui->txtcode_8->setValidator(intVal_8); + ui->txtcode_8->setAlignment(Qt::AlignCenter); connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_acceptCode())); connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); @@ -49,6 +59,8 @@ TwoFADialog::TwoFADialog(QWidget *parent) : connect(ui->txtcode_4, &QLineEdit::textChanged, this, &TwoFADialog::codeChanged); connect(ui->txtcode_5, &QLineEdit::textChanged, this, &TwoFADialog::codeChanged); connect(ui->txtcode_6, &QLineEdit::textChanged, this, &TwoFADialog::codeChanged); + connect(ui->txtcode_7, &QLineEdit::textChanged, this, &TwoFADialog::codeChanged); + connect(ui->txtcode_8, &QLineEdit::textChanged, this, &TwoFADialog::codeChanged); ui->lblOpenAppURL->setVisible(false); bool status = pwalletMain->Read2FA(); @@ -66,7 +78,7 @@ TwoFADialog::~TwoFADialog() void TwoFADialog::on_acceptCode() { QString code; - char code1, code2, code3, code4, code5, code6; + char code1, code2, code3, code4, code5, code6, code7, code8; QString input; char* chrlist; QRegExp re("\\d*"); // a digit (\d), zero or more times (*) @@ -117,8 +129,24 @@ void TwoFADialog::on_acceptCode() return; chrlist = input.toUtf8().data(); code6 = chrlist[0]; + + input = ui->txtcode_7->text(); + if (input.length() > 1) + return; + if (!re.exactMatch(input)) + return; + chrlist = input.toUtf8().data(); + code7 = chrlist[0]; + + input = ui->txtcode_8->text(); + if (input.length() > 1) + return; + if (!re.exactMatch(input)) + return; + chrlist = input.toUtf8().data(); + code8 = chrlist[0]; - code.sprintf("%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6); + code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); QString result = ""; QString secret = QString::fromStdString(pwalletMain->Read2FASecret()); diff --git a/src/qt/2faqrdialog.cpp b/src/qt/2faqrdialog.cpp index 6d5919b4f9..fb21f2343d 100644 --- a/src/qt/2faqrdialog.cpp +++ b/src/qt/2faqrdialog.cpp @@ -71,7 +71,7 @@ void TwoFAQRDialog::update() pwalletMain->Write2FASecret(addr); - uri.sprintf("otpauth://totp/DAPS:QT%20Wallet?secret=%s&issuer=dapscoin&algorithm=SHA1&digits=6&period=30", addr.c_str()); + uri.sprintf("otpauth://totp/DAPS:QT%20Wallet?secret=%s&issuer=dapscoin&algorithm=SHA1&digits=8&period=30", addr.c_str()); infoText = "Recovery Key: "; ui->lblURI->setText(infoText + addr.c_str()); diff --git a/src/qt/forms/2faconfirmdialog.ui b/src/qt/forms/2faconfirmdialog.ui index eea127245e..7efa703a36 100644 --- a/src/qt/forms/2faconfirmdialog.ui +++ b/src/qt/forms/2faconfirmdialog.ui @@ -42,7 +42,7 @@ - Please enter a six digit 2FA code: + Please enter an eight digit 2FA code: Qt::AlignCenter @@ -226,6 +226,62 @@ Qt::ImhDigitsOnly + + + + + true + + + + 0 + 0 + + + + + 0 + 40 + + + + + 0 + 0 + + + + Qt::ImhDigitsOnly + + + + + + + true + + + + 0 + 0 + + + + + 0 + 40 + + + + + 0 + 0 + + + + Qt::ImhDigitsOnly + + diff --git a/src/qt/forms/2fadialog.ui b/src/qt/forms/2fadialog.ui index 896ca6c8f0..c4ac288ee3 100644 --- a/src/qt/forms/2fadialog.ui +++ b/src/qt/forms/2fadialog.ui @@ -19,7 +19,7 @@ Transaction Details - + 30 @@ -78,7 +78,7 @@ - Please enter a six digit 2FA code: + Please enter an eight digit 2FA code: Qt::AlignCenter @@ -262,6 +262,62 @@ Qt::ImhDigitsOnly + + + + + true + + + + 0 + 0 + + + + + 0 + 40 + + + + + 0 + 0 + + + + Qt::ImhDigitsOnly + + + + + + + true + + + + 0 + 0 + + + + + 0 + 40 + + + + + 0 + 0 + + + + Qt::ImhDigitsOnly + + From c7b2c0fcf5c981b5be4b74bd8ecb85e338e46ade Mon Sep 17 00:00:00 2001 From: ALEEF02 Date: Tue, 25 Aug 2020 17:15:57 -0700 Subject: [PATCH 0405/1888] Fix UI formatting --- src/qt/res/css/Dark.css | 12 ++++++++---- src/qt/res/css/Light.css | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 9ff09c7c31..d2b1c8b2c2 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -59,8 +59,8 @@ QDialog { border-image: url(':/images/background') 0 0 0 0 stretch stretch; } -#line_1, #line_2, #line_3, -#line_4, #line_5, #line_6 { +#line_1, #line_2, #line_3, #line_4, +#line_5, #line_6, #line_7, #line_8 { border-bottom: 1px solid gray; max-height: 5px; margin: 5px; @@ -417,7 +417,9 @@ ToggleButton > QPushButton:enabled:checked { #code_3, #code_4, #code_5, -#code_6 { +#code_6, +#code_7, +#code_8 { border-bottom-width: 1px; border-bottom-style: solid; border-radius: 0px; @@ -429,7 +431,9 @@ ToggleButton > QPushButton:enabled:checked { #txtcode_3, #txtcode_4, #txtcode_5, -#txtcode_6 { +#txtcode_6, +#txtcode_7, +#txtcode_8 { border-width: 0 0 1px 0; border-style: solid; border-radius: 0px; diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css index 79cb841962..76342e3d2b 100644 --- a/src/qt/res/css/Light.css +++ b/src/qt/res/css/Light.css @@ -27,8 +27,8 @@ QComboBox:disabled, border: 1px solid rgb(51, 54, 54); }*/ -#line_1, #line_2, #line_3, -#line_4, #line_5, #line_6 { +#line_1, #line_2, #line_3, #line_4, +#line_5, #line_6, #line_7, #line_8 { border-bottom: 1px solid gray; max-height: 5px; margin: 5px; @@ -411,7 +411,9 @@ ToggleButton > QPushButton:enabled:checked { #code_3, #code_4, #code_5, -#code_6 { +#code_6, +#code_7, +#code_8 { border-bottom-width: 1px; border-bottom-style: solid; border-radius: 0px; @@ -423,7 +425,9 @@ ToggleButton > QPushButton:enabled:checked { #txtcode_3, #txtcode_4, #txtcode_5, -#txtcode_6 { +#txtcode_6, +#txtcode_7, +#txtcode_8 { border-width: 0 0 1px 0; border-style: solid; border-radius: 0px; From fbeb933c78c18afd03c25d0c0ebacc6fd5f19d0f Mon Sep 17 00:00:00 2001 From: ALEEF02 Date: Wed, 26 Aug 2020 11:01:03 -0700 Subject: [PATCH 0406/1888] (Potentially) Fix 2FA invalidation --- src/qt/qgoogleauth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qgoogleauth.cpp b/src/qt/qgoogleauth.cpp index f2af5f8ab2..c11b26eae0 100644 --- a/src/qt/qgoogleauth.cpp +++ b/src/qt/qgoogleauth.cpp @@ -100,5 +100,5 @@ QString QGoogleAuth::generatePin(const QByteArray key) | (hmac[offset + 3] & 0xff); int password = binary % 1000000; - return QString("%1").arg(password, 6, 10, QChar('0')); + return QString("%1").arg(password, 8, 10, QChar('0')); } From cf0130cfc32ef12ab6a41bc9bfd2bd6abc68d6dd Mon Sep 17 00:00:00 2001 From: ALEEF02 Date: Wed, 26 Aug 2020 13:06:11 -0700 Subject: [PATCH 0407/1888] Return 8 digits instead of 6 Should be the last commit needed --- src/qt/qgoogleauth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qgoogleauth.cpp b/src/qt/qgoogleauth.cpp index c11b26eae0..cf883d03f9 100644 --- a/src/qt/qgoogleauth.cpp +++ b/src/qt/qgoogleauth.cpp @@ -99,6 +99,6 @@ QString QGoogleAuth::generatePin(const QByteArray key) | ((hmac[offset + 2] & 0xff) << 8) | (hmac[offset + 3] & 0xff); - int password = binary % 1000000; + int password = binary % 100000000; return QString("%1").arg(password, 8, 10, QChar('0')); } From 9a34344a84ac8168ab495c6c085e7563d8eb2785 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Wed, 16 Sep 2020 17:54:29 +1000 Subject: [PATCH 0408/1888] Update README.md --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index ce410d35be..68d84475cf 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,6 @@ DAPS is a non-ICO community driven project. The project has funded itself to del DAPS Team The team consists of a total of 20 members located worldwide. -## How we Compare to Other Privacy Projects - -![Privacy Coin Chart](https://officialdapscoin.com/wp-content/uploads/2020/01/DAPS-Privacy-coin-chart-2020.jpg) - ## How to Contribute to DAPS We have an extensive [Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. From 5af92cb89f9fedfad43519c5b9c4c29d482b7ca4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 16 Sep 2020 12:46:34 -0400 Subject: [PATCH 0409/1888] PoA Updates --- src/chainparams.cpp | 1 + src/chainparams.h | 2 + src/main.cpp | 98 ++++++++++++++++++++++++++++++------------- src/main.h | 2 + src/miner.cpp | 4 +- src/poa.cpp | 24 ++++++++--- src/poa.h | 1 + src/util.cpp | 2 +- src/wallet/wallet.cpp | 2 + 9 files changed, 98 insertions(+), 38 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 63bc09be7a..c5375db22c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -198,6 +198,7 @@ class CMainParams : public CChainParams nModifierUpdateBlock = 615800; nPoABlockTime = 60 * 60; //a PoA block every 30 minutes nMinNumPoSBlocks = 59; + nMaxNumPoSBlocks = 120; /** * Build the genesis block. Note that the output of the genesis coinbase cannot diff --git a/src/chainparams.h b/src/chainparams.h index b3e084f7b8..7971351a3a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -107,6 +107,7 @@ class CChainParams //For PoA block time int POA_BLOCK_TIME() const { return nPoABlockTime; } int MIN_NUM_POS_BLOCKS_AUDITED() const {return nMinNumPoSBlocks;} + int MAX_NUM_POS_BLOCKS_AUDITED() const {return nMaxNumPoSBlocks;} int nLastPOWBlock; int TEAM_REWARD_FREQUENCY = 3; //every TEAM_REWARD_FREQUENCY PoA blocks, reward the daps team double MAX_MONEY; @@ -162,6 +163,7 @@ class CChainParams //For PoA blocks int nPoABlockTime; int nMinNumPoSBlocks; + int nMaxNumPoSBlocks; public: void ChangeMaxReorg(int num) const { nMaxReorganizationDepth = num; diff --git a/src/main.cpp b/src/main.cpp index 34013bd5e9..f35bfc204d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,6 +95,7 @@ const int MIN_RING_SIZE = 11; const int MAX_RING_SIZE = 15; const int MAX_TX_INPUTS = 50; const int MIN_TX_INPUTS_FOR_SWEEPING = 25; +const int HF_POA_REWARD = 665000; /** Fees smaller than this (in duffs) are considered zero fee (for relaying and mining) * We are ~100 times smaller then bitcoin now (2015-06-23), set minRelayTxFee only 10 times higher @@ -1587,19 +1588,6 @@ bool CheckHaveInputs(const CCoinsViewCache& view, const CTransaction& tx) return false; } - //TODO-NOTE: 07/06/2019 Remove this condition as colateral will be cheated as a normal tx - //UTXO with 1M DAPS can only be consumed in a transaction with that single UTXO - /*if (decoysSize > 1 && prev.vout[alldecoys[j].n].nValue == 1000000 * COIN) { - return false; - } - - if (prev.vout[alldecoys[j].n].nValue == 1000000 * COIN) { - if (!VerifyKeyImages(tx)) { - LogPrintf("Failed to verify correctness of key image of collateralization spend\n"); - return false; - } - }*/ - if (mapBlockIndex.count(bh) < 1) return false; if (prev.IsCoinStake() || prev.IsCoinAudit() || prev.IsCoinBase()) { if (nSpendHeight - mapBlockIndex[bh]->nHeight < Params().COINBASE_MATURITY()) return false; @@ -1620,6 +1608,15 @@ bool CheckHaveInputs(const CCoinsViewCache& view, const CTransaction& tx) LogPrintf("Decoy for transactions %s not in the same chain with block %s\n", alldecoys[j].hash.GetHex(), tip->GetBlockHash().GetHex()); return false; } + + if (atTheblock->IsProofOfAudit() && chainActive.Height() >= HF_POA_REWARD) { + CBlock b; + ReadBlockFromDisk(b, atTheblock); + if (!CheckPoABlockRewardAmount(b, atTheblock)) { + LogPrintf("Reject poa transaction %s\n"); + return false; + } + } } } if (!tx.IsCoinStake()) { @@ -2927,6 +2924,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!CheckPoABlockNotContainingPoABlockInfo(block)) { return state.DoS(100, error("ConnectBlock(): A PoA block should not audit any existing PoA blocks")); } + + if (!CheckPoABlockRewardAmount(block, pindex)) { + return state.DoS(100, error("ConnectBlock(): This PoA block reward does not match the value it should.")); + } + //if (block.GetBlockTime() >= GetAdjustedTime()) { + //return state.DoS(100, error("ConnectBlock(): A PoA block should not be in the future.")); + //} } // verify that the view's current state corresponds to the previous block @@ -4459,6 +4463,41 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, int nHeight = pindex->nHeight; + if (pindex->nHeight >= HF_POA_REWARD) { + for(size_t i = 0; i < block.vtx.size(); i++) { + const CTransaction& tx = block.vtx[i]; + for (unsigned int i = 0; i < tx.vin.size(); i++) { + if (tx.IsCoinBase()) continue; + //check output and decoys + std::vector alldecoys = tx.vin[i].decoys; + + alldecoys.push_back(tx.vin[i].prevout); + for (size_t j = 0; j < alldecoys.size(); j++) { + CTransaction prev; + uint256 bh; + if (!GetTransaction(alldecoys[j].hash, prev, bh, true)) { + return false; + } + + if (mapBlockIndex.count(bh) < 1) return false; + CBlockIndex* atTheblock = mapBlockIndex[bh]; + if (!atTheblock) { + //LogPrintf("Decoy for transactions %s not in the same chain with block %s\n", alldecoys[j].hash.GetHex(), tip->GetBlockHash().GetHex()); + return false; + } else { + CBlock bhBlock; + ReadBlockFromDisk(bhBlock, atTheblock); + if (atTheblock->IsProofOfAudit()) { + if (prev.vout[alldecoys[j].n].nValue > 50000 * COIN || prev.vout[alldecoys[j].n].nValue != bhBlock.posBlocksAudited.size() * 100 * COIN) { + return false; + } + } + } + } + } + } + } + // Write block to history file try { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -4685,22 +4724,23 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis coinbaseIdx = 1; } CTransaction& coinbase = b.vtx[coinbaseIdx]; - - for (int i = 0; i < (int)coinbase.vout.size(); i++) { - if (!coinbase.vout[i].IsNull() && !coinbase.vout[i].commitment.empty() && coinbase.vout[i].nValue > 0 && !coinbase.vout[i].IsEmpty()) { - if ((secp256k1_rand32() % 100) <= CWallet::PROBABILITY_NEW_COIN_SELECTED) { - COutPoint newOutPoint(coinbase.GetHash(), i); - if (pwalletMain->coinbaseDecoysPool.count(newOutPoint) == 1) { - continue; - } - //add new coinbase transaction to the pool - if ((int)pwalletMain->coinbaseDecoysPool.size() >= CWallet::MAX_DECOY_POOL) { - int selected = secp256k1_rand32() % CWallet::MAX_DECOY_POOL; - map::const_iterator it = std::next(pwalletMain->coinbaseDecoysPool.begin(), selected); - pwalletMain->coinbaseDecoysPool.erase(it->first); - pwalletMain->coinbaseDecoysPool[newOutPoint] = pblock->GetHash(); - } else { - pwalletMain->coinbaseDecoysPool[newOutPoint] = pblock->GetHash(); + if (b.posBlocksAudited.size() == 0) { + for (int i = 0; i < (int)coinbase.vout.size(); i++) { + if (!coinbase.vout[i].IsNull() && !coinbase.vout[i].commitment.empty() && coinbase.vout[i].nValue > 0 && !coinbase.vout[i].IsEmpty()) { + if ((secp256k1_rand32() % 100) <= CWallet::PROBABILITY_NEW_COIN_SELECTED) { + COutPoint newOutPoint(coinbase.GetHash(), i); + if (pwalletMain->coinbaseDecoysPool.count(newOutPoint) == 1) { + continue; + } + //add new coinbase transaction to the pool + if ((int)pwalletMain->coinbaseDecoysPool.size() >= CWallet::MAX_DECOY_POOL) { + int selected = secp256k1_rand32() % CWallet::MAX_DECOY_POOL; + map::const_iterator it = std::next(pwalletMain->coinbaseDecoysPool.begin(), selected); + pwalletMain->coinbaseDecoysPool.erase(it->first); + pwalletMain->coinbaseDecoysPool[newOutPoint] = pblock->GetHash(); + } else { + pwalletMain->coinbaseDecoysPool[newOutPoint] = pblock->GetHash(); + } } } } diff --git a/src/main.h b/src/main.h index 36cc499e3d..ae309b3739 100644 --- a/src/main.h +++ b/src/main.h @@ -122,6 +122,7 @@ static const unsigned char REJECT_NONSTANDARD = 0x40; static const unsigned char REJECT_DUST = 0x41; static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; static const unsigned char REJECT_CHECKPOINT = 0x43; +extern const int HF_POA_REWARD; static const std::string FOUNDATION_WALLET = "41jsGvYo3GMWCvFVZekSnrRV8ptJfMGhuhRjB9tYEv5NSA47VqyLp6gKSCpS3wHTBhCGu9DJ5k1HMWXeHVnL9nUs15CjyeCQDiT"; @@ -226,6 +227,7 @@ void UnloadBlockIndex(); int ActiveProtocol(); /** Process protocol messages received from a given node */ bool ProcessMessages(CNode* pfrom); +bool VerifyZeroBlindCommitment(const CTxOut& out); /** * Send queued protocol messages to be sent to a give node. * diff --git a/src/miner.cpp b/src/miner.cpp index 7c0b1ebb81..67bb3e4620 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -142,8 +142,8 @@ uint32_t GetListOfPoSInfo(uint32_t currentHeight, std::vector& pos.height = nextAuditHeight; audits.push_back(pos); } - //The current number of PoS blocks audited in a PoA block is changed from 59 to 61 - if (audits.size() == 61) { + //The current number of PoS blocks audited in a PoA block is changed from 59 to MAX + if (audits.size() == (size_t)Params().MAX_NUM_POS_BLOCKS_AUDITED()) { break; } nextAuditHeight++; diff --git a/src/poa.cpp b/src/poa.cpp index 0087cad7a2..413e86e315 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -292,7 +292,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) bool CheckNumberOfAuditedPoSBlocks(const CBlock& block) { - if (block.posBlocksAudited.size() < (size_t)Params().MIN_NUM_POS_BLOCKS_AUDITED()) { + if (block.posBlocksAudited.size() < (size_t)Params().MIN_NUM_POS_BLOCKS_AUDITED() || block.posBlocksAudited.size() > (size_t)Params().MAX_NUM_POS_BLOCKS_AUDITED() ) { return false; } return true; @@ -393,17 +393,17 @@ bool CheckPoAblockTime(const CBlock& block) if (block.hashPrevPoABlock.IsNull()) { ret = true; } else { - LogPrint("debug", "%s: Previous PoA block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); + LogPrint("poa", "%s: Previous PoA block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { CBlockIndex* pindex = mapBlockIndex[block.hashPrevPoABlock]; uint32_t prevPoATime = pindex->nTime; if (block.nTime > prevPoATime && (block.nTime - pindex->nTime >= (uint32_t)Params().POA_BLOCK_TIME())) { ret = true; } - LogPrint("debug", "%s: PoA Block time: %d, Previous: %d, Current: %d, Distance: %d\n", __func__, + LogPrint("poa", "%s: PoA Block time: %d, Previous: %d, Current: %d, Distance: %d\n", __func__, Params().POA_BLOCK_TIME(), prevPoATime, block.nTime, block.nTime - pindex->nTime); } else { - LogPrint("debug", "%s: Cannot find block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); + LogPrint("poa", "%s: Cannot find block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); } } return ret; @@ -415,7 +415,7 @@ bool CheckPoABlockNotAuditingOverlap(const CBlock& block) if (block.hashPrevPoABlock.IsNull()) { //First PoA block - LogPrint("debug", "%s: First PoA Block Hash: %s\n", __func__, block.GetHash().GetHex()); + LogPrint("poa", "%s: First PoA Block Hash: %s\n", __func__, block.GetHash().GetHex()); ret = true; } else { if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { @@ -429,7 +429,7 @@ bool CheckPoABlockNotAuditingOverlap(const CBlock& block) for (size_t j = 0; j < prevPoablock.posBlocksAudited.size(); j++) { if (prevPoablock.posBlocksAudited[j].hash == block.posBlocksAudited[i].hash && prevPoablock.posBlocksAudited[j].nTime == block.posBlocksAudited[i].nTime && prevPoablock.posBlocksAudited[j].height == block.posBlocksAudited[i].height) { isAlreadyAudited = true; - LogPrint("debug", "%s: PoA Block Hash: %s, is already auditted by Block %s\n", __func__, + LogPrint("poa", "%s: PoA Block Hash: %s, is already auditted by Block %s\n", __func__, block.posBlocksAudited[i].hash.GetHex(), prevPoablock.GetHash().GetHex()); break; @@ -446,3 +446,15 @@ bool CheckPoABlockNotAuditingOverlap(const CBlock& block) return ret; } + +bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex) +{ + bool ret = true; + if (pindex->nHeight >= HF_POA_REWARD) { + ret = block.vtx.size() == 1; + ret = ret && block.vtx[0].vout.size() == 1; + ret = ret && block.vtx[0].vout[0].nValue == block.posBlocksAudited.size() * 100 * COIN; + ret = ret && VerifyZeroBlindCommitment(block.vtx[0].vout[0]); + } + return ret; +} diff --git a/src/poa.h b/src/poa.h index cc430537a3..ec28a8f764 100644 --- a/src/poa.h +++ b/src/poa.h @@ -45,6 +45,7 @@ bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block); bool CheckPoAblockTime(const CBlock& block); bool CheckPoABlockNotAuditingOverlap(const CBlock& block); +bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex); #endif // BITCOIN_POA_H diff --git a/src/util.cpp b/src/util.cpp index a7b51d93a0..3de10c4773 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -237,7 +237,7 @@ bool LogAcceptCategory(const char* category) ptrCategory->insert(string("swiftx")); ptrCategory->insert(string("masternode")); ptrCategory->insert(string("mnpayments")); - ptrCategory->insert(string("zero")); + ptrCategory->insert(string("poa")); ptrCategory->insert(string("mnbudget")); } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 02abf59954..dd8c7a5eaa 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3569,6 +3569,8 @@ bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringS if (p->IsProofOfStake()) { coinbaseIdx = 1; } + //dont select poa as decoy + if (b.posBlocksAudited.size() > 0) continue; CTransaction& coinbase = b.vtx[coinbaseIdx]; for (size_t i = 0; i < coinbase.vout.size(); i++) { From 8d6cccbe640f6664f52a212742e9d3b09b3c8632 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:46:47 +1000 Subject: [PATCH 0410/1888] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 68d84475cf..28986b6450 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ DAPS is a non-ICO community driven project. The project has funded itself to del DAPS Team The team consists of a total of 20 members located worldwide. +## How we Compare to Other Privacy Projects + +![Privacy Coin Chart](https://officialdapscoin.com/daps-coin-comparison-chart-2020/) + ## How to Contribute to DAPS We have an extensive [Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. From 2a482e4f6b456f2e4114178454c6e67b1ff4560f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 09:08:17 -0400 Subject: [PATCH 0411/1888] Move SF/HF parameters to chainparams --- src/chainparams.cpp | 4 ++++ src/chainparams.h | 4 ++++ src/main.cpp | 5 ++--- src/main.h | 1 - src/poa.cpp | 6 +++--- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c5375db22c..0b516f92de 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -199,6 +199,8 @@ class CMainParams : public CChainParams nPoABlockTime = 60 * 60; //a PoA block every 30 minutes nMinNumPoSBlocks = 59; nMaxNumPoSBlocks = 120; + nSoftForkBlock = 125000; // Soft fork block for difficulty change + nHardForkBlock = 670000; // Hard fork block for PoA updates /** * Build the genesis block. Note that the output of the genesis coinbase cannot @@ -346,6 +348,8 @@ class CTestNetParams : public CMainParams nBlockFirstFraudulent = 9891737; //First block that bad serials emerged nBlockLastGoodCheckpoint = 9891730; //Last valid accumulator checkpoint nBlockEnforceInvalidUTXO = 9902850; //Start enforcing the invalid UTXO's + nSoftForkBlock = 0; // Soft fork block for difficulty change - testnet started with it + nHardForkBlock = 92000; // Hard fork block for PoA updates //! Modify the testnet genesis block so the timestamp is valid for a later start. genesis.nTime = 1590109816; diff --git a/src/chainparams.h b/src/chainparams.h index 7971351a3a..8f21203022 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -103,6 +103,8 @@ class CChainParams int LAST_POW_BLOCK() const { return nLastPOWBlock; } int START_POA_BLOCK() const { return nStartPOABlock; } int Block_Enforce_Invalid() const { return nBlockEnforceInvalidUTXO; } + int SoftFork() const { return nSoftForkBlock;} + int HardFork() const { return nHardForkBlock;} //For PoA block time int POA_BLOCK_TIME() const { return nPoABlockTime; } @@ -130,6 +132,8 @@ class CChainParams int64_t nTargetTimespan; int64_t nTargetSpacing; int nStartPOABlock; + int nSoftForkBlock; + int nHardForkBlock; int nMasternodeCountDrift; int nMaturity; int nModifierUpdateBlock; diff --git a/src/main.cpp b/src/main.cpp index f35bfc204d..3f4688df4f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,7 +95,6 @@ const int MIN_RING_SIZE = 11; const int MAX_RING_SIZE = 15; const int MAX_TX_INPUTS = 50; const int MIN_TX_INPUTS_FOR_SWEEPING = 25; -const int HF_POA_REWARD = 665000; /** Fees smaller than this (in duffs) are considered zero fee (for relaying and mining) * We are ~100 times smaller then bitcoin now (2015-06-23), set minRelayTxFee only 10 times higher @@ -1609,7 +1608,7 @@ bool CheckHaveInputs(const CCoinsViewCache& view, const CTransaction& tx) return false; } - if (atTheblock->IsProofOfAudit() && chainActive.Height() >= HF_POA_REWARD) { + if (atTheblock->IsProofOfAudit() && chainActive.Height() >= Params().HardFork()) { CBlock b; ReadBlockFromDisk(b, atTheblock); if (!CheckPoABlockRewardAmount(b, atTheblock)) { @@ -4463,7 +4462,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, int nHeight = pindex->nHeight; - if (pindex->nHeight >= HF_POA_REWARD) { + if (pindex->nHeight >= Params().HardFork()) { for(size_t i = 0; i < block.vtx.size(); i++) { const CTransaction& tx = block.vtx[i]; for (unsigned int i = 0; i < tx.vin.size(); i++) { diff --git a/src/main.h b/src/main.h index ae309b3739..1d56c8c5ed 100644 --- a/src/main.h +++ b/src/main.h @@ -122,7 +122,6 @@ static const unsigned char REJECT_NONSTANDARD = 0x40; static const unsigned char REJECT_DUST = 0x41; static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; static const unsigned char REJECT_CHECKPOINT = 0x43; -extern const int HF_POA_REWARD; static const std::string FOUNDATION_WALLET = "41jsGvYo3GMWCvFVZekSnrRV8ptJfMGhuhRjB9tYEv5NSA47VqyLp6gKSCpS3wHTBhCGu9DJ5k1HMWXeHVnL9nUs15CjyeCQDiT"; diff --git a/src/poa.cpp b/src/poa.cpp index 413e86e315..a768aa4f97 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -22,7 +22,7 @@ unsigned int N_BITS_SF = 0x1e050000; unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock) { if (N_BITS != 0 && pblock->IsPoABlockByVersion()) { - if (pindexLast->nHeight < 125000) { + if (pindexLast->nHeight < Params().SoftFork()) { return N_BITS; } return N_BITS_SF; @@ -63,7 +63,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // ppcoin: target change every block // ppcoin: retarget with exponential moving toward target spacing uint256 bnNew; - if (pindexLast->nHeight < 125000) { + if (pindexLast->nHeight < Params().SoftFork()) { bnNew.SetCompact(pindexLast->nBits); } else { if (pindexLast->IsProofOfStake()) { @@ -450,7 +450,7 @@ bool CheckPoABlockNotAuditingOverlap(const CBlock& block) bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex) { bool ret = true; - if (pindex->nHeight >= HF_POA_REWARD) { + if (pindex->nHeight >= Params().HardFork()) { ret = block.vtx.size() == 1; ret = ret && block.vtx[0].vout.size() == 1; ret = ret && block.vtx[0].vout[0].nValue == block.posBlocksAudited.size() * 100 * COIN; From 57d0e12093146b475173b2a9480f002c33e79c3c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 12:16:59 -0400 Subject: [PATCH 0412/1888] Remove old horizontal about image, not used --- src/Makefile.qt.include | 1 - src/qt/dapscoin.qrc | 1 - src/qt/res/images/dapscoin_logo_horizontal.png | Bin 4048 -> 0 bytes 3 files changed, 2 deletions(-) delete mode 100644 src/qt/res/images/dapscoin_logo_horizontal.png diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 319e5a11b8..57610e51d5 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -368,7 +368,6 @@ RES_IMAGES = \ qt/res/images/about.png \ qt/res/images/splash.png \ qt/res/images/splash_testnet.png \ - qt/res/images/dapscoin_logo_horizontal.png \ qt/res/images/downArrow.png \ qt/res/images/downArrow_small.png \ qt/res/images/upArrow_small.png \ diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index ed86130b3b..02fc8e1bf9 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -82,7 +82,6 @@ res/images/about.png - res/images/dapscoin_logo_horizontal.png res/images/downArrow.png res/images/downArrow_small.png res/images/upArrow_small.png diff --git a/src/qt/res/images/dapscoin_logo_horizontal.png b/src/qt/res/images/dapscoin_logo_horizontal.png deleted file mode 100644 index 24ca1b20a76ff1271cee0168f9813de4762e000e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4048 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 N1u3Y>qvT8i{{t#*^k4u0 From 73e7403f5e3f5677ee1a7900900a36ae13c21e39 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 12:59:53 -0400 Subject: [PATCH 0413/1888] Update dapsico --- src/qt/bitcoingui.cpp | 2 +- src/qt/dapscoin.qrc | 1 + src/qt/res/icons/dapsico.png | Bin 868 -> 2503 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 8bf906ce1f..6226b21b7d 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -642,7 +642,7 @@ void BitcoinGUI::createToolBars() bottomToolbar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); toolbar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); QLabel* dapsico = new QLabel; - dapsico->setPixmap(QIcon(":icons/bitcoin").pixmap(130, 107)); + dapsico->setPixmap(QIcon(":icons/dapsico").pixmap(130, 130)); dapsico->setObjectName("dapsico"); navLayout->addWidget(dapsico); diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 02fc8e1bf9..bee2294500 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -1,6 +1,7 @@ res/icons/bitcoin.png + res/icons/dapsico.png res/icons/address-book.png res/icons/quit.png res/icons/send.png diff --git a/src/qt/res/icons/dapsico.png b/src/qt/res/icons/dapsico.png index 80e82ad637df0fa85a899a238da9c3f11014af74..326f2f3e934d7c13f26c77632d0bc94898eca485 100644 GIT binary patch literal 2503 zcmV;&2{`tNP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D30z4;K~#8N?VWk7 zUPT$k??(keWR0mp6cm)Om_S7oNeEIPh5&&?q9g(df{tWvgwkd`V4xIzU)!gl#RXXa~eOYicX^PXkSyuak>J9BRDz27T!-o1?AJZwG_HUx-ehq3~y;)6fIxRkSu=kN?%_BPw8Y zEm~LMPsEMTM=02x(Bh(qXNDW0Z&0Xbpy_IWwQ(c#1qyR>G)gTnk>rf9UX0EJD99}c zi_kZV0~z2(SPM*`N5IACkm5ilxDh6R2{tAyM01M+8R14)lQYnvA(9YQi++z4Z1-;FVA zvNl3&7W};cSodd6T;lc8f84ayP=BF=kKhMwlIA_P7z8g4~Vpkr=ZlcOy6v zH-b~(MsNz;2=y=?V=}lA>S1||$>2t?XW3vdcrm7v!Hrr#&iKcXM4i$(Pz=V zeEp9)?qq~&0Q65Z#79QwgbEy8jNVe|Pr#doy5Qof3Rkr&eI9)hX-&h;P?Km>lRk@X z2)EXObugo*A)eFs(U*$@qod~O8MJ`k_gZnJB%L(^7fGLOpQvx3olu$fybY!`0_V3E z;Z|gEPI_Y5pWpdt$c|3ujKBrbq!X=ObTCrkr^u8>h&90qv}JL?2AN?ie(zf$I~twn zN8rM2fYjc~(SJfeM5&r!CLDzV~k6Lg%~ zjDQJtCfttP1PM@!5io%YUws7Dy=P8M)Kw!~jad-1W)t(bR9}#VFW!co)>avXdtG>FY1k@^paF|V5T!Y z7DiY}Q2#+yozP~RzvYs)EO04S5<1rUy0h)?S z(8uC`AJzgo_9mK&C*rqs20qhVH1YnWDw^rlDXP3{m}x*trPW%&ug-DA+ zY@}mT@N|rwfX}X)?+>Wg^E0a$VX}#wT7q^SCMaHja3R%KpczgYuP_tzKA{uv*}q8m zNyzmZYa{3#!Ks*_SaUF%K(n1k>4MhFq^_V{n4I8}`BY>Yl6y$6&w0?oodVp1!r_Z7{)%7Usl zi$a4pEcs}RUEs$t_8to(SU)y)W=I&do;u7lbGi3e7{U5Ru~SbVm_hq4%|VlH&C>@g zW<&pfkVHn{UOmQ!^GusB?H5wNSlH?U4;T#Srk<>XkiU)7UmdYvXU7EqjeB8g1JdF)A|miN6oIS zHE=19zRP3!LvX#UmMm7Mlos2(E@aDNWrW=ckA$29ds8^~#`K3!twzvvdn+^~;BbED zlOa1g7B`FPF4Z8FPId{mL>+xAQ=x5>^iHHSCPs+-EJi0(*-i5qYMSF>dSon(pouP8 zI6HTqr-p26v5#$I92qksaPqGa&I-A#X>;kH((imMYXqTnlAa66Y|*Bt$zf^)Y6b0^ zaCFFJ%hDK=!n#I~8Pw%`Rmf$>QqDigrzdkG2rkA+1g)f&8iIlcq5v4B^7fBOHm;C7mkTfb;~;MLns#pm8GzE})k2SHF0Q7gEi^F`UEI zA=?jHF@oSij-z8pYF?o>{Y(K3zL~@4z9D2ghqg#AMQcVF!bM$%G=E_))YTe7wZMFI z0H4*O3wgNOj5WhGt;pp$g+C1A RCS(8r002ovPDHLkV1j@)g=PQ% delta 858 zcmX>u{Df_Sczrep3j+g#pyMPP1_owrPZ!6Kid%1Q$4=dBAi(y(!@)`A!2*jLRvLU_ z>_;678Th)IA0@ngaG24e;(Jo{x$Vnad^u*S9BA1cH|2wa+GKmhMH(jx|GpM-*Ld+E zJ(0yNfe@;Pt61QCz_Ye>%_mOz^>dlaZRW%DbcS#ZIuS^vQW4v+0l4s8sQuV6Q zuwV*m5X^C7SGH2WF2TyZ$+iEUg8QpNyM+#B^*gz~b1d8I)NgZOiC5aMTh~IA%>OWT zIT(A#2}CJ3g>>jDEeJlF<{PXc+@$hA=CKvaWPz+J5@HfA>h1>^i;S1c?}Iu^AB1dTD2=vP+_aN z*SG!!-1Xh(HN;Xn1y6ktJgCd`M5XA;isg?lsB#>ACUE6`+0L{VQ)C$za?6V?cJD}8 z&Sl6X;n;3q#B{-sNtuCx&CS9m;m!9phk|Oi8!5MPihsKm&;EQ*VA*1yzZ#o*m>ybg zo|U^%%7}N)uU2vWnN4}emt3ya6xbwTV*G+ib5>w&kvYXwW} z{|l3px7cMbaMRer>m;PiV^^(V+EjNv%GImj+P(cHGL84FZq1*6e8T;vgX=8iIcJ+` zC2ZQ+`r+}GliZ@&ypt9wnQ}TNm27Z{vN`yvCF-`XkfF|P2d~}$$*Ygv6^SyPy!7_T z6^=_A&sOY3uY^a@KBO5SU`njxgN@xNAN*QrW From 1191f83df28813894a5cf30ddb4521394fc961d3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 13:00:22 -0400 Subject: [PATCH 0414/1888] Update About --- src/qt/res/images/about.png | Bin 2592 -> 26193 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png index 393014c9d686497138ed5deed9f907089719c33d..732e7110e3346a119ea94507e0cbfea03e35a5fe 100644 GIT binary patch literal 26193 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 literal 2592 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 lk Date: Thu, 24 Sep 2020 13:00:34 -0400 Subject: [PATCH 0415/1888] Update backgrounds --- src/qt/res/images/background.png | Bin 746614 -> 588893 bytes src/qt/res/images/overviewbackground.png | Bin 195518 -> 224876 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/res/images/background.png b/src/qt/res/images/background.png index 6a1f29dc2cbb7f8010f212897ad343b3773f8469..e98898e7694882d6b998a3829bc5999119954abd 100644 GIT binary patch literal 588893 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

IfOo=5;iTy=VFY&0)(K);WO# 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%0A-yu%oPeqQ2iSaH-3*W1@-sW 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

3eI3-=hy{lqK|X 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

^V0C8jo*4_HB+FZ%-&kx{X5xeR0t{yCt1a8}+ z!oao%wg1WNy}e&E_}1+8jlhMC+rFgWf$TeywDMQZy$a2Km>NP$*j}M>nYYmRV}DAL z-X;1*#op&^!pc3s;=o!tfYgf%y2cx@sYAjDQdoi%OkbmZb-v;uc)S2~lnPj>AeS^~ z;6c;OUG4c-H83dPpEDYz**wn(!`kc)`fHXju!B!(09ZI!nncR>EG0qnN_vow!_^wv zh+j%0xi$vN+a8sz+o5}2IO@?KNGB6ac=c>klAz`&3L&M{zYMA{sP(o#6K0}ux& z;Szu~UZSrSuYg}+2VvPf6c6LS+vFa3op6df1kX&zb%Izw|~k{iyC~$p-c=B!Ck*yAX2HuI{R@ z)CHY~F_da;-Q3LtgC-6~QNTM3nmN#-fQRCN-trBYYZwNLNg{)3)r>5U zffcZpFErr5YVAhamJ=TJ0sB^l1sj1$3iFrNg-?5n4FH>J9H3Ah)DgNS1`|A*@ba6i z^D5?0zBgdmFcNO1ZOQJz@%LB8=K*5l^*knV9G#0@6H_IKZHOxJLDxvin^(cN)g6Ho zj^OYN{Fo4iRsP)yRLc1UKNG zDU??tQTq85_1O1LdG>!{@K#&v9^URL8T@5>j;d%qq5ya83`?(C?hJ>$b-c}*dlKyQgCv?4fuEAGu`lYv3 z0_zEw-z&dmI^k#G>m(S=cPy-HFo#E;!{a`Jzd!+x+J+Rg5&9Lhq>dhb4{b&<_YwZA z%+Cu%fdK~Hsr5M_2&>qlJDJ2sQKZ(+;?}R8qw#CofA3}b-p$JSKA%K^8N(f0*M+}O%a15Qc4cEYc&JRYiJt3S~|A~ zic-ez!!|NRoxpn=@GatTSQ_-|9<4zWQayNY@$MOF2ah_CfP95N){}4jT{uke( zR8${OpzEBHF=Zi%GLPmS6mTYVN_z!vprr~}@<*lvxFmo}|3Y!aaRUSKCwBonY_f{p zxc-QzFmWhR0e2eIL^&tKb;{SdLK%f#C1& z4bEMex3XyVcVA<`(mFyQNoqHtbyqc7ScnWu@n9hU+9}}HwEtEn=t09Du7QC`Sh9_l zGQxfT3>at*AuXnXeStveB!^(JKqq?+uJrGO0pJvJunY&VM`SsBf`t`97Yprj=0SxOI$l#mBVOc8Wt>T{~a6#Yv_SwOpC!wI}NrHUP3w1Fp zHUx~Hc5~K5>>6yd0XkziiU!VKzsUoAaSQ0O>+CrOoKL_?pWKxpmKj1nTU;JetMefswvoq^@?-L@g26b`dU;KbsJ!I@Xn1M?_ns6iT3 zK63#fj^9DTzP=rp#WQ>aWg2>>SYjKK8DE>6^Ls%1XPx;_A7t4P*x>O2|B01awb8tg*)y zLPm=9QiY`6XGL!ilCqGn_ySDxw;}yIlpFA%5#T{ZMh*192plz%qi9 zETYZ$EhuO+eRURh4|PC`^nEOtK6;#Cuv!_nz~Y#r9PqsafWd|(7A#f3_jmz)=Tcy^ zTfP@hmIGo%(^sm0;r=TPgaC=A|Hhz3XOKs6;0e%{A;iG zyXctyQBPp2fZgm((g}=v1o{~BB%Vw+urRP96PB+8ewZ@CqJ3#^vIE7pB`cT(6>!NT zZ5;olLSW)>WC6UVMo9pR_#IFJHwHy%VOVzeEavClD?;BP+;!YU_1hMXY8xVQ8p$y54&-Dv$A(Oq($3na0g`&@AU5%kK&PWSY-lVx9dnujx2<~ z^ahMYgcJn+Cmh433fM)FjPZ)G9LZpyeH2(7&;o!)7M4uiLl$LQF`^qyw}!cr=UWdl#a3^k^(BE&Ruofxl1Kt~?6`$RB7qoOU zqYW!f;J(r=^n)Y7Q~69_OnBR2Az?Rn$e`R>NuCdT{I@MI=$1$D3{^;tT!S|(Ly{TX zn_eUU7xz-&qat|JK0*&nwlUhE>;B)51OJ{7)<5dEB=3FyU>|X!%@Ye?e%blUA0;+G z(}xW|oEwba+gv#4{Xxat^40RFGTfJ-HS1(6;e#Mj4%j4H)P|Bxk ziI5zyX`5Knv$A2`f?8lxg`^f}4kA@$lI7C>z%Y_(U;$AUH#Ao1GWLq-qI-HIhuP2|5gec|9+@i)Gr zrw{$rqptNYjKlYeZNL}ZNcVU?F9s~i9~B1WM%c-wgpn?E0B(qZMdXbV0p1!q<1+|L z=+D&rY?sijqBs2LbqMH_z>$StnMVg}=V{uiVDKpu3+}+v1}?1W#D)byB=KQg=?45G z3t>{gaTTF@t`dyioB`(Ouk4{s3Rug4eI;<7x=X2LVDtucG<0mkqEu3cR_M@*)m3-j z8K-bt`JsI+u+0bGk&tyZeebk^jxZci8fiGnBJnj>eoL`p5eeGvxS@-1mQyf~U<0G1 z4K#zG+xaYjG~?){5E8X9bozZk1x%Ben+O+{MCHr!Sqai)nt&C*l#Cb1bFef(qb}&f zIb7|YvAh0x{t}Gd^%J{Q&@lLNzs;-R*V9YlUs*-NF0WaZ~$%eD$z{4zd3}zve~PzBFX+wUOi>#o%z`UuT=o+-kFB40x7XxYLkU@ zL)I%T0PZPtR4%}R-=GeLLBY?O{T;N0kb00>QNG*e%+HVj?mlrpM>k+=bCv`WhLWbq z;;_#88oI3-zo!dmXNbOTw1xihJ%z0T{wFvD*YlY18@hx}SV&0Q=ES#OJAAX=P0HDj zsoSalYB3%xvw%J;BWw)`x^+5u4g$fZ5qOy`m;+tV@Fp*#WeFG!L>B zI*`C7vVK~WEi^m_eokHJALgi9Csrwn~ncZ}<2tbtQ!X@0gM!^^6QNTk#OXe|5M8+UkU!=fOh8R0nWZ^!?JXp=^Q;hUl+t72|9Ibc=7{K+8~U^YP$h?1hf zWPdJoNK^(q^W-g?=<+hq@mEnCIDdQo2_eu3#u}{$`g*K@{SG=fz5c&v@7MJ>>Kny? ztCqn&GIvKLEG1rzFn&k7h5r7271#6kPmS2InEBk$`4^rPm0NJ5x8IE2D0$$9(O0a2 z(FNTSc*AX>6+k&b4k;MJ#&LD4(nctKv)tvMTv6dPz3FGzHh5&xz@J=#1xuMv!5PN! zRjPqu1^w0qy-VJoyn99fvR(3Xt#+hK?6dTU=Tv)9QOaebj?gZ zs=EiIv-c)(Vrye3o6Y*DT-Ei^18_&2xB|aGd(j6iVBEP|@L0bDAL-8&1-2VV4~Mv6 z4|wDXN;7Gs3bf4uBlH%T8DW;Q2><{f07*naR4=|DO<&_mFv!zZbher^oPsq1+>Wk@ z@@NmqtO0XH<9QVyfHw(>;x1yVR;VhlSsITRF|O3 zX2&iM>{g&{)lLZbrRm+z=R z_vZ4886>npyWox|lP;Zfvn=>ez;FFG?r)V8u)PfT_Kz6M-QN97ZCKhvd4m)%5MeIi zSV)6zxOQWI1Z|W}nMArQ#RT0H{9VeTWX>K5@XGO5+*e3~?fgPz{-}nE_&~*F&w~eG zy2D`H&clGb+1`$ai1J-$@<+pY6j+64{{F32==&m3;5+AlLkm_Nh-Z|b)rO@4G^@|L zjKuwuS%Y>}(0T#RH{L4wO=ndcCk!}3us!)22K-Q57B6(F9fBJy;vgBias3;|5_F9e z+t~(BfK5~7h?|4s7>lr4JH^oA7~$1Bu$cdj^xQ}{;M@V-ma8vkklIcMflV1@p+K^a z<6-#Ng{97`!PG%OSFsAv0esIII9^_OhBmBMeFO>M_xV}qcdayAt%er64_zZf>(8%m zW*MHfOR!l5eib|P$uRI{bOd0(8|1+hf3*+`2MGs^orN+in64}~K8hf9oC1dNk37k+ zlrG98=YPu?IPd3_2ryfrjqd1Q!38asU^Bo#x^ogflCS}q`ETlA6^WZD6O0iiX22P86M?QCfV)Zpcp3ux z9bySqI08Q>JOCe`fR9?B-w4pv0*=pGCquN?9ezXm#tOjvAq9>wd@zUvrC7!TJqZma z?rXlpF)Ucukfw_M%qif3#wX_iEqPSLk(UU&R;+w52CPjSOQyg}wqlLhh;`lbp;z4l z))+87_EnU;k7vgS1#~Zv2fkquNAGGILzyF1T}Tx8Z1A|~;5S2XPIF(bv_wd2gav-b{iQATE3JX%3ar?H zH7tkVTbULtWELqf(Oja&vQ@tDM-Kd}hQT?grvnp~ZKeLG59=#WK^ZIbEpy+@f4_MR z>8%b8Ml9390S>GmDBsxTS+)s5gZ5cqa$^ztY9%x-GR&F*ez%7-dNv#*NoEvSJE0Mn zb%VkAutr2#c>C}SIJ9v96jS4sfA3Y7f+=~VJ^h-8qyaErd3adPgZ?TCIz0kD)@YAG#!2`WT5A@5+(3R<< zdI!hzi5X{wC|&^Y7Db6NVN_tb-O5-ppU3R#9#sL2r{) zpr^VKS`_HQgJ(qHP6woudZ1IMy_BPZ@U><3OEp-cO-RtA3|l%zyUV&UO1^YgVOKqxRo)@PT)nV2}aAeEYrkngN!-RjqyQiThsY z3{38;zPZ>5LTaBR3Vfjn20a3|i`;%K23ID4!GBe^Jx`|K$__Gc4p=B~2JKF`ftey4 zunA6rdtdf9fD_YV$B;u@Q)g>>IvXP z_0JtAkCgf*jg?W##F-6dD5q7m! z*oLJCUwEI(D_yNkOLb?+8(Amx2-5SIgO)~pwu`{PiAN~z<-0FgXR26zNLiE$_06W#xRZzYgLNZXCJ1eZ|>S?aN&$ssHvnhr36=S|O6&&U1 z*GInSr?2G-MA(foylP1#m}J=K2y8`Y++@h@D4T&`?iuCvXEwnz@-8Gn!)H!0V5KE< zU+Ll4U07s;zV0Z@5Pa1bQiCKoiqJjp5fVEKJy_QMeAg;0>t3=+U@J{mwdlXp|J<7> zFzx@EzL5Ut&)DBWFxaE7>?ErL8ePyAEH$CXFU(&Q2Ha2-J4??OF2Tz8-)r&D?Vww} z=Wk8szBI&;F?Vb+2P`_Y;lRK-j|!ma0z7y#)nt@s7N37fZwJjC`0mM^l9fM-ju6~3a zW4NmN%$3hAlU@!7!yaLDVR__DEf}B^^WVf#Up<`V7_1>^4s4Ru{ zmK9)$0kaCdxC5|Wfqf50$s!H>CSHFh7!@>Hv>tjLEO)~M7h$)XRB>O091?vsfSu5X z==-IS;NRD1!n*SVxB;JQ(3=C|jdkc5j=&N-+S~wetp!W!ud0aK&9-~e*sx}>LAP)S zZj&p&ic1XTQGr~hzQ}+RWqUD;^r&!PCpz^B@+FkP z2F*S!fBy9~SV<-55ras;fT>ZxYjKV+IT?B$+!hjX;JLguo0h$ z0n1Enquq%$8}u*x^Pm*&r5=K5{s2=*f3_D|+pnzC*#?2#HMq)vZN--@!GiN|-;4Te zYD{_%_6czH`kTj)mW%8F@9|%%y=pEz`pXbp*l#)gmi#X&&;@>5kHDG(RtuI5B2BS; zQoPO+BI{&0?!=$N%isvGLtxX6RYl{@R6-wDaY*{eNzh;WCPQ{%-T4N5s5{#zFpVF% z5HP&hOR!E7A{3M0ym1k9p}yAotRbXMvq?g9 zpw}8syQZvHt&Gx?XR_|RTcFFUcnO}gJS7SK#)bgOX9V>$>i+_X@|3*l*>|yqx^)@TtjL zxrSk=!0zPp$IOCTI02uzp}*9DWo2mcV|8Ci_zcL;44bk1+m5<|=OXJ~;o@-wXxLKIjn&~w;9DiB;5 z19m&WPlzB*6IMADIDWo2LE}nLXu$Hz3-4~f>-js@SB3iqae0l2C57oVqV9TL4sGf< z5Q?7%Ct%wqMmmGi-$@HnWR7sd5Yk-gpaEHThIm=3`ig4qq-RLZajcN@6`V~64eQ%G5IHYJUwH`%$MV-ZIG7o1o2PXH50 zeeC6^G2q_*d8;Bcm2cqm(cO;!?&5R90}T9EtMk7^gNp)9J-e+i{tQT-3KK$zA(M%#4>`f0ZJj?5cWx$Vk_id`HNHz9r#b`8P={*=EXkA_~ zo4~lipr)%c6`IJf?g0}NmuFArz^yFZFaaL42TQ|9op@v`ZO~fh!4O&(SQQ!{* zcr#Jpt=7gd=$BgHgU1{&zoeW3=0)IzbZ2J3Ws)%4pxYuptNP5k^8ySw*Fl2>O{A=0 zGAx(i9aA!b+(HoeCP?h(3aWSDS_M@Z2>!obg3E8#A5i1)Z@<-S+colgtF0i3_eu${ zkl+hfKNlD#{aKPovWb+#M@52eB>lTI!h5X>-B9-x^-uBzcr2>3*sxlYL8?T74+aPq zP>(as755d90RrNMKY{7dwD2>PrO)PWd~g*0{hSxU+=P+NN})^n2DNY~2LJwK_xT!9 zL1EIMXS+p+I}EHrR|b%X-xBI7?M2yHLP-k3j`hA#qQ_7MZHhOH$jm=!OwbQ}Z>5gX zv{61x|Kz`{U5Rqy$Pz>nEkGx2D?tS#mNP9$qZ7qWtJ4?o~F5U~=zi|PfS^@{r&+qT;x!X@wh*VMFAdf>2uD80+@GC2l zgl9TKQcZ-*G0U#VZxBSON6@# zLKarZER^LhT}U00)FO#4SA`ZU0<0PEOBisNT;a1FeZya}?L@cd?e_l}KHo|T)*}=# zpF}|4PQ}o=tD#n3mD7s{(53_Uu9z^BUy)lSY@i~$Q6>{ob0-1x9d^MD#6M#R!^jF~ z5@7X2fpz{>%M{q7Z(RR7=ZLJj>2qeum5HD1%sMzDNF!;UvoAE9tGJIrNw7Lo3;baS z%^TsDDMmVk&@J@=e>MWIBD}H^td-T#?ET&K`j;rNDj*!z<3r1_1bhK=W%LY`cfFiB zi|_ZUfFVeQJ~-|&Rw>YnOre*!7HQP9J*j{0pXGaJwhF!Oraa2 z#Da2Q)Q1?2RkOtG>NaERpsvkVQ6}Iy|ZvX^OvIB0bCL|1krs=cFgRW-JCWdk+$Q@3iuN(r0=qto7hG9Q{ z4(z`!_3Hg^mcKUiIZ`@%_UqiiVIbD`1xatW3_fANyIz>{D4%mb6%pR?*r=fIu7z0Z zEDAdb!CKYv7#A_X!5bdTWesSj2LP@GeW>d!H$Z5Dd`@Ve-QoI5FrVBU>1L=4HIfJs#xCCyGt0;V)Y#Cvg1wBv_Wf#Rz&ffUjvHCgt#aE%c za}J~F%NvuB-ocrORho22f}QTFx~=0laQh1ojB4mtNy7T)_fro8PM?2whTC78L5WCg z8W}<#uxv*a%E*43fmrnl2=30alg3 z@Rn>q*zJEU0uOUcgWqZqtb(9t+ktc~z4}qrM*#@Gf4+*ms;KUE+JIE+sH*%81F~Bz zp!UCL`^$ZBRgzSd1Iyt{iQ=%-mr5B3dKLQaa!@5kK;!k$HnbXK0hqgO}6?du^igeCsu^rXK$!KRT_|<^eo)%f?WH4rTC}; zJrm2--S{WL^UqD{;hh?ZjDlZFA`#o;7|tOOAByYl`z;%uwbx1lU?w_TB}7> zA*luMQdbi$^%{6Fg64Yi96Nmt2{xHn6ne$%nfAYpxz=$d z;iOZbCvpMf`i~cag9YE+1z@@K=g|Di-qg2=f<6&K2bP0uvTKdBQr2(V$rL)swk|%Rv}Gj zK$>v%TeiRx>Y(Z1j%v4ZX<`5;QjaRE0>?aorYi+^T@rL7g$#%sO*v6;(=m^3+@@3Q zK%eQXL8!6_JDYIr`JpB4^YPJTROoJDz3HLF)Rozo{J=repszS`7+h5^Jk>s!m%-K1 ziRiEH4MHy5hG!QOp;7ood1M#{ecUQXNx7E*Xvu$WVD^kAq>*jEoPnjAe>>knIGiZ3 zn45|VX_(dO_qaA&8f@0Pvkf|*VI|zDEXqMAdqjq$a)jU)z#l3Z4g}^EFv_CE2V5cU z?mWP&;=*44EGR59Xq~+QSi5V^%gK|B!jAu17+$ZCSF4}3`AAr>2Hr(g0WXZaQ&j>y z1vS8|lWu&*#u79TekdW-gXo47&r*`4VYtksSpePW>??_fZtKA`La>!!jch-nc2?;m z#N;C2FcXWfT6%Y-w_B41+)-I<>1!V%3aqm?_;Rl8M{hfae)|ouj=-8PJ-{c;M_({t z(~1!E{hse~w==1;cPlw0H}G54Gi*O!NVDEXjP0OoP7wVcY`SZU*TCzM#MRuks#w z5M~OD^JhJR-p|;uv=UCtel_y)1lq9Q^&wCP|_Hl!eHLu;>07GV4^&lVupSkdn1Tu81AWpK^cL2YXFu!EStl@ zpIuACXC^cq2Q8ow3k@jDhq}`aV2l(NAMkk&<$Qv^I)(BAeO(gek908ngodMUBvv*{ zV{@3i`7n*mL8wRM%}bp(B*^;bwxCRD`-uya-XZ@DTNxk(i4)kcXfu{EU^Fn~KsVf?Q#z4E1)Y`pD)S^7iwLQgLFFjk zC5ajN>l87wfr>@KZl7}$ys#If}L--g8|P}kc&g;@*HPX#oTZ+2IB9rHz+zR=|hs`???m~+-J;!GuVHR z!j33~BWfQUGH-LU*m(zi`)~fuwjY?!>CtS*Ql*KeoRH2GBMn#J`yvL+%izyGVA=YD z{)(X2rcXMk-NW%SM__eu&%`YZrUj|fNtB;9z^!AzVg80Fu%Q2!2F(*snWt#w>xa*a zy4w{Xog`g-aT269-M=dT>cG~f*AQ-fzj_0#oJc)Pq}xD(#b7*A86iP0eo6#KCn=P^ zjF9Qipz4rnAXem;%Z~y9*4s#*XS@8JuVl}G6UlTBn#REk=aJDzIW+YY)%lSwcv6f7VGHb1h|GDT|}4hR_pfuK<0) zh18+=>JQx+se*c>x8V^6(U=2$(BTF|Sp>e&2b?8}vb^&r=|yTFtqHN?9&ulpyBd{J z5WhErDi}PA2J2LO^}b}ldid^h(v6*lFBdif4VM>~<R z2HB9>stXkO@rUgm0;_}bKH>AG)0~4~$)FaohTACP>Z}%6Q{WT*vkHHf?m-e>k^2a> z(A7@?wR-hU;3iyt-5CfBwko#4ENd&MRnKmSA@5L%4Ip6@V;)LcX+94 zf;o(1!APv-Tnqi1cfVsw<8M)Bc?O)r5?BK$seu777z3bP5uuEqe>@Z3Fm?lU&lUka zxH4cDLwSzEJKF6T>k{Pdh7(% z{lhdK0W&+!mcjWMDjJCXdhC^Mi$a2%X;|PC%h<+nreMRGOh#H0u0-HIJ} z!!}@Mz%sf?<~+h82147^@dTP#Zy{rxl<0g&z<@`LcmniAZBj!|TpN-ar9_RWN?GZu zXqjZp`mL0sWqh~LWPi_-XTVLXQ5=$M^oDzl5d>$o^N3czzuiwuAeeDjqbC(v z6&7Vs5(Azkhf-3oW?2Fk#q+GET*c6v132mD=E*Mw-&Xn0kpTyB^IPn_eTHXaz?F15 z#8bLCG)uA+gqJT;Ipp)35%dq6egpP~76zfdKOqCURlqP<2(&GK?~(it&If$2mcQ%f zHo$8%Ank(4dkDa?BErIVHIZY7WpFi+cJpX;0(V%zz*=RAg?__<&lJ(Kh_O1cBe~%; zM{?8zc-9&QfMV5OMdJ}4+?0|KP0;|s4HA7>_1qXfy98(pU#(tp-ndjpck+HWLRub6igK@{P!0o8wn#N|`3yk2@tpxBPQ^nvw&-EV^szn*opNQ~vk zLV)w_;Rn#ff@32?j&5N7RdWjT68h_!Jb+2Y-VQFym{f2e0Es8H}AoeYYf39gR zmSj)vv>KkKI%4wbx7$AG`E(SogXa;wzsb3`bn}}u0$OFylXMS?|Cb#|0=}~p5V8mh zOh|~n7XKXhFQh%jB*+_d8x_~ZEq!LcHZ-b@#cY`FX&AX7k=ssG#5UZhq2Hf4nXtd%G+6+iL zq;J^DcQ<+qDOjM5?y!sD?V{J&ew{RHj;d)IOv5_Z7cLnCp0O55vnYFk-}z(;y;?Hw z=IHOngXhiERvX%nDE(QCzXM=!Xh6DE6~Gq#oP+2YVE5r_e?9wsgT2p3Q~3O;UJy2~ zwF&5adJJ&cCbRy!!8abXTf#BJ=XkSMd&V6k)1D4{>lLqpAsmZ-!dX7(H$5`iu{ z=!6EOG)WFtXXED%q*r4j1#7yVIe?p@rVs}iIPb-qfmLbsIRg69EHqTxuYAEM@8x<8 z(UaFY;_B*NTr^g{SAUN2*?NVi3j)59yV0tkDv&!#`UVdy(#Y{wvt(e+Tnc=6y_pF^ z1)(HD4+)pRJb#Y;gMhu{-aT$$EY-V)ZboJCy*6dM9aY~vKo34+%i*x?gRz@%cn`gD za%t>-bHw0G5-d)7&U{AD3n=_!8PIfgq(5(&)y~d^B&Hu*76Nzty`Eom`76)15x0)#enTY z+kj`8L-)-T4(meNdX+;f1qK4ll?<_iPHM*N;Z~V|mqr5RBPy^w;@;j0o@?}d z#A3n6^DO5o6d=@)_IfqgZ6(TTj*-tVK7rBVWlwJbcYzDT?SVqaW~SC+IHNQxR0T^j z!$YH?broE|7oMatn!D*&K2(F~x)rHUgI@u23UoQu5K7iU8}TJ?DJ>Xf`D>w+jKl}< zcAZ3Db&A4%4}6Vrlv6{*biH2NvCvlwhjzMUp}tC5brZ~AaH?qE`@3VwuOrUQxM#rG z3W~w&Yr^Nqgs)TO{~aCK#S9ZcSOwdpH4No!N*qVY)l^BUnt6**ev9Nmnp5HxaIeU_ z9vfiGqD&1NQbP%C5tNoOnHJG4d*849)!OXMF5Ie0a?PnXs|Ju|BgLwPHbq#=8N7UB zM-nksx#i^qczF+OY0$Z)y|PX3S^o2Zqj^Im^f7%dMEB3d!4)BS_mNBEXty5q75$~L z^KQh~MNn=kv$6uDUF(7O2({fV?Y{=fyV`ztKZ1rTq;vXP&!EdkT~RmyX+W00`&bTb z0-jeCL1X+CCPG_9aIaA8l+SCAx+|1HO8{l>GbpzKR=}9YzbvizE136`dL7L;^a3oX z1PHs{4=O8fw_)QeNP^Mz+r(WHIYnR$km%l?fPePoz*?XFmhrUuHh))7e5hyj=x6-g zL2!P_PB{3JU@e@V88J9NVldWHK9?MHSQ2=~Em%IEWvg^pJ=0*w;*cQdnahwkilbu@ zRi%xt0HC_DejrBcU%K}9N_jr zdr#~>I&{%x0^N#I&~q509tmm0I5kt`)=O0n3wLGx24iQ zFd*NIDf{8IM_~RKBw1wn27)CVE4|NxhS15@0{FmLYXbi9b|g95Y!iI&-rGepL^xCM2Ct3-Efg5y14USy(fQ zu~s0!^J-BX-5TPaLlo95$s0U{o)wlAedk&YjV-{E+$%BAvI6d57R}GHcZ-7-IKH=h zz_<1gI`H2|$i4F1_l^5VN6*igdG&7Ld#1GVs2Y&30%wny&+1n7H#pMUc$CINzD}U_ zb>5Ab9q%_qmWiTcQG-(8To%FEo{5wK2>-p^kpS}^A})hfhc!^I$DxKMGm-{jK_J!v zy9&X~q9leRSq;N11bD)6XeSK}B!TXf`HqbZFsQI5^a4AOYwD4wYZHF2j`(^KOl0?Z zq4cX?6oys8qmK)hBNYo)&9+L0C9~66h5uM@tD5Q%N{_wiYTVbqNTEjMiE_0QxvG=R zpP2!VtbQIx+5ned%gkJNrZNT&QQ-mx!rqPvuoVAV2Sb40!hA)A)dL1YCBotw7+AN= z&odEEAMKcPc&7OlnGJ(=*^JI$C=8~t`2gTMyrsXtYX;l^VX*&l3?(jtf&8{IH@Nrr zI4`s4O{UH{bS~Uo>ht~k;OCYyYmM*wW?(B5=$(!O_x(^i*lr;do(%O!2DQF~VKsbi zWpN+@rfbNp1%^=rJ^Sb@puScEJom8>7zA08&|wkM7e4oaMJCsuwi1ne~ukz1#@8zeNu!J0~xQe6{(TH5x2mud>4ev7o)xEJUUL9 z|Jub1F<|1reEH%e(tO_+PQel_b=>)eM6YwrRoMNSIDE9=tErnb*>fxmSk+f@T9Thh zicYhK#4K1U2xl_?(%yGw5wtMi(!@|aNSeaYb4H8PVFB|ke^e3>>64sqK0d=o{9wAz zqk1~Q=a`3EyqMzT6pB?7;e=bm05j<1Q?Z8kh9q7AlL#xHO0XpRijcUFUtqpEh0bpJ zoU0B(4ZLC}68Mpz2-tmYpBBKq$*@B8k(q+M4|tCy3>pEA2;FL8fTkoHKtm#jHTPDn z44qZ_cCD`i2cC5q3^5$)M6v^c{q{DD?o0oXMnShUSZ)}-i7nX5fO+`5@i3Y_N!Cbs zD6u>cb0rQs?bJ!!S``_Y{;DiKo;Ba9$SJI*=V)E0GqN zMGO3v6JB(r&GN8{9cfPG6(UQoSVp_T2wKxPMmljxl%m6u1@H)Al+&A1!U|&}+`5d7 z_{Co;Q^uq!R}d_=U`KoZfbYadFH(zip%lxD_Y%7r#OYLfbv?6IMfkn?^yd*i6K{Pb zR4kbnY2>acZvW*-N`~D+ghyT%XaF>qIhQM|hCt6;!jOUkX-Fx=Z;<}Eq=(ZYIJ5w> z)YHX2yQcAzcGI`7^vweK=JvH-OP0ce&*_Sply9}rgu?G^NcV!wcV7Su?Z1q`vJKAA zf^F%&VpOT0P>-*`fE0`FV>ZuZ$&%|8E@ z4gUwHe~ZI#+53=Q-xW9Tv>qkV8Pw^%+vF_d#EWwnPEZ%c7 zFyx_<{;Hoz4b39Mt`Ol=UX;!wHxh<8EGhy%2=HhGn7ariQxP0DRY-D+_fE0&sPg_! zWnX*oSy;5o^~ug`3+69fpp-$}zh)e+yu{aFKAu81ag3jgVykN_a3dsMjqLl?76w6K z+V@iaGXw58GTt%@kKB;KD}&<#fiBSACtND8!k|T7_p%}?zSLi-c@=LXYDt$IaY@`<>I5tRv-jw@N`i6#Zl+~}M zQ3~GL6nfD@Bb)3aOI&4F~57I>dCOort`xkEP}kZXpOXp;4=)rqBKj1 zW);5ie8v!~#@g6xs?Ju+fXM&B#}{+ydhc9@)IJO|))KQU>+zJTr2lhvCEAT5Nl<{G z^(anRdhGvy>6*$bGOLiaYj^9wc2B!UCWy>9_#cc{?n;7jByn&nQq8q7TRRfZqQ})P z&?HhVFM_$7;e5T(NjSeAX#<=F=D-5MN!`HOOUNr=5A}{_$(+1F=~t4zAq_~0@0tEG-A%jKU#aw2vp2elU{~ID9zSzKZ(;Ox z0h2*TwK)WyFZG*tneKbSZMPL*+0C%WSZ-);;7}CY{i(*P?SKoob-fFY@5-?Ny+^eF zPS{4MVBC56^ZHHpvkjp`1eQy}DpXh&dbLP5!-5bD8a5>biSxM&elD z^_ud|CX%RD0AEsI)KP30*5P)xeR}NV2IVNk5xy^f#n?|p-&jTLHRGqu=wlp^7kLpU!lt!lI40BDoI^VSoUy3 zc6&m7j60$*+k7Q^BNzQ<>YI^QFqd_1Ir+-a_>?v`+3(BEzXPXFQrrfoZe#`wH4G}d zn!p8Iwh+>L+sQt7roby)x|)&5NbksFWL)gp#%jKm7(#|2q15Ofee_t?vDL*8mtM@|i$<u3zqkmhts2%8IKUqJfie@#EW%q8mR~A z72yG&#?XQN&P8d7iNLggn7AXRqe&ok!~AJy8A`~=$1p9O721dX{H8j`iRV2%o;E)f5`1gh+vNwURlT!050Xe89R zNr<@#dInQqz>2)BUL>@z{w*L_VVHUE)ahM|wvn#wBI-`ec2_#r9yDcMM~$HLLaXoi zt?wC}@s&SsL3K56f7y|&bHMq4?P<~07pe+3f32%K(u1Qc4s_Mh(-;5x8^AoGc#eO!AgG{!CbH)HJ`F5A25lIyVgR1WkpE& zxh6gLs&&pZw}1STB`z~r{+bg*&k|tV3jbpUtV~+|m>Yy+^-+ZNi1iEZ8~NY>{(Xl0 z7pfcY4F+!Hy?XY1Vel1m;9syk;r7mZUz$AM>3BGGLPX0gYz|!1G**uOyCcO03;>+3uc2(%ttX zXsiAe|B$Ou)vw*bz4oyt;C0bx6<(2;6o@oY88`Bah1&Ss~Rl*)wX0m0uWZ=Yly@y2phcQ!XhaHS}bL;9ue-TVQ)X2hh7vV4XZeDi*W1zHf91j1y=L z#d=hR(Z(kWf2~t!S$K1QTOcD+(yaQdX+8l|`K`EkZz6ww+|IAfUB9=ihSnYNO$e|q zgwN07>}TsC?khrQ@2v9U=SRKusE5Wzu1#(feqGIP!$D-)GDrlN81XL(GyD#sea^^h z?F-C%6Wyz(q|&ZGD@ofvv#)NFxq+c+~ip_ zS%${Q$T^}*RAk+5b%ibDZF+Z7odE;f>OvU17bJ7?C%TU+@Jq>)6V(4I2v4Da;ez~j zSNi9K2Vn&)d|0S1G#^b+Ke#y9o!lb0?m|lF;}rok>a5%zxKuYohp&sZY7}w3{c`W1f-j4kCk`51CH1N3(ei*4}XkGzT?%+eh7^&0wk;!J#V{QY?P zE0KdAt2FHyM)3JOlzV`|Y^3!JWhwA%Ay~7E!5UR@$2z=j#BgX*#)EW^0--xIyX~M) z*eM)3k@Yu$1F2E=EAwZA-!p`gL$De_-=^9|2(V<{-~Mt3Y&Rz*^#NEQe!f|X)r0Ir z{~#PXuXn}&o8z2`1wZ((?tgXrOQxhprENImZt(gSoJYY5>=Aee5M~J8dseM6-s+0? z6g`9Tiat1q>36tmQ>4UTQEJM0^~7#pEnYD6O|St527F@BWboUOgm@G)1?i0U=%#Q< zSL1j!U9(Mav`_>aFzt?ui+<+|-ez3DNKocBO9C1uAS@ z|9*R;==kjutUi5qAz8K!?dxNW?-ObL)AAy#mng?p?7?SGYG+uRE6hfdquQ_!F&#kz z@a*>bIRJ}OuxQ7dUl6NQLrWopBfd0L;bLhTJ@0BoqB$fDpsA2Ssjo2LlV;t?h(x(p zJb>m(Aic%6>$oAaIX zeEH6oM0W~B8SeLC_yyx^KgzCP^&lnEVGTNS<{Dsb-`F+(YR@SgLIbB-5;WRtce5VN zka{%&1aGd&RIydp!n3W1`R76vTb|}_r32W^c+fJ_aU%rO7Vnzh)pfgOYyN)2U0cxJ zPb28{$K_tFUI7iafV@AI)o;1~^{H1Nyt4SoYxGT5R^a4{kgSEFltAa0Nr|MiHl)cz zb6G~X1jSXO%U{Ld!UgPeumS|95}OC8_O%%{9I}TxZ1#wo%JK7L(CjEMVX#DOw47JO z>Z=hHS7b1n*k^QZe^=2U9wq7Bwi#c}mvsnRSiA55*;xdf5^8hFir0`Ex2CRGp>*QD z&j;^!_Wr!#=vyK6Spuwm@NEb5>)-J4Yn(>6(e<#|24hg95Y!c3IkYT~nxzbh4ZpOC;B_y(N>-dXPfj(jVgt6k?JajAQ6W;IrjQeY2kJ#~ zJK&@PXe|SFF&uYjU=YPsBX;1+3=UOb^?j`sNzm|yIg~yc8ex|gz(oWWWK9eVjFSSt!dbsH|4Jk)3lfW; zw=k!ko%mS>M2-gY4j4Ov={sqS`C30gLY_(%zqdzkj~*q?rZKQ>gp}z+EBp z>aX&_R1Ti8gaJNf3A^CMmcm+$v`nDR5)Ia36YC|_(l{2ZLu%Z*w?W5J6AA=z3O#@s zxN(fxIvA7{>D`Box-uP&Z*H zo;bI=v>{0f$G{bY(uZ`O%d-vXJSM#irh-QB&Esc^;^0PxzL!v}TKGf|C~@h0O%Zd zW?U%;HrKCl;>DK`F1YhuYNn*6oG1tL5yoJp6jLg_KDwMhd&Y~dVdxsHYMe6;d(~As z2hD2romlNWNz>6Jh9lYgW{Q&=Ue6OSsjdik4~>Bvc|a*+nZsR$dJ+t!M76;y|D;qI zvTv0CG-!T3W0;k1NC>p^{T7mY{T6}wMK}DlF9v9M{1VtUG7Lmmf;Rrk*_9|Jsx3hQ zAzV4KI4tk~zx0J(tIt7`8FR0}Xf`KWR(CDRv9|(jBhkLBZpeNc7Hq)*(&*A>q1*Vm z%-4Hn;M+XR;!B7-HLg!})Mc47hfZp0izZGc?;ZrRk%*oxgHn<=P6A9}(3${kInbKD zVFD}^3f*PpYbIb7LcjGNWxG-}`eeH3(h>}mlxEU5TihxXw_iw!d%A{>Mll4ROJd*q zLPpm2yDwqJZGVdl`21$yn14fqQIEjdWB-w_g!`flxDO*}=D%{s#;#vS;CqF>qlzi; zxe)jUTtZzAowU|SG5^wk3mcF+9!pyjgH4}#1uRbBnv6(|1nw;sz4s6waPtTntc7X7 z^CJ2R=58y0j)uBi}&$KrJjw0g}x?L*_z6)m>Zja((Yz764+(TSDY zqe*^sVDK}~pTTw1fV_$caEg;=N}QA`X*!oRZ({MQQXfttILxt54;6tciEi|rT2H>KMFA*@nE*DYv;W(c!s|-2HPf7Fg&4YFoWM`$fCvP zh#%@vbdlsQoaND)Kc+IL;w&#>=NTr_v&M&Lp@fBE@i-ctNIH>r2AtG37|9X^uZsKP3{2+bZm7SSAITmdH_y_SbHW)Pe$Z>yZrjuHy3gXM9^ zO-ffSNg<;n%%PP6cR-8luucul0& zfjH-=Z|r+DzI`>rhD@y7NM)MuY?+x5tP-16SxomL(EiO`$rOJUBfC6$~N~V z7hrQs7ruJi^`d>)Nbn8Yf#vp|pJifcOSbe5!nO@@SA7w+kw@(=W zQF;t|=u!8*BNQds4%l)yQnVo%6|SNldK{wr7o}J^?XAMP7l?Bg)zsZkhEPHcaE+f| z$g$3)@Cm=)zZgFc8WnDI6-*!Dot@HQB{e#96d)GmjkNySxH1oxge;ne_r*0bvbIAjPU9}PRea;#q zc$LHF+ZcH7dBYo2BHcoov!JTyVSUj$m~MCTDu%Bt1iHVCE_g0Gnc6lKM+7-mJ$`3LUenl>pL-K|!?EK}w0e~`-hAn)`qL;C0CP9#^?2MghEt@~b9K`#`HRdWVq z-O;&F-^F*pl!B#pS=*E@=4s<0-18A~Y#-_xlGpq6$GqwvHST5B)n4pdY@FK?^6~OZ zZ>^F{eTs2>f4PR5dGGm1Q6J{~w4tEvtvSeAY{82uvYOfuxNgLrH0sh^}8n+OPoz8T6Eu5dQ5lc*u6bNNuqRc=YzcQF1x-C_(sDz})Meh6`PD zWgK|PhNEXS9tm{GdZb0RW^t`9 z(Gp&9XfnaYzBHz&O#Y4MI>Cfw_re9TEVVF;RHi`4EZ1cMn_5}oK8<=eYn?VI? zI~;}nm)V%S65`<$ICKR!ya8?&9ZN&@=JPg9xcXJ2FJkSV9Bq%H0SV6!LRQO!P726| zv=geY@-Bwo18*ukzypBrFkn&An6UpS<$Vi5h!x>?4DYMaF?1YU5Iq8!iLjRec}VU+;v*>kO&Z1_I%vjT>i$(4oJUWF zQm{8sG;?83GKZ4;j((UfXVOKeCHmyg-E23z0yypw@Ray|Lb}c02gC+Ij*z$G!M;WG zhVQIjY~S#E#Ghq*hqRx5T={*_1aL)6p{X-7f^tfuh>iz!p{ zXh2s`t4g}A0fJ8qUh1LNEimG*Y=UJvDj6K&UKO`db@zVxPYrxwbZaYAjN@pr=MR{$ zW;5f}6dx%r;BV~Yh%1&p-*Bhf3k60^v}}ZLzCI>x_1B2q581vs^BVPivG(mRiYNLq zkW=Rct+;>b1x*W`N3M(J8s>!$@01406AE3_4~q_;No>Wd--Ypa5j8ZgfKM_^N-J@M zi(+7rl8#0Lq1}OGxdWQ~<11E=%@77`{=`rnie)FZ2>Rtf%06S;GG*3z-7EB@A=TiC zxHZ8^eeuG&F&?TH;LGon0c+wUFkm+Y(+7_~2O}v%u$;kx&|VLp#Cda?vJJ2kU)N!k z@H^zygTod2x(f-0(4$6emi&Vr|WgVDKf3aaRFh;4;cu6kynRh6Yx-X=<{K!a4uoLz3^8mQG#ayJ4hN5ABi@sKY&cJ4c{Xc-zS zK+6rc47u$(INsq4W;h(b`W^<<`v$KC=)j(Fbib8VE3G({{yv%|aO;qWYp5(d~*1vaXP7q{+)YBy$|*(46G9@L31oI|vIi2Qcn`#Q{t(Y@*%^7_Kg( zuzGL;gCIJR&Nlb|YHo8IUBJ=5D~sG)AJ)B+AB|2T_V*ftz7^j>4ZwYWQKbk}Hymmw z;d>h}+*$V)WtuE z8!+uBOaU!p6sg+P*;{;lPX`dJ;j^;&1wAIteg8$q@!|8ZIfWT=@EFjKNWX^&$T%2_ zvADs|FFxQ`tOUSi+ph*aTj=xgZte`1lTzLkgEws5J57b-C?~#C`dc5;c^V;vlCU?8 z$=Vi@o04?jYax_k{3TATsnFwqGAsts3bU|q3v8^_u(--YC^PaMo*utSjA`OYqEXg8y*2I=jPO5Aq6#593 z^jJao$N|}MB4X8M=s&uu@SR`pA|`DF9n?uEJ$B`CB){9gjCrr;zW#1An2a-L1zMPH z@5PINiw}L|zxEzx;o%j3uHuSr$Co~P%_s1#HkuYN=E6db(GmyoHww?Z69x`^Kq!H# z=Nml_&f&yz=_KwrX+`RU1(OhKQL05q3?f}EKoSaUU_$#~owf=qetU|0;F!q~OOK3+ zf~+|}@Ry`n*=K#ZaaW_BK~x2vUbg*$9y*AxWV>9ja>Uy{T93f_Yem6v>K>KQvOmA; zBE5CzQERHKN)n*&cUcCDIC_y92F~ADxPGB#&o2+5MGZ|?TNP5n5WH{@G}B;?38$54 zW5C-O{t5)!)5znQrCH6F66aS?SY7xX_ToHFigJyHeq_}Z+G@^&Ov)$#>|({IIFiJd zB>7o_#(c$m^NL^e0+-@vSnr0SU!FS4bqS0}M~=XM-tpWi*nzWBr0GHqEz{;;1s-X% zEDK$kI`b9uaoz*-jVy%{hReyBZ^|JUfKlsz&kiI4W?`vAw!;-nt>lK~?T|}X(Z&>! zd?>ff-ofCI>opA?!r_vv!B@i!#)Fj-qE4%}d9=o4yT4CUX%=wik*w}U$oII#=+=|Sq4SC~gFzEy15B%4TK)L0^Y|uyHMmK`= z-+=9};kcYS!;_0gbSW+NdrKz?=iT_fmFpaY5i13jYNW$T$@L%b5I6DR`5h1LN1{vY zDW`a7_#5(qX$Oz+C1)AHqEjx2Au9QF?1-9@D_InWHBP5`cn%%Zu~3BfT+{ezWbJ5)xam&rwP*xav2+4!kE% zq}1y<02w?uM|i+5Jh5RI*;)8Gz(I^$BSah}(Zq%G2zBJBy>#B4!xX8$b~z-*9EBqb zCw%Zi`L#MJkEnCk-!H=Gq>8>jvdTE?qQ3Lc*Wi>_xTIb76)$O&9fAKB+y3L9cKHXl z^#YeKt7$$dFhU%2>*vQkS)lAM;-~!#H2#Um0jW@mNNQgofC0Bfa0NFJ6i!7+2ySW7 zrFM3P=A&YEfA#SHTg%GRVHb0VmdS8!RDC;$H{1$$XG-wXUb#_R+mjzc&QI8!E zC(U#I;R(kk z1|L=6rhK^AwjGn{rhh(YF|fd|$h4X+x=FL9P4HO8(?DQ^a7ZAB2XG`U^k7@yVb2?` z*m3DBg-QTN&VsyN7aF7)8s0RoMDJB6#a@mqUb;pB}{ z7<>DCtWZB^K1?pAc)nNun>N6#kxo`&(qt(Q2JnU&)tiE+I2NQh_QL|f=vK#@CyY$i zAUqE*IfYmR>L{sNhkH%uwWe|mt>fY~V)H zv;C-z0&AsWTL&uzzTK{B5w`N+5u6zRRu%t#7^Dl+K)OvL61Xz6I$lbh@5`9!N(T=ptj;rScw4C?s zp;?C0M3J!#K2sag?%Z2~&jG#XoIT0HD_&+Fk121{$?qZlPCmIG*k{rQ1>J~*K8TU& z;6YhJk52->x~mt*SZhlXRkVh!NGyjaqMIpck|ZpP;n3|cG)eo-Q=m8N0)`Np6j>U> zx48RJroA*)0}RVrc5!YTX5gD^n!|0B1=1w(jAT8X8pZoZldH%xF*VQ|x0~rBw$MY1 zAy`taA%zAB9=t$l7_Yk!Kz~vGq!HmKqBi-}^MlsD4R7nF zUm5PZxpeROojT{QDXvyZqYNB&$@7fK^b9h)dL{7O=UnN$dJ3rZy9&r}A^g>0^GfdB z0L+qOo}DW94M>Fwg+tC&rm4^8C?#ycX#w0!lU;n03N~3CVOK_2B4Oe!_2sCjE_0IEFLe>}_V>;7SzW&Vapq26 zlp!IKa%X#Cx=C#gsZUAUfzMR3M1PpyP7z{^ee4ariSL zD-TEadL3+Ge6YQ7R!$$(9jt)dSn=twwad+mkxn{-o}voLegKJ;5f9oRWGmrl2gb6L zC7&Fn8tV`WLLZkbGvP6DO2<+oacC0#eT3AYTnKYj-|^k7!PmuRcRb0nN&3S549$i# zZnpYW@Re`wx=STUw)wTCaD!hPLo3>jqP7yYD-I*UUBTbkSHp89*;U^{m>s{-1^kc5 z$!Sh0S2||qSS!8TsuboKBWDodIfHNcZNnRrYHWDT(u?Ft1K8E6>-y?1Dut=;%E^>` z6*yZ6s7o~eB-^(lPBg~VAXbaQVKS0(M!0i(nFK0jJ=1U*68>l_?{XLKj+ z_X%$IxeEs?VbNrchej|JTM7O+_3sOKMlL>V`+}JnYBcIri?}$5pbY3Cb;Z7ZEG}muNdJw;!Yu z`=RrKpNHG0g#rBB{cq$hTC6HY;ikx{Viblb>k3tLG#To@Ze6S>c=ST85sHD)L!^<= zAulGpy1;x-Xt|cLb9>2`3Fxa%87=-jSozWMP4si#l%BgjBrg9wX828e;FmS8kCmDK zKEZYO0UF!bv9n;RKC*jRJk1YO{wp@(^SUEuon66avJ4+7Hza+e#4K9+D#(5w9e4F+ zd*r9?gbO+z4~4{9%6^qT%QPB-E+NRrLfYw88eD`EtCQQ5SegxuOz6F)bp#4;NNMzL zhP|7Tj1{Y;)?QO%-$k?}v(h%w0*eF-U10Q;$7tjz1{@~{<|;C7kwGk%&Fw6EqY+-+ zWiOTtjdwf`9Kqq|x4!Hke#XR^9l&2ztVhj)WJ}(PP>njc;<={$E0AJOn2bB%M0!(x zba}^qClWdvzfBG#^ZCvM%tUSr6&C8KS??^xSG+o6Ui%biS6=Cmc_s3jWzJJBUjUAp zXbYI^{Fkmm+Qp4ZhV#5TmNz4#!FET{J932*L;NRrTs9t$q#R>RxLcnW*C}Sh%3D7&@ykj!X>slA&8D}+MEgQeQG3G5}gEs0n}7Q zfAt13t|u z-*}{9+5OQktL|N}WhW`&Hm8R&-iPmhe;yPPbaQ(}Q)B%I4qFyqm1~^iQ2J=a0D92{ z@Q`CG$BN|x0$paWPJ$Y6Fg5ffueeyNXdZ-~b;j}+{ez|Ch>15OxExaq2j@Go@XAA< zUr6uAIrwa5xM06K4|i5H-Dx?J^Wn1_g!QhoTz6?$S`Ul}tsR#LIG0jkFXzL3c?G+4@uF^_HsK9xUj`oPb#i?~#ywRyc#TM)Nd^hpD! z5&XR!HqYhG?+}LI&GlF=I#YA705G<|z~72haE${=`YdF( zI?O&lN6|ma6uQncr$1MWp?S!BnVI$eQiL@9YZ4t?IGPu@18H`1FQO)AFD{rPZ=;kn zXLcj7tFD|4N7_btMawA!&V;+gT2M6ZLsmfn)8<7tTI>m1*<$SI z9F~@0$jKjxL|51TEDJA)mL%$uh{bx1&NA2ZR&>(WT&Pm*Kb?Yhea+hW#S#@5oco7U zSV%OT{k^g<*$%tM>JxZQfIj6TIt)2T%mVdt+KDn;&Dgt#qFlLdyYn7SV4RrTCB3q_ zl7t1zM!qgCkoIn@MW@hE;9YbaUA0^5(q0G`#AV6;qCxI}X5f7xk)X_VI2BqU7p;Q= z6Z+Nhz56$LfJvkawK`fWaD!L9i^R~n8@8eJ0n=z8 zbTL1Z92CRwL7IaPoAecGAV-Vsz`aP(YGZ4L;c43^VvM+CRSSz(Ne>R$PrJcv+gP%- zATTbQm1*Qg-*M@pg!p}fADW&B7%IOHbA?SGW8-sb2R8B5GO!5CxN`fmUU!~p1-I{4 z*nm}f^;KyEEvjb`R;l%9(9Ny^ZMc+RO0o#b3!98MljCxE+Xp=5pvmbqd~(WR(DNL* zlg4S);k&M`f}U53z0w75vGRm6t$~x&1I+TMFc|S_H~EaFc!;stQcBtab98hm4%2CA zY)Ky{n>Bkl76`HK$%<>Gy}IEv{lSD0bG=*TAzf_9hEeO#88joKrCsQZcn%krw)hgyK-#tuG z%A!Y~tBzOQJ40+;Z;HcdoShPA3EgCM>QavDYt_WH*M!*$%DFS$&P{{%BpK1;xw?RD zihmZ8?|QYX)h}oy^i|PRztV-TBt+kEZ}VGLT>+~jSa-l9PH$u_yu>z`@}g@~LSr!; zdOVZ{!)|VCkP}{rvPFRzsbKw!JW3rzH|!M&bora?xg2x;M!)+_hx*m57WnQMIF;Y} zws&U`D}>h%N;a1Md}3=_52O9}{2{#dEJ(dmF1_33OlcEg@79n^b3in&s=3?A&N)hE zzIOd-vS+_g1ClO$RR&$mn^ds))rbz*lVkwBwO_L-Ierr2A_8f-*~o7L-S#2Zr%mnL zn^p#&WJrAwP(EpcgM8iSv3z19oKbkA5}_DXN3xW+4DDUbB@0)}W!?r_is(zx@Om`K zSI*wbJ`K4!sBC$RjtI<@^*6v)4HNXFc-}xQqM^`1TMkJS<%M>?g1l|?+)9D#7w}gp zu9DhWb?@6^&rYQE-z?4iZsejlZDi*P+Pq!p}je-tCyM_TN@}TF5 zs*fy!Bd1Ung3dJrRBMTh4a(by$+0hJ1CakC>d>g|Nl=PJ0s0# zo%G(GHV}dnnh<1ZG!m|Evw*TN<>4-ux$!`n#}?sSV{+e>l4yUm8rmALlT=1IdV%o24U@l zK>rG3=ShO#EezGKeD0aeH2gNkX^8DzxPtmHB=s!i87NB{=;_vy--@1@6vwe1EOELN%2h@AGo6(g- z)%lJOcH}j|`erFu2R4%Wpx4dOhvD>LZ=CdY1=^>+CP;URdz0=$z;9>3h4bJAS<#;5 zfmX}o7(8188YdODMdA`@jB9q>3a68(*RWZmD{%Es0!y-Cr*qRJ1Dx1i_9hRK--<}9 zRiiXLgYxA(xN~6I$?VSXWZ_Y-=d@?|)$iY_Hv0_tJpF@ibhe!%U;aHC8W#Yztl+^T`>iAF3KH)E%AqJ<%8;Uj0XX|LEct>K&jeos+Ak{24vk;3X*6F( zzFR`1ToG`b!&Nm4;`*%$zd0qIH(|bmxIM#qB8cuI;Cxi{iBh9W0&HzEQe+s6n0yz@ zN@dF-@M52!MB8vD${@cR%rcw@cmA?f?kd&Dm+sd zvX|?cAiT2uVaZgM70^snH9%Im>H(IN46%N6=&GN zUI8`YeYAj{lXGaxYB)b-7bm z;_dl{CB+_N%*o&B9>oLqBEs_}FdJH1>n>)yLuF%)iwu>vx{8BNAOD62tMpZ1v`wR% zI(E-}1l*e$I_xfat~kpx-&yYsSHXa9^M9f6&>N&Cr9qlT+*OcX)*1N(_hDDH%V_eL zXTOvGbA~)k>CXCM`>!94`}bPlB+O*i6Uqti&&ZgzL9!GN8_)d;#+$PA{eCS&a(noo z(9c45xo$MaTNjlv^p$u@hEe`=yHRWIe77HWFq6aI^cxOe5AN$oPHufU>F^q*<+g|? z%M~@l%g>oUMQDm^@yb!SG8`qsgwR}FGBl1=;sRtwYc@IZC+Qt7msocLEK)=j)RZQzDR!u&hK-&Rt&}jmyWA*s5&|U zq^pg45%FB3VX(=}H}{1vSy$ue*MYUln0WiSZz13}K$m2gyTLIHW`|Lu4_YHOz6Osn zI~KB6Vc0eD&o%qdIO8K}tqQI>Sf*t4Xd6-}dC)du@R9(&$((oLVZI6(6n9=QCkv6z zrE1BdrW=|mm1WxmU`2A4e2(C`OA_CXwKX7^JXo9MvT&|~0Sh+9rf|F*Yo68$rFzf7 zaNR+6o$WR^QtuwUeNxle2; z<{;@zg*$E9zhasBrFkRo7kPAKa=yM5Ix5^c3ZuAa=(>owZNE7AiC)rNdh$$Rn17$| z^U`|c%i4X920nkK{+zVkFe!Wi9S8g9`_+df2M2;Z1fhw0Y6s9<7HX4 z(4Se%u=(Vd>%Vhs9?kckrohkdTS#MQDee=)U3}EVWb##* ztfolcz?he7OU85`L3N4PcX*{AiQecV{?bwgJiu#w=J4OAK#!ynsP!{*v>5~)30Iiz zngDHT!!6RUpgj|)U4=M2i(~P-xz>DGUEy*pXbLu%y+ttAv0(O_1}xY%Z8;b%4p$S3>)=;wOkPi28*rcJc_29@(Z;=rh@s|$4McNWqA+Csc#v)Pi zkuL@F>X$gW|3^NrT|wJ1!#>*4|CV-qenAca;J=1FH^4AgjLr|>B6bpdnD?r?h|8zg zt}fGEg8X=E8Hn#DSiCDRZvz;Mx2h!^+rK$g=Q+c!=(`fX^TvFuS+;g(^GP=i!ceo- zERN@GlQrHg&fPU>QbcMoN)LiI8F1Saqe+B)2T6+x{pD&-ii^}fc(ME;EXMZ^cTmWeLW4>*0!YEnvKf!mY-b*k8pT$KFVHs(-<@sk8yn^z4u4L6)`{0 z=qEokrQ0~5wwM!i!2&;Y&ixynEesdOx!G3vT~%w^zzlb^>XgRueWdEGyP<2V}wjQ~F)XTzE9B+I|H-W#dTOteBNQdR@&r<^1J z`q8Jwm;rYt4CoD+-0KRp4^a(d&*!zJ@cF!o^Dv8dAsJA5ze~XOf`F4{>!nAxo~2>Q z8@gL$R;t5nRrdoS(ME4E@Lg>CcfnN)q&yb1BssD!Lp&DpI2KFeD8`K$(P5mo6iCsu zLLaCuBu=W07_S4C6D{YvJ(kMdRM-q&qsDioeq|@9v_hlM$e#Lm84w*>@-UAewnr6V znL>BsY+Q7#cF48c_5zGPdOG%TK!Uy?Z?`$e_EC$PL9F}M412DQ&8AgnVTKMYRD~7uGHKVWsK1FqLHD=mJa?dll7ZXT5$<$@yWl1$<53|w~#)+L%l_=pwy-gP3wK6Qvts)Xr(g5#uFjG65n5ezoo7Uw$TlmXe(*$ zjsRsqn!gcR*wjP|<=3_iDBNo$k0zX8Cv``5W<+-d2+LOu)5W+B6@XudDC}1r()_c% z&irk5-*((pEZh#!G;i~D!I6N=l}Ql_P8!K~yV@o9divTn zM1y@TyHQ>U5%^Ep&%ZINw4&RxgKVXc$guHvW^Fu$Gjcok(Eb>T802yp*v}+;6~mHf zaRasUMWmT&9DmWCHFNTLzqBvt0uKs^9(RqPdSu|$gw9`hr)W`rOb@IB=R7xClAvXG zY<>84Fg_unczQUMemoPapWda!42|I4*-;!jMpCFau>SEDd}};E`{q|>3eTPE8gDga zxuYn$sH_g7w?LX>s%y?R!UZ$-d9Gz`_$AtbeX8pfg&Rs54tvQkchwS2!H%`oRv7t| zheu--Bvj(|Yed#6iP6y~#FO2~h7P}jOFxnT!0jSBJbr1NFwbPMe?-m7e^Dh5GX}uS zlT;jbvse-5ShIHxd;^8;(%<Sny1~73%L!^7(>Rhwi|_4 zOYj+}41lHVJc}u7b2oD=8f}5kfx2S@k_*cWp7gU=Mp2fF!KwrUj>uif;V4CtI-)B{ z2(N2|B*gSy6*se11=(?m(+1TDCzZRr7eZ2Q^<^0ucZAo0?ef4&O`>Mkb>MLBRrht^ zysN3Hbq_LJhs%|Q>s?ltMSk7|a9{hHrb-Wes(Lmt)Vt)YJ13=e74ujiJuP4=qA{0q ztyH#S0{x0f^ks*-il?&C!PLgQtIb*+G_{jJdz7s#+*A&NaBCPq-lj`Ek zlN|PuB9s@p<18B)$39lC3Zdwq+vkLozG|1kYf(R!L~R z45m02)H3ut6-VXLw<&rmP@Hk5=9$rP((VzZc_PkpS~(fUllw&=y~JKg^XZG( z&{9KggqH@%#N{Y}Nf-`Zo#)DLSyx)cpQ1x*274VGMJFS^{(%I|)T;A$lo0-=U1|^e zvrlvz+7@iRfDj5W}l%yf@Mqa4;Qn;?yUX4 z9bi2zH*L%rw~^sj8hJlNK*#JiSaE;#Tw>PSmBtwMwwU;0o>#eWbdivgG75(T1{0s9 zSUB;I^|HfCFtDQP@8lKQSN#%6nv)ls4Y$^xwxWvoh2k_Iz7Pk!X_v--YhN=9fO>Sz z-^t+F`xqNAbo4nShM61W`&=_j>Kgkqa_>_fkIUfkrCY{P1$AxdOfQjQX4MD>_R1_K z67A3!>Xw$l8J?n1*e=~1h#iwZZw|NT;YnC%^0TG$&+D=6p7*Q%#6LpRvFi5?saH$H zUwv-l`q5q7&zJ;97RUUPzz!KOvq zw0oM})cly949voO_zSAD$779F>`6+7@7Wl9j|VKi?w`!hbBfTxf5Sj-YraI^E;j>z zg8=t|fCo%EH2Vikn1;7%wrpoR)HLVCT7e0*v+>*hS=y4e+;3@)rf=Hg4LVAM?k zJ+2<4tnsa1+(ISMne_C?8C5O1PC`dYPfOcabj)OWj1Ixgw?Z5=Ef_!hZmczTDHn4| zxnN9D_^upS7QvALs~yP_BqQ@xifheA+ZMtpH+!yWo6VZ!PvbMvTKGuIUx#5n041~Y zTuz;VxFv;g5OKFN^xlWJ$5dRkMICd{Fvm=*Q*>3BGY7tVj=`Fukop~^&A!X!E|`I~ z|4!yFiuT^=tZFW6+?r)@U1Oq^JcViZo-k><-_?iDmEa0CEU5{A-xUoEn~#@EaOvvr z0$3#Ua1B+dp=@j?B$cFH-drE;3fr>;X5|0P1jpX=`Wo+w25qqws$6P(hfKNNo#bYGImQ!U2Zl)n(v@`V@-Ck+)9>c6(96 zcz=saaN5PlPFq3iqzl^nn?&x6lnCgTtQLhPfUIL?9?3*hJ63Y&g&*VSlI&5pkEXXQCQQ!geDXA4&y(okH(}+iaoh=DrV>pi0_xry3_N^rEa3b zJ*NuhUDD%=Wjcp;2JD5y4mbyKxOeyx3x@B`fGuAGQtYI+nnN?vXZullZLTAH)Y@Tj zwM1=(j9mvSq3Tptv3SxsvnE-+aCrhVW@A+wbd@g?XsKfmyRXDvU4gnHaR&BQ*ot&M zE0A4OtXvBgTP}b0llZ=4gMP ze}2AqOPF3x!zrGc_ZqCg1w}`mB+~yaZiliTeGDxs=x#mwO0ugXL^;1{vRF#E#n#^_ z**YT4WlteJMmky+{%ce>L_XUt*ztCCwi^Pl)>C4oFMq>Vg%2M#!cqGa(wJ?z>yeTP zjE7;!g+{)y4Ws1{Q|U$_X3OhcXEpQCz^n|ydvQDO;3-$@dR^tvxyC9aA-|J|T71hp zCCxJeu0-`xDXH4ZsTN6Zs3v;GA`df0y(;#_CX#QO#HCh8t0+VyfW=v}C6@28{6vPs zP*#P>^OAxp^JulEN8vMOzXR+<2)dz0abaI}$;`f{*RB|||8yjA0o4+HU?xW25GHEb-J+lBVi0A$uN&e9knN+js%I5Vn(F8AQKOU~P`VlV@*S zgPI5#l*8XN(0_sBG`@}FTHgcbSu`PWoGFTew)r9}+gpgRx_cqR>&Hdr&oZLcX?6dS z3yHFlUuwE;ry60@HoT>V^e=PH?k=hr_x$ky!Vv*j?;xgMc~xcZuVeqK4jd-^CJ3Uk zYE3^843$Itq{1m#`-;-4f5WF0rd>V3_mZSOvo4MCJ+$@mDNPo}AvK`TMI>>Qi=8I@ zQmYFTR4SqZ8VA>2>P^WdWq&-JotVpzI6CW-*FXbp6mk{LpDBd0ov*Vcc<|VN_sVPrV+_8cRQ_rw~)XQvmiZ2V@REW(HUgkqBXd8hb&eOUSLD(DXO{59z5w+ zFwzR^Fdtw~Cc27E3ziQQ!h&RVR@OB){dSagA`JH~(uTChh@K*TS}hvCmQ)4oiOzCi z^ee!J#h&@*5vhA{;g|@RL2r8);iP9JB->A!lZk^amUYEN=pF(gc5m(uHXO{V`1DgC ztcfz7W*4&OdG2wjXF>wOq0G z^`Y^^cknQf^m?YG4u+b=S}7i^gNt&ndJ)p38e~^=({RH2hO~D>-}wUqp9+IQTYc)h zpKW!kBjNtPT0YebckunD3h5cHUL;(B)Lw3p_af{HvC#AbyDa)*s%pxdU6wtnH2ZS# z#H%@!OQZ?={2qlpC;{eaf9D+4dRg| z=eFhpwN3rJ7PL{ci~+U@)mzE?zJda)4tcl!!9|O9(RhT*8>E#zgU_FzP%ZlH@T*NG zF*n^y%|dWGgI<~O{$q?!(BqC29S;?vd3wvf>GyY2xH_zsO40C2v zh_aszCsx5&6_c9Ec``bSC@fqtuB*~3%cU|^d*RAvEeen@Z(gs^-(AI5sYbu7rE`aA zCX{tPqL?uB7A3WV>v*$mc8|%e0TP$k0E${}cAD&AqZ9f-J$B07w7D)A<-$?LvHPFS z{~Bho^*=f7J`ZnRF@;pr9#=ao1mi?bw>}mR%8Sk9X!Z-|kxY>-M2wpQ=9E=bM`Fyu zZ!O5khPiU>aNDrj7xZntfTIsfbeh<(#*hKC?08+=huv;tgJ9{}s)0Ivd=O47q}Q~} zO(o1%#o8;Y1@VLt=hRX0!pJVU@9;5cB3NGEh~PZWZvn~k_<;#qH7})4cbgDjY^y6t zR>D`wT*sTQeerd-o5e-3|qZNHxGWE=eHun(Hj?H>(O}#Jq(fm z4*s&}B!OcEDzFB0CFn?P(!0adDXx5r2YCXJ7t4$`fpj(Yt3=rK-93u(%PNpG zdeV}iHwEB8i7k1<>K1;v9^QTr-w;bybk3R7Cn(ldOs7d?i)BRrCY^K$gO0kY*N4Lg z&%ucF8GbRXR{hoet%o-lb0c{T(CZLAc*^tSDHv-)aOCHO33N*KK%VntB}c0djR(t? z-Al@UYgE-Onx6rsbyb+TG+7qCq?iEFXO; zmgcHr2@Ok1iZx_ni~M^6>)x6s#tThLT0(o6r1-d7b%38;pt6BJXzYWhR1pER4k zdz-#XQQ0fw;|Y5fE@GPK3_H(iG!9*d5bF#?HA9i~40fgNst;TvmHX`ZCFpuKhtuI; z)tR$CD`iOeVArg?r>-IFdu2yaibZD;^!@+ZW=X5Su~*+eQBQYJPlbq9oiMlNo4k36-w(UZ{rYo z06G&%kt_*O^~C6B=qCEZJjZItf$e{helV%LIm9_*CQ1HVY)<+5Y4`TRa7a}N1tk;> zt~Di1c(K8G)=R*oc9HX5O8pn7&7OZ8dp92@T1<7mG5z=q!QUjlR=jQ4``r;W)bCk& zQ0fchc#Hi)CftMJu@lA)$ z6OdK-EYeZ0mYpHIcEaRYz~RbN4gIJV-z(8!gxhF1RSPB(>vI=eMqo{i>{QnRuGBCr@@l$?11wwjuS>3IIvU40)icH8!~9Wo z_3lCnbQrJDmGuiYi@0J4J?W5H>mZ8?tMDr@xeKQH_qz%DYK}^obO~G-kk>ent}5;9 zJBzL9?spA%+hJ-mNi^;|ngDH0rYG668}A-r_xtcmT5CE5Li^F$@%RUv_b0I7{^JF} z|NZypT%2wA8y+Np$6}L5s4t`%jMueVlW{p)dWg!RV`BqO)h{>(0K9Ce;khHL9aMq7Pf5+;;UPv)#XPH1 z!=IG`4%yVZzWtJ2zb3|-0$lpodIBaF3$YrE0h1P+e`tyggD!v;k{eE`tDjn_g)Zz> zHIcJ^LJx3VJ%QJXjp|mD>}qxWPRh05d#IEe#6{KSL%9je$RTADdn_b)T`WpH`%fM< zQ}rGi3BI3>rB7-nPP`U{0*_}X89Fr=D4xcCKyT?q0}(E@?`T)RAN5B!ONP~`N^rLC z^J$p)9}#s;Yl%xW{y5&$bIV3Zg4Gfl-9; z>N7hU511#b^K%fLvf!`Ys#QNVDY+FX^V*=O(h;*Rf5!m6$ZEbaGy{HK0CECN9g#{M z?F&i1szx^6j9JeZDOFkdFfQ826WEjNO036! zuF$HlpWa_*TzAnUsXl4X|~*#zoYp&%@{5_iqlz_Rgnc`-(@r`+4N9n2>)<1pdU;{0%E=u`L6CX;%tFcJ>+VO1INp zY`-jFuo0M6B){$8`}~%gK^lWC_X?k!Ng^LZH_pvY_%A_LKbtfph0U3e)ixr%VVx!R zQLBa8CZa>ShU8imc$G9bQi}yk(9TlbD}6>x+UVMEg(9m$5Ac}dFa5g+#OlytG1@pd<$+CD}W^PTjd@37JR?ijBCiS=VnfDD9Lfb05b5!$^FwQY{i^FzX z_bva&_&-D|J;q``xUpRFdHI%gM7JQT*PD*vNy3xD!lnBS%90zK5kH#(w9l(nqn$-y zsj*|Y1maqaLQ}h(GSn?@%ybdeSo%dGsA_+sShDE)yJQ;4)YeZVs`M_bvsWM`y+)` z*y-*9x_{&EpKlJpb_=}q?{ls=4b+oBuGZ*~vemWR{>9k-YUe=KFa3Vns~OG^n_aCB z_<1N}ux&7g->2d8^WIi9VB1aKS~Xv5cDs*W0!NB-ZQd^ZmEl8VjhPuSZsqp{Wo3k9$x5SfY(8Jq-&;mzT8$JnGpwl4#|eonvzqxQM&SN@7H?i3b6L+U zbJ+BlNpsC3=ITq)D@I<&Mq`N*Vjn^9aFL@`^y@9`0)S{OrEg1bW0(!fdJXD1DtI?1 zr^qeKf@s4xw&f5^QKTCgLZpF%Jm5O|dYkHA8QSA7fsZyWt=ke`RssfDFL{wV48MAd zP@Msdm9ZO(uYApvxwz(T!Eoy`RPTy2(zud~^;Nno3*|XB@W2jw>C!)1Z`K%ozs2w* z&-aI}cIcXj$Rw06_|!!fl3k-1I_4-&-Wf08`;Jroum0brjzPmXgv@Of#lXp-5pFfz zg)y<>34IehAk5MQ&KciK2d_m;4=srLrw1jV72JogD2ohhm{NGfyvjkpqo$D|(HCFw z0jmGPE1!%17)%j;VJLLG4hmA`ZOZlBje^0~-M$th1KRlj03ZNKL_t)1)mi@JrQT&@ zuAg+4;^Yb@Tui}^yFJmjM=Mfzkn(K9NE$a?EPch_TcojaE98frT^;ktwIkIIS=y0o z;p-Fbzwrj1nhY7m(OAEIWg+uPQ+7>sN5?*d){!)(^H-aXBxH+9tVo|P5huyJJm8rlZ;#;_^Y6%*EiaJ?fF3Eu z>Y-RoPf>*92l;%49<~XNoHGlK!5mGZv&({Rt^Fsqy`nnKQPhg@s50Dh4E9S`M?yc2 z9uKt!(uVGPeyN-F&OnrGugjLT{q!;eS1Fls;K znrU}f*YP>kAh}D<^G9QPP()sRKvs1Y`yA9~G&ku5S6H+$i7X|1stQ8ztt(;iao3B} zN1tp>Fa^5#Vt2c2miPKrw%)l=$jq4G!N%X%D=Gq`1&{4KX!C8>wF$2m$J`Gmo~Ncw zzI*E`dOP_wDUFiX*mMyp=1-II&{Lyy3ZL-M_=F?UV>(SuxMgi5v`*pBQ`einW3Y&( znDl&-mL;8no0#fJdy6ALQ&KjM{|fxe{83ZUF`MHO(zn5{p>k_bg<0G?7{_6PJB#6P z@qpDH6=1HNZ5B`8@JZNp2Ud%;_=3Z)1ua9XgeMpwS^dK7WNeW8#{X{GraDD#G*;YJ ztaf?e;*jKpGA@@NiNz1X@8kal;Rlw-ahcxAKt4Y+4FSiihf%u5tdG(D3jX=`-R)Gd z^?CO)h5Ma@@11*JXQ=Tp60M%cjqf~5X(1{YGJX=g^BaZpYsXR1j^EjqytC8|mP0A< ztoHK?Ip!P2**qqi$4 zGm5EsjP-CY=^SAL9#z0tuTweULWSkb^x2vP`*R<>GwlHtTj!psgMII>{5Y-W{?NM2V|i0M!A}vZ z`I7lH{Na-RE39N1N?5!gYx7mTpTCxZP?QSFqmkA%G}Pd?W>hX_7Y6v+wVBKMMxT3o zOuMd0z{X@YQU=Ne^SafqLK&f}u<)W^S6^~neF5y_?@l?!o=WCQ6LX(Sm6by7@%_sl z_)9KrFC6!jibcx8Q zj{tioo@ttg2G#HLDcK}gT-z2{fGv%ec~|G~$M=~z>0{F~LYB@o8m@7f9#j#BH%`KC z1P)X1Cm_Z7-Cevt0myhEOKc6+!T9|k8SH>*)X$p3<=RM;Nd>D$d0oT)>(#jqcUw%V zjTL{xQ#r=|G$z3qe0SIh)jenfH7>Ws@1I=u?^ABN*A5~e)m|~MbDizWCjMP+*KixJ zc}c+_AdkNd541h(8gf!Uff+udtv7sVX6v<+p-n4`M=031;+luW6;~t1WX}>FU=*sF zXEepy2L`nCn-VSP=*3zXxZSmI5n%aYSaabxY~tN^z8xAFQVfskFUmV|ejTRfcTmd* zv#oq;(yWX2K}}|sS%I^DX=<+rrgS2U+)6J4ERHhPxfUFK`f{C?^d`2(=H$j(QI>Wj z9VmlWada4}xuh?ui5n!ZtRnB?5_b=i#>)W_D~oX^qjeD0@%L<^ti_jN(Z)glg;)D( z^rU-_7DUf~x)jEQUd+H|cfYjV#HM zMM%-7aHt0^5|)+9tGUf~o=e|kZOClQhjm$36a;do{X<<5tkg-isr{A5jt8A|QRbRF z_b8DaV@j~QE_BXgRF9(_rX;y-ksD)C7P=4ARRuJDF@HCzj>aq#EYLYKW@E-296Lq7 z`F+;auV!9F7*-Z_rFf_wEfFha528L{WttllQC!8YTmuuN_ISTZXpP^JcsU2jb{m`y zq7XZ;tqvNwb6oXq&74ZG10lSpTS4h(*LO7IFR5!=MTw6AQ#Fp%O`~`suP2?z+uF#_ zQcm&+Vr>teTB2>YZP#V^hQb#UtZi%hpCm~aKzz>Cepu3Qri5qQD_x7n0V8B)@zw9* zavf6B3|2Da4ewF((B`OY+ehJ@4J$r4_I9}ELxy7WB7La!mCq!sZ7WC`M7gYaj=>=h zLkq@QhID+OJf|p?Ge&wcDf8)TP~o(H+1DUjWW{>@juZ34`ZS$RLo+Fh`RHqqD~l-y z`UZ8Up``jxi}UBqXsv%8NLccxc} zUeH=!7a(5aQS6j+#f#8-7+|ISeIOE`>sV=Tabf{W^m~I#pFMF`gEby4QS~ojFw|K; zk3B@56oh742f~Xg`Fy>e19N*?g0(RCYAR^hknZ2kN5cy&OW=Uq`j zXZsPb_51tCIv3@h`F2ek@Hs5OOynp>@I^0!WI^ZWyJP6{R|u-Kzety}qR;A@@T>C9 z8yw9G65^5Cudrksmc~rxbC2&>XaNA{7vUPPGWD4@Id%lwG1>;rDDOd&qb9=zH*GPL zBeNxYDxJwL+xgd1CwmX@x7r*v{>Gm1DzQ}j<1<7EFFB6Ph^lmwi}ekHnHcBeCdecp zp8`<+g3XT@mVljmX8MhGIG70dj#HU)6Yl&ixo}w??OU@>+8@{gQ?F&(NIX>Cf}8T` z>4)I#zH=EIn_=v>59pf-0g#mZ1k`h{wLenL7SBsux4-{R88)L)R(^Dg$P^F!J9BqD ztGoE@!;3}jdq!b>`GqOP^jW6Vy3nIkAjldVhzBU3$vF?CIkPi+*d+0;lLoGrHl`K`idS62oXGhZMfUDDRn2wJr(UW_F2gUMu%4v`RTalULu3CME zw&Z9!HADXNDm=>xTnP16@;x<`$Wx2S-P<^m`r|2r!2jXvS{Rc>VxT;a0xn{Kp8x-k z9-GM|S!l2Qt|}sWtumWr9+o#n{v5ST_>1C9iP3SVya5?z$gPzc^Gc|H=Nkt{S*1ap zuZZcmn&M^@s+1UwTbP=9g}e%o$?{PNmTwzzZQI+3BfCwF!Us^-!zKs*5U4LjvNyW| z3tII_BzveLX#)V~RXaXed0nu*+>!%&U*;bn;mHDwWh~?gh2x{}p+qe#-#=_E!=3|D zBuf=69kR@gg9aVRK{ee07GLQ`$zldDfV+WoNg=qVND12Ch{SVnx|(b}Tug$i7=olN zhbAzrEZeyxS^sW419Iy238hTNT6L=dYi`$ zsy0B`&k~Bx9A7PFdJFwEQcjlB*A}zDIv8ef%~+m{gBMfGsLfz(!^zQ&7}dL~^uE~e zp;6@XwW=*Bb-a3TZsQDT*DD?SrAXC6nmlML4ONLxy^xoj7}@OF``+@@dH42mw8hyB z=sty(P(S3Kh|jFqwdg(e%~s}{U01wyp%PXJDr?YXz+qEqo;Qp}qLA-rmd|n6V#Ryp zTwlD+*Y?d5l`5rzA*gu^H5Q=glm9VL;_I3n!d@&GBzN6>ge6A-bKtg8s|T-&mHKRs z8?G@@gbKsTjJjV6Kds?!l))MZJwgQ>&72FeROmbx6>b4|LntJ*MtwM4${rpF)sD)d z@qG-WV(F1n(RU8b;-P3#hnE+uKVq{w+=KGBD-Pq5sZz&0{Fcl({5c99tTC;&WS#qW zm|a=KZh-YPDR)o)=;&crollPSUM)m2IIlQEo^KE}F@;+j_skGHXGL5k)iTT~=@}&O zi~>31SH5BfbLv{T@y#80BAa%DUXg<0uF*Wbupx)4*0`D3um>yLePdc7>RTB0z0Te8 zM@ma|@#`AF+a59aH7)Q;B29MSfPEcIzyyE+vWYPasA7$UrEXYeO6gKw?KhiV*qu5` zsc#v`F#RPx;!&H7w<=c>2tK!n<~Vew-JTNg+spxPe^Cg}MG#W5fo=*OlO^~DzmC$W z@^4U{I5_b@rO6x7%pGLjDf`eBy;v*QvG&TaDmc;3f39zV3o+n#W((2xvaBPJX6I%$ z10{Eztc?S06|bib6)6ctAkpaVk}u7-e!ZP-L>$}=c(KCNY0d7OhJ8PL!TBj1Y7~q& zts{%}EnCeB@1db>JM95}{e_f(8@kS+W96@N--}mlg|90Pb!>g!h-(3o!O2cj>KX`E z&XRtID)=x0+7T+^(D{lDwSp}c`rpN5JBqQ?QtTZ9UT9GEM9_={E7x8P%R6MU)tmHO z;3nLP`9`bU2Fblc(~@IgVe@<$VVZsE;IU!C-;5lsla5-eg}dP%`ZL5pzQ}P7)7362 zdtOi0@zT9^GS($mDYV2dk%HwT9XYEgMv7(d5Q^C$5VXrsiJ~QK zNBqqwD@0ceY8qWtRdIJk$gQeCqOQo$ig;c5G+9cH)lQ2Ud{egq%5$%TW~Y-_xa41LwyAjwLfy1Lo`K5@N}%%%r398AEW8vq=R-eRW=Qx{ zP^Lga1u2di1EKOjo)uTsCNw&tcH{eS%0xiJ3CP-pmZXLgdq<5-Y6!ry**~YnNzdn3 zQU%es}~9710ZfP@HS>5Jq4Fa*C!b= z8zPgEHFFl6reLrUy3iHTxx)LR9Pv(JLad3uJ&~87+x~^oeP~>(RlTJkSq4KtxnE_g zMp;n(!d63Ft=NxN`#6M@OhE=*dm%ilSd<$1hVmn^?AI(_r9v}BmeIIs2N#s7Pu5Pa zA_MzfcsB<9Q5@?!I0Wi&?5`f5Vw7WY13MBEJJ~!I_pIHOMlZT*#qlbe);>>m`#I?A zIq&@#ePaiy@?Z<TZ}-&^{UTPz}CZy0L&G= zu3F`6b>L2e|J=Gdxb2k1)waajwhL_NFNI(MpszpjfD5OLE;?BaL#&CTp+)IB6|R{l zY@{I zA+J{vtcV%;IyDp0J%HhY$l3O77MF7g_-i;rX7!+3a@neBD%u8qW*LE*)-y&1bY?lh z(OU0`*0-{(M%J}Z^)@aQbc*UYA`xjc5~QMSGuAZ1GWGNG@x9C`N!wVVHPEQ&N%;)` zp7TC)-g7B?(8kF!-t$~?upk@`rSp7M1?R+I#v?VQDdlu6pBH!M2+H8Os$3JSz*`J~ zXZ^!ZHsu8%BBHR0xr7%j(sU_oOH4KT))XH+#k>a18Sl$kF)Xs^HHp%AvhFm^HYP?L zsWez;yYQtHs-ZeS*U0S5)0N4>jzB`}or*ZoeglmErO}n-SO?!FkJWpQ9>n+b?186S zHERIF(;@f$vK)gK+dUh`v6tcQaTJ7Lx$^wo zZt_F;fgHtc=n)y6+F5`*;&N@?K1mov=Rllp1awB!26daajw6vwO3~8~@ z1&33?T&;FF0A6hNI|nYb1MqT>8+34myT{!QdRa=qT@09Mmi438n?)zU(_CZ&N2yU% z2UpXL79E+=2BV2H+mxrm7d>wZwCLz$84~&Xg1FC`|(l*^zs6 z)O4?`b5(34XJ9f_z(x7%?P$6|Ljs^?SRzP@S@6n!wmG22<1wc9N%;MdZ!Go5!zBru!w5yGVGI`Bnoy_Ey>SN<*S&PUQ9jC~9_K*a9O>(&1O(ngG4(cX0 zwapRJysmatBy+|q_iL+nQ@Zhs?pmdrhi8tm>22jVf!W#uyKzVg;c*GT+AOdNeDg&E z+xI~^?NeeM8Hb6Nv8MSOe$hHby3f*vL*GtqJ?ftGjGDft*>ph);8uM65%hc3#Mrg3 zIXaO63$%1?ukMCw)}a-%GiY0NCeBz4KvpB@s6iU4)__FSPNjcyC~UJz_YsQR#|=#j z#?}7AK+cf6YGI5{+jH`mEx}V&TCbr-(Oj8rs z)m0~FVOYrs&1=eRgbp)ge9fy;vGsdgU?!?i_XLvH>YDEwbcP#k6vbFgM$0 zB$QNcL3#0{)H9>OuGYSEeV#Q7X?6Y`QnO4LKh;RB4RmCSFl275u70!}~hmz8Y*slr1S+ zLlh1VR}+(~vGzR)V+|0zMolqyNZ?VgiQ7}RCbUutpG9}r4!r@N@&RyAM6(nEfkmnOlIEZ}b>y4N#pU-vze162b;91WjH2P%qjQ!Kk zWBLAt3&b11YQeBdoBi%G9LN zP%DanO&YA0R??L2skOAAhRMt)HJ`yUg9E=Rz%Kxpw=G1SPLz$YSrNX_=(-Tz3?ns3 z9)DzU@!GFpG6_PmM>mD=-sLOiV{h&#_4Ej-Ly_9V zp{6=c@0*bxiD1?retC|O0l)k_+?SF)UtvNUCXy&de)H}Ky%US~;3o|xb|FeCGDh=L z8X8k*6|~Ie`HmNgdfc)4<6&OsWlH3U?gDP)!ETstRkRrm<4K6`& z)adfj5P4!xrWw}BorOdz(x%t7jVa!96Y_^kWkvJb2%!Cd#! zD4LHliv^Yr4#F?<S(d6tH;Q zkaW}Mmvqhz{#uB=#*&8iW$!+2<@^S9&pnGCJGkD9xMFFXdL#X}VgqQ(4jBYjAETly zRcgsGZhIlBUg>SpgByTV;NJ#$6-K6&Dy`KZRd9FKq?rc%Y^@O|n z4CwFQX9n8TP3VkRS#skDx^c(*z3h;8@x3tkarMRS((9r_5N%GQbjQKSa^>@?R}~)E z61-PETh@jLV{JdoC}e2F;d%CXwB6TIqU3+tkuu{gIgHXRPmatGK%Xpc65$(+oiy7K zR>~Bg5)WG9C26(w;9biC5cIsj8J3w2o~kiq(Z6 z(ylIUIl3B)B^cj2E*Pd(!z4~j&7$*20_0r6Uas$#V zE?S;(k75LC5sQ8k-^%{PY}ad&9`UXGbP_V0S$GLrg2wOy^Zt~+`Pd1x-BRTto*`Vm zyQu;{<%iD{egM)s7I=6R*v$-I9PX>Y#C(dEBggrw9Wk$^b`y%a>coF0f4&^M(2m?t zX{vc^gfQLoWV$VB>zc-cMxsrNjb!nbrz2Br;*&yYud zdUVz2JK>cR*KSZ;IyP&tJ9K0=&yS7jo`)VCiH%`GN)H(_uWo$8MsiDkD&WXIbYtl5 z*)NOa5@!ekB|*ZTJm8m3>{^S0<)Xu!(m626A*MGI%qpMV?sE8l*kT&#X=JoWovHXc=TCRry# zWlSY54p9=^HUCyO8ZmSu^I;m0TzPdc){9lJnt$g*3W8QC)@+04OE-zORq$n3y>K%D zkECo6=|Vbny~Pw3tKb}N@h}%{>R$lRUc}08C~Bp|fm+SLMA;IVwfe z1*2#Qh-N<~09LrLfMmrrpFocY-BR#8D3D^jTPqt!WYE2F(uNtdLacC7*~lu!uGrw} ztGCtIGhm1atZa7XXghEjbXpz+j$9fh%|fr|ribNXL&goJWg&}cwY^6%+in2-P5AW| z23mlV9NL$)E|d0Eu;`@R4QxtiL0sK*KWE~vVf6F&xdc`(`j(QinS0%qr^9w<>Jtu2 zlZ8mv)K-{!3zG{;R9QA-9&C4scWXocmX-mF8g#AF}lcxNOTw3Y3V)2AV0P3XG z!Sq>9wjGvhSP6du8&n*9K6hEr29Z04*<!K)$&4snaTiV(=sh|Geu8_de30W|2VhFUGMSatwj za${1Ljnz8F8?<>@?6S_Oroq!Ux{9N0LGp$LgI`f%jg6aK%o22(K=UuxzfEO#W2w~W zCG_pMaou$wjc;^WwYnk6JjK5B9YceKg)pMBPDYDIOXCh z-F|Cfk;eV+o)(#Q!6__{=NZ1?%>(LN*Oknl=am9x=8w6-@e376X+UxPid+HxQHu9M zRGxeZ0`CUn2TY}-0sUf`qV7k#BDoSx(5~E~S2(H*!)3k_X5x2w)>(3h2ANu!yi?%`1@lYdS2;z{157t%X{DL_xEn@biiO!Nr>jpJoCU*nBRt zqh)}tlp$#}$IRHuC9jJU)dlQ=fAeLkM{sxv;fSlLu&A>5h(s6_NJQ2Vjw7sttK)F1 zhRm%d8P?eI-jWfw?4-|a56NAK^eG}aG=lQvfs~2j){$mm8A9@&c&l}WYhNm31r z#a>OWoIXrJh>61-JY%27dK`?N51u?}ZloiB({|xk-g-pzy?&YNmnBH1!lgRt$NfEq zLR2+*a)c+tnQw`t*2@JRu8<}r{<`MoUx#5UG;)G#cimHkw~eNQJi{?%d0Ri025sT8 zkrwR)_va@kOS|Rh;n5%7B@qLF7zw02O-`9__r9@#Z~4I(4Kz&M;uNP7oQL}wVH@^L z%n^KGjR`-n`pOfUFJ8S^z#br-NDjvA-K-Z!<9>iG|G$pbaKi-43D@R>_uw2rj&%q< zAy$S1X~{nKM&VC}bzlHZuM;KFW?MR0JEClf;Ra4t;b=2-0dXmRBB~FgUu4duN8*o6 zl$9V4L)shT`tb6~q{PGCv9!y=Y9A#F#?nN*oQJn35+%Eu{&G@voe!y}LcY0@DepPC zfM1r&WuH1ycI8nS^v|i#k^W(dqZ`OGU)HTkr76^MTZ&_A@#(RG;l?T}Dl-LF6>t?M z0mld52kUSev6lK6in*{)6w~qcTc7aUbjaN>RpzSMZAvE8;sO{;;nj`{geat{IEyo8 z(Bu_gLbcFyjCvP)QD?pimvSbsG2rJfgw9K3U@6^IcKcLM@N;|2udZ>mnGiI0R;H_e zmW!b6(bBLuwB895E*W_WhANfx~O` z@XRZ(69v=&SU{)01~a7-_u*payGLVrIYg=}&I&T3p)0A)Hmpxe^@gDWzu(h0=doaq zyZ1KUJa3zu_MbTOu>|f%r#Qbd^y+FSGyH)%q3&zNFJE3uqj>DqS++^GQp;m%)$-sq z-k6WvdFU$Gm~iE=9DLX>3p`1a_6dK|om7~x#XduwNNegez?hh;EyKp!PN|4M@nJ|6 zzHg~!PlP)*obYoXqYe1&_^yHYfJY9oPd*3R?kKd}{CIsAX(-OyZ$UT%-#HfB=eJoO zeKhrU+4gOZ=OIa=b1X*yu%FWG5>0YQs3CC6p_k{*RJ>2O%uZci4(Y9PY^<=QBM*7>xGs}=T|qM8n&6^WNs7_gGud139Zc#Y(Sz~^_`_Ucp_ z=qpex>s?-zkE1Mow}V{y&J`nRaOLHHd|iuT+Q=5O!Q&V_I6xtE|NloXBk4TGq_^E| zSWFBh*~mIak9JCNS^Qolf?hWvD{+|ipb8n;YM?B5m9Bc-$4K`|tLO}_;>(D~!pV7V zoKaBQ?j-Zw>@o?X={%^$}_uV8ZA_b@9#7N6rj*Id-;C$ghs)U_r_c zR?|)_XCEn-GJ>dn62z(D0A(Wj9kL~(lM$&QDKvMxcLO!|`|8Hyn&r_e`%&phTKhgkCLd8Ne2+?n$RlyNwt?TpR?<(;?|537#M3)jp3LNW zrj#p{je8cRNy7dkAkzuO8NgxcR$XCS0THDs@|734CE#mKnvl zb+%fq!%^&5W0j+XerNN&aqL3KbuK(xqzAUb+6}i!G__gC)tXLZy)5gT$avAfB>8mH zX)QZ>?rE`f=_N-n=9r7$f+sVE4ueNt4SS`uQQ)Ox!6ozGIO;suZuDo=ef?+lPt=2Q z`4n0IHYE=&R_U@x`o!p7{JiW66Z?JcvTqmeTZwZfR|4Xoxh3nj#?VBMZdtl1QW^wU z=HgLAmtNnZ1T1{ufSNL_)dt7V{2Z%UhDkizYG)HsS?3SL(2+$f`J3r6a1Hr4eG=0oN+cGgiT^4avZ@ zTGJr3&HVLdystBFz24w^#u6BW7@{m7>Y>)0R!PQcYvG9C*g$7BCw{*>73=ah4#LjV z{sLo{v=LrnN7l`=tUM!Hq0mHE@Y|?o;xo00$V!skveMce-4uCCIGmOiHk96qkETOR z{~JFp<)gwdG+(NLP(7jLaX47xXVPk`VF9wMp!)! z(^C8F%i*i{K3ol$EyOakR8OToKJt>*Lod8&=xGyj_Yry0g*Ovf2$s*7a~ZL6Ft465 zZgg#>(OA*dkmh10MQ1*(D8gc^QIe+q#b-*wO7BIE)xIL2 z!`ZqqU`yyD-s*DedhV*QB!-U4XeqO7GJT-%`dAMZ6GQN&K7oY}oIx`vYveq-p(?PI zxI8K@Yf_A5DU*!DYt$uqYV>4YBx$5~#e<*zqMWahEyG4}zYHF;kZTw^FdlY8>>(Xk zzLJ_NqOpcZwA5ickH5M!g0{OIn3ugkEcGD{|7YLbyO@{kD;m2>#pR=-A{&r;+#X98 z?X@h?u(3o&*cFf$3apWi@0MiB&<^Bd*?<~Id?Pu2;~00xqfELKHJdTG zQj--a9WC{8qYs&(TQ}uswHBuKSh#!T0LF$|^JNIJHh^qH(v5;4{RSysF@mnJ*nlB# zws_WOk{h>Q>jnXGQ)Ufl0VeZ(eS4o#L)t&VceU@8*y?@P5y$@iZAU?f8_#{CF=3eD z&vY#{CjFh0HdfET`u5c5hD1PKK_q~f0Nl`X%Ml$o3x?W2T@U4G$yO3l3+=1*A5{S` zhudw&ym6IYInCbW73X}qeR;N3i(oSjZ-UMZq5@5*(p#@O4 zp3zhX9C^&OXmU`*2coi&mNi-S2U)NRmuA|73;v&J!C3SR zk4=0qsO`3KDIHnkr~V9BfHG<82&W)5^;HJlp`r&J`hq(%(9{jg>0 zSw;cv8~4g`Qy)XLK^ruW*1v=>jv@{8t@m~!uET%iT9_8`y5JK>u6z~UfqY9Ix8w{? zpYdOy)Xc{O76augj}-2NX)J0J=xw8I`38gPwwXQY2IeLg)n>dG+h(nYIVp8Vl1Z&A zk8T)2znF8?cENvMf<)l15#9#2&1`gTAKI^@`0oY(0rpG!+ve27XpNlftDhWO{uFdw zQc?>`>$j(3z27CkV!-JpE0PC#ydT`ww?=oXv*eWGQC$4&`(VxB!K+1c!GIAKUUlu$ z5V|3M*^KdS(rBeTaygXB4slblSI>8+?gML-W|dmcy32BOS4p)-h2P5=d~h8WD+>j> zvtjHwdqJ@0XAyDdgvk;^uLR*^6f>kfo>zHvg@nnv;xy@~URlq}LQ)5FJNz!hFBzZm zOpRzyK&<73z9B2H4YRJWFQSW;?Bw#_>&5c3EV?4R!=Aj+6HptGGcQVVtfyTDaApg0 z)x`riy~EGKz?j1cJM{bScTLwF9;+P)cql2*hP~vg-uCDgm}Q^G~S4 zeo|2cW43+_g*k=b8|G#vyDYGZ(+dU*YL+y-4JGvZt`~y9&t_JN{@^p}*z5xBaP&E} zsiKk0fjP^3u$lE6lA8@_YLb2hRIWhb3GSs9GD+hw{7D=)kK6@=2?GF5ErvseVI*Ol zNaPj>qfcGf#qd$UF#Pg|Z*v`jg~r3+6xD%pNJ$>?soi?msIqZk!}rC3IjHXvd*h`q zeHc1IoI<+-ScjdN=pR(pGAg@NfVVk)?eC@%Q~GUI3I$ziySTo4UP*W;%Ka zga7>f`}*TM-&csN2*PdiYk>TEJ^Ww=<$b;M2MtHHdcBb=q&+LLR^!-4fB~ziUC_i_ zW;^ocK~pwc>ro~7B^mzyuKOxNYdnJXS|YF7Hs|Z6$P!GVx0orcF>l884R^`g=>3^( z*Sv`hk5mi@ht02)#nI)r^bUcsp|w|-8}RzZI3l2J>uaLvaTfI@`!%ed5A&Q;JG?eH zi1C3{4n*P_OnA+Lny@3O9rzenc)x zzgq2rCZRlfx!hAPgS9~1bD=F^#47fv47*%YT(#fOZ8p?L4cRq1CVZ~Usk#l>J!qQV zXXShFdf}e4pk3SCg^Y0TdN)kgNVu<0cp8e{0oAB85`zxW7!fzQob<5RcmH^Agr$p_ z9E=Z$cjBx!iPt%oi)7+x7suQBx~Ry_zIdGtTvZ*E=~-CEvGN-S!Kda>HUR>(e@C`i zV=nC_huHXXBn<$bNRCbPe8Tv-rEYL5ToV35^gQ8G7U`6~giY-F2)kWyNmSEex06DJ zh&d06hn;dNXsyqn{d`%iHSCnqgEQ~1?uoyaSIC&a`Evpad?`N<#+5K4J;m~ zo9~YS(p(2(APv%sC%TFK-nh`TFrH%DmBr#Ip5=9}GZjmLzvdZqH2orGou*2H_X zy>MNLuN#9&aJCW8AXhNxt4+Ewh{jD*TX`9mn~t`9BJ|D*yfX$*MwsVpO~UnkyL*;O zYl;-!rAnrD70DufwC#D%b`m}YI~nl@E@`7q0@)bh1R zhw-7}2kTMYz%r1UPsP#tAZxMtnJ((VHp(cI3;Plt_YOhN;V32pGp?!8=T%2Ttb5s0 zbKPZ7aY@tD7^9ldh?tBE0%Ccas=A^~Ia6HjCOYns(vFEX<87dLzo*zLuS>E5!>bp7 zn@!4crGpUXCHDRC^Gqj6<9S;$cMEnB;`9=pk8ZnOEgF#d}vIVmf%^2qiG&xL$caJ za^RDC8emHgj`JcP!1_!4S=b+hN*$F$@X z@Lo!t(z%9YavDC=V#_f6Qm$C`Gv~6q97%mklp~+KPO79z#j;oucN_J)r0soy)RqC} zfdbeHcqx*zv=oaFbrQpdN25qGcV76s-Q1v8^TE~xeLLJ5ucxB;W zdlL%>&eUy51ig}v)@mkS1#^wA=4!4D&wUJ~-7)!GdKyJ)SKT$Q z8bXh&JAgwhZJmWWIL!xtRXr5+FgKR8OsqjC(u0=6%BME9?q(uxb5p3Vy|9|Ldx~jT+z&U3V^EPV;rRuJS z1xefL^nt1EL$hIT89v9N(W95nQPg9pPZR+$R;e;%>By9(NG?A6Dzjrm?6d{nsa^?A zCR(XRnUXfYsFRSDDrHl-h)dhuXO7r#nVDjsU4Q*G`huZPb4#yF%_1T*>{2gO8+pdY zGg=ye%sg;7lidb$XX!5-WRLy1+VRYOIHU+_UW=FQ>fHAHbGAp-vDQ^W=xfB4D!bIK z`#D?r+wrXEO6`F!rqb`*VETtU>)pTgjqri_9L1#1l|VdK?+~6LfnIB^Q3z}w$jHI! zoOtyb!@7RjW9PSt^H^c;6XFcR)9Lh)6+QiKU7F%crs3%=XnJI@u?ik94$`X$xX+}g z_o?|1$}weP{7H4^5sf`AdOh_#vFWq1(WotA$FN+t{}7qZjwxI3fnT95?w~tK6u>vXC9PTa5!16q}zji?|VbLF`}Uxv_PhdzM(dmXnd1P zsZizH&uu=3wzcr>J|PHt$IX9`AsGP7P4Fe1AzI$M^Y`o*LjrvV(T(U0dWZIFk2&%g zAg*l7j@QZM>q*c)gTAB=;K+V1%`L$m`*?BI8zy1@-sJFY`p&p!MPy-k+!&FD(j-D{ z^R^FrBpt)uh6u{f6b@aGDecXnps+2d#nzM@D8PM^Y@qRyx-A3ET~TEHTbGoYymNvl$gqOzA z(NX?jn?b7&(*)6IFg#)pvXn!A52M=9#0w1GP+Kq;zYyBo?~ofGt2}zW~@=?E(X9 zgXN9M-ZKxLid{hQa+QXPK`aDV5Mha|3~2kksz_{wimE@%j0(fXPGMkeu{$I3xkp7~ z4!tu5sh$~030HA{^uxh!P&R|oK9Rm#k0RR-DRs7xY3r4;>9*;(Y{hG5a91&Ygp1nX z+7`vAPBNIj5QA+5ZJys$g5=UG?t3|8=2-aF#aNflgN^e393#2v&XOZC&x7xQ@6K>V zcyZ>R`;UB1z{-nO!7;4PMEH>6o+Al5Q{J2r9V_F$2-1*S-MlYi6 z{uFHd-ROI-rKAcmJ>S$=QkcJ0SSH6RL+ZJd<`I@AjJypyH#nZeLWPk16Z{~?WS`E! z)1v~ZQ#B9k?v|WSeRc$(-s^aF>6f;}DWl_I5mH07p)0BVU_jH}FejyNp&{ln_m$fP zm3HNv`1|XXvptlRk@^T-k^G$z{mUuzxAf4_;P@P*Xb;zPYXQu^@D*cn!{4WlHm=dR zjKdxzbRwftYhZbP&#WpudkQr9?$t%niY7hhHU~P!UB!3i%Xe`lmhF6-HzZMTP&O77 zvZ}BwF1zYRB=ZLsXrk9Xgx>F2z-~#Lh$=XC&AC^mjxG{Pf69b$=P7T52N$krZ;;k0 z>!7ChiE}2bj>UfxE=mSHWo?#YZLEtYil;s41E`y9NYeoR@2OkU^cL=Q`ZY2#yLNqF zyOQB@vyMr^YH8aQUv^%@=zi6@DxMn$K$tq8C{!=~5mw}y?Psc^Z*_hH_}mI#(H%yY z4$1v?n+#|y3N~->{;gwbEv|jGvngg8z9RM`siM$wE6V{xgEoO1L7?{hnI??J8y7b7Ej)a<^V51yq-h# zlNY}cgL!>OwJTwDZY&HJQ{uW0|K@p)&qov}zFa*0^eyW%qvqetlLKF)1^8c@7b1Kz zn6@Qu{0%f_xCRVG@&vnA>FfFOUPC#OO*tMl7+B^~W%iU^>*{`Ot#&nXf6z!2t9b6= zQy$jUQ#sCReen26?g`F*%%l{`euK-gbxT`w7ZO8bxC(~ssw)Oj-eBYB12xe`gxShq zgGp0H@I!v>?^G=x?ZbQ3tW>yyMIs=%&hz}y{}Y?wX@29t*-G?lhK6r~-}0l=?ek4i zV%CnP;{-bNUDGr?fhoq|gSso*jE8XOY1~wQ!tHO$w8UpuQsQ1N)uT;nvY zc@oge81ETZ0%iT?=>Nqc001BWNkl@^KtR()ihgE8K+zY%eIvwq&DWpKatMnJwX z>H!Eln~)3Bqpj0G#Ov0^V= z;Mn+wW~4-TJN6z~RM@F*^ba{6a*TYu`)K-jam_OYSuvtcgJ^Nv`$f2!=g@5+xsY91 zmBhU?w*a${VgH4g1iDZueQ^zyw?xlF&CvkNv-d1Cws;VMId^Uj+Ve+UVdF};zT1+_ z6|96x4uDle2#1mjpuvh4*_4!~)!v}Kh9nR_d*Sn4DE`V%ETzDW{n;@R=Ulv6@JEA# z7?DL~Q9LysduB#24*+_fI}$`-8tI?Fn_;miugdTAseSf*B{E$PKh%8staI9Ds&&s1 zSMn*vacPC>4Gv$P?a?>2L^Ebjr-(?ImY$Di0H%_t{wk<47;Mh#h#B&?ti|7{k?|GR z#^U!Y)d**+@82N_3th@c+IVSx{WQ+1vc)GOK&_mrUn8%yE5jdh9mS9!9ppe!M|(B0 z&*=YV_DT}SbARi_l?NSFrDSOJ2OIdJcfszu=-U8@tqcpZ zCo4iW_P5oF#p7x?T*?acATzEGyC*u9{+}jm_8z|}^u|-(?dE2M(>w9}bQ7PF)pxk{ zlsC(h)f@d8gDR&}9y;%Y_|Mqd^h;mF^!}{g&*oI?p$2I_4M`>^t#QpsP2LNR3k(JQ zCAhAHRMb+X8|koVzff4+yQXJ6*6E}XolmPf-Q5ZB{x4qRvelyD^Hwe8ssHqo_dp^sai-1Rju^;mtSY!c~$F>{K~ zG#!v>f;Y^TF{VZahoxL8`kL9sUG@x{jq*ph1GbTLxlE?8vI?YsJX-RH*&KpkHVRt& z##xEaXR4TGHgfBae_g15wpp~DY#+V8-U=+tK7^0Aqv}6D4(s<&Gjr_BO)!v-<7-)u zEZU>r;@%l(!@~CBs^~X>x3uC(fiv zj~6!|35&JGU0BqhEXoDIU4i`WiH{!&L>D}J0hs=RY$l;Faj?bXVXOW|l`Pp8$O~uO zQlCmFVKmT}+wZh*KdgVX* zI~cK2qZ$4sSMe(XuAs!S7RTq)k6Y}z2-|pg`qjf*h5PU8I+SmC6@${PlmUHU?gp3h z3Ynzh$_g$U3lfnwDF)0*Ger3YycWVy7d9mkb*scU{o{I3@|8_MIpL{daPw&>NXj(< zSaY6!&!#wiW4|6c;1*g-P=R6SC=`B=pnx+8>Vf_8$e&U!w2O4MdQ{Efrsr49x z^~=opt)glAed#>}QHIcYCW6i)z5Qiat5)(n%Mef#$-xq~RK7;6%jjen<7+#;nWn|Y z+#R@2R^i-lyYc5Oo1NyvZadfAL9!Bxci7zE0XHPy`bW=Zx54xnUk4;X_e1o%wr-K6h#|D4 zWvPw=)yK%DEcfY${euR>B~;o40BRxO_o{JkW_R&xzj zlXAKJ=fD5CCn~LNZ)qNKb-%PyatudfMCVOg<>nN&b)mGT%Z)*vEqjMx0}hmGZ8+0( z-#n`xyuWpT-4$CZC%Vg^hF(w(47IXCv6zM>Vq6gf-2ssbtd>ik?0&UMR2WaP#fq3j z)j@Rm@FdUKXC-{*0kY4hp;FZUi)-$nL4_;QjEwzmHZ8Bp{&k`o*&d3Yc5AP~wVqB} z+03AZ;9&}lY3aiiUS1D8WM{qJDjF!bdbxWxiV#&25i8orvdEj>87xcuc0US ztgZY1__`Lww2dIBLpm981dszx^Z!3uc4ua9Pj>6HHs+leGn(CbsIw4DdOE&ciLO-V z#eUwgSU4r05zI#FKw41_;xa3|U3(Ii2F|Xx0)a9>&%@2dVHE2|=%GoZ7G*vIL5i}V zx1sB{rohI^=!$9V-Tm(E`JtNOfY0B#az|2}{n4$#gQS`D!si6ExxkQ@1dsj}EPbHc z$0U(au3i6Q|GP1<$|Fqdu*N8=6;b*6ec3oOW<4_y7auE;R?QhphSPm>e(VGoL+o7{ z-hR#-hBtw{y~X&=-yr>_t_H>aGIBV!ov?|f?7tlk0dRg_jWE47yYyt(YNuRACERUS ze7zd<@?O#>;A~A$&GGY2arC}NCxe$KT~S$F9KsR9v7=VcQxJU!?U>?AWW_Yy5CaYK z>rMh(d{FJAxn8F~h{3YGuaBYs{DTH0fvbPH5^D_s;WvtwKrJJq27P6*Nu~kW@d+rD|mhZv#cX0e~9|e{bCQI+mj+soZjM zM@f_CmN_uWh7Tj^s7tCp65&umw~W2rt0dHx)Vc_^mlEW-+B9aN)_LU_?k=iPwN%Gx zd6rzawWnX^F6`V_qEPEvmnAKU0oZVNuz+S0*`R*W2GUDIhA-z%_FlT5g7IF0WKj#v z!7<_X*F!x=^aDkt)kEoysI0w2goMI2kedkT_S7dyn|&inNPh&gW!MEvBEB5Yp3gCV zImx7+A(3`P^IxS$4sA-WzUS?D?&#X{Gr+E&(Gdu+&dJbzt!N+q>W2e~`34jI3r!ck zQmd`yu%66Ag9047;NSA0;@?ML?nV7pJ-RF=&2!h9b6$Z8OAMW{w%xJ8#a16gc$HS2 zUa?j3z13v`#n->&PFQQ8BN&@sFkt|IDRH56mX>x?a>UX@oUlg3OuBR3F&1hZL)XCG zdLH8`r$HTE53}9r+*ib*bRP0FvcP#7Hp0`81wBbKokUk@7(r`u_~e0S|HS__|a`~T|aGS zzJJOXZdVIiseo@-&-V9A%V_St`dRks+U;eun@stH?}(x&fG(Z?@ z+L01@7P)Pz9#kAOD~wXsCC1lIRB=yb9F2>&-sJEBmu?zD$F#P4kCJH!l)F@!fHA!8 zSez+v8*7o)z7pzwg0RDh}Vq zJ&Mn*o!XX|TaWt<2(Wuvwp@b6c zeJHylefpH-%DqJ@4T#8M>7aXBm4i9wvD$f(1AnRQo+9Tw?oBh^zZv!7dStPK*OwmQ zr$RJ7g}#qxE(%WJ*1a(C8Bvli6)?qpCq?#)l?!@KXl%goz+c{mM;y|M{rzHurL<<2 z{q^jF0XVUKU6`S1yX0SwaENsj?zXbQ55!Vo4B)u$H z_~LyR{$HO%`~MBgMaSU^00tH2JlPKi7i2yNTDcNlXg>X+hoBb((`!@zV;ntLbBFB7 z97HvO?2u%cOhf0SY5o}4atG}cIGLnZA5MfnWGfy)KU3<_>-4h{E8?m7*5(&9Oe(3nwM83U2m z=g|7j@%FceL*F|W)-?E@e7yI7V^Lfpb)a(VzHW79v`ZVL(Y#Jv=CrMiP>-?>U|jkbg5E83U(gju1? zkuptYtPSp~KeQai0r1g|7$6*yY4k9Nr(=(tRo0!L#~k6QLH*;Ck(7_f0gHp0)V(lA z>S!vhoO|MP-|nZ6S>+$l$FH*a@+_7dS)-A?tJejRdVf1#eW6&ooTo$G>Dsfz{US;jgP$!SsXRQczk=f-gI>Sma##C`*GIh z_}o{)=j35Jj=%pu`YS~?#|Yu<@+*#;x1|R8#lbYc!OtgXF%}19>5BrSZ(#dtRQIg& zVtu?|qZ}$~Dz_k?wl@u1W!N&q$?yA9vlHtAwrfhx_aCV^?JNMVgREgOtrWXM@I`5F z-B-t`o*ga=&-LkPx}5WL+U%_PW{rlXU7AlZoZi8f>z;D7oF!io#^vI#o3g15am}CX zZNxWE?4lU!{dYC>m;tb_eqja<^mUN^Eg_aiUR?q>u_9K;^AT5Le{8WGNKy`|RaQnf zT-t7O;X3r*hU*E^yZP6<8)6GgihYZV8%S|nEI>}79D`N2-2%m0=^&fFYuRqw1yqM5 zjnaNlU;()Jg>&V+b6(;qSP%@TAD zNG=_dLk@A^pq(0ed;s0n4{7YSwk#&q1C9#N(tW+UAht9eGu#H$CCxsH{HOhZo z4&6=*cZxRMw3jbva5Z-kyLbf9pKg06djY11qY^Sv=4~ATJwZ?gABE5NN2S_b$`o4dpOKzrb#!1MhX&$EK z$(PSQ6ETIA2W_nWFb21~pY2C=y92PO?e54sgWH}QfA?;ruz?PWycl9nfgzO*sMkbR z-@{(jhUR{`7_kqzuWfg3Y+K~{jtO;Pb;C8p*c@sDx6z&GGV2CEu!l`+Gif8r_kA=k zUPOcOee&_M1wsGg{@>q>-Y_t}1D5YSPEx?=ft2(F3w}j>WnH>onc;jL&^PwKj=v_g zy0IeR-m^E_HA1Cb8GX-nN3`Jt;@Wd4tZV@TI}Y{=_tG+bk<~% zt=~k@!#+5;F$GFR|1Fg&XrJ}Q{j{}@toclUsD{J~XVKXA4rx~0zt)Jt-HO(-@)Qx@ zGvuxXCZU*xN#m)h)B!0!xh0C_93ru1Ylm&QS1-Ohw-?~Ig~^G`xplSk#K3hn-`{8{JJO^ z+FU$y-!WTr!{;k&rgQ2>X03u*VrqwTmKeQKoHL3Un7AR7e)X@sKo@3~jwjf>AIMPa4QXwJYIt9%F4 zou==F3#kn-$5KUq@Ntkm-e?-Ow3*f7vijpLIb~grY1F+cVw$oVd-@?~By}!C9M*XY zBLmp0e}Uf!m`d7;75$ckSPClxvMRG<_xh?TL`G6&pt&!I-`7#jsG&8KRiW}S7lqBJ z>)zbJ=w_qY8L&^D9ffhu?B*ir6dVb0tZ45Es44e1gJ|P^Fmpx+^Pm2P;FD*|c73Se z%U}7Nz8TE>dyd7%8Rag!GihVJv$n@Ugy}$b{4K=beUA`oAhnkgW1&1x+W-F19Qt=O z0V@RhPai+u`yYz4W;H5AvqD!x9Tvg?$i5E7M%cbwe?Vysx##OWS2++>^GcTvrn^F% zTf5(L7PR0|a%kF-TAx8z7AYj(@36Zq|K%~N+1eB67}noxPHKY@n8w^yb--T7RnT^X zCGb*Wmh7BV36glJGnPEXc9l{N->Wo`-Z*H%~@M(;7zSE^iUZZASI zbff$R>%J2MDE$SC*ycz~!mP+fhM|TQDy~cDW>?se=HSt~1Rl{<1j?T{SB8G{T{7`n zb1w9pX&St&GgBj?m?5G+dP;PffA?_BU!$M+(IY;dkw}%}uNc@I*HOh`h_relbh>#e zMncktOR!QNN6+ziX%~zEcn_*f3hU48z@oTK#Tar5`{zr@$br6Hk{;Dp0^DRwit>e1 zC%|!vIcNU!>wDsc12+4CV($k|EEf{r$_uF0#&=_Qk2V^6H{bCtTmUcUaIjJkxam-I z8%(~nj^pOTR&-Q5kC7b5o`f7YHDGg2l9X!dV;YQ0NiTK&sf&1M{+*H%`pAFt4X0d3 zJdoZg2SrcksHf;|t*z7GjV%i9u3pL_0&H8{Ef84o+%ZwEOTZ>O7-$3jm#{0*ZX?NI zeWy=JEz8fD|Nqfd5dg_*Yi5&~M3!y&h+8O-I8L~iCLcppm9_oAdQ~4mAU|So~7h*ST7=0%U8}tHyMT>>RNtv}@ zcDlUxew`!NGvzHKF>l{J%W~I%S`EN=FF5SQax1$rBv~nX!{OD619SG2R=#_#n?o9u*ki(8WN&y8QeFYW%{vIv2j3Y(eqwHc#j|h|!ZH~H zB-JO~2DhcrNSzB)E5Mf%YTA6gTw?xEc-|^!deAnx3v-Dzs`IH;xz9c)*5t?Ly>#jx za*vus(XJVKQ8#yM}<8i?hl}!%*0Mhe(W&4BDYr#dqdEvKWb6jXQc} z?tiUuKg*UbRSEM&YTPs_*17H#oSUkRp=mw@YRwlXZ!^~}rMd#Cxp<>4y@u&Pkk{Bz z6Fe#@dya$4l5P)5a2^wDB>)dY{Hr(#c30BE?Xgo`ji{$7y}-#d9!@d<5MGPvNp_|J zu+!k`EPK5r>b-B;x$o?_20qU)soSKCwu=)_Lyzc7ONsDLUguiENI|j+lNk~R-HA|G z5kWm(`{2l}KV3jw^j_!M|AJsnsJr0Fr_wOrzkV7L;4g)7d@*zq0nuN~fOcXl{6!w6 z97$D3P+!dN+TGhGPlL&9tdt!M?-?QcBhQ%RSF`eJfjo(t4G2=u2%%0Bk{GcLMsn>d$a z1SD7fY-6#|>rrdmR^GtGAQ6C61RbZDz6w~;OBhWf2fBBuG+8lvtTwoZZHWQq+wwNp zQ|r&t3vxKnbA;$CAjce$e^_dcTy9ncgFb6+E-93B1UF6a#E*#Fe9%XSdaB7iMf0EL zQumv}qN|~GrD{%zTTPSGr=g}!UZ=TQ@_v+jWmj;MBxj?}DbPUAzE)qLSR3WJ9(BSU zVBBpZ7A3sDJSt%p5$Ti*W1|&QIZ1CdnVsqMtMi-!p22eUf+4P5@ZiOT|Dt*2w6pqT zTVMR>^$hM&_Wh6=L}3$n-@^Ix?9~cpNB7gP zzPE!wT2C|910u2V$()@hW{%4GAQT@Z3F|Krn2}hZxw=t>ZTOaV--86ZPnTn8pliX^ zd&r>+xZ3M(_Mgq5Z&r-32Y6qm&{gB_Zh4+Qh`w>Ln^HY0i4{7>;NUF6Y~hF3<_GS*@Qi$ijJ`H4UV#9FgA7MKq+5PLhX7(CvRP2Xpd^ ze)5l|HzAA^^bOx?Ovwk5@Bs$`0eA#7cAYF%hZ>#^)e0-FIxc>sOe2`N&}1tY^iGEF zXlIHJCRvs+#eQ-@{H=U1&ext#I)s_Kp_Q~}fnf;k{@~~HdBj?LWm&K?p{@AnN9wE9 z%Ln_lPVUy%zxJtHqwh<*YEI|a!aLkf>aV5)xYfTk97nb-8QgwE<~w8`@HnOp2H9%n z#SKT}2a-Eqnu0!%;JSqO7ptts)qm;<@H{uwD7u-eHsHvOY^rr_ygDadrSc+2`ajjD zRn;^7{&K1>v$4UzsJ*X!vrs5F`0QRZ*A}`1lQ$4L0zMoA7W6TSd_zMrq zEtmRUFWDw}I~K{_`EU;Oj@xm$c#G`9KJ{DAMXb4mhgaR0B9sSCnz_rO$1ajuW2p7T6}{)pXgZ?2|34V!tpqw7hp8dFBsc!~l4{Q?PAASF>Z z^w2xgv4F!jT7e^`!@yN)tBlk}c748F@K=H>ap265^ZSwlN4(X=SFG?#8jZ5nSslIh z>YpzISu1j=Ot@sm4t0ovrn*Z(S2xY8>C;INyUEhyW9UswVYY>npOfoq0PL|C8wjU! z=BZ^7FkVMBH0~VK@(a?;YT(WjD@~;}aDc3+4myLjmQG@zHmsU`nNN5AU%N3gfA3TA zZ*C}hKbzXK@K1J#CIWm!m#?2NkB34rY&MJC=+m`KmcD_^Nr-X}PBRfp45O)4ymN+G zc)L%PC&eG8XZ+5+P$n0fbjmJQ@)Q~`qtv*@NuUi{JBM#W=F>OJf_4Hk_}%3D=d+ts zvnNAg*T==GYGj{vJ$?2Y->^f?!%F>nnf2Ih!Y_nZyP`{N5b*kXYBiMEEL~0|4YvA% z4&~4^F7)Wi;eh1iST${n;-fuhb-QYgZ%{>ca4T#-Fui)Rx+)_}Luj6fwy90?N;*$H z)evZ4t4S374qhX`PC|}Q7nb^XkFCT;&HwZIHXj+UhhId$!UgnlMM7e)l^`k*cb=;z z1!PlJG`UH69nH1VD8*Wh9!J@HJVbm*pyZKc2?f?N>NhJB7DvfZyB%(L7fhmspcZCD zZY*K+V#!ya$|KLtCZulbWYIHG-ul*JoVeow8B1TYGs1p!njuN7pocmW@J8_C@vng0 z@i= zf57KLiPz!-HXYXc@4ukH<;C5X!FQ%}*zB1T>6=Gkx$^3+HSYaRTI-W#sj}{(yuTD# zu|mEqjc+-VL#TVBxQkT{t;WJzA+>FqEyMUL050Ls_tb!dVe^=hp<1MLjN>&nd26Gw zVRNz7sIZQrKi=`7+f8W|g|-Rf(moi%p@-&9!S^yi5B*suv5 z?_V&H001BWNklJN-zVmyq;KGa54vK%Wv?+BSbpHa0Ga#jMetPHb{=3UaS+S{ zDmV=Gd$Ny-7{UECRlP#+iF7PR)q`_lK`;Q;F7xsQ$Iz8ngWV9mg+1T6Fll;t-Vd;% zrkJ1av1$I=EEfi2dX-20BRDs3@Wnl+aGWQzS4NFJMuidj0RNQAt0B3+^?n_L0h zc(q{qGfYPD=vA)Ad^Hu1xoI$U6o+wm^v`vit8$6_)$#iko+MT;Q0m6x4wO=Xif!KX zP9D)AkJvIyvh(JJ@ffIEbXd#eNzd&RnOSYjofq6Y>5c{2q-Aq_+Uj>g{3P@wGz542 zxid$SyuxP(Ywzm)Bgd+gJ%ibA7e;>nLqTKlMjTHj*FCTxwj=?FHJ&(!V&9zXk~V7Y zNr3goe_(K02p0kjb@aJ67(dg3WWSsRf0ahUGK&6TT-MzezdoIIF6?)M>+;@Ga(LsQ zn#$?>c5_T7LH^)Ux@1>&5wUavqd_-^ zPqZG&SPh_C5!@`u@*FD!NQI$xiOL!z}o3)Mma4V>Lek2%Pz(bhLs zq6m;I7Ih3(_GWJhqQS8;V3p5#8wyzWlKax_ohsq>&fjXc|E)W&Q;t5%*4LbUq}dPG z!F{D8K2mSpLGj>WlT|hYkg2^ae~Ae3^jPM|oRBg}wM2$XPU+ZDk6^`c53h-(5?fDD z-Kpzq<LHaQP;gSs6hdsTqO+(l0E94S0(#tE_fk@LXvXaIgj$$D^k-CJ#x! zeO+IPz*AKc<>Qq-I8I`#78IAIu$0jnyxa)y zF?7Cb(fdEXu0^|1WQhR{tf7H`#78)8R^$NPznaO!8}@z6No~*ZSb`fvNdGgk@~?!ytWcDF`Xg zZV{ec@*H{qYX;;L3XBNSDC?W$_{o4)3c_ZMtEfYoxtg^xx7;+`-25J2@YgXl6Hhn8 zV+UpaMK>#ewobrX!eR~a3e)jraM-L~X+m-~6ox}zv*+u0p zi|MK2KZZgny2))lr+}N%rE>IqN@oNw5O<%adTs6J;bgq3>u}J}Y(MGDtYSHqqH<`c za6zNgJVZ=ZaqX<7F!q@U5%5(r2WKEZ#^f0WY3SFin2|a(YQAsOE+5$4L%|q;%_OTc z7>R4a#7p@iCo7PY(&eI)a7AN`++ORD7!AFyRfe^%f!NSEjO?+RmI503eY1V70eSsZ z@+AVQq8Uy(<4jBq77DXfKq&91b%87x)6fF%)3CCjE%RzwM(@?bI{4uvbl3e+()U+v z)T4{)s4iqb3Quc$(LH6ONrQYu0dtLneuU|_(Nh141PP9$-^=K>tN3xRkO-wrkH2ET zurIf$u=04(#XC(gdZWf&;mT+pXSIJzdg1tci;AWh*aefuJogpICnu!)`9d7@g-lA! zxr`=N=Yo|~UPv{yt|a`kS=cUlnGTIy%7IR$t7gX3?lcMvWn*~Oyd4G419Clq*5+W_ zoHg>q)zW{~{rz2+!M8uh=cT!e z-iCm=9Dxg6eSCQ%un)vG_Z~Hk1NW@9siblgVC8E-FsI;hpaeMgq4lWQ`$Ah)rq|Di zi&^yGQWs_qEtI0=B`Vw2ORWc|Can56Ovrz}GxUrcPWJu&qUM*h4UfnVxl zsIZGwO^ua+!Tu?_wFrocm&ovsz@~vVu5;~jl<>RO%%^<~A&awPv=Dvv-7wk)L|%`Y zpNFtPu0B~6=gw4hOXMvLnrS{~F}|9*!L{M>Ly{+rQXXfb43eFXI$8&fG`1_C&u96= zZPP$qKL;n0&|cS2Yk=B;V7 zT{}*9-AyJH3`-HXL*+vAAye!IZeTprM|52i4Dx6s(A+ss9{)Vj8SNZBrR263Ru#hn z_*^Ebm*M1{rD+@(*gXPC?fJTRU$dptlBJfH%wjf*)IA`yTbM3>-4V_~>p^m*q$Og_ zBXt;qy^HU^>=G6S%wsz+77KaNqXH@uQ&oBC3A#-12@8CUWPh?1rm7}!eld^0`NEa( z={|r|Pm2ZU%TCF1xdxw4EY*@z`Q`c3cNW@qz?gu)fx0vp0W9zMTaMZX9@UW){$M>E zayT~8(T9zk2R~h)TV5D~W!+8|D2a{;gk)h|+;keEp)e}}8r$H*QzMTWv$1979A~9( zc+XJQK%8?3y~@@YRRPuO3$tuOIk)oU(Y-{{IJ?+c;nC76_nd%LKS+@6dycdsl)XAaDl+kp=JRtK)0MSH^YOpY4o#>o38@RY2DI0SU^cdmgnCa z>y_s0T{pizVXdnd%;J{-Yt0{!K$HgwO~{R6zC9s|c!`casVd^?=83kweXpNsQ8o6B z%5Te4zeZ1p6%!)0Oamo14S>q?6H}qy=Z1@>R;wtpq_3u6JGtI#lurw@@>pF{BN14l z5@)jqhAv{B7zU@f=Rr`c^BqbI2y2GPisZCtlM=L}hB$m>{KR0m%Kx~GmUfc>YNI() z!#<$AGpwvelK{<~K^Tm{TPvJ$Xiv%QWH{Xnm6K1^1FWhBdt%Q6#$H_c4H$u~asl%% z&g?ns@nh^i+qTf;Zu9NKcEAfYM6e?njp`yJ!q>>m>1;YW9GAMP4f{12MBdpv%blY#}QF2I+7zjoh5D+@Sg z3Z6ks%v32;Rgqa&r30R4rr_wAL^a6jWgI=dWA<&bH%^Y)D3@0p$f0kAKT&7z5n;F!sqX%d4VXr1pxkrlPJohnOpf?*T0x&H`hjQyoq*V z!(RhQyxWXP+1{N2#s>nq>;d~4$`Qez5klCVf^ z-$SuRZxI~(X3y)NW)2I0D~f@#SZsyGB#YIqnwAecFRI|b$Sp5v_70v zT@lTGBGx4sPKpY8oeFPyh2Te34B=~@>@Z~GE!L)PJyv|==L7Wf@|xFv0iV3oJp)y4 z+6++SCxDrNq8dfhVb>!}yk6Bp4NAlVwh%XSAh`D$?K~#9FQ--gWPY76-2Nd6b6P_*z2`mq@J}gPnziyR zud;_t+OsUKelyAYEGl5LYaJ*BOBR;qUI-9-L}Jm9Zi*nxXO>h9<4lhhTUPkg3`#D9 z7sBxL_%FHDAL8NQvkhC`$6tBST?4dndcEz2V})Tf4R`mkxEhIL=tdXy%-ub5>t6oQ zmj8A>16SgCaWtNgwQY|Y6y}R8LB=`6P%5_x%*0o_hU9+O$Y>QMarxVGDDDC2<>-)k zRb^!hW3>Gm{uWZX8k{`*YG#gW#r0KuPwdIpb z8J3ov#>svD*tI&ZNnbxg+MPxL+XTyNxv$tQ+ddeuZ|BG>DM)LrOmk|c-f;}GFv}Re zeBt}e1_mgmf-4Cq`%Nnn(0apO_YfF+rq%Ifuu6ngF0`g$>Ys_n2ilDfQqma%@m52z z!diF>_$vXHOuL7IE)+{S^)TAx< z>Mzm&tZJj&lYw^pm14PF@d|DUu;De}D5NCBSjoNMr+aO>bqpUuuRn zVa-~NN453F2HzdC?@G%`-T2BG_h#w48h#rm65;vza#z6lWNhQ}qzCrLWYZdI=^z$y zy_+&NqtZgeGQSX?3=$mbCw+@uxNhU5H{1@j zazKLV8org{2Dz{4T*Xr{7|~jD2$q^EggKjBIg^DZWB~$Dv)H|{@1w!PbA@_r+h!sg zKHSaBqx4{dnY28GR@KhH+x|0^V8+gLay@ZO2fI)D{8#9eULTx;GeyLcd=VRMnc2 z{Hy&FlCZjahe8|I(II5=(b$q|MR4ml?ruL}=t63PsDlQ&tM$geCSmxq7SZ*ntgz(g z#q%Qjv5kFRYUb4}XA-4YQJ&R%KJ*nA!}cK;JqA6;+R+N3Mc$WEq#D4YJ~pSc4Ln_tk-5?dWLobs!Bgg5McVg4<|@&V*M z2&iAM`*Px~BCMj`f_-Tt>>2}&mzqv_#Ma=WhIB~2MF2iH0dE*lO;-0gxylJbC@H(~W7@(yYZWX1@!e)%WHrTotYlcW`7BbIn7V60&Gv11_ ztHIS(TV3ID3@)lHjly{2BQ3>M{2UiKa}7)_mSMJ?K)3a)P|n3@RBpb3$D4d7p8T}K z0{pJKV8tcvsy3o>Xr-ifC&PSt&WtSVNJvCY5HSxaaYj-r&BFSVK#tOxqf$Xd8Y2c$ z_C7WZ?q|)5d=f=Jm$n7x$wDcI;)yt^f8ovlsa1VHKd3me`=O|5kRfWG=g|1%TB-pV z*H?88kBS(8tb~px)0SX5MGoV_VOjL{pfIShXjK;m-G9!La%EzhHjSKm`*HHTglQV3 zY6T!)uy{!6(kvrS+R-!u}hSRJx@FZ(d=44$j56x|q{iy8R zB_VZYL$Gap-Tq5PfWfMhQXUqxGMHJ0%;`c?642MiU{KTS7HHsiip>jC%ieZ(VOG}! zL3j6$Y#d45y=@`pK|dbNbPKK3KatOFQzpA6@hV&h#9eO}LnlMaLRdjhE!*xrP}4Hi zv@m;8*@k>EBEhcm9#UcvhxM!)rAC*|3gI}>Eo^IBBWKDJ4T|ckmz%rXkUdgJmCrse<&uKJqmoYM^^c0oIUtz2Jx)$$X?Ly&7O2J!6TB5|<8X;NeIA`eOsnIOwMe$ol>oxc5lm*m_Oh~!MULy1;X}l7SD`eH5F^L}!sBQ75$UT-( z+MUpakrmjgD|Je2tkH9j;&qwE7Ks(+Bc3?n_pSb9545~Tf^BrRwZ&U?{<0d2<>0ni zlj#|2V91~0**QbjOa@0^cfF{s)?cD9Qt~0tI}=nMckKy^^;&}9D*?a1{V5&L8*_-3`VteOr^VwamrZ^PcWZOOUR5I91I<=QN(#aF1HF_sP# zbmxGMB#G*TzFMy-Rzd%+o0!?Ac-+oAMj2{x2hTAfG8_; zMzb@kQGF+p3__-z9LmQSQdFTEof243P>Un+i2)XG@ zOjAp;jlGK-N9I6z+N_xO&f5CE&cG zp;ljK*zA~}F?8GLHN?|k28L|V-=7Ch&N)fLER2BGo#U<)r3S(WCDlMcUnorsVO6}@ zima3rJbpwYO{~7hG}bsmf;gW4{yo+IqFqIJ0{6abRAn`y8);(;Y_yG=4~ne{=U61F zo!xy@ubywzegC^j zCw(Q$*(TcEH8HFpabD9~(Y|1KHlCT2yH$<8w-x)hQF`4^*NE)0z<-newd?CLbT@6c;`st1U<`n9e0M+G78r^O~eY2lJ)!GM+&Z-roww9l`vyl#oxERD#FRG zME<3EWVXj=<6M9tg(|EVqdUG3z_7?QGJeSY@le6%2gAW5oFhFDyic_TV;$u%uVHY- zwN>USq5>eHP<}NwF61cL#b|&64xK$%hKD{OSo|+AAD#=N2m7rHk z)9Rj@D*xW&PU+^dFS$WSXM*&UWz?sP!kXeXy&J{^nka32=OH?`Uq=VB=NKf_WAZ6U zo-`)_(H_V;>+%p=04y7|c$hFl2WLbJ&Wv7|Y4?R*!L!m#>x8*9$}bZa?6^{$cJ;{M z`pq9MbuYroam8z=;I$2|b1*yEKD0&?pY>vE+Y8sZK3lG*)`z7rykVbv@;`>pHrLkF zCZr&2$Ob&iYvk5mYjADI zTxWrBC($L$W_EQ6G}pf5acmeZSGLB6Hdsm;wYM9v3K0U!zq~SK!k*p25(+4m#f#u? z52eQg`&>)cnSJnM$CL>5jPvLR0_$z0Y^Auy3f#?KbP+-sJ7*PJ4u;XAa?*_Y>#<@S zkh?N#r~3MC=gB)3%=bran$3`4Ph86$qE8>=Z6^Iuzom6CH_>oQ-5>rmuT$(D!+9!< z1->|AAC9wvh%a#WBXub1jj00WF&r&!QP-Q9LLm8dA<7c)&;CaUI!S_Pf$@66mf55` z6L7!9gW7H2O95?3{qSh}KWk-P@G*&ve;LBs^UiDzQ!iY?u1;Stb&l zYXw%$r=9&2CML~1kJA_$Aj&Q;Iw-B?D0?cNFdRc^03{Ecq8*@1LUuKp>35*}fb=K< zE@*^AM}Q#~)>Jq;?GNs**b58x^Lmq7tg}6x4V!MUqt-~{0C5IK%L?ZifiVa7Z~MjB z=L|p!aTV{{Cxddpw%6``G{UckSHC&vfwz+!yx&{_e+P;KSjwk?prMYo>$krO?rr<_ zj+pAHTRU1#sYxlTVe@Qm&#?+TAsT&}$w*cLA9sgL3S0(BRZu0(FC#37k)J_Pov?EwDtncv zv#pW01fS##dSFw$t;y_5-gC7T$tFBlcYGe4dnM)WW^>YQkm%|;Wb6iKtLT71D|B8z zhr^eMv(x+byJMPIuefoM;;9z7d)mQT!7~&zN5el@563XMim3oomXkQClwG97kuVp^ zIfKmN_b#4HbkUAjCjuzCKVm$p@)D1!(4m?*#L!;F00+JfFB)%YQh=sgS~JfhvZXrZ z)Raz-BfU*Desl^(U)YXl& zFC;b;%!la*wN^>QNP17$&O!`P??5m=vUpPvA!zTW~?MH9J58r4&09d&Fo&2QF#?E|qajz1V8xEx` z+6*r?#^$NsBvIW&v0croJe0s-GiRNM)=_kZK3g~0`%Df?F?U{gMj%k~yVkq}+19bz zPfZjg+4cvldH5`p+u*@RiasK4{umgT0_xR8b|;9d`aj6eWNJ!$MUQeW*{^THQMUod zGSwY0Kv?zF^II<#O;{bm-(W*if@QV%MsCOVlU-^!l_Ec>87p&4?X9h+E=YP+%lg&R zk@%T31jA~?mX|7NTmAx{!DiOVu(7aMvQ>_?>4o~sK8In39dELW{G(`#g>?4(;I&I- zckGm5Pa0*bzQQh8a%Zyv^P(WlBh_Ihx8kiu)5chai9I6+(955M zjsLd(w#ut^0-d(7v9SGm<3p#ydV1UDe!bt)iP?o&41G!|NN*{=K6d`nYWb@z`I$`*e2`MF zeihvA=sAbB6E&;5bu?WE(Ff432V3NWx{9OsoUU`k16oZ6-AdwT>whnzVd>dt>W{|` z8}HpQ0s;=embhDEOzvu>UA=0u*Hp~Ek3)oxwgQ(%0zJIhk49~R0l+?%T7X5tdj0!n zZlfBDWdF#g3<31F72s+RMmj@^2Ch3@8HigFv}?DXw+K-3 zntNgjpKo0EnjHFkvvqH9fTgYiYZwa}o#87MW&6;xA_l{K}Wf+O7+ImWO zh>TrhkjZ)SQoS|aUl%vlRc%PFBhni47pN^6iHBbbbcfzho7TEreQ&orjv&d7w;s2( zeX+1^`G{xq@pGPwr_!YuTMz5;3G)m+wHY4ji~pgSCL2a@3CA1w#?f@XlC9!{*D~`U zCozHA2y6Q(lH9&@KBhu44I0eN22Ox&5=+s5?Td}?+FA3#0rkly)Sk+LCWhHsg847$ zu_1;EoxYnayDURen>M=0Z9S#r9#kIb0M0FPi_x&6UnssdI4C&)d?@Xi6K9IAI9bL; zS3)no40glO;+I6}*T?tYNAm$+Aa-uJ``0TOZZ}}Dv0)6Lg~#6y@O`m8`28mbR$d~Q z^4)8za%bT!>_!|zUuFNj(Oe{f)%onHlXe%mnZSAx#&Hqp9aU8bW^C6Ql#f=HG`dUa zdM3YRFVWfe#ktXNEIAmOSJHe`tUBb_-@vsm(>I{Jl2v$N(&WjVz|%!M80nO%9Zb^b zDNIUArnqmuvqCmQ)u9F~oG72JwZu{(CXhn^!|;4z9G_82P3 z-6R*WEKGMWYMvHSN(bu@jYZpr2`&UX5WM&bc5r1xazX3y^i45X{&Uy#oigcJO@A9r z)1Pc^nV9c^z=4RYUKHiwDMZ!hfJt_Gl1$ZW`}~b@B`6mq@Z+APiU?6}gLg(|X`w`J z@pbeVtvB&MQirV6UdE&FxgPy6gMp+8l`CQ>s$P^KevIrHHDyYs$n3+I#d34>_+gcx_ozDd9(s&q_k9ZZF++ zDrAXOUlDw`kY49cHT0kmtlu*_ikAkXTbb)$)?d^bAd1O}yxA_tipI!=6AHfxlDS0+ z^%YO7c0-eDS?~rB_e3jj8$F*I(jt_`3Wk~_n!=Nr0UN-+O@m%bxpMsFF&m#4!^eZN zoxY#1J!(3UTmS&2m1%1jU$m#}jk#`Z|`Zt=98hO3Z z@ynDeW4fG0BVz+Omg9wGN$2ZTeZV8|w-qZG0u#M~$7KwG7M(_g@cMnzl|fpp{0;nd zY>hZ*=5Q3(LR$rc2G?it=f%5v&$1`6s&_n{BKwMHd{Q2kr3FRcbM93DSSv0XnSNH{ zJF9OMcYf(5f53^qMo0)2IKdkXcKd$|Mkfp;u!*i$Ok?uUW9jJ%)R0^hw! z$hw*Il)!qYxEfgS=%R?Gshm1Pyh0{y?7=}*NJpAZs7=~VnHT>H7 zRQl^WLlVz8Jl&A));PoP2W2s6rt=(&kFqRLQw6AYD|*FdxH8*Y)xV4U=A+V|jr3al z%Y!hikTxITo@hHVX>Mb#1mIODzWnTm*&JSi)$3VLMt$YLU8=K#^WAKf3;M^2 zXeH{JY-Lng5;R-t{`EC5rO_bBwgEP*X2hhnzkJA~E(Z4+(Uk;Lmfg4gdT;DoSKqyh zgf^-3TiB$-a{F0kPUN0i0u64!M4vnH*UUsd*=+^b|NZx(>xlW1jpW(_n0lvFb_;y` zz7ifKYK^^yPrq4hNNqDOFl8E7b3JU+D9~Cui_EFuHHVZ-eMRRkDtHl>!*j&z6}Px@ z+MeHCRs4tk)ZjhO;P3v|=uz$#)`Mzc3jp&jHHCqGvc%Z>A*NGTV$5`E<$>6y0Ev-Y z+qn;fHsk3eJJ3RbGh|CloT?P()DZzxX?cfnFs77P0`tD#Z?Q=DuZYM1wM{avs{e$o z+&5!t=>lfbc5&lcyCyvwT$dptCM18RyS1+WTKgXIl80mZRiNUUhQMi&>!#mBU`G}x zXHiy+u^lTvV*K1Q>;$J>=v7u?4SC0$jszdEs!sN)VLjTQ*M1n^j^8}X@;&jw9w{6 ziqeI}A$R$O3D25G7X@*=|GM((4-+S?pWzR6Sbrq1g6iszrCw1cO%c}HpT`7)|nFQwvF$Lt# zxedvQFag-d(};ndFA+EyJK{*tpH8040Yk8LA8i-qVMP>&0w>>GfZQz#S{^yZYedZQ zzQ+*P2fQ|)-5O1Ny)2z&b@Jl%`b&J;MfG_w6f z8M5V*>wGI{>wQeG1&R4)2pg+GTM8E6BQ95MQYr&)BxOC z>JMS>V0&FSXR430fx<&h+29wYbfobhP#XFuj5WK3h96N={pxi%pz#p@$00xAnzp|m zc|n{B>yWDiheJ?TpWBhss)yn5LJp#`h}Db;&fcZe&{Pt0KPTBl16zAzx*^(v<+@Tc zk3k4hQ;?bJqh=kqY_-A0DyryxcTtv7Qg(;ciP*OHB;dvN*MhNN6()h4y|A3WX9+{) zlH`cX%D+6!nHkZFc21zUDJ6(;f3O|n9Q=^`>4C1L2am=+0)G&#F`-U*8_PdR2-_dr zq|i%!Tn3DtO={&txB=>=;qUuz*n!`F-XX_QXqKz6uCB$x>i2fJs*$k$CL+5L3D|th z+PL-YN9VKp2xq%uBA>nbHP|9E-}!2BRs`XTXG$xdl18HI$k}mG{jWB{$6rMo;Pat( zp-1FETy_qlZ^0c&6lINK!zVCg#b9+iVYM`zQ_tYJ?_G#Mty84#UO0uO7uW(kEa4DM zNplpVpT&mfXkM7No0h;XFr3v-2jh{1{?z`f3Q1ejoh8?M=$SB<#bo*QqQV*MPzImy z?mY9yr+@Y(uWFHmu`yZRQzm72g4mx%~kp)QEBlV9q%@G?a*P8M0 z4qjcL%WP*;O8*Fx`2KLcmbfp?NP?C6BiXt9BhxvVjE1i1Xid3P{uh9<#YIc~%31 zqMv`Gy|yjpy_QUk=ix6_yl>2&!FjpnZBl5?qp=8fFVY)^BuKMv7iLi!oizZy=446X zbTk{?-o)SAZF3t_yEr>A&vGiY`y1NM7epZwnJ;9MhQOLY(*oQs-!50pqPYMzrkl`H zIULt$O^Qmx*a1fpRxFUYLGH+~f$eFe+If`nnT1Lx=5(Bd*oxNh)$Zh0Bjds6*a>@9 zRu^I!`5lB<&Z;L&r@7#DNmc{jxwXOhW59>E3&S>GMB*88QkTg6Gu8T~KxWNxR6hjT zyCXIV2&)0{E3gU;B*@3w#Y4aR*Nb#m>*1I=zZ?hUO}Z;6137cM=Xv`_u1KS?WdYcPX*VT*wIN z*kt+p#v~`wWb)7NZ;Bx!w!=zg#`kQVm_ki~X)0q%iI=R9pvd{5I%2HqPSL@{f~Jb@ z!!-o2rPjn*z=FtwQ+F@lo%PN={L+fYg|PIp)LIdgDZ{c*2!kEx)GajPV{kAZ4y8lD z;RCV!2|lHF9A%U3+GT9CE3QSk(nCir0iqv$4`H_Ou0uD`7Wy_j(MK2Coc&Ch)ebod zB$4ch4axfJRAij8pi}?hpyNb29wWT6!GlazTEuWEBY4#WgRWl~#^pQXj{+rq<02JT zQ?=tbHbNp;BJZsHkFG1xQX5-h##?)Bumd6g|D}&xlB(*OH#waNYo7eb@)B!94lwqS@N|MGZk0sn?{JH1YZRoWW=+EbOQQes} z4%%vtdtQ&9q#A1>0Jkyw>VwWV$u#(tod*FAOcgthy0IRV43Ts!%tL^|`-uyPOwTDR~U2u3aV!AvRYuvWn)~-fd z-zBVCDd!462ArZbc-?Nln|BdjqMZS@TR46{C_PB>wQ^597gxgNhR=9h zq*fxDS#abzHdyMuxU!|T35fqZefxVxIfF`tF`e!j&G(1;KS^5qpdHpB#C33%MM>iR zkO=$ra)SBwWZs4);VCDRIbScAcc{g|3zL-`El>5M-2GU(vBmC5X|&@Q^RExQDmV9Z zO3ckR8uzGZvc+)3Yh4HB)|(U~?xT&=>7FR=o8^@6d&|0Oi+G+ToYMBzOYH_4P=+e! zB0z^NJTse{EbAGLm|&_sJF&@HA&q&n^V@S8XXkmY3;q627DY4VzN6fR(0qk-lyQ5? z?F=cnBd1%{_9G>iapha5XiU}MEZF@?Fn-a2<)>VlgeNS4vpKmIV>Q+Du04lU;c(3| z7|bH!vzn@v>S=oQ8^r?xf=kZ`WL}hf9}78P^5AE0sfXz_^wb5B}qbJ z^~U|8m4S-ycc`tj5S>N04stk-;1%#9f#p^fA{XN67EWPv~6>@#Q=C)({kAJ zHVkinSG55%kR#!59&lI6o?%47t=n3+EDT{p;(FKxUGa!MhT>Z|kVIFb3kiN;RwS+3 z^7=gM?MS&3cuihk%)u$7GK@$fphuLQi)fZ3$^Hs^UoG7Cw%+AxH9TeQs~vEQCGg_i z3tcoJymyh#02-KacW8>w@^z8g_SBA zeliL~(O0|oC!4X$cm&sKys6#?rNg^s2d9F5x7ji z+yP61#ij4ti-37ku*us!etS3v=;v)4SF+4dL1T_pPhr8}58^K6N_Tfcx&ZKU_x14S zuC8daxC1uYxeUplD=pT)u^ry1msUC9x+#XzH_1NC#$D@gt~FYJ3CQ`5zq{T8E!|LgBEBK1nzh6*`}U}GB46#B zXIVo%xuZ|%{8Q8m_VN}XqiL8`wvbl4?lo@m@EbeQdA{}nRV&=owEN}anHtki{a0#q z;*32P<7pC*Z*FWh)j%c1M-baSan8m2Gv zQnG%{I3XICq!Q1fSKD{TLg|6S@h}W&poVjJ;&~h0YxeU$m}Yq+!diFI0VBJCaWT*K zZHvXQl zy*QD$PJmrbvAi_Vb7Um}&3-ZFYoMp;v=$T(4dG~O-vK|E<@-3*Y>Y0#$e4ZjfM3oG zBVOORmTuem;%^BEY^7x&4Gb2yPZMH_T*GWI~Bi6&tKP+Mv*w<2y5j)E%*!94< z8OdjuUqNMa%0*$EyvD6h#+rp`L6*>Nfi7iMLA9)FT`E6XI1XE=0}hn`v!!ICLC zD*R5!24u&=fkWYuT}f_|`u~EgEQ($l%&_tSlX0f#IYA~+SPoz?&sgOGfHmf#>&Se) zZ#>NAR4#oxEPTrYTiB59g~7% zX&q!s(*D=&!3lhaO1#X3tbr!q-x_|0TWV#{-{CeU-Op*b_t>kOtDYkbi&eqUF{fGB z6<8xMd0eBT(8XD*Yw+}EP0eNVyE@-&X_SQE(VEa{TTxVH7yDsY+JN8GOJjy&?Plls ziCPfTD7QF&>Ro|y0W3^e6<|G`E|#0fLLqmiT9x@$G0m>Hk|tS}TTfGte(aOz>+Eq_ zAX5dkGYwOtuzUUJ$;C(S^~9!_S(=~!3FKYO$iYmTCTmqKzO0Ak5dyH3IKqGCQz~tp zZbyN!or*vCsxeB70xc;z`NLRLDzS6l#M7OQEopR4EKy{|0@K(fo07EiG_(%L+#}{g zt7aUk{2SnTSjSPBTMFmCRg#D}L2oN84&L(W{$%OpVrYC814fJR;?roJFskS8DsC!=9 zl!C=5=SY3-0LPn&n+3(A_c35h?mVKBWAZ3b4*G(-l~goZHoHwF!CgLFN4I<{4%(7e zV>^PKr=KZC1l3bn(b&zZK;g8q-{pbs0wgWJ=-~w@Kb}gYdcNH01j1R?U(boIblH3G z!61=e{;}eJ-N39427s*;)&-y0hNK0wcD*zlKPkd?piSY=uOPXTI~o5dbv>|F@sUyi z9uc7lVL8e4C4xSwFImJbJnSH%%oI|`3wd*UX|#sWGGXUZxE)*fF5!wDOyG6WyldxQ z5Kebed|?J|bqmE`bUeWVHAV~FH`StZe4C%$V=5@@<9~&m7as>U5Gc9e#?Zw#-oRp)8YM>He zfLfl79n(O?JlGFwsJ^K}$)aHnej%2l04m-b$A~N}%Y(M%?cef1yDWXQpLGbM(}MZvX%w07*naRB%4=eJ}mM z-SJ;b-!2&F@@sG2^!>hFZuRf|XG53<#La9c3ho&QeP~ ziB{vv67$xM6UQ%($-vD2|L9AXq^fEIH|GqC$wGihSt>0L8^8p@Oy98aXxAAqNFQG# zK=N=GDQ(l&^huQ|MIj&FzXuh=uqb9;-R49wbBy2nnqscnl#TVlmWE>e3K`KV{kbGI zIa-807mM8W6~S8X%j53{cf#yTT3MfzBw91@v7}eC%7J|x&ja_s;-9$%o{4~?^hhNR zvww~mYn#6J&uUI1_b!R_>JC!6Q}8leCDfD{-u!hM;y)**O}7u?1*ef=P`dH2UgML! zV9cbriE7=y}UPAagpN1 z35ETC7(<=6!#f@nXGKdf0lBH8Iix*lYm25sTAqC5Z<`n{v_)zEOo8^MK4CQwzYwYA zpSmNxZb-UiyO-Tsh&8y`R+^Jf!H!a3eL9z!;o!q*wwW&lV}Y()UX> zmLj5!ingd|9-PA=9Kgtqtaw3PX%n?cF1Fd}NUz}}l5$vOyyd~#dw0DnHw&@ow(5i{ z$Gt>#h;V%PIH;4^leBgg1e;ms^~#tQboa*YU!1J&K)H}q*|OKEr`^rKSp8=G6|WjH zGCbcca-v@z))4_)hH5`OQj^5_A#aqtM>{;n3VoLv>j>wQczFa~MzgTDRV0&iJ@(J~ zD)QI|3i_Wo`0tYzc*KF*zPa8y)`%eTYK;6GB(RfR`}?R$ep(T34@d-uLz*^!BbrNKQ{*|$t=&Tozh zmu73oqjPmpK;)+MXgSsPW=B#F30j)>5{HWq~ zmb}ZY$K8+JjGdPgcA1X$5{FbTrHO17>F|mb-9$O;60v7sI;zJ z>u2zQm?vy+Ml9PO;!_>>L-zOBtC&scx!RQ|X}HlGWRfj&ByCK3X7WZIf*TTPcVuMQ zfPMd^GeLuTE0f0R$XmxV6wc#)5b=zgevO(% z?;BBawXR$guhcnn8XL@pUzp$+@7nDzIb%tv3drT;{pDBsB-koB=xS|hfhp|jE#9A*8{XMYt*u6*3;J(q8v@zm(i;7?>!&nPSy~R!E z66pJ8u!h$w?ptJE0;bB&gv#KY57FS=LDr-mm5i$N@T#Y?m8p<4u<1fwmP!&?}-RHASuX1ms} z)UJIS1#-8X2d;t7woB>Tay5h7?tEF2wW#Uwbv1OGc-@^2X|RbnHe%ZVvbM+Fw~EE0 zr*cV~?Mx1o68!U-h=z{Je!_OG;)<%G%ZZ{dh~sFhn3EDZ$AWtm;uR@e!Frg+>e*X9 zRxcm0C39FH*34>#!9uBq^G4Os?jWKjW*@MzMf=_Amc=91IhLP1rMG;07b21#WDA4p zmi!^dUs&ex8`u2bm#up|QV55|JwMn?_@1NeRRDwhfr0CiXlSwScUqIgNpt%vv+u|i zE-gai0}Qk609Qb$zkMs+`GpUwhzRRkQ$~}X#%{O0lsbNJ5d3RvWAtZ zSqg?m0RuftYc67tSE<)rAp)i$pq#wHO9I!d~QNa8-jBG9mKUZp9hq8=xi^p+*Cv$AnoG8{%wsm~(Eo zjlK3a^9GQ}b@>*C2mCuqc*G-txVFh^X&D>VJ%E3}wh(3?tnuEQyat$lITemGi!cuD z?&L))1^3E&I@EP@%+qR2g_g`wn(8n1CaEh}*K6}sfzZV0iGKKX=Jf3W>}G}h9@L}sOQIrkb}x?C2VgGIuH6q2&?zkZ29Pi>h) z*RE^Q!CHJAT^KFne2oLe=Wi)37mdni+LG#G*b-W7l^|cYn2#r<&_(4)%17;umbPP{ zsELGa3eRjnn8@$~nhw%ABxuaWu@U7(@anS3$hOD)PrKiwXXbq%Ps?8NEKSnFv~C;p zsX1C>y8b$0>ofeNk^uwwgFYkx-7oEdYa-g^hau6F z{ao>~A>cY?QB!D%6R2gyR=C}Wck+OUdaygxns}uM zd2L+2JeTWBTq1R&cxBxfEd$2*}QG)4t0Do*~SK)*c1<{DYvOjGMU=7_65k_jq4KNep z{+;17OpGxgS|{Xy367wE0Q8>nknW~=+<6SC!14zv7{FNQZ4lOknNhr&wW_;3@F zbI_RWcH}*c4uRlLOMa#b3&(eAv~y9Cmf6}a!xKa)wbWo?T(Ix)rT$*zZHL+WV58SY?VmrIy_m|F&Nj0-fH|#kl_0B)%4VOF{E)5>$9HznZM9)X zz_tFqIWq7bCb7-4anjd`ej-xMJ)rRvPNl>~7ypdt7$)JXGC4qTGvwo%k|nM(zI3^> zq03=eDS<1O9WCE5@zOPhp2)elWD@(*!rAV!oGOYU-y`03%hKNRhine5dnt&rOOx)r zG~l{4v6OmVr9JOhE-C*ii_L_rD@|^@Wmj0Y>asRGyZjJLvXmcu)((r`FP&52vtcS4 z-fzQ z!djpuny9{Qdk(xBYY6KL8!)oH;yp)KT1B=7-cLU`jc{3vLC>d{voseH(bVsg+dI zj(%sSp-W_NOwc^9fp@X`bvv+olU9}^0shYFGjs%8uQSmXj7ZA5JD*oK4TDw&^*nnR z$2`#BWL6}$7fPO0Z$%SuH2^EQa&?#Iija=v6pdOuo1IkeL))_{FM?DxeJaGFqolqn zYVd6`cF1h)^bB-hP`jd&-x0+HGFu{G8tYMZa`xRV7A&?a5GAAP=^sY20z%byaX{P_4aVZ-BDiJn#LK}2()FCGpMCGk z4e+EDFeO(A&*D5b0EF0JEP=r(t8$5D01TauSmWYWq>kkcS5Dw-v%bBSQzt>=sa?88 zsTCUOGlje~QsmQSIoo^FCiwfk=IJDh(!uaSWsTfT!SvC+ML(WPPxRNvw}GL$xnf;gKSpQ_J8f zL}O}`HcWOk{O;+A<=_8Mm@V2 z*43jUGxF`F>ho^k-qW6y&$0Ht=xxF{&QV!YIpuFmc`VNk!ENQM#cwZ!KH*8)jprHt zhCr}b{KA?<>D7DA_N1##YPD+btHrU)o#)xz!t^592&NKi6d^5jjU8Nv6oLdvg1Jv- zqn`)97K5FBpCw|ksBLkUKW)OT|EKF(l+@IMpdbfOG>QQ&|Nlp?XS#c4j^1pgvKs_- zD^)f<(+}=m1+~;ES{)y+lOFeKV@{JDvP0}lYJFDhs?V8`n{jt;$)+av>^Sj-8oR2b z?{NIV^|L+I@_=Svh?gi5+pbaO^pxUxdvc;|*X>eBdtHR-ukPHN((Z)*rH67cr6*%A z@tw->YpRz}+_V(X50)gq14x0L96oa&yw`H&9lsVY0OHmg2mm)X$~#)Ao>tbZ$P?q_ zOuoL~Wxb9Sdkxc-CIFL;D|;ZsimB^Ef0L=HJ^o{m#!8cFFkJkpV%WoJApEjDmRU^o zXbzTO+P@$MggFBd&Z~!$vdU+*Q`+UG3Zld|57SpfWFYQ06>brDZprfZGC41pr`$@I zDED-jQU!3C6K!piwVL^MQff=29H&v6e3-wN%sBxhX!UgXs&i@z9vfW#lAW`*q7)&n zL-1^lBNjeXK<%*fwe+(hC-AE8RRLY$)$Yh}sVBD>->tcA1aYdg;2kF3j`k#sk2dEL zQSuD7da|YRN*o{lIXx~v%iIE{UHs)%LCQw+6EZK zg9O#uk)-U&zuXPO0Q|>W6sVDYxf|#bwM7*biLDnTO){#AFl<>HFAR}yH>#i)u6*eX zUOwEpKGFF`CD!@%x$^a*Z`dZ{7mTw>Fy$rk1n1#L*33>|CTle0*JC_brL;thv|Tx- zC(}g(@pp9Z(IBE+>Fr=W!2=?qHAiN4C3tTK8`9_5)fWu&uVF9lNh)e~DaV7kl~7s9 z6RbX9xPix>Y}uT{W+|?hsARTgWqCXYKU7V$V4Dy_&ffi|$FnwpNO|i=nBK8Aq0{w< zFqv~y?^P%rd!J=vS9+D}_{o zVlJET)@k;}sjR{7#xbo7KRbJmP~#LQ5^_Iq$AP!76sV5;XsNCF!XA;S$PWHavJ=Bo zO?4VZ;?^8NmI^dQhcXAykYkC`zEvhAuB(+WIWpcl1=O}&<`V*px8$|L9-Il8S0#$p zCHV1pmCg8izH_%v=P+Y~;QU~gk&9h_DQo!!uI}ZgAF^G<)YE z2h`%dvx*5%DP_uGIORJwa;p?+LHup9Fb>Waa~fsFP^ppYR~v0*4M=+ONnkrQN2llt zo^l2yzfCFH3Uv9`E_L{40@(kgJvWgY(I634;quj%l=ag-f3~+$N+eI0Ilq^o%wGs> zM+bSk>mAZ;SsoUC_F=&*?7($IU6;bfk)Z>#8TRT8)*!kAQbPuOHz+T5!sjoGo$kCz zsmx@`SY{ANS0t}>Hr2LGhQs*hrRS31w7@4-5M902F+0}MdH!4>_5bnwPrz^CkM%v2 zQu}~kQSIyb&eBt{s=?{$izJw9ivm#AoC2st>RF-OK9Mz7* z0tZV#M()P37W$5TTKK}>%MGbL=}{Zw9{b|k5$o6P^K6Eqbp0eg8qhdI-%;tD$3hy- zcmM5DawfZkwMe+DWv;Z&u`C`CgT)*yrgAWtl8P(^QdS0RE92g_z((+G{X3BDUV2=C zX)_40&!8>&N(`)XKr{%1Go+RDoPoqMadMTg9 zb_}W+g#?(UCk&-A_>~q}^Jz+pA66tmq#=0R;QPNO(Z!RN* zT6*!?Uu1WTZWadn9Xm*}x{;}FhQ?T2K55cEAd%H*aNv?xbs%Dtg6xeb;X9M|B^O8RL9@q!5u*le}i94>6Re^}* zprJAtt^m56RJO!KN>9W(<<({518M_0T!b_?B=`%04~^9~`G^j`180)p7EhU2;~Pr4@4p+-`1-RV61+e&tCw-e;SamsW*U z_-1l?HUKrYz;nkSQ9pRFV694EOM#yg0-es{(>hDss1mFW(Jai1HiND8H=t{&qG1Q; zRMl(^oJ5-tE9s(T$F;<*w3%&M1CM#b%vi3~Uar1s=Z_i|cX-*==Bb0>Y#pYqxRn|B z_KHztDSqv&=rR7|8t zrd!&YLg&cKH^2@{WM}%{FWJc!h9kyEF8OfP9Z+Duq!! zb|-&CNrYw?>h9#A`{u%A;pRr0546Pwp6}qHk&l7J@zdGm4(%3a!ogw5Z4E5B!j+)v z&B5`zl}_1Zcn>-a>gS#G^-WZMt5;bZIfr;)hP^3Ydqd(jZy$E)x&X(9!p{xyoSQnS z5UhQ+0t^OUKbSkl+&+&5ukJJ5ExCR^9OM{Fk9{LJI7?LBdo!Yx4V^_>j%KlkXbS;Z zm`<`UK4K%3u6SSrVgPK^;3oOh{96V1z2HUPZrdjKkFOkHJ638%i5+BDI1tP70absWlp%7dk;yhZKrl6iKe6Q zf*q|nxDq_PXhv-f(d%hOhj0b4sv{n(5UG;r(}~@|iPe6-s^^Cux8kBK(?Xj_x_BKB{ltkvi{ z??&n|W57V(Kg`lV*0ZEl=5W2x?CVf#T}TX{3;?D-X`v_Bky!Co7baLSHIjqs9&HL2 zw-(Vj9QLE7iho@IP3Nqh@bhi3SdMzA@9^;AC{14KxLN;iI~#Oh-y4O3ExC;d%7Jmt z6iq){d{l?~#^a-VThZuy6naUPi@JLaGJDH@3zjWX{VtFslRWTS%;q zR8cKJ+6uuJ!tVkO%iVC_6QcperjJIxQP1jyQRPYOQgXhFpvvCUIa1}_(Z|jx8)1*0 zSJEE!G3+e&s-gz5Sx~6Q77Yd)BNZR;scvi_1hg_2<0{Y0BWbPfR5Gbv(8HTk#FQ4G z5$Fg()lLGuZBB;izfG7czZBWupPTf^QgVU}H&2j1=1GaX8}EZ6Vz{S=7X zt%2*X6kYlI4ufN2uwu z#y%FsOYq|gxns|*2?o@iC3jGWgQ=vkph}MlwLPa?TSyg_hR~(y@l6dwhi~oFA>(B8 zuW9-{drD(tf$ua;-voI|2bz9CjwQ6pE z(UMlVxy5mAi;g*;PpjTgYbocWd_P0ISKWq|An4}&niI1zl$rrl?gJx3aI&mSCYX*&Nbp1d#qI?3Ot>=F<+kWc|NGbaqeCjMDV-iaURa1zDhKtt+^TW&tgiIoFkWjw(D%snXqBi(a z{YgiaFu)kBYFRFUsjxw}-O*ij6#DCov)u3W5F-^*qF;)zXyVx%F$MPcj1+3MQzfN%jhwR~1@zm=uBT#UUcK%A@pUCyYGX^xyNwOq;I`rA|9|vx zOHx%`(wUqylMa|A1dvOmrG9LlggDpEe2ybBsJW>23P`S- zo{>~6~T*0Atm-_khfq8_Gk%w3BGJjbYdvgh%zRWb9bT`3l#^Kl7*n?K9S ziZ!~yO3@?bVL;KK2H7^jMynTiA2>bxni!7Y=EWK$n2n5F{y{DlBAtJtd7%ugp}}Hc z1_V`KiouW`+V;j<5<^q&>=#hO)$2k~(_p2eR)Iq4wgT_>$5L%cY6!e4d&;|gub_gh zws+V98qvC;WiK+p$s7QoRfsgExaihROMK%fLCf95G&doQl9j?nw%DDz5E{g}E2OO^ zSb11fMO#poO}qx+<%G_4WcEcw?~%O%<%@i|GFSirAOJ~3K~%~-MVrqN8yV)nR@5M2 z!&Vk-Ag8y9(&^4Rfy)=+nsTsshu2=?3HQZxB6%9a1))hW;>T{_55nSyC3&< zD0Q;TvaBDpIt4Z9W*%A>&{D*7N>dpl!g8nQ_{O3`g7D4~VS=`0Jz{Bl-(B`>l}YC_ zl9;`V*rS;RuZVxnA6r)2wfZ?Bbb6F|_W61C zALdUBR0KvhIlnq3d*$w@i0PWERO>*?8f&WLk40{-6sbLqzeRKWT}Guc1{<3lb&czT z0t`im?@@8!^BBg6!eqR36WZ!>m3?E|;(@s&g#sRf`R3?NG`)Ul+`T*DlF|12N#R^xA-n1OA|vp}HYu`34{v_Ij9aubTv9GpIF-ms*Hf^otBZu7 zjT+zVURap=_*D84SXn9ND{1ry$r}zX5TOG#juO^9#PlF&K^KCK16$g1yPkB6MUYP zd6sJ8Bde#LF#-c_9iK64YWz&Vt+CTdU_U58Ugl(hDs)*+MDGfi)Ux@0yDLTHWbg3q z^uexXs{N4cdZ#0MS0M!Qx=*}Z+?*KLciU$(-Fve&A=$N0SuQu_?>es)Np2a<} z(yuYtq;XtBbL!pq4V!D7<9}_t znm_pc5w*etraf~0b!pbcvnLIR2WYes&AfTpkyQ(B34b@g2GcbT8suu)T0d8h3PQ`b zYO(VjDu0xzO{Nr&^}cpcV8OLsC@$?y8up()rLrRCan^x+!?utCThhTU2@<9en zS|&5+VD|3bZ(^M>4&T*0xU-|k=SVQpsa0sA=%Z(??3-}B6#bL7|LXH(!hN{0A^7e2l6VNL+0~21hp)6 z*>zQe2n!6kh*L4!b%{agJw9c%YU1K4d(maKI_2!j0aaZV%M#xf zO!DX^b%I>G*5vx{w>93)lfAu7i&a>m_XP1i9ApsqCM%w`#`lp8JUoHEXo~T~yQmdd zKFR3j1C*D~?xU=Qngy*D6Ft|{u`8;8xG`ie&P&&1c2p?Mp9|*S*3@&tNmo935N z2!E=}FSSlpwG%n&vCjJVcroTr-*EGhSnUw3a~CazNAbH=!WL;{4ywL2XvH}$)gYhE z%KqR$!^Tu8l&UVg42StZYhHgduSjywWWk0xKaajlsP(#@Oz@lzP=k zlqIQ_Zb1-sp_b{VzST=eSytWx!%V!nO(^_AgQQO5vK>c3;5Y8PUYo)lInwG_rAU%t zc5@OR%7tQa$p8SyB^vI zIf}9*-zqogaB6{RSY?Jv$I_&`iJPWbsm#Y^fL?p`1dDA}hywAIo)O~(JNP|4L5o6Z z^C@BKwG@s1ev?Fc?JPtK)AAZ-&<-Vr&Q-!!+N-`$x+zPeg6#IrI$MpdH;%DUwtH9f z2CgLwP36|zwb3q+Hh3zoAc3)OV^6R5gSYqeaAqE2poVeyWM{&m#cGJ2jnj?s)-t9! zYlj-@jPT1dtGPm3&AHwA?>|VAJa=DE^E~2&{po1{{YL^Xb1v;%_o63}5uSJXjt^BR z?0cgBJiBexvEkX#w);tgRX934w8L8}xpdg_>aAN3$; zI<(WtmQsFOmbj#12(2ScptetyM;_>{Gzx`Cz|w3;U6MlH1_ zitsuAmo$3*1v2NLsGHwovzEVaI>#J3OP)Q4pUGF)OAZ9fq;U}Bb97W_uwHUs6kCnc zyt~xHwhN+@xrx0LO%hvI^YY>b<9zv?%c*P^TlY$pI$__lHp@TRZVwI{QxQaq+4%9f zZRQ%7TI3O!+dWhy8?jZ)jmFpE)(WFdKZWTPWrq4z?E9(#>5Z{M-oN`r5^gKj->5xs#yx? zgs@*)hl#B2#w?7?VYjFdWPBt+*%)an6vU?-mxurt z(ryA}&yg-rOYs)K6-diFhpm}y!nW=;lLh3^7;-5z!^s56Wz%>wj)OrRw$8=0+fISA zp~7;ud6Vao?xo3>z*o}ImdL^825#dpGJEA9akrnSQ>AEzpem6KCSBTl5yWt_tjd+! zWm=NZBy?Xn4H=KTQrA;R;@xZS?}r9Bt2Df!FCgT(H})CX=!dyCQlAfxdIaCBZa`aY z+7kH0jNs(?qQFGo8gb+0x^kRep9il2sKZB8f4< zcBX5^z$U~Q9dTh09zaIBU?Y{-jtZb~fpkLVs-f^hFUaRI$c zP`{jdXU1;KP3=%hv~{e0XFXIt=od})U%kQfFvUiitqgOMEL%2q=D)|BcgjuU^mQ}O ziTj>?9i4v637`&^m1a8a=0`r0QkJ-UR1klLe&lJ}RbyNbhD0is4_x_1X7$A{|Jta@ zhH{x|<#vqV=J&Mspwz3hB(_VMX8W9SIb8S%11!Usf-h!KZgnhRo}S~iu_A__A1-|n zNNMo#O6->Ul&4iBh1`KZEe+T zsBT^r3rcl`13@eo`SezXZ0Lq9P>X39ZL8wHYIoZX+0;A03f_*9@$6!%(Uj9hCR0`4 zrn3OJot){W)N0ZoY`uj8QJ-zW16IG&<|K0}JVM%Jrwg>wjfx{rpoBhJS1^A=3Td?n zZ_a1~+$XH%cMA_!>`+Agkk)JX1HB_W)B5xadP&dTJW~J(KuGfPuF|FPqh2e*E2D6u3@JGyD~*6&+?hu02i;+3fGTS zIo=Qz=`msU#AyK&CC$K01z)L0k;hT&<_#IFCA3YhoMtx**e(yW6Q3F1?Mq+$Q*ZQ- zZ#@j>U92;Dyg^&N743sCAhoTOU)$_Ea0V`9Q(51Daux;ya}nQg$@FB9lrF2uRrkNR zVX6eJ8h$@V;as<*MekC(g8erGqIsS_Ohj``#!W4_ntd1S<8$6O|DUhxKxiWgf}2J= zY|siJ5dVMask^Gftnm4KwoyWeP*dF%=0uF`;#O7NT8Q&_dwy?+m`^EQ>DkqKHaolS zYtCJdJ{mZUqMP`TqykLn&Gx$tV1rK{58iJY4OAlwd5tQyedNhzNA)Bp;FNo#v00y+*=O>dslxNSyZx!El?kY25Vmq^P;W7t*H zBdnp|vNk{jRbJNTF=?jbpd3#Qn6^7%yh1;uXL%s?SVd^bSFLkaoa zM%<9o~-52|G zA_;B3W8!?v(kmUI#3>H5XR4mr>k(6!fmt$|Oxdd&ST$Ho$CA0Tmg7_?t`GwJ0oFs0 zrbZFmXch=WN-U)x$6?E3*sWrb8(ryh>V5mpIDR@S=W-9eC|i z6o=k!`Y4}Mx=TR-3I4(wxnhJf4HCrh;=aGptzhBLAiq}sD}P+&`rqf_7GTp{v3St7 zyVtM-d*xA1hV~&cu(h{@sOgAtmQTzjQ03tO0ydRm3Q4q%+FVs%vg!t3ky{8~SJ zf<0`QSkq)nL+(mBRi?s`O1Z9d3r{xUxNv`8CKF$&`K)IW3SwR;xfYPK(K9x>lrPI| z)UBxUzpj4hpxb0xEKI_@eB}xm9$->rBt4H>Du~P=)mSl6(l@^wot7ZJ^agM2EljmZ z!{B`m7D@zFmor=gVAL#(i~B(FlX*nHQ4A_AI`ZZT!K0;C(!KHx0Wu7yH!7srNdOVF z0Vs2qxYLd1U%8+4@T#d;-_ZRsko7@&r(u&azHZYezLCM`y@bSQ_WCY2tqC^Xe2+3; z0y2EY+JlJLOarOA5p&CTjF<|#bl9-G1J0F!>L38#D)_M|O2)(8eUALlt**0g6b-+Q zE6|f;{H!kPePrJQ(U7X4Py=dHxeybCl&@&BKkn%OE%_x&jM>BPXKV zJnY-kJmI;kwrBTUy&?D9aQZZOk93b*O;JgbVN#y6dnwb`?tJ*MLsB$FxQDpQ9TA3{ z_%+jgRIFI1q%d9<6Q^f{4G+gFy@ znsNI+p4p2}Z{6X_XZ!VKx@C*FGOaUAMEZtKsh@mH?zFIiVbvfkOWkPKz@}_IY&N}m z?JwJWp?5AZ%7p`XJhqjj+XE^Mf;rx{vG$83%V+uZ(SA(p_Wb?*T37gFW9FUJl~zWIS6Gd7-mLY4Cb1$&GAN5_2S#zn6^dvQjcsrzut~0x#mHKM zbq`0G43nT8k(V7{M?@jjLIDH%eTk1y@$6W^DiscG@(pWW#{a{4N>;4ZMmO{HLYiw! zU&4&@YV{(iLih2o%nyU-1*wQ5skm{yArO`_rcGfwnyoVkb@$vXydsK~7rb0Nr~uxH{j7Jqb8~E=A&#7D$bY z^*$V;zTjFyLD(a##^5`PfFWOEB8AG4cW;F7plhP956kZW*a7R(8%FCl=l4>{crkbN zVgp@Un%^yEbAfpovvIsk!(tp;6PmsG&|WM;wmu)>`VVGf$WwcfTf7{Cz2kC^sw31= z5Oz(!rT}hjRTNsWb`VDbnH~Ew80F97U^PhIXB9LU&5|tJ!dIlq{_q<|JPckSS-3DX zR#r6=DjHPw{Cev{sBcjwEXE@^`ys<}2a*6Yc(R6Zym#5QQ4^8Y^cD$~x_7I`RV3qZ zO~8|*qW-0bp4;-lf2T^%smtMy_3fNuId_p0s&Pt< ziEqo{=vr>%WSAvam^VW!&DS)4V&R*DrJu-_h%4zt6AV zt(F&9Yy+aDu_;Bf(qyd(ZcJL8=DL4~DbSF1*sF^JI8Fimw9-OsfA?-eEATl*^dwr4 z;P9pQh(BAz8MFdeRc1oxI0*NoKWaXZU@eS59`j;b-)(pb1zv25swoK8?}uzFfnKjs zAHbJUj+BV%V#NgAMm#0=NWBKJXOvrryA z5RHXW!-4+NCV6^?s1{>P9xb%6&<5e^ma+cA*9{oTVJM*$5W+3ZHoQA18%@7^?So$e z<&%{`Fo1%wj0@AZl(R3a8@@3*3OiJ(xL<-U!UH`*9u^8E(rW-8meYJ$^;{yGVmaAZ zF0dX^7rFT?2f_1%}XLxi?;K4z#{_o!8eaI zTk>aTVg2O7`3MHl)Z|%gIED4t`^HoS%6e1-3%~WA;2t%>;s@3a1~}h)9}FqfB6;67 zYWBTZ5m5M!v^Bd>MxUfmU?6XF_w}$*qtc5BbuQpBhsIQ8pEM+ z&qic3-Xg?uT!-jhV2tk$UNA^Fp7prI*p!!-&xb2XR#~RHiqf_$*5X$+fQDh($ z(bz0aH{H~NeM6?T@1`uajqy(BtbPE3I97-(924&Wk0h6oaq4y$*v#OLyRC3_KRjCX zBF_OpTrl-JP6iBXR}H)#~$6r5&R0!;Ef#z zm%%tLyCoMce_;#fEZqjr12(|SoYbubL!Kv%+JH??PoD+)igCpaMIOj4Bee&wl!4`q$r54(Pz~rk@-}cP?PehiGV(f zq~<2b<1J&li}0)*ZP_TH-%z-FqulkhXP)19Y^qmm*1+}cM)suBOBe(?u=|mQYs)1JOpSGqoLl>f zth_&-mYxlk(juIdk;Tw(z6LyXoq8iVHM*yR_!*qG(lDWf4$6%2l5ifWBZ+k{FkWF; zr}g4V>8HKe+#B_wM!Aw~U2tw9?HFnNL^*$fUp_vo;)QXJG9@%R;003I&&Eg}Q?M`Ui}{iI z2`PXp0ysdVFS3`>i=@Mf#OZD&!xn=_J0*VSvry{Ga+(>_@8rGHoN)oP#zluEIF$f5 zE{bT_5!`?ql2!sr=evhs(S6h~^x2cIo|jdim(=zbL6!!p)6|xG?MrSlOxB}|(e_l7 z5YRJ}+Bk&$Y{tqm@!o*e~IqOEu~+kG&H;<|1kP6 z1YC*g3^&uQ4&-Z}?y;}K@|Aa9Enc%++Zb~R1wMrdIPxbwGxE=De6AXgHt$^6Muk1w zUijk^aty+nb#dwAgJTlzczs*(W^=GdZ)_|il#XhSE{2r8q1296oxn54U0l@VVBP>c zfBrPZ(wloTk~h4m6$3N74d*t5(~bL;DEYcK&L8UsaNMwO_HCF(O|(0YbZE-4&>?Mu z2T8*&SIPIfLk<(MjEp3?;h9jZp30K+>u`Ta6~OL(Gi3>cFo_IQsz zEZnN4e`v4T=@Bd*f$`W!J-h$_AOJ~3K~(aLFE%pnzWaScz3p1__NR4CxPmr)C#?!# z9t=3bk1oVk_>~Sn9?#iHL#KGFMTNg`jqN-#;6MWhuTvqd$CYB-cj~0Q6PUI6jWTMj zHXtpSI1Vc~6^R?*oei1=#&;Qzz(M0EDy<@u*6%EpEzep?a~g3%TU(JgZR*O&F8r?s zRFbAHB1*E|a)D!qu5)oganhfsy*wx7l$qj}PakC8(q;SK zpEOs!ew*OemC=`B9GsVFap`OPR(}$9g_7QN*lRT`N$tE=FkeZ+tZNO|EbHwfXOYsL z>G<8`E865W^6U-r)3}QGWhG5gc?H)9aF3YsjIYnz_Tb-dl4_iJWW)bKV=TQ}a#&}94ejbSVfo(`?{ z_ZgK6*ekEvmUEHwS>_Oni*Kef0|W zMD$+c1JqIt+?3Erk1mehU!NreTis{bKZ{{86|tYOa|E^*MAXFD%j)NNb07mgd^FW{ z5w`0Du^nN;tq`U^ttASV}@K;7#8_<`%`ij`yqmlr-vD8faa)T)uPT{F<4RMMX zeR7+7PiDqpg91G5Aj90G#G)! z=WG%37{kd0zjuEeJXk0cgx@yB%R4S+tM%Wv3(QqufkT$b#uu^a9zoT*B)Mbj#bUJd zYYb_aw)L(7=XC2b=hv_IE7xNWkrv4;c-BQJ^AM-1BQnh*Sr~?6NC>r52Zdq zaVWaQb-5q@DqO@5a)>Q%Fxg4oj7njwLsE#OO+nEYc!2SbzyZHm!8o4`!J*Ry%$Djv zF2G=;zE=*`poo2?wi?@F?1PhVn61Go$K5x&O6ef37r=_pd^=>l>V=*Dq z!|RZ)buNd~c?$Dy?PJ))OS@bv)YGsst&^?0c?_79MrCxieK3)xwbd*H$G}dnQ{a=w z_3RWC3zTXvK$*k`wGJ&qXs2adT}mnhLr$fy*h>Xo(i{f;&QCMv&a&;8#oS^|T6 zekp!JZM1bQxx;L_2z-2xxF2sgDWh$8xON2Ofs%$QURi8B<@VHDr2%dK5%=GrYoO1tMbY{a|P z*v`Jc)I>D`s9j%$aBFu^L1s;Py04g*x_{?7|D#Y3!t5f&GfpW>JRhTb-&EM4T`%J{ z@TI%jvRH3~l>w0#Q*WcP5H@V$^AibapzQ;C=i^Lzmjdgl2^jh-77|jHC8&Ltyv@NIzW2qe_^o`G4&@J1{Bj8m7N%VKeoDoqLNCxsVio$Pa_vv3N~+7` zJDjSDQ>*YddtJU1Qnh}foLi6-o_PuZ`KH24qRKA=cNS`eIJ?GjmXdYgWjIa9e8N(w zXDT)x>f*Yjh4@L^e9NiUCnHiGk{x|5)7e#pUAQE6Q9T+|5FpuDlH~g1$g$>(kA%h9 z=N6yR#Je`DE5k}3iUbGXkJk-)`R}aHYa6_6-8^}{(Kc_Px{45vW5E3gkdF^We9+Cc z1h}2U%WGhu_nOJEy8>{-PhusE8x-97C@Vvf^0C-uXph+h$E)(P1lc{?mK)(L@G+7< zG5cylZECx(HU`|$x^hl|S9aDeT*Px1A2w|%xk}G}{B}XxBlG@!!|-G~sbT|ktCrzY z@LKaA_5xg|*+yI@6Cjr3c>YLU+xL82q+m__pi{WnR=yxvF{-^TO~@}epxprY&U{I^ zp{B4fS%$~tnUxetLxv^4QmlmM=y0_%rC9g*N>%^=QA#0~lrGM)7keV8^Up7dwfR-m z552`%vo-$L#Z3T~MM)B%Wp~bKBGlg=ibZ<%6&V_YS%flCGEI$_!Y_fUoN>J@po_qf z5o_64$vQqRJ~(^kW;^=cT2Fya9<@8SV--a--@34QjC4plko>Yr@a@7h^#k%n0KmI= zn4^21J?L=^fgHcNC{Y%FKnpKUHPDX9{#ye)moc5Gjt3?^mPY(|ZHl!!y~`t4>xRIi z+BA4H0WU511(5*Je5VEP!`lZTy|S9$rbQ>ngK2J5V@)sxvwl-e3k`Kx(}Thb{BwyO z08v1$zXr;nn`#Y?hIBV9gy-^{%g`sGRaIP-?C?EpBWt+xS?!#0>~=esDk=J@BJgmk z7P@9ros+YwdpFCUQ#QwNS^37)`VE?yG%r_?bGh1>l|Ff5qRS~gBv&U7U!v(WqSl1V zi@AFER#OL;jgyO>xh$QooPoP>hupAuZf8h*Mj}0`R_r*#J=9(le2oy8=laxZM4ix2 z^eRm*%vvKhD~+|;QLOQoWABPTc-OBY0FJQd50%fG!?6klkLhOvBP|dHFq5M`aPs{o zhb`w4Q!GDl{*ueyH1l=_IYo09YvQ{4*wAOWrz8 z(U`WGICWeUb8{L&r<%(QXr)pbVk`F^1qe?9X&UKl!fsu3|$Lt=(;w1wJ3&pPm14gAWB(+gy+S7-O@6 z%ZA<-*@xNS-ZOC;leB4F?D%Idb>y}|e7BIPDWMY9V8F10vr0iY*GTG`LKuJ(n$~Ps zWx>Hqagm;9_})Fd(Tfd!y?98mRMGEaZ@6yPEJ-1E-dtBuEwYaJa`AmFh zAj;ViU&EY6M@J&+k7s{%yt;*CL=*8oy4Pxy?yFNF{n&X`lro^SJ>HkLd;Hvy+1)X4 zL%CeaAwhpJM|_kS|0-be&8LDZa6a`MURi8`xRL#(nCGSA31vSX#2)sgogyzS3fO{d ziYf`&QFqWu@6~yc!lLYNW{u$aKE5qgW-N;q;_PAIlXrYop_91M*rv^V+d1E2BX6hh zjgiA}*NN)4U#JJt%P|StFXf#(;m5;QDt5|j46WUN&#es8YI?T_K2z)l2&Url*0de2 zlGZ-ruWofVI&q%mBr_TuQG>S)Knl_9Wtr&{ui?l^FMO-D3-&-F(>XA9`1*6p@?lp~ zorvaBSMfIsU9!UayznhaHWm-FRFlw9ZvU~#9`ZMoM(`*+PIGkbHsqDd5LjP_+~HRD zzq)I`IsdufX{*X{|2c-;+bf=KSCjXNLFZF}Fg5%8qZZ%05}fajptn=?LkhJ#d)!nb z6|!pXG1fE=ua&8`S(x+i%pGw2>7w{(+a$8mf0Y8=eK7O>pRRM!Zrq4rsNNdABFAy+ z{r@km2!JyjdAB_$ZPv2mBwlk!0vCTUh(6gNiVZmK4TAQ-F=j z-(7=ZS&;nPtj?4TvPRIrW}v@Kt(HuhKeugJ1Z)scw|{=VV$~n@HSEcIJtp6(#b8_l zGzy;)s)oY@(_V1cU(k|UA-;|m)aI9(~Ze$XZB!Gk1dAp@QW5Vz^L9g0}#ho?17uHhoG+QrYkPe+|- z?FB+D9<${s+@d$9&%jF*p00QO^MO-}wAL&-&?~VCznV;w%|| zp~U0(a!5UO^l}nYVkgu^_xN>T^;7Xg!tD;eOdkk(2)k+97m5E!c1Lz1Z z5?3`mbRvvl0n-%=mwY}>)o?I16%{)D9j^4xpq&DiOtt=}f=i?i2hv>4sZ&^TmL@t? zYtlJTo`adFsjjHT)Md?j|1j6;s`SCjyd@TXAS+AJZvJYDy6u@`-mso_DzNFYPYwg; zTf#-+-2y*ruH;xHbt&khvkn>OoH2I5O_0vzAM|{4QpJ?R%K2N%$#ha1bDY)~gsnF0 zuCOwCU9s=$d&kfd&6cpy86kb$|0==8e3t2#s^?zv>Mf);P`r%h`D*C*6S-qwS1lfQ z^wV}-j_|#zk>kHG;)Zm}+SIbeRp^3iICz>aYhO=eD3G%KXIHsS&al>xmjm#YtLCwU zb6jn-?}P~u5Jv!aMs2o(!XSukLLD#WWX7MKXS-;r-Rh74b;^Jd9KDjJY=N4zm1H!r z-~uH*F;WHsv`NE0ESQ~4$x03My;o?|BSU6QovVv?G)aAS9j}=+MY#{!AZIm@`2Q4p zSWGF`U%h^RZ)|4&lNW;m9?(x?F8w5E3XsSrQCr+Eg8^+6;?6y)tAxD{$v}^61ze+F zS8=(K&3w~+$U-1ATtJ0C3+Bg+WR6zASD?E9@)ub0XRX%#~gIdvc z=)%(Bs4&lJsE>U6QRxU)Esi@SL-!h>OmzM_b!;*Hr%B@eVnRGs`+MDVNKtpcZ6PsZzB}cuvZ#uf)GBU^fZeUW$shyreXC(BYDrH>hdT+dsth>tDzf~Gyv{ub=D;^fZmD1U#40HJ!x#ucNTu+&1 zvp(m!O5jwh1OE(%;Qg-xj57P@?Wu$7`~CX!(jZ!LEKHSm@}&AV{kyya#mv0bigKr` zPZm`x&>gzpb3^m&F5mTp`nlt>*FJQlRc>wsmf5I}sli*jmC!;)KQ;<&zRFXAAnfZ4 zBj&c~rp7j_B7GX=Dv1W<;xw6Kasqz(Vm5DPOx zI~M4okym(?Rq}=a`@?%3(YnxBV`JA<_75f&PR{IbjNrQaJFm1$05B5_@xq{#<4Qsw zp#gq8Jv0CfEWN335I^=vGb#NavTWZK3b3^F`_+0 zhGw7oAf?1eRp>I&)UGyj74}1&?|P^(QJIw^Z|UV_ab)Iko^KZt_NtQVKnwCX9P#Pr z1xn$%+<S` zNe#ir8kEsD07u?;22jSm`V?eR$_2PdbG4fd1u*KLZsj+9kTy~cZPs^YordqZ3k@=| zlvCi6q&ikG4A`r5!`e0Vd3#ggJ?FcdDugQ){8v7y6xn(VXed+ZNbs(|cfZpZ%XLw; z7fwjb93KCkl~|*!z47K2JEaeRW~=S-cI$wx{=WY_wG!6w`NU^vXZLQuZM@X3xUCkY~WV) zdT>u6Ql5i*a^W0u7FF;`Lww~Ynz3XaT|cU2a3UpEz^H~CCST7sEfGal)=N6!EMD_B zwZHCPV#gjlP2^+^;CEPV1dB5t-98TZZWgq{iaVy5Y#UH{u^L0Ppq&X$JPhx=l<5%z)fugo$JcxJUjR>q%im^p|RAyTd;%%j}{ z#Vpht`%v8DlOWFrm%Thmblf1Y3Lbu}=*u_T zF_f3TKQbWc*+t(xOxHK|trgA7T^kNcYEDv{w@5*BpI6r zFPO?;gUAXm&5=h$ylzd}zcGDbA-q*f6s&-`!tNIyY<;D44}U)vRZbA>c&>d3pi z@vUaWm6W!rV8+=;Bt3IMAkR@DrECVjr>l8GkbP6$_dh4vx^vZvhBh_=x6<9*n<^>R zt@-CtG$s(;4%VJ6MB zs?8l#x8Hl1QryQKDZhiqDRraR#1s^4DR#2HZT9`Ph$^YVUi)uwZekQj6WG&Dvo}BQ zpLeLYXJKpXMV7VZE6%bemXpZ0z$m^CE{aV`Wxev-D(BS*cavxv9d^H`We0-3v^&Rn zqk4Iw=E}^&JsBG=kM4335`YvrlEKQsSCrTE-TUy{vK6Wp8w@N`@gDUYu* zn=U$OWhlKABq&;iAjmnvhe3J_!KL^bnSGj}W(oD0T{q%V;#nCo`6&&VbG!gHIkNA` z+(4WNkTP9JjDdK?qseh7ps$xWIL8A`T`r@Y3y#rl=d`GYY(Bj+Q}TV+kn+fGSCp_r zln)5EIa1ev84g@Y>Q+)U@Qf&s8j!w=Ni~zN>`%VIWd63Rz9l~UR-EU{5fA9+2wXDYcmpbT)4kV_PcsiJ?qV4Yj6cWowxm8>I9WjDk z>$>qqg>G&^gOzSJv@p$WmFuR{)TE|LW@u8(aTo*bA~j(z8c-V*yGn-r&%wveYp8Yn>sf&Wb)qCR*iCsopzIVzon0M7#XgeD;HOsgWSL* z`QulUcfaT9bLU)+uWBn1mg}KmI~>((gPXF2HY*Bo(g1=9dLodB59 z3lkQNAM3ZPwe=@mF;4WZ_VNubI_O@-6%Tay$;f^W*Q1+c+Nz}cFYuVQ%V0x$HMW3L zU1irE;@jpO-zBsI<6>H?=?3n6O~E8;1q-6g58h0>0jXpDH19#1Fg5orUP_yW&jai4 zaJ^LNV<(1V5T2c+bpsEuueRdQ3@RY^XHRCD;+*F0(U_ZOWnEP-dfzq?WU^GiG zG2zBo^FMT4>8AFYXTPfQE;pgZrW~hOY0)xDIy-~|TRJz{@kctx&Gan^$sC+E>Ra;5 zWdsXr`O7J!9F%-oJr)&tAc4p9j{oVp686NEBcg{}_q_>2 zxF#W%OQi!0_(F0cvUXz;8_n0axXYPIShlhKMg$fw3rfH9UYJQzymSTK4c&pc5`Eo6PS-f^6kP%xN;Hk!Ie3K(-yK@$%ytyC4T(=$xXH~^&7tg_W=+9qId#|dm)#l>3a#qq| znFmcBcI6|Xq8fvu{B47hA9~&od!=`r%u1z_c1JVSjpmBW66G7?r4}xhiq}FgUiQHSuL`IvZj+hnN9kfWO)+*Y)4Mbl+!~{nN*}C^ zYmKdKuv7;BYZvf&#eMoG7P8KaTB0kB3O-kvUfp$RIn^f&Ym@Vp<-mDEx;lRg@p)`n z_@Zd;>Kw7Ph_S9?{nF%<xjRP zkH^$ivStjlWg@TiUQ1C|PZb%G(@X2>StaMB|EL=Ahm}iND57ZIokBqGo zV;BaAu+E7zk%1mD)Up84X5-+6!7xS#5YhxXt+gHG{#wu`w zpJZctD%i=f_o+}Va@KZtEq(Fn{eJ&Zas5I?pMtr}2jvY0@*@-P!J8XuZ)5Dn8@}>J z)dkpbBuNqGmAGtex->4i;K|cMu&>SDX=Q%A6pk$cw9X)uD!qAj7azxK{lFYE_yP^X zBqKolve6Ns$gB}Ae(9a6G+@fi!2X(RUC6X#%j&77*U!mDVa&pF0OX!SFn?2~VND{pUCc8*ni<5fs~ zb=#gt>2H?ZWnf>b;LN4M{r@?qb&bH;Z8(?pce@hTy>aqg)Mk^`zw25F!@K$}x@d=i zW*1u{uNU0M`o2pUyOjRV6bncdEPl<#$A4Sh9kka8jPuQCavwd>imac?H@4s?~f_fNC)}D2R^^`VfI~H z&>HxvXvlrbegnJW{lh|{o7We;1pM{_N_`QRPwLr_*MXn<#Wmj zQ@!c}d$AVksiIUa`@t9vebXIn3C>6^Nwri;L9y2WE!hdUiC}t84CkEt(8a!b8;~=x zCr^X&!4kF6mFo%O{3L>9bf$S8UFu9zI@^)#a_VJNw**S^Hs_mv-g>3P>6a)mb%r&; z_|;oW?nYG_d#yc+(dwanL`teR7vrYibkX~HHDBNbcKRclhJCfk~o_jxw1(pW`O{41}}=(~2#PUE8! z6&>qFir7^tC!niGCK~A(*MdY-9EeUu6sKnpOv7eUot`H(dHo`3w9J?ZtK zR$2)iPe`HBv~c`-2{5<6xI7$(awqL61`fkJA~w{zkbImKb)B%*MF&y{Oriu0>&?1J zjfA*KkiD0)szNuk6(ZY=Rzq*|6$Zxhs&UdaL9U;GM=%B;Ss7A5)smE0uDoytI!p%u zIDv}R&Y8dZCx(JZW*`rLMw6VzE5=)L;U3}>j?d>voQX$f-WuA|_XOwf`F`b@0d~el zi`yy|USpdX);NLGpUt$11JOBoPE6M@`~@wTc*wR}%{2S=xy3-oLT+sXmzEnM5zfcR z5UP-<9vM&`kEKoC-~qq$3LUiu zK=o)yd2?P;Lgy65=grkzxu2J{^?5kX)HH&ptsVjxZ2tp+1-|)0{qa_%#2;^Mx6cnj z4A$gqg$wBO+c-s^DEYJ)P7{IOo+b2EK!4B)^zq*tstBF^!)INu9?=7&_6kT)i355p}-OQ#tj$6A>%1Lhf7 zZ>k?FRuSl-yJ@Nh;jWTlqsxZ7f~eTuqebDE0oV>moO^+|j>G&dAGwdx zwSeQcMS0EGy*7cL!fvGm*}XI)+uUGV20Z;b;_2~p<65}!dH@Et6TF)>e>3x6yPCu) zXK;;mjQ0`?^s;ntsY1D`)0#@GhN9nzSRa>6Ta;MNyvQ#~ZGFq{=mXyGhx!PKyr>0! zDVoLpO4eYsQB<9f#=#0Aq-=QGZ%7BhhONE*=YzWi zFDOi8YhA89(jvCnjt#IV(b_H5q{?HE96lw+}dgjmk5?M4Se2f9$p){Y=ZR9m>;egp)RRI9kIX zvaYjc)=VUC6wQ)>9ARc&NkQ9h5uyltK)Ey1LUdqr?^aXhD@%^NkyVvM>y-!FT)5|1 zSjCA{S%N)|QLHrO)P6S(p&Cp%6TkoO$KM5p-`BtS0Gub~w;q@(>hq!Tn(4x_fz&phX9_;n~A5a=aJAnng7{9)j3a+u>k+rd zDkE!E@>9o6wWDd9JhjAspuU}DqjxJUSK;$T|J0QL=BD?keeCL`#<~e9qxCA-UEOem zS55ewly!^S#1VO9>$ukEGJsZ1)V@HrnOToZ1h*3^+a8R9{S|4tcv^b{tUM1e`^B2~ z&fturaLq;(-Y!yQDsY!e3Kw;1&|PSXOFu{L?)DRjWm&4w&Ah)~T4o|vSufXBbrze& zrFy>!*3}2hD&XU{NtgW1pIFgQ0;3Og9i^O!g{&-VWMFm`a-r=KfPMHq_Ur)8eqXF< z*)vFtCET8`=0w(SoC+|YQN{PdrPWrP9DL7b<-#{9k<$O5Wi}N6mT(zZ9poHDer3+h zuorzK5!k|ZnQy71PS9YfaS-f`cDhy!!aim`EPWX(G6;y{o<=RJq@A5O_Tn(d0o2+Ybx2#a;SJ=TeZfm=827^D zJ7P%144X(CYR2Lp!uS{6#(|(^ z%Z_9xBrc)A`@iUUXJ%Kjd-vVf5=bD0;L+^PkCR=^rW+(T(8dm%A=ht1;a*ba6@aX3 zM&E>5CRTMxpymL3?zOcVkV1}3m8MA-%yv=xA|p~lgzd)}=)p$!D~-Kadh(h^b|uI^ z<%%ua_R0Y@`uQx;`nw{YV`@})@*c;9VK7k1XPve1sybelR7lff4j~}$H)Wo}@N&&! zK0w*5?%$+Q5%w7_15TcnQS=>2%&f zj)~3ooQ}Wts!kh)IWPQ#b`8RlJ5@IiTxFlmE~VQ;_wk^&t{cj4>FCuA)1AKj)=BYh zm(XpGy=>$Eg8_S%^F91VpP!0{CM$L~uqR{1BA6)rY?K$VR!H4Y@-o7M?`UI~JYd5N zz96bF0pDTnVRUnZCes_N9zp^yqLBf;%&17pvILkWT7-zj_pbV=+`m7QtCDdKYcLEk z)XXnWaQ+Cb6t&H0dD8Ri}j6GpIEiPf}ia z+9VGWRR9bJuZ^S;|IE|AFxP$;W_l&n;gC17+XdMhm^s60nK_zfpCPa`Wd;r{n|5>K z%Jm&ijYdT%x}tIwpo`=N{E94-=E(-rHBXP%h!ZU{wY2uNtbMx%3(d*7d=PychItCs zx)R7ZX^uK7!C`gnmZV@jFsNyE^~~wsQcV4mZh1I|x`aG8^PyWWiLPH>5E0p!z~cZ~ zu7`ak{EJ#+r^rO*FX6PIckG0gF-?lr;I{aIf~JS>!a0F{cr2EuNwE`y zKNhd~<2PpV2dX^7-g+GX|AGz;puc*q^+S1X)D#wl%#taea zCfGdZ2$01??b?N3_9_U+;TuGls9U)MuBNlk)&JFQb;4)T*xD{9r%+e z4hV(}W*?8E;_=Rbyc@_rw3&Fn^0jB2Yk$rurvU5XMsCj}>kZ0%boWUHP%d-x7D~y9 z`8M2TJGy^7P4UcbhWESG0YA?{9nnenp_T@wL2DQd_WL~oK}Ys4Kw)b&4F@Myg^{9} zCnj$gd`|)@Tc|$qt~;ua=S{KCLQ2wBhh20n|IVNno@!0AN+~7X*Vld2~Kc5@5 zVW7$;JF!oPc4$M?Dv=jLptmewrZG67gM3Tb$LuI5w23^lRW`$`Sz#QA60(;l>x~G+ z4B*(X72c$R!DTSZ3A{0d2n3shLCk?C52;*KUN33}6)v%MdQd`5s2t6oVnF#=O-n0o zh1=6YCfqDas%lpv1uZa)jxdUswar{Ktd7a)_=p@0Htmwvg%rsnkx^mbycn%O>h^89 z#*as9^84csCQsyQ+ubj1e;txL;@i>Zc-I&I|J6qU;D6uhT%@}D%Y!%H(qv2a{Rg=s z@F_F!nIdpct9F?5TCpFBsNG()O_H$N5>J~LOvU3()L1x1E3nJlKbM@qtbBfwW#}TeNK+$iqdh%MaruF& zY4qTyo*E-waX~v`yNSN{jk7-1u*Xc~XPQL2 zG>gbOv0lCF;lQZ5|sFNSj9V~Xtk2ATe#a|(Q>r0)9Do=c0 zw#0$af!AN{R%6Ql?w4bejE6u_4gCIM$D-_5oRCIB9BP=KD``LqE3e6t}n1g>Epq;dTmczBTUL#VGa>SLM{qa6WDf z<=;-iQxanzmvxRPA;KzZLo47a?pr;7QW&W}Ac;1`>D)_wMTzUV)lUzawPYUZo@*pw z&QxUaOW9@4u@cuizSTrr`(pTtSG?9NC=~?z#X!0m?%M54ioA19O%%oxx7M22ZWFuh zarU(Qzf6pd+6z|!luqQ{G2pJTN~m2*m(F<$U4i+4Mu~3Cnq~ zX{75=vobs!c0JYd^Hcposu)yp(&p(KY4d=|5&*n8%yz-hnuZrM8kO|XnuFof$L&U zA{8qn{;_3t#}ErSonBDiMhm7{kI-~Omdlcc81kYCXU;%Xu5=d`1y7^m3MV={$6lAS zXe;b}5A-c5XF*;gpeQc)4l8S<7CWQ!>pQ4jR&X%Yvd69CpPS=SZxbv*jjY8UlN{bB zcP*>r_QAL<y>6Xd1kV$y(^)g5Keryjdnjg@uJ{g&t&I>sIUc+E9)FQ{vJ1!C)KpE%Ls`YiSxXT zg@ZupBsojX0$xa}j-%v)3AO2=9h-FJTi67*VIv$Y#y$%|njD}NkYx8>C#`#tZbaSH zf{3e8mftp^mKlZjW1WFQAh4hu)o`$Id3k(75M9DHtM@#>SY9Sw#kEWfy1m$Wn5dD% z6GhBmBk#kRHy6f^HxJK+mPeOTt~ZMZIRb`rRuZn4nw#G5uf}$LIPDC!@!P+lOL(wvyb0quqZrFux5#ZG22cNPg&&@|exd42mMw~hm z+a_}8l}P29Xwe5m&%K++kn=XEg4`ju<{DgifPv`xjpvuBL-hMmHzz}rvN_D*RNZcj zJ7ZhSyUrz+`b95|WMElr>Oy?9LD!fKf2WbZ=C(HR|0Y`jPhiBk?wa3dDm{YN&bWcW zbp_vL+8Zx3y9U`+%vcImGezA>i~$hu(Rq(OEG!V1g-v})MoZT+AMj^nK!5-I#Nb&z zBmaPprGNe-?b^26#*rXF0yJ+5MOpG?{{KUlT~*xxl{x#c>zwfKw33Jgl5c`ZLFOwe0lYb2Y@1O6HZ{SN?K#B9F}1|D#&b^sM0u@UZnZ7R5X&M=260DI5aViJU@l? zVU@lDhGl0No47%5q;sh(rq*Z-zR4%Vk|9GwiidoQsUSn-d0=1IGoK0b?<&NOkgXBE z*yUCOlXU|kzDgEc3Ct%RL)b+v2FpD})od|-J*#=?=?!t>u&TP;)a)9ub^NV>o7H)5@=d8zfn;G7a`G+r!x?n>Lz zochKu(sWr?U}y)A+U{^uA)%*}M)lRm4L-f(0NF$JzI?5Fzby^rzJDO8#qM{_%(m+3 zQ|g&|m1q*i&FmbAc0r7GcuxwUxo&~q4pi7boIRTca;;p-d+S?QFaA>-&(NxkJdeK> z9e=!c*SDoZ?b3DXE-gt-`(D=;*>#OgMf2&8e{l~f=y-a|b|fk{p_vV*e|vsYQvvaQ zqNt~c1|ds{X|I;KWo{y=BzzXJpMiv$0Q*TNVkx62sV%jTNmnp66V38mW27aG!qJPT zEXv*S%RR=nCPuo!d80#Vel&9!+@8OXYkPzM0<;%lS2n?`c+3qBz!#i$%ogWH*yZ;& zn6A-kEQ|;8U~bp&tUHopnv~;fJn*47Ep!6lSf;lHO<`zq224paGc|smSElRlwg|)0 z2c9Thc)CIwlo+-k^9vgyFOp|j7S{J*%?t*hFg!H{|O=;%CpM;rDWp$fytx}-zR{>Zh7_|aC5(`Pa&@duB zN`y!f(mh|2nbFzPt@Nera#H0w!j_Mih@Mxiq0`FB#gX+4T<~UgFksS$JfRJPYEWno zyV}?xgR}!&0$0TT^cbF1SQ?9J z1&~ibIf2&dbx}(I)mb{GLZCa&nj!bf-(uGRTZlNG4nS?JFm)Bp0jd`Yft?dq{ObU5 zr}b$Vq7-mJC&QD)53ffQGR4?gkz0@GW)C{CeYvx#d3!bDEX8^JhS#{o>5J3& zOHf`1-mi=6xRHB3uS)J{T10CF71pSrAbY++)^+n@Vax>YAR-1Sa;pkM>kz<$1OFj zLDP+ByXwd;^$o4Cs^&{xvG}btz+bJLIS8f<{klYk_XvV2MP7k`IE3;k%-Y~~vzvJx zobnvVKXd0>a;+Q&uXa4eKVt~Aib(DO?rD#lb@wuJLTt<3?2BFIuo`A+23_B>-XnqX zuu!*!NDGi2mV+Qo|B}YmN6evlY{;`_&{|(-D$6piiSMK|T2&tmyT8M)!lAe5-;HpN#0o!|mtZ^cQM6LEHV<!8=k4jcXqM7E81r zJw0Jy88A8>y~0MSRgh+xcl`lXRLE+9p=xe=HTy}*JW7X?b00|^=r*j37z1LBl10OW z56*@`y%wZv7$|G->S{4p`gn!yZ3%Hvoqf}MVEG|>nldh6nr$;IwL=)u#yWaYEHz-4 zdtyg4S&AI%9?{iQ;qmo~`X%~*q;e(_8d@`WnuaAGS~o`HYwE{Wvn;-hrZ4ySdMT)j zk1F)1q*`qhSShoI0`XyLYvyT(QfX7GEfI;;tL;JE3%#Uwi*J2{=#FjB#_BVWgmJVd zq4f&T0vKme8YjrMgc)z%7==RFB3#;#r4vK}Z|tX_0# zYxKgf*^GrnJWFX5%{7HEqAorz*@sg~WojSmEpm!o@l|+TTMMR31jN+6M`CteYY=YB zfJL#(#Z@C8kdFcAAG$sxomeOlnnh=obKwN8^PR6aEEQSNgcSSX=_(8_v$JJvdO4J} z%ij6h^As=4o|(I)=#@OAD7xa&>?lV`NMs zOHDMJ7kn%&etU@49uC2MFX5HKgb)e`LOeSIK7gd(KSU6djOm5GJGf|gz|2_ zB;dsJbg+)_`B3`g(|5cc_e_W#HqhPkr_dCkjS&5 zIytO@B~=Hp4S^@@a8-CD2EDr^dSb1hLNnYbmM{;X2zZT#Vb<&3S6Yu;+ia>J!;8f;6t%1zdL?_PCx}s&s{SL%KR83DC`?fk zHNJ;8cChBT;LAERb2L^V0ssaQwn=5>q;)iiXaWku4S(%%~3WqLMw~5M|jC`b?!JOwNIDwfx}2 zi|?91j3(}>Fk-H8+Dv7-YO3A_xz$H|u@Ti2N8iMe$*J)!fnAlVAbn%sJ*D!z*B|oKoK`2h^aV4^@+7q;m|oNV z^UpUv=WV?!BchS!xNpe^)@^JC$G(Q7rtFfh*lz-CX8N;-O-`ZVq9Muu^yhOY0GsB? z8(PAupp~a`yc+9lws;aaRDc;(HUNT3nxa?|JVSX1BIsxMx3SmDdnlN7p7pNBENGKdb z7Y*0T;E7q9fnwDv&kXSJ&J-wSNZwEwfI+FX@tqhAUdub&SrIhU)p8UPkMT5J$?b_; z97p%e&1CA<&}%S0hIO`OeU)4Xk9X6u`kRnUQMbW&kEOnAudTO7)F(dUjaq7zF117C z*Z&X0RaqTQWO=84f9w34!*sG=uTQ>vwC6qAo1_|7RaI>!HmysKmJfNyMg>4O;yXsI zq~6J}Y$9@&QI|Cq`pmibKz>Y~h{JIGdd9C`$2p|zE~=ub>;9_ni(o1M?OfW>el97s zB<`jr2e^b|xa<3Wh`j<|d*qVd7Ogjt#_aYP>KScsRS!!lKa=G_ypyh(8XK7Ytg z$bCIL5BdoNe*CBXWX&!0EtJ&wJ#`oSbzFpxH+ z%|_Ht(zR{qP=XYD!%%vyEwDJn;|Fo-x#3$m;?vjiePQSre|@ zJhbh|xZ0uxiJ#{=83#kBx~YP<@ph{^v>Ynlx;wu^n69-Z!hI5K%P=vAX#%U3?R(W; zL~^bXJa)BSBt>7_h#1D9v?4?rLT20St`w}Hq>#X|ORo0p^*QRGf9Avfv-wJ4^k*fy+|X2sJ5&BH{t+dWiUhP*Kj=2F?o zsgq%!U`No$U!v%yrRl!_HMhl7c0JiNp*yK-F>*5Du)14VrZD*~^Ra(@|Do$jwA+QFrjnJHz1g$t*LO$B4Sk4B|b<<#fIXTF1*l!sfazHk~vS zS~!AnL%go=E^(B7E9_Qun4um#7vPH7@5&5PT5PkgF_lniUIG)gr_>?M`M6+qyxVa3 zo^f{YHSca?<$O>y5dQhTzrLB0NWqpWCr{GzUQOQ`$82Ks}~Fv^6wxkd^!HJ z0cmeI%bMWTfY`iB5IkF2WqIl4j5!FI2jTPs6%D{?4wRoxV*2D^>%St~imct0lk~R!t-kMDT zDB%iw^!@Nuc=DvO2!$kS&O9&^s|s?DH> zgO`cj7ML{1HLZ6wzh=;?yFQCG#E@Ef_0gcRUzg%d{(~`kqotO?wmO+6>Y%kTLysn0 zzAZj3t$KN`R!f~D`}wSNL5m26(m4F6ADe2MB{oeAsqMh6sNJ0lgj!;`w3gc@Uvg$3~34O+%slH35|MN@!c+|=BigvJ|DmTz7V!jL!WgPkosHj z2xtOjloKjB(anbp>lTrk%FMu+f^WwmE}XHn5Lc5t-^h>YLK+CXf=+N{A42;yy56{G zxOd6$8c$fyyL}mngY#nvShI|uacoSe__Q64h+}s6f0zEvyO4yOBNP~#0JZ#X&6kl zWi3f)bg+WMomr0$-B=TjPeLoDSm;8-?(UM#K(6LkWQZyjdb@1_ce8r-=LUa`@ zMnz6#D^BCZ+7(4@lesM}c4AMPjubHWMR+yAbCglOpEj8kgY#$8eQRZH{c1t?)d8!~ zMHm_twiPpl-i=4bQNsp}bEM+gd`Fw2BSB;txq(vPBo>^A!4nNe+h%k_($WBXvF+zJ z*S1dF6{|F1qlQN0S&>=6gZ76iZLR^o)I8gH9!z;-v9e6I0!&F;PmWcKH;TZIAkBhSgK3;x_?6bxbEUm=U|5@`dYM`S zP0o56rK?_%*mzXkXcgnt;8qH6SdE`gX{29e3{B_I>okgfm3cJsK3;#*wraA+{~KA? zk@icf>W^7B1!9UIxt1yVm9lQTnEz9XCztV9l8^E-IR&0Pbqr5FDAdwd>ne*FWHgcn z3)*_i9pcXtig4&KN^bNmm{W-<6DldzWhQZCR3#&W(N7qYPM+!SYo@U7N;;2Oy%ecy z(*e6?tbCFV$1~`DgeEtnG}g82pODB_Gre>l0g{z$&($%yxV86Wit0{L&z~m)XAe?a zGw2L>@%6A%jp&PZT`{^K+PeWYeNJA56k<6yNezu=*HJ2I9eRl%Rj+&XbegV9#Wl|q zwR5Xq&I(c)WG4)kC-?74Y+QBHL{?;{3LwRB)2&XCeRMogwsn(itHIuILzZ;7mDzQm z1Efr`t2`RtkoMBAIe)^^ zoX3ol@)3`@i4c-~5@w{@OM;^ECUKX`n6t%06N@!%9jE z5$+&6(EugZj!=*z-_=7{iUciT_EDP?_J@T*D=J!L!tVTqW48CmjKmdk@7y!^mUr`P z4JWk{L)-807Y5VpkOl`XqAiiyW$}!S7*y^ME70pQOB1-f4Q?-j;v2{ZrkZTvmfs~X zTpP_{n`m4TbG|*4Qv*u5ldx~XeV671q&?Z4tt9%kQ@(=5v4&BS zHCJ;ptAqHzmZVERO(EQjyi?=E#cF$DDiv+DzE)nZ>LbUIvPZdvx$dOBH5nH?H=E`pM2MQtjJcRLW?ze) z%-@Kq#FGu%&_sNP@|tp{kDsZ;v<-}g7K*J>&2pOksP41Q1x=f@08>ZdqFLv*S{HGt z=*8U2pEBTPeB1;xS85xpai{D4#x^!2_r%YAKRnOfd3#&qDCe$dqfX_3XS{5xcbxn# zZQ_5MfOQ%`drLzbx6v^8!i`hS4WmLWEQ)@N9%JJ1kkG2o2!^o6MNLL@;|6EFDODYM z#~dqZvNURi{MU|<6_knNfhC8Fi>w2sSVUE|3)6O{?=1MpI7D*HiKAYRoV1`Bj*mks zz-l{OUV~sc3^%RJjNWqOY*0%NaJW?wvk$)HrYeZ6cjag9F}`<1R%HS^4hEb%6YVD_a!1)xXnsZ$)r3y zBe?$;xf(sdQpRImVFLL?js{9U61+hMf<4Sw4C6E3Z%TD@Y%_Mm@}Y)MyDY>L3?vzL zQGt|wL=q9T??hm$ji4U2SC?l`Y8#Wli>Jp*9RcaHxw=c645YO3m8FwI#!;4(x=-b- zd4Sny^~P95LPNX7lnw1qFG^y{H#P*D*hW7N)rpEjzXqBB0jz`BkIO^)T(iEoi?7BS)a5|B_HcVAXDMX(Ybl7%B+HW zU6XP(pNO&VgdHS5SZmi-<*;Q(J7Ndqc|MgKeE_eM6Dc<;OcQ3#bXmfp!2!k=ROy_ z*u%S$FMz2F(>E6uhE@iToyHuYXU>b?G*r@U7xoT;%}`?PmV*U9aK_DtMPZF-S->E9 z9Z@p~xHjHuo$b34t}@W=Qe~4XCSn(&OILSRVOI`>?%fLS@@O=M#Y#9}hsc znh#tQT`L*lVE|upEMuay89%>06DI=<2l4>(dd_qCKt215qtb2h<&B12?s74F{B*Aq6w=yn>p`Ne6uiYRcF z%`#n#qf;2XH^R>j$aC{GD%GH9JZAbyw)-MH21n{n^$cn}g~F5gD5)?#$*y4ktpi zk=%KyPOtnyb#z&w4JPt3zA5Zp>3xB|-&A+7-Q1=tmdR+tJJOHiptCyE} z9znOM)ALD#UB8F<+$DT^9h4Gm1rl9Ye8F<9d86ol1EPe|A#)+a%GvEnXS7Ckc1&F-MY0n;90yd!mV;-OCE?$ zlMoso?hk30UGH!lxNsjEQMNz)cy%{mQcz%)AFk9&d*b9|I`-pG?QE>rWv6q@Gy&Kl zm1~7Ru}cAok9W2#M71vht+ow7yRQXk9dT9QcLi4sDGay9 z<$=>q>bZP$-K7~K%?zeFp;2_FQ3*f}I(t`jk$@e_Xx(XJN{1Xp36mq4W_HvM5@vA( zCopb`{~#3OiyX)DhwRoRf!b^x)&9DBJSLQ7xAXF@H2-gXlmbU_q20qv48j$P&*iS8 zur%>HA3BdN6PF2z`IXuCVEl7-ogfR!H?h+EI0p!h(=K&m&}1LyNH!pG@K$^IR!hxs zIK*f@?Zm{%Vn4Sd^x|juhFEg+>k6skhUkn-j*}i2l@V&`sVO#ka#(mL1Q{ZK%B-)` zBvVs}k$xD@>Wkun{Cuv}6wIs^B)VfO!;*$YP4zZpcY8(Pd-bL4&8Qe#@GLv*xSh`vwjY1;D2+h5w`tYybK zo?GOHWl#?{Km0Timzt9!C;Hn?Cq-pOrJ{6H58tQ|FL{xbG4fQ=L%B5+VNAC4$ZT}B zD%#CV4^>&M;l>h|w`pN7kGRM|ZAZpMm(69FFN@WWOUaw4P24-%iqcPu@+Nt99iyUz z0*OU6VEUW4XWasf4%%{T3Ff8g5Uldqi)^~ZDbBg`HJ57c{^08DvcvJR2yRxp%}Csq zB{hj$tu(7K3V&RBlMaM`WB{9Ty2b9)=n57+Bp4!J0$G(>Q%^2=yFz(+`iRr6k~GOfU5w@(=o%9_yFcqj#XdJ zcw!Hc8Ea{HRZM+`C=YpWokK4Zp~%0$a>lg#wk(Xc0O0GUt|gmxuQP zuLc?acQ{r;m4i`g0j+`kEGEQM5oq=sEMY2XE#Ce^GUKyp{B z8fDnPAvNeMw&6f6*^?yMlF4DCWkSna7X(I}bgmH~;~4XIKYntLJ#ti~<%j843qSv6L($|M z=xi>yb}d-yO!a6PMEh)Uu1gsB{%46fH@pKL0YEONDCbpTR9+l7$z#|kGl-Q&`28kB zT?l_kYo}}tuxsF#QE*wEJ48KI#zzvBTYE!*L%$Gd=jWrM1mh;vZ|Lq|PtDeTc0m^Y>-C`6Mg>EP!hsu&8s0P>zh5z*6UsUdp`lCc*L{Qh1| zpmVY874P7*O}LC%k6^J3Zmhgrsd>z)NSc;-?RVjL=1ym}A>ykkE z?agter@xg0qMa^ZHhH8tVE-_L60g6rGOG~m`+q-AD!v@wRc*^=%hmP3qfitdI-W$8 zmT@u)Qy0_FWA6G0Jc+6w2WxO%HTUUD8z+UR2P0L}XF;wSf@9QJ6#PtW1-Hl^hh3F) z3W~fY9>+@y@ae>z-*C9)hv&<}b#58*H%7bB`Of-2FVS1gPPR#o{!YJ+Q9>x0l-)wfQC0OA=Txgy z`;H)oCa4Z4ot$GmofWC2w2k2y%r;;`1xc()|?YoLy5d z3osnxa-ctAJkox+Y{}kZe)@9Hz2n5VvrJ)kvC$XCVPquVzjO;pX)2;uhIG941W6Vj z0gm}z02@~g05)7j0PUAL77|G8L4Cg4z(p*ETV`E>#a>q`q)|>-F7-QVzo}FjsO?G< z7SS67+E^&>w)aZ4RY1K!*32C()nl6}AG)6M@XDt}kIlW^NR|unZK981%^6%F^vd#eo47`MB;hWV&Od&W{=7={i zX-&lx*S}-px;v?E(NrHc$}U+|rY=q}6V|-Y9pn06&Qv=YX3LxNT!}sukxZMr{&*sw z%xh8ljKexO`Fbt}_EN?)+!$zu)u*w7xfha0B}t1Fg5`?dZ~#HELomLfvPaq|hGMCz z0g#N{X^K2ak;X#=65pEPR-wb1!v-x|Q&^s~h)ywzYd<@%ZfR1%1il|q)@6$Qb~P}G z>j$M_G#jx1P!qLS@mmxwO2@^n`oyB*p$2$}I#9Lo8rx#h(6t_suV@OlEsqp(JL?qI*X7MHxc-|!nN?5tjYZjZEYpru?aR-g zqeCVAqkcv^zHYZ#xm@0*M-4uSQ1G-ZZRt@g^o>3)2_>HL(gUHXf+joJ9)zmT}Q%FIp(CIRmP$8mDcUKgEHU35>0 zI@V5j%#jcY#3`uKQ&HsJ(_Z};c?|uLz?K}Y7Q|yd$>G>g#1U+kZ%6(hS|0RpN;-!@ zL@?_SlBUujoiWYgeX}!}bNGS_q@$WpzJ31uq~jD))#szh*8=D)EmaPCQH}B-(jK#` z5nD5ozLXQj%ix2Rt!>5!T~0H8%{qf%=+zF8BYHU+bk1y6_mNT|Vez@&Uta}ef4@Ef z$5c+;cTKBw4eeZ_4$gf35>3rk25fgZ^(Ly96LnauK;hyTqAWUqlVx5ct4TFacVIg3 zgMuXhe}OTBE`;H}CPitL zGl}L_2v!JZFz{v<3%Og^1%}ohac}El*vXmD3NG|qBtkcZuZVFOky|;anTNyU6irNJ zFg1eQR7U8M1Wlv_@td8-!)cNMI8>dkx|KxuV&1+nz01?Ow9mwL`EgeF4FYWRd8jiQ zrt>i2KI3|}V1W}qpT3MWbZ8MT;;b*{V!KYl6@s;bVzpu|Mbu@`;RAD-O-SRb8nhK( z#hw#DD_&}YOgLrPv506LCxpgp=(C?nzj{PA*VF96N`!qnL$i*)xVsr~)hB~6ko9Ye zT4DEgn1yCnn^$?YTzWb=4gHDlBCS`n737sz??a+&o+Ovnl$)!SS9wT8Ud1}Zgd5JJ zHe8~cuXVn4(cD!B%&C;_TwSQH!!~YmZj?>qwSCtK8!cj93F|W;Yi=^Hni9Z|OPfQ5 zR7%)Q?cAxU|% z%tAC3(c61p;b9^%joJ6U3o!>QhKH9bd{y+zr%cdlB~7q{vYt7wa&3&K#xAowJwu^4 zR|(<4uiw{Jlb@LaIhi>ITicHsdAF1Ct@TAzK5xjW+=F9QzI4QC%*t=Pe|;iYV=w0o z>|6KGv9HApQ50X(EE+x@cC2SGhCgNpDTJ{cgHyPR^R_HJ(K0Af8M@ zXLSk5W8|svthkxhkTw&5HSuYyDfV_~W+TR8J!EXD8{*isu0&ObLWcHMyJ3#D&sDY| zHphn!NWBlMU8o$NZ#TzVmG6}k@vwT|N-lUwt561sT;&tGneWLyf>m5I`PW!Em*)~e ze5*cTe&1Rsm#2UJ{5(~#yE+S5D3Zj6_}wA}TL(uCOv)9Jy`bZ>6N?rm(&JdM-k( zDz2K})Lm6E{c*{LY`4sgjcyG`-I>gBrO;bR)|J41&&*odbTQNe{b2AkAIv=#xIv%N!$T7O42D&(bZbkF4F@EEB@ArdqMia<8L6A#u3 zPJrSy3I{!);scDg#8n zrb=)Nws}$k6dzrW0ke#|zb}>D6L>KXb1bIp8NZg{Z3tx*7ruk^(OVg58KHq6v^~9$ zwXrKy>y^rn#{Pe{u0**_BnmP!fH*`DN?dZ~|37r;;|+teTa~TYL6=syuUeE{~EZvbbV>DFV7^HH_ISF|Lfl5@+En>2wJq zEl}35j$kc9zm3E<+mz0aQcVJ(5?c^`Q?nB{(_7R=L=Z@=M4r9abt=gMqE=cZqIrgX z^xlf$LRvr5U%ysf(9a`F7tcdO5B2p&9%x<~FsaiSA|qhrLC^}I{paiD360^pxIcbI7HjH_N;B{1Vd;;G-YLaoTPypol#y2CbC`ks!}wHE^|LTs*T*(O~tB!a0q!OX>BMH$PAox>XE z{I&l2#(MIc>UjSXyRuUREHjhp500Y}Su%KYZ%m>L2|vV>i!N>nU<+%&Hi%5n?!co| zr*!lYUL{T*=r`sxt_PBaG2UC$Z4c4j)C1sN!`wYeRorEJN+tr%J65_owy_Xlt!n8- zlEyQNk@l7093RANWX;z?qwn)`0%Xi)c#iPjZ`B@U;A!_6WvHaNrOnEKKF2mhSq7@- z>|oOZHC-M&p0TLVORGwHFhPN#A;985KEF11y%s}LNxaq?CcTDHiSb#au=mfZSjyTj z9P_m46t32!t7edUVI)~QI}36yP3ft&oYnRPMTGD!D$AT`hSCM3lEqmo*z1xW2)LIU zUO-hvzu@r|{>9Y$NYGvR)6njP8tPG{Qy62N|l%|ORd3jHb)K-8vm>=%s^BOPj!*mA@PrzO5{^z98Rw=j@dP!sqTDdt%~R7 zGkME*o?9ExJqh{N<2OZlf&M;B)BklJbX_a#dfWkV+alN&B|LttfUo~Qx;s;RH5Ffl zh|}HZ)cunU-2^-TK=<=)<=tHoU$>RGZ{qBWxo*N4R7U3#S^}LPIkoXwpfA*2G;3=- z%auL3bf9|Dh6ubdSB>Aa(wTWSJ9>5{;Qit>3nE`)NT6BlP4kKBHXz&WrP5N2G=35? z4IM!qt-Sn zDw_4dW1X|qSC^b@d`d|b4|O!>+EUott4lA?oFq+FdStq~483L+X0;8ucOs7|X4MEP z!O}j4kWJTJF{UdJHF$VSpp&#$+&N95iB6(~nPmcHHdC|loO=!2%x63#yNE3i9d+lV zjkrlO4pupWs%pIbH4Gk{m5?+k$H;Z&LFZe*MSs@m67hM7BaIXezs8z zUk_ z8(}!YWv;&oq)JEd30SrG;VpC>eDD)OXJWCY#F3N8I2R-BI+;zE=Il~oO4eqf2HJ!3 zWp^6XMi_?QkYU;S?9xNkip-kH+OgA>OyO0MPf6JzL+PHo^;N&kKc6!+D^be2Xy$Ra z^cNbd-9eO?tL{$v{xBaB(kU)dS2}!AKZrslwlfsmA7QktKdZb)=R`eUAZAD@47@x~ zK#)lz=7ax?v`Z?u3h<&0#RW@etdc3I25Q5dV;c;tl~y>R2zkrrsX(ojjlvq#j%Ai} z7az3eZySrwuUr!ZYS#*fUr~E13P@5UXgy^xMlQEjxoe8X z@!>?DD`{qUi_U|29Wb&00+2K*fPmV5u32hQQ<@d=3=&Vv*()GW&=-MJtVTlDf)p>w zB&~BSu<@Py2+l9R|9-DgJ3z)dY^zHkA`S;{g2z7Rnnu}Qnan^kjKa#+Pmc|1mL4g# zomytTm#t1n;{0O%5_?{{f^2=+>=IJiaFNw%%y1alhV){(g>*rB=tTui>UZ~OcSiF~W_$=o`e7${Tu*n>SZ825Tn=YqKCPT%%Ey}3G)_0358TJa% zy38eXFU^>Zz!ss=Y%8{2_4U23lEBJ!^T>R!Y!-fzGjia^&4?{D~~TeRX1EY(9u*cDEnv}MDuiu+^SK{E?}q`T0@Z9;Y7LzXk48~p{;t{Tuj&GZEpU! z_c*k${wEh5A=6F4LwC1fH6#Ew`bq_fYGrz_P1aXql_xUYU^FOQ>_xTCb8)KFD+!oF z@;->OqYCSABo{L!IahnHPc@0Pwe^mdjlRm7#1Uu;e^+hE_Wt^MF?7;zQr)D~(j)d4 zGO7-5RsI`LbfHUc;XEaatxm!yWH_g2N?aU|F?{hn)ro|&G9!HE#>R=hJfh@5lCR_7 zhDE6zyn|gfq+KYOTISu!SX4#t#KlO#DjLA_^g5FA>8?Qb_cG%G-vPymJIJU4c7-o> zS{dG?Cl;oA^7rt~Y1 zn(5fz>QK$yoj{qNVnunRkVVnu!wKkgjbFR%N$Z*}5fxoUHHI?6v4$aZneIuH=xerD zI59EPRS!}y(7h`q36)>du;!$Fvqa%8E5WT8y&+u+Ib+f|7Ir&tj|vrulxcVZRZSTd zWn4JFt)to&B-IzRuw8zPy4+aA^<%ZsWC7yE&`4+#k1GKeB{W&q;F#NmisM`t!y2JH zA#)5x4n--K!&eF~vY(5>DP0&`F8$I~wy$O)0iwzg^DAsoqfaY0`>^YzNk}s3DLpvF=QajRm z*DQ{fkMqfg96I8nza-lV{A*nNu6k+JIglDyG|=CQuQao#Tos072k#zsZS0hwcoQ(?a9tAwJNFU3oVtJc|S5-U~X?Hk^0rUKvE@2jua{^7jH}x{Ci~P`@__q;a z9Y>M4@$wzI9U=HJ5Vkp{%KF(rRtMG>;H34a%_}Oz*#v}2|tBgr2s~))3MXm?8x>Q>4 znC(QnnbxI6{zHOgBzc@4*bfSZfrR%WaQxImY2arEVDTGzQOSjZy@qH%q;!?`%Az|o z&ZOx6tv;v7+zHs6d@Y-pXidBEe{7xMdg8beL~Thnwrqoe%q3sm|3R<1s#=nh-5;}= z1SWxiTisoCisY=8lw<`MI89E`v|2{1&I<}z)usR5RlOng1g=^5N}OkiqZ~Div+}tt zzDV%|1iYRndh&4YG7R^ooT8QL(%ELu)i6IZU=XaxT!ZcB<}PvIF{6;|qBmEhbE;!& zh3(Sl%Aqoejwv$H9jpu(d(olgTxXxNS60eoCD?KBqkOix_UWnzO*l-U?0%y_cm zief69YxN6{IRy99(Uq?st$F&M9vvVER2Z@(>bf~T-d!n=U2kp!g6l<)G z1b;G-mF=f;e4{5uNtez;LuRe@Y~$t<{sKI@!%Cl-cu$JIPTrmqjO+?;Hqm@PN6w@9 z$hP{LbL$#jkieHuWSnzxME?;cORKy8u>38ztFz^ClDM|{f&DWufDmk`=%i`6XqbD+ zb5|KVrSo6zMIWVf)hhStN7p}^psGhn56ho`!r_wM+fTx8OV7)yXz1?5QHy>PjrY`O zZLV)nul*UYd!O&)YR?C3krk^ye4>3khQVdf;L)fy)4N1a8R5_~U|3INV$oVWQ-rk& zMisnb+WGg%S2bQoRs^Yvu+kfKijII&MSl^C6!VNa(LO!$EOL{~FFaju_2iO75Omsl zTb+)T9?hGzd|(e+qRlDw>B3Lij%@#JBkWNgKGVZpK13Nrhihz%RTn9IE?FU-%TvmBb)yIi|4T;b!2LMX zlav~LD-JZZf#sS}WC)izCuT3qLP2Nd-8;h3dTb;F(V64?E2)jVXXB-~9Jn|%SAiyU3A>4@|*flSUMAxwAW)Jw$Kz zNJ9cHRZ1Q5jD2UQbgQRCWkLI5J%mF#C&N;sPUd(V9<(@XLJqmdmp%H}?QwZZipB)t zs)0|YKYu7$QJ`|O;)&FqaOSdx9&d6 zes8kqs=T^s%DnUe!Q5>-2Kwq9zAC%g!h4`aquVq0Mqr#O`qYMgY29`37aGaXO&12w zHkt_Vs2`O7p2oUgMc^jFa;brQoMqE6j5e6w94p75T>;_2nr!uP=37jSF^xYM(rJa8 zxvgzYEhbVLXJu7b46e&7SoIGYta2%`ZE^69nv4(eHPkGN17c!pPMjlYmng4K(zc#^ z49_mu5a^C)(#$?t97K>g7?{k`?ZP#@S+IdMxcB>R;N^Y){<#~baTz9y(Z!)92IY?x;&sV~m1v+1AVbV3~mz|tDoaH3B46gT>35!uO!~m$|?RF7H?O}PhlR49SIO4q+8HWk6I9~2sXr4fXRjn z;N){Hx1z?9S!)!E5&hDYOXC zncU==eSpd3%j;|Vr_`&X@y8AN?%On zqE{&BoL(nL8Yp67K;yd20TJYnSQ|S6L(}A%@vCq>Zjq^l;<*_;tp1jxR@R<2n2D$M zv||a@X3ggz%2F1ELz2<mIG1dSx=dy{~^z!Dvt%P@@tXE%|J&$q(8^F?19Lmpng1G5R0-kfCNZ4~c z`Xq+RS3#4EBK!{=F2*3b(KsJIv96fw?8|07ULHq0QVJ7j=oRLcuw|!8@|Jv!!vhMZ zOo_bvsUuG|SJ6dQ4BSM|tXifH+t_qW-Nd%#Ep%#WHMqA%U-k;ey>Med|MmqfUWGlm zaJk(}%Q7xq3d1tl)%SM$FQFBK+J^Si4Xyp|`s1lv{~|D^n{g}J$*1m>()nBAr5Fp3 zLSCvU&7Y)koR+H)d_c3?aF9*YIAmaxz0oi)_6$#WGsk=6{Zqz$F# zz=^QE;^p*Z#-IwB!LD*cw zF$ayD=T?7l&q{+vR+9J2={ZezghMRP;f{?jLWCG-K%~{<{nlF8^jW3MZjYV83=jLl z=Rvy?x@L608&}1pLR+wK0K3vOP#9(#*Eu7=&`^pI4RCpHm8Z#SHl@xx4kH`9Pi85$ zoiRFMBpy;Uy))0D^n~L`mn=%QX3x9&W6><_R-30TFoI~RB#l*KW#v_PJ#^i3YlS^M zVXTBKaz6O>H7*{J8WKdiD{-APW|mVzqxik1BI0U-lAAOgADPiGF)9_O{iLiz1SDCn zYm=Ta@$n{Xiou39_`Na~%rhMUrbM@F`f0qT;U(hLcmt%hvy^m(-_a0JaNr}Z~ z+(Z=rn4QNtch>sR{W1<)RzgFh6xxpyAy)fp%Te%93P)K9c|{R+X1YZ5oCZ2}_+42p zqDU5}nr4Z!-J+WUwo|kVp)HgcI%+iy5+@Ot+&VJ>L6H~b8&#aMLYkDe;WOLBj$;Ni zJ8&Cp=XYP!=a-W#;R^m@{K5;*Z}7o4W)UGf>MM7qZ=MHW(sj-@cNV)A$1f!cGmlA8 zi-2~KD5}F%b{RLuWK7B z_qyo5lwG5OyV>&9gLG@7=2oZw1Q;#78>yR1-&)LX`LV7rt7b*EG~ip!2zJNvFT+t6 z$+TRuAi4*!ApX7gBrlg$_i}0D{RA;}kx$E?)p$*rYTs{FdgHoQ=ab0GIQiJxLjj1` zq1F71LGVjKrd7*W^5E&SvV|?l6K?}auZWjqoz(m}q7fEu=iqxEqGlTK&e#9`y%-R# zOBRob*;E}GSGf`-qBuimW!DLGyCJi>S_mf#Gs%~&CI@FiVB-)~e=n;!psKi-%++wRxL%^*UehEJ$5WZjHG>Jwz$L5K^X76U zEP)M-sV>rVSvCAu>)feD81du9TGJ8d3HG(E1MZDQ0!>bBRjhxBZvi9<1F**a+PY%Y zaaP`yR>q{>dz_G12(Kdy=}c+>7R!b+hVNKQLtiQ|ZUOztR1>Z2Y_*a5!1M+tE+ld# z0nt)sF(!D{UW7md)~IGLRb?!pf<9R$(n&r}j$Nr+1tx1$+<}cUt!gOzXm+GkP?8Xn z{1UXusE1%}WTg4VELW4p&Rp~6s3mc9PYai_EYIGlVki5mM%`E=;x&0@n;NPi%K45M zdoz#$nTUrc+#(tAMQXIqNI4xPZi|SHEbmTvy!1OcAKE=V?r+Ne6M0a*n&|A#Y|ylW zpD+LiXcZonE@9A~&n#ADghG^~XUpabzWLoo59dW=KQQo7wS8np;Uc>3iGhVg_zIQbOH-0Wg+pnElYz=ZmCR z6|@fy9F|`JNKt??v2O4wamlN#~IfOUE6&Jdkw>K z^($Y*)V<^CawxeHKB*F02QAY%g=Pf(gk|TtcnZgWne<8y1$2VURPZ=M$(5`EFTOr@ zQIlPNupUN?FE_+YBy{#mri<6tzrK5fkshHu9;4abJfqRd7AtE001BWNklH7uJ5=9-=E)m>D zSilO$(q!NfT^TAf3tvG}7v^e2ZNcuoLDjG*fn)~xJSmtQqa4&!#2A)mI88tjA>qN2 zi)XMrwvqB1B0Bgg-%y^7ro}pn<>v(u#TvV7#VPpmvi!#4>+4{cVCjk% z{vJ_jzZgTGkBVP9bC_FZUnF~&h4`RS(K}S49B^GWuREkx9PpmL)H#(6h;6I7JcGBGFQZuKU>66*1_1Lc{wfrKU-&_+%}Q~QJ@bHCl5;+I`;oRbdg6j z0Ll@b7)z!kiU+EzD)VItj>QZvyoj91ybOoVE7cf3Ldk!aeQ#8wx%O-ke6BmbkRT<8N6aQu^-5QA|2v-6!R&=2*jIC| zx-J@*z#vAN~8Sdj}PXiXYJ2MGbKah3piiFPKXKt&j? zB)$=O7lU-j5%J3)q7?mEaa}Gj!fs60lQ9-=DfDP%+rMgZ-Z z5gB?NdTEO~S-zm?0*LxMAH=Qa>=C-=svI}zM(S%d|1Iu9TT82Rg+@|_O3gEChs>}M zO~^Af7N>J|!`h%E1uZUb%cF*h{boI|Hmm%=Mxz+zD{Fa34rJJpfm?Y9DGRTKteT^B z&Xe1Fq&Ljl_kTYgn{P-e^spaibZyi52z=99<v#q^~lo@svV5Uh{=dO{|lnPJ{A#UMjb!C|$NDML2Je3^rv^K!lU{F71ANtw`dM(KVHHh`}@3B>jpG zELIv)f8R^)-qm8N%u(}Rh-*a+UMUg2-|whocc2{i&)zF{nyZ{Y_ueUn@5miYiWNp0 z;hO0dCZ`#}gl{^JP-!1C+`tRy8{lW{|6}RhOYz>_vJMlX1r7!OVV+USRfEx6vsVYI z0};c3R}Ne+)5eq@dk_D3|6Pxr_Ru>L(1{0woj{~R7FJ-qQbfH{C2gu{7F4`F7a}7k ze?}7OBd|fYa;@gKCTfE!W?`n)Rxg|_^K4j-Z8YK3bjxwRJXR|{RfqXi6UT7wffcsE z4p@BWBGEL039Dj+3p(IFL|ADt!;)h|T7!pk2eT?kPJNM!spUu%BNcyg_T==KHRsfl z_M&QO$+-;`)6s0ltuCu50oz_1zGpEmf?J5Ok;10EBMo^@w7FIp%l%}|Rv<8o3lB%$ z(k>+x>{)mmo^HKC)`)j&ZL*LVY1aM~wf*O3i>M_dbmF(>tw{YiFkB5qWs6hJgj9#4 z7zY(!2L8xCEHsZcQ8YnI=9EyG!!Z@Qupva-!i5M;WGQb&iUKYRI z2aKZYx)1$S_ir3lL<4?uDo=jkOVrVY6nQDI5pCEO%(qst$IEv1V+%e0B4k}Mp}O;) zc)Zw|>b%m?a z`{2K;3hVwUWcQ&dUaYoKPb_F9K7#;XK%l=l^_vPT#uUz2BEvh(?SnvP6(;!n(Vj}UI23)2!jFLU?RWFeqz0z>3 z&Q?YEoXWdso3uoR(q#G-DOlbL_hK*?FM?GlM;%~7pXFin)T~QAG0&K3ul-*BzTRZX z>x+x&0L(tL+KXfBzDbvLZmguPb|aKoRDL1_SQzL+IX{Uquv>i*;*z?5p%^c zFq`jba^s+-rCMBcr?U%-D(DlMNXevC!Z$n|G}$s}=o_bI%+0Bm+KV7OmTQ|!Z?2uh5Y&2FQGc~k?6YRB?42m%}ZP& z@1pJVN4AW7p`lw$ZJzDU518c z>G{NXS#MpRB;e5+JL*FV0P)9%PzLZ=7#OuOh!sC*o<%c5^|f1!8fVzndN30&!Gta% zwd>9zrLj9Jg-@H-7KAYV69XCTF@u4BXaAm5Tvuh+l`J{N+}dB(HpEv^^HHa7N1+aL z?gu6MB(*xG&rv%YUHaBdmvO;(1!Kj{OXNRlygUiHJqe03+LING4sX~eH`HCI1~jRW z=~v2N{p?zdF(9u}oU8^HlY#vxwYJiAj{kirx?E0Ok`P`dWQn&X36xU_Lss>AJ^wh+ zEXDGcQ*7SOuX-$elf+vh%2=3X<-fI_FGJ*V*p}k}aMENQVy)M!G6InYlht1Vn|>nt?4lv1kU^l+hUHJ zTc8j3!ev?r+)ynBVp`+q2yZZ4GUAgI4}Z*ljU86rkZek`#*_v_rW{*PbNH>%ac8?< z^1q*`yIAOI@jAI-V%Wg^{I=eU45|S5m*lX+;+`sOr6FLZ>xmUrZ z4!VWfR83g5g?^eBs}b-S|P8qNWF0H1qSDo)Q;A-5$L!jv17it0gTG zHOnikO>maeW1br-yA(}JG~jQm;vtSsTI=&AMxa9S*Jw0O=~1z=ET@Jpb^X;mMnO}J z2d%wGVlayWloBUFkX@3Km3SqfnpUnr7T{rVTA_s$Q#0ALXn`@H$R}aZNd|mm`h9?r zuUHMQYfppS+o8SsKrnaB*n6EN-##IcH+zLo<@@$ab{(j!&PDik>8n4Q^beub=T4k> z4UY-B(=lW`@RGj&(1L(Cf>8}?co~I0=T6VNBQ3W;CE2Qp^D`C=%+aJ z`N!^089YPY6AwxSu9i#FScCuvb`UTnaWFloKbQ&*Q$=4#^O3IanqBrznJLaapG12Y z7S|nGUX%G0DhL#7xh;vT14r{jbx+I_(l|I;UKu(kB^auq%UReCu6{T7&(`*!JtD>7 zsVtvOYG`+2v5KCLwQwF{;~0{r29`Vu)il{UmE>qDA>nOP(jkaoIa}R4NB(Urp3!A~ z%Um`4Hk{+q7W8~JS_kIHo0OG*_;(SX`6$X0tiwk>HtjSO&rQ{=S#3%U?}32hW`JU$ zw<9@6+(Brq6DgE&Na42D&l#Uzc&7R5W`-y#N}N~AzzFjg%(6)m(o)K9v~d6aO?op4cAyohM2q4&nx(+qrUU+B*1 z&AT7?RG4r`cRo(G^M@F^`$t}6rxE#FRCs)x9cHJ)y7(~YYDC_jqv3bRvyN7%chA(R z7UI->bYnl;xymdNQ{o|A^>g0N}$9I%ii0)Lh>IX z?u%E+ki;tczQ5IrZxUy1^#(t$I(Lqtd7^Xo=duOMTaoamJ`y_>2);mP)bN!}$C6nq| z=tv@KOc(`Q%m(vJQ>4!f5fMa{Ak$+qoxr3fIpCKb%jCwEn_J$3$}3T!zEI3X zVZ0!C+YhdmBla5+dD}dI4avHhatMlyut5Rb8tFz4S2ARi#Ok%9=|`GaZ;f-=Jw|1X zwPT6eJ0&CMJY1V%hZ?0lCPL8}TJpLYB}G@UeskhdF2u~MNmb0P>MnFA0-X#Xp@-|Y zqCO;l6G-0_3_Dx2+pYwWwPxU5)qLrxMAPjUxB)7`@KI!n35-CuIYJSN*`%_Y&$H@9exS(pq0YZ)8vx})NaY&|(*=W|K@4#J19sp$<}kNV|( zSv;L;f|-SJz}M+ipKw%No#yPx5ncOi+~Pe>b9mQ6vkoq*k4VeoXnzuNK~USxrwYW= z`_%0nih2k8jql~8F?m@UVGs@^d#!ub)h|k+popa&ZnA`0JSt(Et6^2%9JbnP{($27 z`HTuc>ZWloW^t@*PB!*GN0r_W^&3~B@8FPBK3P*qsf-|3NNr~Wrt+C zv8SqszOGW3A{TZ7zv$G6MNO82jjQzf)XT4^wx;OFWy2sgm4mfLKq3YBO*};}JMhvqHg~NwTC`3B}zUvI(dgv75$|y-Z!BydmtVII+*1v^o-_}V#I1$<> zLhdJRTsdqx+_UGgSS{>9zT&+DAL}c?DSu;hCS5JBsL*k zfBi;N405yU-*QbFl$B{6pe~hy8bhvbC?xCqWu*lOZFYdWw~_2iq_mZCve-=0wI>f@xA{3W2m~VRY7NUX)!0w*bAnSfjMbw_VX16%d6n zL+G&QUMW%N0F;BmtOh+7H_DiN#d$$)!NHe@!N|wtOq_;2BkOq#hd%$Dk*@h%D*)F4 z_m8IC`%6fCa|B20X#hg=k~$f0f@bTb(f^D4Ff*%y-W?d66jZ4Z7;@^DLahkB3T;l| zIa19pW3$9CXCkp`5(K}r1bgL+=nmX}hO|NK7_9ipYdD~pT zR*x@A)huiwL`4IgLO5J=#k*ORMcTP{$8cXr#BmtzH5lipEMm8eVl-$gCYW2mW-tNiv-8sU^!Rr8N)loEcML~T5Dj?4<69wVVxKhLvUzEASx+7rXE`b&G< zhne*?w9cjyqRm*Kim6k@eH1iZ={N)c|9Y6ya^I-@%!5Ox;BpE-mr_Ncf#P3DQM9yf z{ClsClY)y`(>EpCUvgK}6M^4ksBY?(FOsz+pT z>#VjkxureKEbDZ*;o|<9cFLbeL4!q+8%st3*f`D{N#!b zQkr0lI>`Ht<+pM-VQyJQ)5`n@i^Rz#qPemzcxpyg*~?R9Z9Th!&tc3|QS*aGZ zA}z{guD|yD6(R%eQ|hprpQ=AffJkRLGZu9o{CR5SRcfS()8P@K86WqQow>roEsc3p9$qZn=X^)GHs~2{_ z8@Ijm2iG5%dpA`%5Oy60>F_KRB8>H>+l&Xp4Y$i5R5`E-DXB9FE+VBor+d;)*tGKN zzZWbB9E~%Kf5Hn4)<1VCBdNaHR6o4dtzlwW*0JSqO;>ltD>{p1C`E^1?)UuAR>1olRZEemmtzH`xb6>i!+(g2wdDm zNOhJ-Ic|DG=7L|mS?k5kIV+cxwNtT5+xKz>tgL8Cj0UgyHm!U?`H6&vDof+V=(OpU z=XABoIMSArK#<+94xe%Ww0E~d3vQ&=c{N|1n(QfB_(V){Y0N4lGuw=*bPYj-Zs0Ke z3~849G}j2jQD2~H@zjV!iPGW-%fbC+sxLJ5gsV!)mrmZW4~MWG5~ngaCM@0rDy*3- z5r3dUHwjRC4)qX?i7jf!vhr2Yo?I_5jDD7^zZhb%1ajnLczHDR}@Z;VIR{a9RiJJZIT0Npq_ljHT~#wk<8Pi!Dkn;|!d= z1)JsVP+CRktsFB&Jce+%Je_DW`?fl-a*Hs~uMnfV8QgKb2w(p1Ur3)s_!YiE8hBTA zg=qVW>%RW}r70!|rlAmKbUWtfXlQyVl*F6pW+LzfTI!18FXl&bcUxzs9`PF$ zd+P%+6%skoiT%Iq>_wFGpoEX4ng)A}Hu{P$>`*dZQuSEhv>wcBsc6n=n2X&a0{EV^ z2v*fk=#+tp$nokEh3Y?}xM72t}6<^_AmOSft__x!4|=ZOvx~vd)6uK4~ipyw1JyQ(fzWL!NVsaSYqk z1x;tLGO2~OKxQt6)l;|#f}^`3Zv~~n!c@`wsIfqku%3w+PpLL>*_y>*5ADOvd-WYF zjyNwWpYiEc@XFYVZ&%dS`_gm-Nz}L775WkwuVti#5J|a(d77}{)DTzFaYS;0CBi#$ z3hlM30I$s*l}NL~Q?CJ#j4sxnj*lJ&74j6dC|(CyZieU-YDrK-n4FzYQh#F5q!<~k z244hTrh0I)1}@eKbd8qWVX%_{?Gi~H1b7(u!(8$xP?OAUWqKqjhcB*@uhFiA#sggW zMZXlSRJ8xv3N2-IOSN@s3KU=#Pm3zIDLPrql^oPPkj=o`P%+F7rLklDzAle5Epa>ti{kUU=CT1=1jMKZY^y zRHaKrPCk$>Q&!ch?spD+5XsUl$o5W-!DyU!H8b4HaMvSPDP%Y6q~kyUS2yYKy+ zn%7F&pz-aU^%4W8q#y<-I(Ue_u6sT{fB*m>07*naRMDVLmTK)U^K{izcv1=ulb4CY zU#+qSO*Pa$d1cM|T^HTan{HR07?Ngy2%5hq<9a6xtWEg1I~G`>OH?+At)W=H`<_2P zMZATq%C;CQ5NQ2YDwB5AFe3jLpu8sILJZ4jv1+!P7c7B4h~i~aPj>{q6`|G4fxz%y z&g0gxMm(kfMW###i{La1pQawBixy=U<_mZHR#zp{zOfk)xR?&d+5XPS^fvxmWJW% zVX7R)L4fJqmDtYx9n^q4tT6gEC&ORQKI?2>iC#_ z{gY&SB;!r(V|KS#yIfXhw75NezqJ3x8+WhbWjqeBHR7=DUi9**u}<<0=n>2i2JxfA z$B^o*u0HXI^>Mx$W4{kAZ*7cIw8Tnj*q6WQ^v}KqCXORrumaxR-hbcdgtrp##*98xRlhNS&gXR2)&juNdxj{4bjE6SBAXs(VLinY8m)AjmBD;8~b13Ss(o>0GL zKCtYPqeY8w>z_S0Mk>Z2Q2pmPMy7k;@s=upr`JT7vsLjYlV_m2u~dL#>9)jeM5VX~ z12U!RBr+wAEgCcJ!XczEdm%CVATd?4R~OXjbq(jKyW?bQP8X8iWF6K-Xry8hFlKH0 zc4v85>x}~eD_9i6Rv|$5J53L+uJ!hDPpi8@359(~v9vE=BTmVb*)@F4-pq=d_mstW zoovaPCiK6Yr_nM5#s}E83;}ff6TU5~G{Xj;tc#(1w$Yp6QIk|_rfhnAO_`L}^>*d9 zX{x~(b;Xb(j?$}x7N+R*hz)P>!3Y|&r8*2>62%!$KH4>`ATAA>Ter7iB@H%kc4clH zzUf+g0v)n7i+U`{vi>H}AQF=eiqh=>ZBo{6qZop^7RefmSJ1sXSCK(V+v5 z?o$q<-xauAj#$c*F}R!u+`~r<#P5T^a4;=@aIr5Z9rWe5B&`Chs?}GrHy-pUX&#Nt z@ZBtoRoUt(l~^yV8O2NSl9nQKR-|Np!oz74H{ErNELfEpLfYcVk{-K}xMezo z>neXD?}=J;gI--n)A_IrUbYSxrStu!^a_a#D6y!vTd#Y)@-th#h35I%Ebm*%S4@=i zcBLyI(61Xd!1!|cciDq(UqVjRyu?UX*QrQsD89x9!i<;He-nTtar2%VBn`u1KzY?VcKbmt3amMiEtK{T1_p2h1y033ib2- zENUYwrF}ays=8ki<>zo=@avk0knjbNZ!mMMD}k0#Z+%o1#jE1M&0yiq)8y^Cd%A2Z zN{5@trWcJvd%?L?UY-#9y~_sE{?KsJYhx2lWZVlnp=oe{fqT5rvv;Mp-6q^5(Xk+v zs6tOuF}#G;MpjE&lsFSGS!Fn5O;udf(oE?2cqg@ zz`ni>F}06G$|q){YJrmqvl1Ag!~T|UxbJt2rc&qI==;4wh5_mxAw`01v9DcOeMzsy z8*8re1i#mZoj4?o3D_^GI;?G`1ukXM0DIBmQ0=+9nvyQgKs4NKKT^){PrJ%)&~ ze@+m~SID?!R3v`|ESo~NK5XKN`5Kt!D~idK@Fd%nQ$2!0W_YwhmaWgJ;au6lP8>{L z6bKQ$uAII`^?UzkJkr1sEJu$$Hu_}AoK@t{89@^ORs`wj8TpeGPCD0N*OGhn& z@3xMZ6|L_dcG&WYuq}~@rSl-^92_Hap51u|OQjUWSn0vxl~1|olQmbPaq0g2`R~6! z(skf<1zTRa6p=K;T+)iY1VTDJY8;X;p&j{TK~5En6%a3W!RbOVm5fDOzk4G(>c-D) z1s5ad>%t-eTBXAp=H}XvAHC2ZL!mJ`(x|W$T-}aog)Iz9sL8sNL`%(Iw+rBGdg+=V zM$SDNS$3fB_sh8ljZ*jo#DGJI5rn9Xy(GerA)D~gZ|8@_`McZ?qj7!z{mNNm@tno4 zlxffjg+6WREcy zwtTv^+`rxl$xPKRl-7#0HnF3t=u36YZU|R1ECrz?Gg_Kx1MQrsFdyeck}Gv=-N z#i9AZQ|-@vij>3c(gSH4u&mY+u2mZ7&Q7K%%?GtJp4AUF&`ZMLxr~RIbh>12bsOw` z|Gx1)h|ruWBcpIDmF$U|?ehyOvIek4v4rmhf1s-o9MVUt^<8FbkMp8^G9}bY%!L~k zLpHfJQwd?gy!iEgseC4Gf#oJrOPXgwDd8NBLA44kODfH>=yq>)gw5eFXT|gY^|1w> zcTw~1Kngl^j$7ww2Cz5nE{e5qkuyn!caGTLF`s77(nc#IO$E8vWZQkQ;t|9pVA8RQ zKBmy5d{N^~#dn+L9&=tt_9|b&OF9BJIEKbUvk%V03=7sK5a&rhW)AKKm>GMU>eeXP{C0m;gdEUSs6x}(r% zsYC|>)4)Tof@?~ECD)&MwskUlSOk|dM&l?${(xlFCU&S>*{a_&cK=I^hL zb|`0=^l<8?hk7pfwVgg34Th6MyBtp($H?Qzh{^|_v_3zYM0tv0aKZH|xa?xN(QWb8 zrdF}D)Xot@Fw$lL-JzJejZz4?{FRE@ssnup-%&R{>=Gc{<5HxL9*ynYaZ?Q+hmUUO zP*Dce*3y`w3)aR~9^WUEfE7H*1jBn(QIT5k*tg98qw7kv6E}jOG#VWvfdFI2j{pBd zGj;Sxu$#PWvWqdcfmKac*D-L(EbRv4rTMOR2Lp8&V7vM7xhc8NqAX{1)bDnDojItd2I^p&pr}yV` z>+1s&g(?zO%zj?#4L89Xp*Zz$7IEpyDnrIc=BQVyP`X~UG`=Lw(e;sTTML>(J(AqR z#A`^Ka5>>F8Tfg*QSU@OHp>WEdUWa4LudiB9Z01RXWXkLBwBebbb$3bah5Dv0P7N{z%A&=kl7x% zM)gbz>#XyDTTYT0S{rKkS3T~D15TS_?T9~uSIW-n)l{vUxC*>S< zv6#v}*v2~@Er8L^+K{ z{rUsTc_o=%<6J;FH8Zn-s2_t3Nmr$OtfZPrQs?1Ay!lP`nU1G%R7(kv36cw zBC_UgK0>hOcSrAh)-elWmzaL%rtez1H#U3upX|$5m(e`Gv__l~uus0LB}_)gl-s;k z>M}ab#OGh3Z9W9&HuYNaJeIRH+qASSW1MtHU1cy7b1v8UiD8b^KR(J5P&_tJ=1ur3 zxu|PbcYZj)k`5;K5Y_)&zL^l+48NR+-JY}>RdF?r=2tpkdn*!Kz`Pma=$Owk&mNU-DmX4a}NTbra@DYxl(ZW1La!6Ich z@}JUwqgJ3~!L~s69`RYJgz9a-iC5?^REz76lROt{sPs*DZ)>gHcr`1U! zf+a;8H@{c5ds$TR2l_h=upXNPG*{KKFb(&wPwSz-xLvw)O2wpml|Nan zrLmS8S}-Tpv8!XaK0f)ynS2REMz5f>R90g%BA%8nO~|l$4XK{v`EpgrcAmFh3%PRL z7sU$^X7*3EPLP%6qkSUxCtfB#3evUY7pm{H7-m;w!d zFlcE5ao%M~Qw>ZRnOyIAg~`d3Tba&kw*rnUmfi!;vy8gT7!;t}CVIrQd~D@u&j zm9(KNLTY5CQI^H}=u^&fap!M775~y~v>53r(kf$3Oh2|(s^B=={+-I+T6`F~D z2~4${tVs28c1f6|qmymeGB>+g0-HwOTrniQ)G!G@H&qml0Nc&CiL}nm{^LHI-ZA-{ z?g-hv$ZMCZ_e4In7fu$^)+^)qXwea3eQD~P8Wk)fo=X^P5w$H?`LD?-9Yf?vt-<_i zbL^2^Gv#9pw!rM}UO-ae zO0^V;ZXvjv#8n|qn*53_aRp%9MB9_c*Q<8fcQMbTsI^PC+MByvft?y697yeR5}ir| zWpB1V>uHjciLb5vTe3`(ji8`ZeUmwQnIk-OP*e0V>8{t7AKt=Ir%AyF!8q`ImOH*t z_!e3m{9oM7KFN;+vBOlt9jpl|+IX}h#@kveAWwB9Wy&E6eoKIUk4|>b)O;R2mj52SY{hhFyynxo`E-z&PuW&&2YX0w=XOHBuwFN`JT(M9 zPqFwdu>_9LDXeiZ9@hz!Zzc`9DOh69#?8XpfO2gtF~~I9nOY4)Qa9mAQ8mPhm)`(c z?<75zrs0QnDW^#4_EpT@2$?hJF~HNpn1<`;R}!#My6%iA-01|3rM_US7Mcn;hqmuy3*y zc;H^xfZHpgw)^zxQn~j%!^BRu~g-T>xua-is$;({S<4#lq z!SX9J!O&7GQjn}s>ATtq2+J$rQa5V%DoygLY!3DbN(HtCEX!8oX1*a(o9L9~PBcu0 zllz184MM|A*)~~R%7Oh_O2~u|=g%QYRAur&o*{nD{T}SJS`6#=Et;I?aj1>?d?`vq z*pGSm*zg!GF(qwdwn3Q{%j-Y07 z`%)AeGSIBWIh*>=VSM3BLJ%hyv( zKRf1*G&AsUnqu_i;7PXl;nDby_Q3q8*PY>Ul2SDcZYpO%x?n!%wr8$?mD@?cLTDF5 z@J21Rb4=}VS3J_SdqP-+{7~dj{yuwbc%P)6w~CcOO6sow&u|;<a2*i5#1H%dwZAOqn;Vf|TYI!W3R<^MYjxHm& zCUG`qteyLfD7J1`*FVzDEC14u)L0l_MFL=q#S3fd*nSk_kWEs2PD1ygif> z_C!A_V!>8aDi6MVs+wNDC3%OSnd)huDOnA{^~ayGfEpjq3KAbkF^>{eyADs-$^k~u z$}qvA2GKq_=vkmN4XTv`a;BC%ogBZku9M1UWzbR31Z9Nl@bf$H5~|C$mV|LRSH^|b zkZIL7k|Oz0#eb3&DJ@EEN$GBX(yGEG2FeYF6c}Y_CQ?>~bWC+Fl|5hMv3_DIg~1tf zG+w2yxH4aB2pp%n`i>;3I%)EGl=>Hn<~pWcBQXnw2H=oC++>J`B-o`bU0SuMy}R*S zN1DvEPHdU+lufF}kj9$4I&4Qw+rX3b&letmNtFD#=vsuPEcx_d1b@6pbKk z?z1|L_RJWO4q$34a_YWO-pu5na1CE=DYA)LHt@U+)Tuo(RcGpb5c>`!XC1^uu0e!E zQG)2eH-{G>Vkf8_DB?`?l4mTGr-7UeFU;)TTqvh-*Cc1%)(}vzaTXW{RE($Qz^?1w z$W}B7oZ5hzDC%IL=lL%|&Zc?;sN-JqeB3(_^Pq~`E_n{8@qBoUL;ZZVEX{L3Z<}`K zW`KhDg@J?Rg@L?C4i5P^tl$S4DLbYC6mKJUt zF_i;`V5x@DYSIhVt_K&PY>GAkfik=TW6x?v=Ibh9V2OU`CQly@Bg4t z9X%Qu@+Cmb`e1F;)7@2n&4usybOIp(0VQD}Dx?0Y!MZCFRh^m8M`vp}b5uzgde!DG zD!X_JPppGAxx{0g_ni%%v>}*DO^SZHWHcNFc)Pqlic2D zi7C3eiQk9{$AK?Y)Yy~4IIK}KZn(Xrer9)l)Z3wqbq5%oZteHCHow^W{(Q&WnI8dP6o%nYb|xabDBT)( z1=NVz8M9^1^d5U%`!A0-J_fC_5@Cpmn zw+9u7USAE(duz{i*qe*SAoj_ltk|7gT9_^#zo5j=a=3+)4Fy9lefcobGFisY-u12W zBNzHOac)JP5JZ?z`Jh3X&$dlfVmJeAqxJJ5xW-^L7ai~gVR6c?rm3#FS84O~F;32x z?A=`Lf6qzsbjq58I5|xh$j9aXil(}HxNG74%xTJ%in=yO<=9nU!y}qA2)HW2O^gpp z&f%PDOh-M07GlzCTvpsBS1{?=0$c)#=g@2kAnim-?eLkd;fzbR+9G7J(Bcz^xw0dt z(S^=~3u?@II|U+%j}ZgshxRp`I)z<#mX51pR3$5}&UzmDtkM~$dhE?gjAu$8sH>zM za4Kr-vt!0CTUbiv0pB;OoH6G;s;5(qXv}5N-ELSB|0p(TYXOEn?lK5=g+dKfM}}Rt zy??JamT2)hP?1)GrH{f!fCop)_f6(u`it9wtz2muKI`!4MB&art4RDkUd*3AKdi6o z@lcQ+p`OWJv=V7?C(C);?rTK#wgK8&Ps&DcGqT##i194}!9(z}9Ow)s2 z*{NVA{?i!;X?x9>W)IPw7_qnl^_?G$!Gd2DAd~J$Q8Sz9h+`5=SrHIEbL?JXV@(Qw zafiZALo#EM|ZFxQp*7<~l=rb$E>;yj(oAe13( z5r?4?^BTNV_K=w63?E>Md|i1~MYaU~=9*%aqd}c6u|{VwZ#}t=)_D3Xp3}e575>f~ zoIX<+rs)zdJe3&4sg_nZ6=SRU$77dKz+W!n=7e?5wdVTV`}+2#n7z&-KA(eV-Qq>> z6*rc1*$LSHtHQ6SVC?@rvTmBfTrqva8`Tu8Xuos1oX#TLbppRt6yql|E)3T%Io zXqAc!g!5ch#qM>%bM}{zCwnX_*p1ZYaYG}JUZBg}kW3;vbX-y{)95C)SIM0d4=H^oEVF9oY*X6ekcnj} zZ|5E|c+9GeGw;TLl#gbbwkd4F&L9j+o5&ne#nAwN{M7OquTPaE&~tRNxCiTErr5W+ zv}2_ybNvFct;I5E3w**|Rz(`|JO#1VE5I@VM6Z7fT z{V~kJfIq@=jOTaRYgjIu2^(8;F4o)oCWuuUx9@LjsM?>Om9imAts1qcuADJzrs|oN zg|)ygg_0C3dN6x(4iR&t3>t2w;_J4y?xN>-btSq1T`)g~Z1~e^1z6jv`8|rLsqx9_ z$Le-5nqF0&X12VnB2;VXl#p18QEfNJ!V#CD=Cd=dBZ&;y+3-8s#v6*Ofm6f2bB(8X z3xn^6yrUSpz7%f9ES-g6ILh0#xmNqeFD--}Lkx~Q>|mv=Ya!nz(` ztw+~&k6Wou-WM;y^_-ewDndZrmUgPD!3E5vZnro7(H3J1hawvR({r_=*ib*{!Nm@j znrXxip(6(S@#{D?F#L!}trwY8d}Ryt&7ivPz1&g{_O+BSPiBi*FvWKPt*cC6>_6 zkd|Jr%sOYj#a~(t2l&fGZ{}OcN=6i>BeY-;M|^T&gI zw%gOStmoRXbYXQ|GKnt({i+o%%hZ|UOtXxmqbMli*T}AuB><#|F zIdvn5iqj}@m2V)3W)eqENGsR`^$7bS6>m9J3E}wiz9Uh6UsVQ2D zN_>W=D1J*V_psf$3fAKfr9=0NNzXuNq4Q;H4HxtY6%C@b~~OW3R=#>Tky_U z39sa2p@w0ijZrnn-$&g)it6#h(R1e#Ab3=>_i=;TSaiJayUHkp)vIIfN1h2}JYo=% z%3ye;=Xy(}S@T4Ez> zX)rrEx2(I&H_KV7G0E-2T%>qf8+exrj`7!ebeDB^NQ`v_2lq|Xj2Qfz|YlE^2-2KkF2 zzs66I)$w4@sZL)0-d1G&S%KqcR<)rkX>0yz2PATwFc# z5H8hP5|!tRO=zlWbCWN+s(Qy;JVKSC`E(73d3QR0RlAkS$a<=3ZUIz&R?t#*^Hpe- zuL$YSJJcl2rU;^|4Q+vgo#-$*t#iIg#y!%X=kj7D$C|kewk|zZ%>@4HoD>z+K@2`? z(ZW4o;ttk*n_qoA_xA_{>ecX+dcrGSj9ZH3qwQ4A^CR`VAzHVg$v1GISK~FXf&HJaD^YF~S%Mr5 zG+57>irnmGOCZNkbK3_0g+D=TWbKOLNRUB1R<3)^k!ZgIfyMiFFdl!jK&)xn)p} zr{w8%&<%vLHRiYHn@v5CO>qgV8VC0+xEV=+>~f_ZBX&9K5SAc_tmQV=MJH7d##-w+JZ>%gb`nAz1!jJ}MaUN(LY%3rFn4M_{yO#zx|mBWe)(%GrgijX2l zd&l;ZU@0P6Of>QB{_*!88k-8a0Wva8MXgDaRgu?kdE@H(P#|iay#wi;d>PrE zRR~Z%+wRJAkXB?0&%ss$^6kJCzRs$0U}?4iRV5C-?APc-?;)dH*aUEnhTF!cp53^C z+ud@2#L7cAQ*htax#B%-#;f5^z# zulw`s3b^YS^&y$H*TMud+G0YgE>>Y&DlKnL(%S%*5NJc97nht+W%bNj*=DtfnuRp^K3Etuo+JqZGvUXe-jaW{xxi7R1+gWlX9%@G?t)cCm)*zR5xKF3q)S7|^t0 zc~Yo`m9AMA-lJZsgxp#@fdtn1u1#^Kkt`JQm(eQ$#g52myHz|6UzDV z2Ct8)W9G#|db5g~v-^MtyNWjfuUuiX-lAmNk*1W1i7TtJ>4R##B7J@anf7YL=?vd5t)4_eOLz@zgS` zl?l1{vGUZiZ0VsBTCYWlnuTbO2#~fr7h|(`xxNFi!+EWG^c~JR&P^PwJd^6*Ux0M}OfHSlD&fuTPV+1!4=D6V3|| zvzQ4e8#(Go!F*oVObG2&ZqUJN{G1Na8RY>wim0fL0XT9fQ!V(#DY!W{#~iWHNne*= z!W9xiPRCUnUCl^C?;SQIS0-6et>Tp_9!(C#YDXxmtEUTCfXy^$sXcoQ#g3v>nAufDv@K~I{a_%~pcF|hVin`)=p>?#(3L3%}W{pRMs(yZ-1wl6LOCMa-FtPju|^LfSK!?!h6*f|R1_q&PZ6=d^|p2g+0%JA?VYZGlnqzS+9 zejtt_8O<00_Q)O5L8ho`=EYNmhEAEX^pG|)2VZHEh`BeyLf7bUa6N>%>S|H0Lgk3n zN`_Ul;L=s)YCw((2-j8fPA+qrO4K36ht13EE)r3dqUoVGtLW*GbrR=sw07V*e#x<8 z^B_&W0KhAQp)ve^e?LhOBmb&r%=7g+A)`alleeCU&~PuI5x5+>m(lrI@YUgx} zWxzUPEm7{!gNnXA#rf`USJDxbTU|*me?6z1_G%QGoaYGR5r$+br8-4+ppRIlrq8!k zc^+i2)yP1(RUd3KygR6im~I6?#XjFYYi*#DID&>=Yh1LWE307JP@nqSTU!O&WW?gL z7@5~NNupJFRU~vPN?J*iQF^6DLZUH#?NKpUfPXH|(iD-3Q5y z)=5>owS1YY^*QpdF*=jL5Ub(JqomjBLQhiN)~^<*nh&2}HFfQmpmKlss79|PDE z+kE}t>}3GP(!)5u^LR1ISW%&*M4n={>a)#<3V(1?;?*UzplB@%H z-JRCQ%jty6VKvb|*)FsNA|-poi}JYbwC{{f#3(^|!2-8t7U-9k9dZZmChQQLR;w}m}cKQ13H6?$3 zV?B&`DiGLNILo|C-XImUjuubc6})lv%*2cW{LG$Cat^ULf$3c35OgE;`wUbk5K}0| z#X`@UgNnd4r#V^g?8IpON%8~2ac)(EY9`d?n0sDYhH-$_W821s5gu`OsF8a$V|`F4js@#{)ag-2s^rxo+<*A%f5cMepCg z06~732i;j?D^Kd|8YWjhxQTY6}=;UMI2V&G0Lif;39h~`W!$;KjedA%vFqAV4HF7OS6EI%}w=LM|L}IbUU$vNLcz^SPg~b8zL_`W)~M>SoBUqLtge z)tFq{tyDru0M%kYIA+P#%f%VFSo)Yw9g$EwMM60j!gYF|;@&`OTeWw2>7Xt0sxK5N zUL!q@RJizKFDlS)yXt9(m60YNwDM$E6;CwP6>`JjK`CBbWZychS8v}>MmJxXN{M(V z?tm$OA~pOZnqIl!?Liu=wSgLE?2LiByY{D_Wk3cLe=^7e8m-TpWYRs<&hj3y-A`uU zD?Lg4nQswZ)rav{o}Jw9h%BRQI!6HW3NpEztIUwt;uL)5IIRxfgpOk2=k@yw66bY_ zAS)t##rIxHsoj-@;TDd%1s#TMajRIsP}@h|WDw5MZqbBn=`(&J-}*He?LHR9Yi)MO znYg_EkFGOOZd=)bD3=-T)M7c2EC2tYkG)_xlhQ)Ko1Mmyosi&Ou$Wi4g z@-bBxYEe*kdMF>Ngq6am9LRYdq}R$p`!gSgHf)N=56j(4ZX zcxa04s@eqp;6TUyY7Lh>eAlDFROvb0C_GcBX4lrgj)=SA_?a)5!-l~KB z;iUdFNngt3iYHx-flubh{GVm=d?qAPdt+qapkZp~(>N?Ns^@~!il9R$OEY{cPv;(Y z_O?&SfR0+)9TNwv4z!Yl*08n9kW*qABqs_0k9%@Ez8UV~VZ8)3Pq-F=h$cnWp z>sQ-Uv+Yz&18%j@E1Rk^T898n@)iVJ9=E`_xb19Pg5<2p9c?l5S=w+kC|zc#jkD;T zlea9A5tVGaLh97Dg+zTR6F|&lC>Dw{<0a5m-`jKUaK#`ry7&}TdggRhJ50M_%luZ4zQiavK1$T>aI+C|85GZf zeZfwZytUTXDiC?kS%=8qh`Z6vx!OTV$j5#T z9t2BmwdtFJ+-BGHRKh#V!K{YG)^@g|#Z>3SSV;gn)D&4;R^TY)>s_vCDl_n@WIRoz z?&q0%z}tE#>79mW!Jjb(KJ*mqD(J;grEUsmfQ%xM@WsqOMi0JPpsrjcV;u=TtJ^9F z)uy~)`l}8B?y1cKu$EXany_8;V$BQrevwr{A!LeRW}8_n#6((lE{Z{&Qg%p^Xd5e(*T9bQk$B*8eR)r5 zzOf~qm7*C&ED|T(I8nDd0bZGGz#)~O6aUwIhk z32@I^HkN+1VuWuvkSNU&Aj{-lj4QU7yHy}0;qwha)T)n{Xe3Pwg;`k#i?@y#@k8s< zE=LvAm_FTw5kDqFnE??%X}FGe>KLYtAYPzti@xm_mt`N!79i~rcX+zH*~yaaD$2!Q zgz7~C5&(@jXrhM~1n&m$VzGxyi^UpS&O;ZUig?WmRegg&^`vIWlS)$=r)3a(N~Kvk zFW-Ova-@vvkX`79ItUst{l0`+!O|+@(*E}i!zTKw7?Fo z3}-!ERs%VBY}g88##G=hg&%ozz*%}?DnwwIUiS5S$6GQsuJQH8g!k~d=7zG8#fmPaTwtE5qB`2vGgBq=Mz{t)-`Kog|1^6 z_|MbnuBvy3&UNGQ!$LJyOT=X)TmqXee@YEoAO5Mp&1H^!7Q83k^8c8?FUw1l(UTUN zuo9MpWB>pFAOJ~3K~y(&E4m;q=Vy`!oqN?&Qr7Q_sBysPjQjy{k%Hzn= zCuW@2+~lV-Q2U49?n$e?8ZjSlu_q3MRr%<=#}b7YLkRNLa*L|B715M1m&lBkfU~ud zhPqdswZv2bu*rTQaxI-trHSZc{0$W4`uca&s2fuUfADMLk}u3tTtxc0Q!#04MvXaO z)fd2v+je}NfeRGl_x+8^4tWW8*1_0EdV3a(8oA$$ra1J$S%J5opFAD%D-71XolfR+ z)VIT00iu;Shz_ih2;V;&9a?usI6#Be_eLhNt6jF3+ax@6_8QY6*O}PsyAuNohB7+E zb}io`!#A~?P+3zjwQ{t`q2=B+I_hb)!n3xc=CEgJ+aY_3te+qoV@m2$S_3tgK0t&5 z(~O09Uyh1-E<1F2RpU7+H8>J?z~&I?s*^KIV1w2RONF~k%CiVtvS&e3R%h_3L)sON zgWSiRa*m2I*CBNBBves9@>!uhOn{;~yk-c9`n#Qs3CFH1A_^xK9 za$7mtD6H756MJ_YdS@UeDcios29Cme$+z5hxu*!T9`s!Ig)mEWpm%EZV2CxgypB)B z*LY|fc=7hI!#JE7sLKj5lV!<%*j!FA?a^9b2^?A{&t}hA_MpUMEjstXlRjQJp7l8P z=7oi;*w_QIC%dnvx~5xD+8RapQh>#59?Wc>1%6hx&1h&_(!PxWNg+(i`PRU_b!|>IKxkV!04DNpV|%Upm4aT%Xzw@rN;5M$7-6+ z72J|nG+xB^G*W-ggU>wSrkVtQ+@{)Ox)i?U$fnOadO8<}dDlzZxDxGCOiMTXN~j)x zJ>^p9Pv=ay*w@Y|;;Cvi2hC$nrRBg@gwd3i)X6PrPYHst;vb^16~1X>L$!vlPrtu( zg_Z|z2&sy;(Ewoy#zBh6VWhN3(cz+=>0M5f;UQ^z%L@HW?rf`zJZT?hO1%8b###mI zS>~}wsBi+I`qx}Sw*`xjfn#781M-Cqtz=92-;e&far^i6Lq;Wu9H2@5dm$z1zHK3i zZOAW;SKQZaTSq4_q#+7nGAQ5MNzM>P65$BjayOWA1^)6Si9Cf^N}BKQn=*hq#C*SM6PtJ!Vr;xGRLC%tj#7lX_6OocvkJaG%M@Y5)R+RFejhy9YPd| zKaX8oxL&2{`*2P5iYh7r3eFAW9uqf@x*co7&Q@^JJhypef(i!L&d#iGG{Gj8RycN{ zqd$xSjXCol0Wg%5M2V(sQjn8!nPA9PjgJ_k#pdIoOe78EP+Rw*ePPvU1x=#4w3^u@ zd+?tgyub)qELRB2w*wKp&BM+D$HtD9T*TqP>%s6rtp(vahSwy{B4RSa?u-hh6)FTt zOUMshH~9KwDLq?!@H~F&5EmH-s$XJUVm%{Lt5Y3ZIi(9IcwtsBhhEwxQblM$WO8 z@kKLQh`7%A(en#6IOFs<@NILQk2}pZcyYS&ET+;jo}yVho;0l@Wn*}wMt5n)dVG9Y z{u!Gp^5GQi@sdS&VkIjx^cYR)=!}nbyLkExe9*9ateVXA;?t!(zFZ`nw65y~!TEC3 z_-MP~rfQk#0r#@pD9V{7h=hPyyq0%u?7COK4B~ z_aZEzcao9vl1Pv4$d8=4B!pWK0f!G!J8JbwU}rv-Mw4C{R%bin5VbxP{;gOP2Ai@| zdaw;%ykw9(r}nutm;fIIsof0jBvyH$zxS6Ec(dmjpDgb? z75Ba#TJq9Fm}6YDbMKrEcl?^>uSzjot)ZIZ9+C?{G-~Qq2x=3V1Hgg)@}ab3OwAnB zVsEzXJkX8o254#p?8r)EFx5&8<@O9jGNU5^lr4tb^nI0IvYMAfU#&Oc$AB0MP)Ydq zqg`vVuPW~8)P~tkxhZ(kN$I>~BjgDC(D@8MOt@9SN8;tKg zkTThMC3qmya(2i$!v$Hz6tMklMd}vsfTY-A8rI%iM>@Qe58&qRqH>j*OQ`=YdIZh7 z%&{XVf}_QrU0cE+6zI33+S$L9Sub8OXSPr$ryChC-AntrT{F`^e|KjQG4+qeW|O2i zbp9V*XQJIUt^`poAPG{UBzj4F^8X+DP)mcLJTH^Uj5kSEWH!3H>K4Hj>}X%E(4%qH zHJORk2=Sma32pNBz6|ByQDhUjDz>2vR4}F4O*8JyLjZ0@V_>~&kxjKYMzMpl3q1Gb zPTM(qpob{2;^h!QJch5*|7vDE>*%1sTnAcEc!n4VVnGIhGnpkg3Mn#>RK~&jFoZq1 zy#4x;WDd_EgWHTafm|->Ft9N@m>X-^#p(T7=ZbVrp%xe%G%dSNvc<`Er;Wjb_T9=T zw5~xQ^F=A*6Zm@0HOr`~WvQau=1HmTERVojX=GSsS!Su+( z=V2pBIyVWnb?ZBIu_(QGS}WQqU%WnVE$PYLa5ZdDmw}7f!d@-x zje$r{6?1gL$y;8wn(0(vohqn17s^v|8j@&{oOe%*MVgdMh`3+KFy*9*qKJet+m4 z28VEtt5P&Fdq83=h8HltU|@$yytErr#Taqqt9}o1;E!EyU*0_*Ya&8f(^;Gm#_DU@ zcq(wx(yXd)>?6D9QZ#W28Zn$UYdYe02kdhRXWlgy=eGcKwEA{QgG&<6yPTuvt3TS4rI`!BCg5@Eup6^N7gucb|x`%wD?LH9r38; zuv!^)linVq-jZ##PIKs)=P(y}YXX3%mw#%dl$sgJRudc+xs17=&gy(u>Q7xcar!@|%?D+PuazI{!-k z?Uv=e(w%kf0?zuS>}sp{S;&_w;Bu+0{qigMP^Q-Iy0^X(JuW%KOWUk3ZM^VXh{J#L zF557~_RIvc*_&>gw^~`u_JcZDkl;PY0nSeAqJajC?VxY_@Y_SzueHWzI*9=ulA+s^XD-U z%Hf2u98gMbfkV(`g)+)L{JE=$S#lt8=%7vR>UWj@eLiykyy;3~h4kbPA=)tNZz^X8 z*3^s`r=)qbf6fifvfPSS1)`-DPT2EcPuJR{94^{1S$~zZz{KEL`3%SwE^j4Gs(UYn zZ^7B1U@Ho&I-cIIOIBk=8JLFUS!$Xq{%G^nc(gVeEtdVOhE-91{IOT#kCeHx;wUqh zjhSQfNI={w2unLs?1^DbdQrU;iFhyKnL*qN=rXg47|6?TUcLu~==JB%w*rlZm>W|W zCcd-u#0)n;Z#@LAgZ;HJRC}ZwK%%TFx*G__DYrv@Wz%tXAiqi6EN+-(pHB@6zvjL( z(gBm^`y3*uvin(jg*bb(U3w7C15WC*DArD)ow`}a=gR*>A{@lf%3L;>rp?)$h=7L%aVMrK(N@1DEXsGH_*&DWUYF{A))iaJwq*JwF^KA-s?vuWrVtE; z2&-9b)`f8E!I^Rk(YUyNE_>4445ycq*>G|DM*UqbP3P5F)Rw&bwgbMD^y>{Ql{9@m znx%ab2Nlii9a{RD6b26INY0Xvsd{k0bEVOUk9fkDygFr&jBOaVPKT5}kzO#qW>az!W zvJ^rJwNT?GSd||5&?nc!H*AXmwgST0<7FfeBD4X;n90JAQj(DwRlfc&UBB=c-MI#i z@FXa*&`zVnozng1Z>h6UkU52po$xeO(4>7ty}*znTL_F&?)K(T!d}+j+wJZ|1;zbx z&Mt6P*n-v9x}b{wtmx1zJzMv90+romx~3;V?f~4N3|`foj1hT`<@0|$)jDS$;pm@m zoI_H(OF#M?GAu5A`_(E>ji-6Uk`+lgZk#I<{X7Q~n$Rmur*BqH&q|@;dkskFxjXJP zo=)i|R;8}J7HVnoJdA%M)<)q-B2hVjM{Sa#j@YQ~HGjtrR0+3s_G6k~6Al$wxhOkI z^+D)gsh^ZAy~N2P*Rp&zBM|XHWDk9?HT`A*RumDptluA1tHd5#r5j4Cji1fWREptF zl;a@7&~A&>rhRTT0Z|LZq4q!-^lS4XHDtT41T0k4N?|yTW?3rg!OkeIO06JMN51dz zB$)vDI?MUsJ$e;n`w5POid_Lv-XZWY92#zO2ESRCH5$>ZyB%%%&76r3^H9%Zgs&t6 zG$q6yBP7stD-Y=YFs;_H0jSp7n5T!-4r>3`~)t@BlCy)=x? zYxi1}WodLbAqgcZ-{HrIfm6!|SdK#m&F1tgP)^4(Z{#+Et zrWcc6DZ2E!NXkpfP2OONrLeOKCDc-U(J@$6HAkvZ#aG5J#c!GUd`!vHZcDDt-`<2! ze>s<2ku|`VDMfw}o8-H08~;+JeRGBp=kXW=XAnA8R$4#4uCTMXqK&Z^>UdgCZ;d$BehYKUyyvj73NyTD$Rl6cT6U=I9HoU`GNKs;Ej{yhk zX5162i7r?1n+4If`Y6E2(`E^x1ZD6fTbtl5k_ffjRm%kRQ7O0ZEPef9kBgEqzEtU6 zsH*5~zdr)j#kP|G4yuI-mckZ!S9IS8GnkuYs>3IQECUe*Lx&kUWJGu2kHwC&_(T2mEt zX}s)}+3L1-O>quDvOzh9rU)4_7JrQze)@X@4=lKqv+A;STG@BWskFdzY|73JvWCQF zV3qrurnXQhxFKJ|6_#!a5ay-h>{|bC@F8*)Up27Hx3q?3c?&tZG}9M?biSfFa_eyF zu29MLtDA$td2k@8sbO|C=?%GY7{^`Y|C_0_ECJZSvsfCk)`Z+X{+t_g^5vVWZsNLw z?;5uD+729+c7Dz}pW!)5(W9(q8|>n?&W9N;2dgQvf%$ql)W9Msm_^*0tifgUj8P)H z`3zQ~O3PlWj{P=|sYhV4JPD7Nw_0ghlh)~o8#u%naq%w)#i2v%`co=x>1SmJ_}1~_7V`lR~H z|Lv7y#HKey(`*(H^Twukb{SUzz70tmG$IsIm_FyZMG8tDwK>SwWMiV74Y`;d^t-Fa z95=gz9G;7>)v}nh4X%hewcWTpMSJ?v9+vA&tUx_oE>)XV`9l&fnunO&M~^MjmLk!B zO>U`WxCd#u=%K|bncPfrxu{h}n4m&?H--`lr}@&nn#~oFLzhbI(D#0EsdKL+DZ>!nv5;}9Oq`NMP?gF(XUNqh~ zK zJYQzW^C<=R92NWy^SBzO<_pzhzBr$13wsu9A4}wUWH&XxZHiNKA%E4sX@maOxL-!x zDc;a{@pd&q0zH4~XTDgvCPtX&aj2@b9d4Zdkp0_YTRAGMmMx5{eA*hvGph1@6`K$$ zEaN<$T62u-e488&_*!6nuV=K!gIBxdm$ct(LLL}Y9AZRC#-7i9Tf3+2%#A5B!>nt0LqmhYe{Z&YP5JxMcKWG(!Bz{0yq5k(#IhgQSwra81j{>oo( z+yN_MXuW}|#piCt<5)M3nq@ZvP?4S^DT{CP91~~t{j&~r?dpPFswub7nKerX&++5u zu1cmaC);$?)^h1+$3S$* z`kN%48e0`nIemvwmLdVCxobu`AxmyHRDe@vT)xDKM&rA-wiBa6ug)XPo^|{Sjt4Uh z$-5%SqweBr%?{fVyW!3WOf-3L;4RMx`@=3siJj@ty|Wx--F0)Pte-`LRoPr$M*_Xn zSXk?Na@~7>yaz=J;hW6&$!=JwsBZ7aT|qHPwp@J&WRg&B^S|V%8YjAPc&yl^qb0 zw!tCB-jgpnF0d_CfKl&&iC)PMnx2VE<|svX+7q)31L-9khZgJQ-5}I)vOGC6xn8Jj zO}UMPMrgxBbjyH(Ngy6r?cU~ap*uBbcGR%{@jd)jvISMq-J%$)elZG#_tF&Q0O_+$ zRV1)Q%@#vz@5`cVnN7qv=Rjxqf;vPkRR`-kX+Dh`!gv51Qrgxb)og$iF>~fDoDfVJ zTXP~kj7N+>sw>R19yncuy|vrT>8;yrE*9LAk?1XMflcydiF%bcoz}Q-+uoBt>UiEu z+Th%rox<;Ws%qw)=l>&!s+Qi`cF$*0^%?nfus73r$va;U9P^vYxim!FA`J04V(@ve zPpU}0P1lh>KmT?;1!YKGcRYit<)p(|c6_uN)$GX&%jNjgzBb!gEHHbH8=UcBqO{pr zksruqaaPTZtcZ%$Di?H{k9;T?+!;IB0qFxZuGqHWQu`a=Az6130!+2ksze1er`vsO zZdeGH|A{(@KtlD8)E>jziy8ysRcRRU(UsPA>mxL5k`};%NltqkEwl>0lrShU*p|N6G5bCV3;u{p>8wS^?!^~jF z>XloozJ}mIb9*enG}Z-@g=HoRs{_Utk`+YN?7;Wo=1L_SEC0#!XJ3M+Q7ofAMLP0h0UF`0;@MjYIna%h11JyC}-gbuTc?}HG{tAJQp+LhxpIB zSqMqga7E|29Dg#*K_$p&>75WL8h9R#4O}Kd8mV2z3X_CO_(L78C*Tm#&W?5dYeo}L}{V>P(F#A3Vom{N?FN6TgVFoap0 z47#k1qn?IxV;5^>R-@e~3~SBtfe7+Jq_%9+j4V>l;oe8=fpe1=mD?}0{dh+T4dmee z-`7L+yPqT@Ac2yDXmzu^!Fj$h9`E)1762M_)ponx*lvE!zUsUBSIdnXcO!VyS+RxP zR9jL02A5y{a`!|^;%SUi_mUtF>XiENGk45_O)Nca4$?@TIsl?=|+2GM_lmmq5Z} zx;!^0%+|Xy>%C?Di+x7 zrk2?ZcP@i5c*f`!Q)QZmA@YShI=3rzTBQyC{ecyUqGvS7_m%Sex!HbyZmUf}Lu`AQ z0C8^v)69}fHrB?PUaH^yUheTt?{8NsaCweAR=aQc&W7?D3@fgN>4YkU_WOtVe`y#4 z%u)K;)OvPp$rglKIiim|Nmh|%r(9m>n8cdIaIMwW7gnZCF%8O_maK~H@b+^Xx$12h zuE3|`Nt>NBDkjsY=>}4cA$P*%&RL0zCnBDuS6U4-4!9*3kyGM<6FAoQA?p&U1Yl(! zS#u?r^yqe&?F_nfo&W|RKx7|gVK)4zqW2wT=&YoU{j!Xyy{EI4(cJZhW?5Ct(e%S3 zYWH7C2;y3Dc><7O6!gnO*mBEvKd=%zUymf{2a^h4_89GwT}euIXl2wZwD7_OVFtnIV2e7lK}h%hQa-d#=y zm|x>O;zZtw3h&SV{`)6Ax)TID4yJiD=s4Ea6-$z5u5Oo@hLp<;314=ysgO=)`%!YL z8ZS_^GZ=sF@UD!kp zAy<=w5|tFBz+olM4((8dQK3xEIi04vM06oK?QkfkAa7LQVoH}vluovr`Mm0!-$;~E z&Y~qwr*d>Sny%&e&4=_yeLNq;%K6gjo|7T`D$cXpbF+DkKe{NV6tBoH5q%jIR?( zj7liPFaQy_L2VSwz&A;XkyE&ml`%Tcchkfd01di_p^E;#qu)gFOrmMv&-XWbyJ^;mNKj)MaZYaoa{!D@Un?ZAV|so7UzK}&|k zS+wj)_93Yvx8CWhx1%;%m=9$TC}nAiNcjL|Oqyp(kfow)i<38cZhK71GLlJ=fJS%p zyFE+{a-j0bn5WLFBR^KWD?Xr)O{C%mnai`Q^|di6iun=-slYk$yDz$t#2a=<62q66 zD9GHUoreTSvhjtoBlbXB<2e_Zl~C&-C3hyt<#ue(+)fg!pl(=G^ z)S~j=X_t*@ct0^Qn{N4$k|y7L-=?nEjy+_h7y>OLZ;8( z8bTwda3+bh#m#W54P7{Ub!ns}N}Ytdkq}6a)IMtpoy4T>#J2Jl7|kW2my^J|IWW&D zS0(Scjbb4f(?KxKT{rwq_suOY_VO~ibexz_u^`Rqy*eHRczmZ#*2xa-BAGtul#Qp+)w^V^@_05Hoemk5LYqilq)$8(&MOhYG2T zOop21`?RbpZs-@&J|wnAd4*N%i|?o|X6-=!8duDK!{wS>s1frdMSr zjCKU48-kDZ@WHV~DcwI-wX>DOK{w%88I-3AJ*tCs86S@{LN0$3w5 z?L&C=P<>`Iir<2EjDZ&~I|BWnJX>~EZkkm?2k|GF${2NV61bxjXO?9+Nn1FLR;=rY zN+?%^kB?T@$2EqA5vC(_79SaKEq2v)x)@d^iG8^Q>^+X0ra&rd`Ky#)=Jf5M$Li~z z*k&6w#k-_Y+(NQk+e#}4gvPE4{PSbjEJ7VE<+UBjyYl}6zKqxU`1Amq<^PkmB(~@r zjnlsLVC9kf=^@?}LlwSQiy^Isq3KhT@comHD9*2qCW*9O1vL54VVLBX{klB^qiD)) zzrE*W&C{S=dtcT+OzY{HRs>|{P$E4|&wSy94y>fK{rh%#*v8 z^IHGvt{`^DZ!2I3UI9KAyi2>1lUem$J-Pqo)ZJS8l1G?CyNV646;|$faatQXEql|I zH)xS`v@bl~YD^qHFi}MGcOZl>{zm0YcHOn!*~x{1XF;i5^u$FY^xXsI%X~hZN~Ud| z!Y)OuJEl`#I#(G)O}X&Y@HMA8_Pf7LIcnkDY&V6)Rg0}M;cA|1sE2>HhI{@_&wH*F zUIlwqWlbdiQs1WM`PV7PQsiCrSpKU&&nBukvU}K5veg z-y69XFZzOzBh1B8ll;Kl&IbpD8k2(F30GJ z;lgZ9Sy@TP@c%`eL?jFU;PsQ$32SyW%2KYlhH-FUGo4W!WOFvXAn!qKIQ3cKGH2{Y zrh9XQp_ZD_Yol$#;eoqM9_CHTKjIWHecmy6#>h_I%l7qJJpR*%%-u=QfYlmZGPq-M zu7i)M+U)g2JppgLDlMSmK6y($|*Yf(gvq4P?}qfixB?x8u)ev-zFarXY-pFi*&D-hy|9A9d{ zB>f=gsf@3FC?2YdDt~+gxqVi4v5cylN=p-W%=b3P_6Go z1SdCa?+ERN|Lfk55{}3C+s5CdV6uMY>QgdQOe$~0sPdEQ~ z8eh`v`D`#MS7vWgO5f2=xx&w9b5Z38PGjA>&b5$ht~p?1TE5%iBHm6VWH*ZU=stI_ z5&bm47gq~bVxFQkW~;^G*I|d!RXxgSA4}{K?%)SO(I~*vBSc#{%b~L*EB>|V2+C?> zEoEDG9UcOKlL)H}RW(1TM*+U0Ic2+g2lpA{;v0-f=!lWPAnfyH6U=J!t{5$-Dswwr zxRj;$=>5J|C6p2?HJV6O`T$WtuD`SiD`!SD+_&)s&`Q~KG*}Z&6Y%jDd>PpjXd6qc zkH*P2ZuBTmz?xc%ETkUHDY8Twf@L)>fhYem5y%P1h zD;q`+m%E57m@;U82)49A3oRQ|Nu4|ACb``9>IfZ9yjt|!MfzSa92wAbmHUTv8!gPr z-3{5|iO$MUUst)TV%CHXEWXrw9C)PvT`bvW1)J;tDn}8 zGeAP86C#3AbVu82%{W)my{wN`3KV!(4uFeNLbkbw@0Od8cE z%cBmBR#zY&?1!0t6D)N%$qgM)8UBpb&r%M`%_*|Bgym(-)m$R{as@i^kIzn=<~zUl zH#Yj0rm89}HAbp7`iA=`o!aAiGCt?=aHTqKPTSH{&9qA${+e;8n*^s-N@Ag9);Wd$ zIHxEJ?1K6_v!E*yb@L?vn@<>QM^;s@YKdD;>AT6Ve%Z{tT&9TGXzDvkz*lf;jV}^) z+AXnK+DE}tE{|MP2j(d}YJf~`e}|l?w9wP!B3_VK(mPL9L2LaSx@w_6hDYCEn!G9A zS3pNNc%g^hUS175n&Bn##c?&6R$Lsvl))fl@1?!Hf?1^;-;4IJ$d!0~-jF^)UQKn^ z(H;N&`&YgtY@u(AbGUFeeZewXCAjsHm-Ul{^C&7CV~Q`6h?m3tFXM?(XD1bZiIy*~ z*KJU_r8`MUz)@-0)?(S*ruKEy)EZOvO=e+*A?4NXNSKMbU0!%RoA<{F523B1Z7Il> zzMZwv$IZ-!Hs4abOElbgSl$f>o%^OzY;m~v%iQZ87cC4|q$V1RH32P$C1BF>mPL0Z ze!;|^7@aX>qnvM#QU!`rFqI^CP9BGXMew2YxG$E-R`^Ck!&2F~K!-jj@YBLA^%iZ( zh9r+lC*6>2t)0=#o-u3sXyU`_V8QJExvK75DVB0l(9Y>_;JCQ5>@B}m>B8&x&;xJ{ z?0xf90%HtS5t+NPO=hl<`e%VF@B{l@m!pf+kokCQw8*P47o1f0S8cJ8E!ayh#wgzM zdaMF9gRIe$*I}$Brr9cWs@Qzm)N=RoVD*$^LsO+6(yNGRL9bacUP_LRdq)>Jt2hsu z-E8;9a1J0ke2JNr!FJ5lRgk~>V1Mx1CKP>9(T3=vYCh0h#F196a( zxE{lp1Asf-l&1<@R4DU7LMvgbc}TWqmCa6aDh^Y_tY|TJL-8frBS)$rTcByw`j*3i zbFXWmG>-Liy&gTGm@5_1ImRzF71$9j;RATdX=GTaO9P{s6t*6Tz`-}21&;L+-Elc`hXQq@2ic>}-fsa!&&$VT` z^uc*Woq61?-?Acio12ON7%-jkX_#9vJTPO5t#ysVgHkfT*mAIEh zsmzjU_s(u^2V*HcOXStwA3GN@g@{Y8;YaS7asAr7gn=B>ws~|bQ5FCcH*9i`-c{}A z<^Ddt{D7DRFD)**xgkb_3aQoSy&a`uTUUZ6aUswgh^S99iqjqR4aFb9IgFS>W1zR! z4WAKOfkw`;$JgJ_{oX28NCV~LjQ8)S1SlPk^u~>N@-Rx31?|yMdnX~WAV6L;dd@+J z=wSI%2+rcT-K}o&qWfaz261RCny8)kmqgNV6|p_Wx?534krS-DjI9HfSe){J|z9BWegFpq;@tF4NE>`#8iX+XY_sZ}@1tGC;?SC+CRia{lW!wWKQkXMO3qu`x8j{p8+m^I=c8w=CMVwUc z<{e_DRRQy4O8toFWtJFqX0&hdj6s$!dAfG#zB&6{`LKh+_)wM?Z1rrTofvfFHR_-a zl_F`k%c64~&+S3sb|>r7Zjm?V2%<^ztl+s??jCBcz<+fMIas=97iVQkX;_BqQ~It! zlC8i7TJa~N`egfaEAX{)RF`0ZiTSJ4!Q|LOF(^kT)6^ju6<8}e<_b3AIv%k^ihfQ_opu%8?=0Y8ozrWl*q%dUKrVI+2i~D7;16`zYV+ zvpMg@M*1cUGq$4;S#Jv+P$lFSn5_?aXT$RsdV|Bx)@0Ncxhs>dmq$%YpT>6ce(5HjFmT!ki$MiKD~>vR?ff@Gb_*G z0!kIW+K}TG*v4Y&uRL{LGgT3@*fn&>oR^P^b26l{x03j(fTcYGgOO~+vGXoJ@>8ZE zbetF@6S;W&!~CVA4qtawOA;q+b^>C3zQN3#XZ5mu?9 z{d)GoZ}gUN@kGdUYuTVU`DJ)8fiY49XtdE^H3{jtCm)$c&FOj{8O1#3T00%3IQD22 z9o+R(+01dQ92^cEQD@SvViD}jVjVn_8sBlSWyrE;POQ~C&nKbO|L8gwwM3F72=~3K zXf6sW&c6SHo{mdaRfA{t+u0Qn5Rt6RjQFEEYMQ>Sp*CA|)pTt|4wPO>#j#j$OPbQl zLbTMxR0&Y+{I;17N8&=0&YLPRdi}#Fd`v=U1yS8Qxuc>xDk^I|9uS(2y&1z75=P6L zj`CZyh zau#iS2ZrvJttuzWz(U`CZ_YPLS_CthXakb+A(zrdsI&B1=z`fspDnoJSQiXu+y%pt z6oTZgR*)=Ark~G;5|GaBRoNuszk3-mGuHdN^`y7_A z11VWCL~gFDcuw|57*P*;wiiJ*hM@#;XoVnwml7FgBs5=~&@}0xd#=tm!Nu_p5lT#D zJ`Pp+Utj9Inx28EX@~YP?<6}@mQf5Q89hq)@a>Tp_L*rgayuc9>b#nhlz+%Ws)={s|o zuAr=3%}z#fgeK#&27K{2L8owbjABL}Fjv1&Y7=~WZZ3^u1SU{reY=e)$}@%_@s0^-%NXkfan1X%DMEJ8@L=t9Y8Y{^}&pSy9?l zE=NF05_(cM9)W~Ja!l2Tq~&TtQe#ZJRfW5`IDCcU?0JK;2qREClM}50b#Esz%P~B` zU~}Pe>YFs3St!fi2>!YbW;%>};LWD? z#chg$ndXR_i-cCr4|C+b4$gQt>TnpUL&=`qu|(_WmSamuMDr4^8?SOzLM3Nnyy3+I zQ@MOgT>S@Ev(8``Ka86cf?7ckd&S)QU6o00S*bEs(9-_*4?d07mpHAxJN*9A{a?QK zPwd5u*$~cc!tz#e5nmq)HKb&TtLlYbCx#~OUn!IHi2+Tc2k;#5N=gko@I;p_97UFv zQH*@@vo;tkV0mxWf|eevZ$hyN1vMc` zN(nyBT~#>`Z}`>B^P1_~bd|iNncu;B9OnMXqI@aB>w8SnYi3}2;cc~Cj;4~g8N#Xc zEdN!&Q-g}EWov!)?5=ViAEB2XL~zYld__#5YASUb9km{Zg7Bsycc*5M$@CBZrks#w99+(jZN%QWrZj=xDobDzTkPqn5esoRc6~F`AZ`ItY|%jrGC#dFJL;B{r^VOB2@7 z+mzPrtP)OU2>N2nx;QTv^p+UPN$E^{)Hn-^RGEdK^eBV^Z)L5{@rET^aX(oZO)&## zTFcZ^i{;Wc6?EzpAfja`1z5wyMF7B?9tqPy6eKmUFR#9|qxH+WR?5C*+>#Unb==}yFj{-B~? zM72^AKgilkrUijqH{V2t%PGJq0Z17lXVL#RhFL9! z?UYncfdRvd!gSohSj|}b(7>}l~rM3jG>-xIMZEv>4WmgSa*IIKA)AFPHE5AOcs%WVRm4H+> zcSQkSZmIED*V%Z~TsEpxTK|B0#0R;_WUjQ6uB#fdTEDH`QUYQnl(yeU^t0Xzmwkri z^=y&L-%}(dX3cg2*QHnEXZQPyxiHqb*;;27I_jhP{o`M8GDJn*D;+}!Z`3#;$Y8In zBxr4Fo1a$(6Ir{=bfvwdI%^l~j#-$=^W&^)+7sEqn|tD39+Y_TG0X|OWxZ-1*Pg#X zKw+9Vd1lfuf&;Jnw{W{EI)T6%^|%aH=wlk}W;$7^tc-^3YTFa3m8`W26cbECS%m(e zKbP$=lw3(D4rLD}cgC!@y(yL)RWYrYpDu(|@_NpmTT2##Ef&C90DsW;D;|i08I&by z1zD^ys7T>Zx~DpulWEmw2QBoX*?WM8w1!DR3{t$Poz6~Mo!Z54RYfP7KdANbpp;J7 zJeLGcPc1!14Rej$HNmJ-)GhOeJQ0m3AbrD{MB~p)f!36vC$!b8bBu9yn;ZE_ED@!xt}^Ic`vK^=X3PM&2fC8_$_K zXf8UiQFC3WX94~2xl6X)rReCj<+dVSovjXO*2uYB2c3Y5f<;TXP|if80}iS*Fi-ot ztw|kBKhoroT`bqIb80rcjRiPWmZY29T(70d+$QF(2isDiGIq5EPEG4t`>uDBB*N{LH4l=AvrrUL<^=%C-yAlAc!>|RbBsdlQ( z*`m6oqu;G;YfTpYH=T zZ)3TeubYg(&l^^?gg&eMa^b5u1xb$-uGC+#D4ylv-TP$CO_9I*YsV5M$vr7m+Tu!Y z%`zSJ3b3ljtW=YY@ky+G@C#*9ET+8~$2Z`)E*jeX%O1bBAiD~)pxWuH4!Ork;&D#i z*`go6T6s0|tLC88?XB&#_kP%9=kwmeX9g`i5g5_M1WhCAa1f^`{W|I4llooID@WB` z)8lQDKbT>~Hvf_<(kE@4=b8I5xss<$=MsF6nq#HA)G(^dOehoMQs ztyxaaCnjw|v`a+|Ee3TkKZy}Z3^CBo^`h-3l~v=#9vh<4?^RR)03ZNKL_t(1N2d%^ zV1`Q2@KOEwO z69Pxq?1}GEm$8S(1^Y$VEwhFG`Z_st(EDt8mC2`s6bg(k-tV1eVdWay3p9#9iR!F7 zmm%tIDVAeWM`a``?}*WC1z*NdH9XfB5za209>}_c7mS7&bRbjZY(1U9+tM@#IXr?1 zJp)-{?yi(4RA88t7UmG?g*t&8O7YmRgmW`T=sMc?DY;hWDH14j&1A{~ZFmq)n^oCX zQiX@rclSn|Q$yz?l&3ZNP*iL7{~VLiYGim5$CR3d?i+6M z4Jh^ZWV(BsPj~CfLbn=_)12O-jk=eq^?SeFy~PzC@FG&Lm-%$|vpX3LdYJpCR8`F? zSyQfJuGKqyc)dQO47NuWxzEZ8#Q;zbn$5 zJeivXd;QT>!&59v){@Xvd{4Qa4YKuP*a6>A7{Qo2%b-j9(AD$}`hzwm;_jU>mC`7i zBe~H^IJ$+@3gkoP2Mhl!W%OQw_xE?~bG!3%o1c%Ko$HiukG&-$T#FmdvyHl}+-H{6 z|8aI@+leDfP`gS#SNdmCEf;2FI+!xr4EyK+uJzU9b4JNGt4W1Ru7$yx8`mL{&M-i58Jxdq zoJ)9&;B<95bbgA5%RI3Wlf_85oVWyT;upwx4Ge7Md;m6Jr|gQhSp7CT8I9-*_^G&1 z>ltJj_K|*&&`L7r*)lAZvcmHdjuPINhpU#2xT3>h#FPbVrFfO6a@gIu^2u~^ogx@g z+vXuka_JIfGO^g)laaM`My-OL)uY74CP1`H4`imrJzwt|z1TMuR-^Fs9!xMM4QbV{QCIlI0!v_^zqS_zXl`qG?ygVF{=2cTHI`*XP&klwSf3 zn~;g1Uw18(A?(sK(P5rHTNM$X8bohla%a?fR?@VEVi|SwOmX6vrGuDmUdpD`Dbbk4 z4o|mcb&G=XL=Tx-7_0$nT<)tn!p)5=_)G~Hr!f$Xl<I!dzF4+`T^D>=}uqHi|E?Z^ieF@a|uHAGn>GDH;7-Uk~ zJ9ew@5U3+y{pIl)|G!^lJ<>skeP|in;c-!%kW!gYeKNv&Hl3amz>zQMlT)It>e!UX%+mSrShV81-HJTt^CJ#{+|qFyBnYjNu=Xrk**NSWE0wMgO~^@>o%xDHX>N_zr3x-2 zkIwq?v*P=;SQgCXB1N}SxhWk&jyK}4d}hL$5=E|lNIUBwc2*_i3cJr z0%Mw)m?=%t+SMUxqoQTe#C3ZP)qH0L8ZdCU38SQ~(<^LBfmtI?D>lZ1iDel|#csAI zYjdrgE)eh_2qsZ*(YLUrNJr6uNYIY_v{$Wi9-SCZrG5gmDLu8Q2E{eV(|;yDAL@- zHOIZ7W@||}&8&^}9&lNDv6Z-j9a+jptoWFV8-W*$^a>7={MuVD)WH$rf+(m(* z>k7GUr|k&LcI!2|s*fFU4J+~eWX7UvBD|Wbe4XMvY5h;Khi?;I9lz+lYFy~MiSd1{ z;{2Rs+S~RUw2tt)xA(T{PaaegMOl(W1fiS;cfi`G^i?oaY(|4!PDKH4wFODIiy(wm zz1tSbV8rSWQvBV2>lNo==9PqMK`a-uYMgubXsM?dJE7APpS2{GFB2=zdha$pQ;vQ6Rh2pwM+scqhdbwB*YIILai>Ej+Y5PUH(5n~b(xN~`Q8nDXM6JTYrtUCvmgh_39W!nr(dyK44%coVq` z@usQ3_&Y=Yr6;&m1hDGwgW`(2UEtiy=OS{MLl+%KBBvWN(-@0+G_QOXm=_A9b0 zFPLu#AXmOa^n&#tGb$mgATbyj44jNOP4>>_-FvS)%{x2+3l50S+iWyGp$oh@vZ zjs_P{J4KZeEpc-YneDdDo%RKE;U{WjY>Gj=g;1*Pp7Nni#W|g=rmZrP?L=+)JdgMj8C^|X)eK|&k>w`hKA-N0iEg4AiD}Q)FMA;jfJ!kn3Xib@HXn`Y{06{& z5&^$5IDXN)bP}r!W;;XdC)dZArkLheS(nM0Kd&kumRah4jVG)ni~eH4GCoKx7Jmpg zrcN`8>o)iaJZ(9egQ|H6DOL0!;S?A1t&c8>|2X-XcO|5wMCfbcDeDwx17=5R*s44U zWQxpC=F!8`79C1mR2r%n(U5zJE9{odTVFH=C4;V1n=}>4g17--=_F0RSx-lEZfc=v zPiFeEy2K^2G{qM6xJd_sL#W0dk(1SCX+0DWxL5a(Fj-F7@#w1^58|Lyja6BCw0~Y& zX-oX=4Ni4A%uBoO_#Hxd*r!%s4}XmL_-3@3@Z3+|66;hxtwo+!>0T-d4u31O^KDlY zwY$A}Dl}WkLZ+#-8t)05T2#uX=5H$hx%#Dc(;ZXXssQhF>vkBSBVA~$lKn9IvOgVP zETx%xQ-W>zWk-`%{1E&#ry#BI2pItbdtMmPIMc_AQ4I3<^2jg$JZ3Y3&G>l1Y!pj< zq45{$tIvlZ8Rdb1f1jTP0W&o+p0Q75Qlo@av?n11dId+V^rt-Ux%##5=;!By(g3AT z5bk!}@F-zf*ByjVM8d1MIz$BY}`3~(D=XPM2r~Xsh zRWG-#Xl31%0{w$vy<>LY=hj^?OH!YHJLN%R>Q z^VGWpHJTT;NNH-Z^BH29@#V`cER_|W+Gglk1WZ87$w(|vdmJ)6It9|`KOgMhMLoOg zsFps<09Cv-!He@?QYy+9SeiJ`Z98v;h2bj!^o4;K0bb63(4^}eoTWM71TAfv!x~Ic zj!I>ti6`bG0keAM9hJySddO~hJNbD|QK%OoAAGpM=H!^np-Y08i7}5232KniPtw60 zz_cQRg9SCsd3ntfn75{anz0t#`Mx=0slq;=?{9L?cg)|nhc9K&kZ|2a8)w*xNDoeA zmLQ(caPW^P>X&BtRkad$(D#$Zs^{y>xGhP`ke`i{!JP`RH>)G?wZE^bUxM$7E~smS zbVkMFL-IV1TUFxD7Zd1@JN_=F?zdp8APdG{tU*y0xa)~iwLa2V=4S@uA1(ZS4h$XY2D44YrNuI72AP8nqJzdsoZBD?A$ zQ89hK7rKGg+1eLaRB56ZdH|h^v?ZBMo zd2V1|3h^-?AP?EkXUW(6`SU<)5<2EMbkmn_q;2 z+_lx%wdQUTFy(Nj??{9j8VMk|6Elk`woszY|DvhA-B>(S_ zRD7)rrBt9$w<%M*s39E0=JcY28B`zLN$S+w z(8T539CKWOU0AEhS@aOAd+_X*L6s|=&PK%ptCys}Z7sKE+SAFxE*exP4-tX6Q|p?h zt&>3^R`UPcLE@g}Bzp7DZLr;^6HE92Hd!c)C@r@a(*-Ou@cW-9I}o|d#Yp7jrb$@8 zwNhW7xTeK|_sTBDvtqb-|L>Pn%v_+KDUb%PegSRYImoYP3|ttav}Wdgg1^4o1m(=C zs~pKxOWR;H42~q@CSAJf=6pZvtTHI(8WOHnQDf2aJ47CbA~#aMTe}%*W&U`OPrDOa zXib5X+lt}9amuw!Q?zvnrB*VOL^_t!wjed2--xk!PoSAeY~ep{inyc8h=@l3$NA$VGeb#<5$ts-csRO zxcz(kL+D(MzazQ)40wl+ajDYXucvQ298I_UD!-BK;66^E);Z#Mh~xRn@hrJ4N!Nxgm^@&<#d|3fo% z^f1WYyd=+S>$F&!?ymYO2FeT%&N}$+rPe|oh9YV&7&>VSw{r6HxXrGu`D7ueoY-#k}rwIA|(*&q5zv-u5=kPJlaq^Mr%7cWhnwd6spL}8=OTiU_&!D_@d!u zIoC~!v(uPbmZu&w=U#B5Y*@5cHJ$lG{jBiykS;syXi$GF@KN3Lj&uvZ$wkF)Nav{vnSu43Uv?}<4dh7Rm%4IoJri^voZgWNrh*%-DtYec7HvUJS3CS z^S}STHvOV*)NqlAS*r9O_tk%JUBIm2jq5RrcatOUKhf$X$r<)Rxc@Y6nrSW8j zW)gH=^B&`avRt`=HtX7HkU2~N5YBVrkXvQ9G9<^k&=((c=bR4Oedxq$j5s(hr*qI= zs>fHCusqapK^hu-sb}WB0$T@{2UQxuDq}+gDZILR2%h{7sA1 zQ}q>ztSz56kE4%|(}s}2G+q$LI|5GKkqHT3n7Tvy544)7p`~x` zC|+g^E{D_W1wVbL{^RxcTd)i;K(3Sc$f(*V zl8A>W?KNICGlZ`9UV2Cst$S=%xi`JPuDKWW!XpCDI-ry8y*5_;#e+*a1}(KNHB-{s z+SE+#g#oO+KkhIZ-_g@v6~;7qTD>DFV~ZP~C}u}2{t8IK5o4iOPVtF)36kO{Ci*IC z`yJpkb+%}HlRo_%%6ZjmbFNU4cNItZ9pQzS=N$!>oOijDa6=WC%QGO#de0g5(0e=s z6&LE?NP?!(OsQNYF=|Q3lhmGn2P3pxPs~7K1(iY4@zddiHTb&ip1SnQ1tGAoHPjoP|vjw3GVrqUHH!2VD`G*C#)GiLT ziP$)wKKKem9@+HYpK?ROuy75qZ30-jWOJB)a*ZWK^K+AXScPr2Kd4-_z?hK-_^o|$ zv!`SY7FFd@R1M`AIXqY~!rAz$DlnMGhM;Swt|(f3J@g1U;+KJhA@kEus(2*_Yy*c+ zmKvr!sheB;MLFMQ)1UcVQ_U_?dmLKU&Z3^E0XYh7NM$Dh1p2hAi)x3v*Fgi5>V_`{ z+Pn5OSd~+X!d6`~xQ2LB;57E&)Q2!7wfTl`fU4!URy0x@`~zK`{Ax>jlUb#mcNM>y z?&odmT|m)2hBdwi9xn%0$6I8?6n%TQEUirI;IFc5Ewz_4DPWX%R~^kf5tPw|)L1u_ zRv=_r4O>GI($gM7 z9UtwbLmJ_#4z@JD>*G#)>9oFH_w{wXRP{1~d4aRi;24OG)mei|6DIx&>a6>!oFmlQ ziQm5S$LoXmjmZr!@A{CF2-D`3qirS}V9Z*oH_fjz=h+uz_9$NAsv@G*b17jNERP2Y z9VzNE_6U*DQyzSO-6f}*u3Ygi#(zuIG+Hg4Y-u7r)1zm6nEbYolS!ArnI(oAG8EKF zrPrv+94)ma*dza(arJ>OFMZc^!&52YD(In&R;GBqtd|`JN4%wyB~->G>*7TKqJa5S zIZ)8R(9diDxcKNnzT!}>L%CKzud`*3sKP#1;GgW2VLi&>VVlS*oUJEIN+s5*j;{~O zYcfPIhY&QsTY{btM20b#3ZaMguJ#m`VK&QAUgrp~)AIK;*s5A12eja&vGgPw=J^&w z<{^le5>JbVIg0NQJ)X5igls(pdOn>^d}dw|BI#$dr#}IW-Ux*f7?T_7&nkbGtBFZP zTrLw6jo$VX;T9+M$8sA#D;f&|u`l_Ky&V490`S3(w$yWEBHwP3cyYQs&awexg)ETc zIl_-=!-CV;x1PB(LH^;VLZX-hDV6d`hGBBRWC%WOyoYHh#7*m{FhbgfvU#v(8E2vs zvxbHGF2^9X(A;h$N$+-FWvUL3G16r?4qmwD<*_)(4vb@NroWBqW_-q35JMe5ILZyc zlr;p1tln^E(*4pjlj0n#Ku8j+{D;Ty?g6SN#<)rd{_rH%(Lt(PXSGo^CjNa+?*`Z= z%(gZ~jk9;BMt1wsczGjAyg{Uv_FMn5`=;eMWPXz%{i|JG+Wu{?+R;4zKzP-5x$E9( zU3+!uB(_t1&$#Q9PQHMXwT60haCntBD zsCeas?>N(!u?WF=b|x?ae#?J8hcVnp62ZOou5ZVei8UIrs?6)Gda5quMB%mpig@uK z9jr&_cOQUkfH7JAMH<8X@c^$GX-K6;KUR;EuchFUT!n?|l|j5$dV(=2mXWv=Mua9| zvaMpRr7n=qiWn{r*xP-inRJh?)jQpO)n2$~)s_hqY2 zT@(dftiJvC%8hF>Y$~}yi^VL;wRO>MFr8iGYDgOrzfHq#)YLTDXv_;|PW109DIbLO z*myMQPaXMTQ@I#{IDA?wUz$qj7xi3vy1Ex=RhageLuW#k!-~cJV8xxI{W>Y<$33?E!r@=y z=yy|)Fd`2&0w^`0-fr@|oz;&wrdZs}$}#iYGZH)* zIc_0+=E^vvG&(#9-Uz<)=pNYn33ayeC3Ox(a_hr&bFNC}iGhXwQ`qBLHLfpjwXI8C z4LaaBDO%@t1UgRXO%v7Z8@awZl(e^~1*|@&^h>_4O5E5!cC|uvN5|AY-){IBOZU(H z??Lj_h;ZMR(+%>f5u&A5*0fYZaFDdZlG_FdcEN~jqmoiSBr7*hj#KajVcaX434Y@-lbw{;DT__a|UzP$X3DuP~5Bpxk=%Qd> zod#U0z{=Ex71_b-H^3QWaWMP{#SoQUOJ5dg{lR`>Ch$f|@QfigqJn$>L$x#5AGk$1 z9gE^@hI2obm&{@AT$*%t(r7U+>SleL$Lq@Ja$J+f=Cxj~>SkDuR+G0Tx|T&}lbqA! z&{3CP-j$VneADtQwPx*Wv5XWI3k5&&hGYyEn1x zFD~(fbM%5~WeKLW#LywE34q>6pQgx{kV<>cP-QtUB^K8jbs8;m(tr`eI5B6UQfCxH zLRN>tm3Jn+g>)6dPGMU!8fFMrW?NlyN!Z|6g7N{#8D5SU_?s=0O8`h`iC$P>>m1Diya2=z_%IHMrlg-cNMH~2` zAP9lAKBa}`007=*rcR+8gP|#4hNxoleg!onWa`}LpPbfP4$FyaVf3oyH#3S#6&Xm> z9FUnAHe=CHP`10gd)q>~6>p+)sC75-#JGs9PzFxHN)#>E*M+m zw*KzT*N-n6d{yn9^Bz-__AhgvyT)U4oX*-WtA)`~1hrpcAJj_6DpDo2yIQy{zsvIW zrxvEQqmSRE##P$Yc!sK=IW_C!<*j$EsT8fV#})0EBwXW^+D2M0tM9$aO>a@dd-w%4 zafzy~xMW&fZ`0#(&)xC{zkJh>iMZTYp1b&bQf^+WT92H@8kSYBT(aI(j_?J{J3wa` z8EzEYm8Rjx8nkrDQ!~up-}QcJk@ll3etqfEq3)IX`ydpOBi!l!eVu@Yg3I;qizN~| zEV+(+3F;5pTr+ zrO;eo;73Y%GJDb$ImpkWYOa0BKq+4@JRMLNGO1Wkong?HHEU6v{6>&z#P$>Mf#?&R z3gI?Y?14!j53Gm9l}uuKpb6!cy1L0Z;z2X2*_&u6qw4iSI<>5Biu7M|4xT+e1^3>&I*DC8%7l2FmyKHF%RKoeY9Fl``+=IIhLlP&% zlE~IIZv-Kgrfd%Qq?9~4$kTZ?b@=4CV8F60gSM-fX+Nsht{3wh`9P8kdAQ8_yRq(4 zVRafCatK;M<}V?`R|;bxt)IO8|9qW+dg`_kgk>z-5+*j_oF1C@f6%L$*_C8MZ`-du zO@IW4u-e_3e`F@Ij{Gk4rOe2)!iS#P1RI`OnT8lXxg<#2hTc5>bO{f%WY(<<0p{}E*xUw{oTvYVbFYFw}NAVX=l z6-`R2%7swh{w3!Y*;*qe{j}$z>%dO}9RQT3Y>%&=Fo-`4(I?bQAFgQ~GN`pUR?(iL zM-tY6bWX0Fohcl~`QIEVBx^ZxDo31{T=X~^A24TU$1SI5ZiUBMx2Th*g=(G00Y5O%8a ze&Sx5spwXu+~OTl2Q}$5aiL?Xw5Qc)UZhlkr9RP)sh(_5Fk8(gBTxarS{Bz&>N#?c zVXB{SvYz=hfHCK01Kr6aKaWs~>I(>rT_~!b<5t>Ocz~2aNbc1jEVR&+D}BRo7Qxti zyr^JCh{6qaB;+*gEIRAHi%}u*@~RISBZJfH%}T6lt7I7u_=e+w zFpeEBgUvMO#h8vOa{;a$I*)KAz;{l!eF{}1m1u`tvCSEp=+zMT&W^JQ3l9TP zQ)4UPlL4bGpjE5HSUag`E8a`PF_b?(yk#QOL#5U|rn9SnI)p>)Gh_{VOp%lV7)C2E ze0z^nc|EPM9lLZ06Wm^GBP^ZOT)_`&0wXt#F0(eKlnJXZEM8Bkyhg`TsThkr`Lx*J z>lYc95> zUbAXyWnw15QY%Y>*2!T%Lu zv~+9b)Zz->Z}BAdIxdF!JKxsxOE?j%E5Z3Ri%6YbTPwvjh>+Y>i znN3p_5@d%r^@DP|0A6hdAGbWh3uER3X$+V$(^RBLhQakx0A#UA-m%kNr~L&k2Rh>y z!j7oR+Dk3oSU*XLz7ZY$0$X`Po)RkY3WE^4*KO7OnPMlFWzL7`;bD`CPsS+bMyB{q z`MBy@YcGr{tTZDIY0KZEJ#y))v79dFC5+Nng#-`&%FiNyD3n2S1D+Mqun&Xlm+R&T zZDpxfRw#L=ftkjuV2~IzBly9l!l{E-4#b(!8$^i4O=!wsr9T-&K&s`bdXzW<*z`-v z23cy7Y#U~hB=Iary3CW=q|A;qpkq`%Ln*SR7_seG1~xiN!EDpsVeqyh_{XN)Dqdtn zI^XrCXl;tBu4Bnlbm^g{=ANQpsNXtqbfvT5uq=so9$m}K_SVu6ZCrhkdim0r9ZI|# z$I2I$*|+A)OK0o*-WIiF^XurT^Ob+839G1EB4%j;N))p4_b8~YZe>9pA%QXyHP^^r zHEiiZtdT+|rCs?65_bGMh7)oaAVt`m(S}FkNj;fK-2r zLn(E%nSz=VaOl8mM8L#*h?IQv=5;{;W#>(;{>Tm}r+&$>7or4~K$#N5qyOyo5UMyDjlSyap%@u-2@g;E(+f0c}cepYl33mc9r4gwF~>%#2}$kXa%ZU)I?HFAc7_ zHjhcJ?E~%6S#v=}tY<-bB`@?sFQYJ02CSViLbOmE2yReh(j05xb=~XDrXr${S`um^ zh&_|ZW}KsP`aD(u=ZK3X0`ch>=&95hexXq-*pbm7U(Gs=HrmLn%Sz=@zYqE##qQRE@8FOOB7ml;In3FR6i+5L>B+T5EHQZL!6wyjRMua8{u5xxAjrO^j4!P{<2w^~E62F!iQ1Ysr0o zI+g@JYaD7G7t?NWWLa8lGyr#R&4lmXQ3SG|P0!>MfzQ+UTe>bp3Nr^A+d<@ITn4O(SL??HwA8KH@< zK5UoY=ijHlwkb44ck7r>R@svd>_q0w%_H0s#Xg=nYD7XfX}>DUBs5_+erTlr))HKz-X1HZAiz#^df1i&~aDQu8S~aN4jm|Qz|e}E{1&3 zCL*i0<8pgKL;_G{Pk{IpTPg3&*_e{8Qyp*Fcf2&)=k&_CVCi}ycmGbZUtTsWN#@pSc?5iL#8*wYV9Xv^nRcVs9Qo`cK_NQQliI|3Y?F9cnP zG0j=HI$kCoe#t`2jWX0vsFM|@Zc)<%2Mh9g0xcKzyDE;5-J@R3?m-m3&cr* z(xUTJqL*JzqB)i@dzYt1yLIeK4Y5yCB9Bl0`YMG``)RWrJ31pO9mEyXBv794_Rwlg zF`KV0PF*@pFu!K>thuh;NmYWH`eb?6KZP3entCFY*E;5Vw-RyE^K^8@&cW*?;I!_w zZ?F&WA+It0&hts3@1$C0M3388`XJ#m`?w3`ZHSF-ydF;9_j|H!t#tJZe#$2FwJlu2 zx!dceA^rN+J^(r2A8={_jis(vPqT#d|0AI~h?dve_QJ882EK(c!blB*US`we-bzdG zsP?x|QIjmC{79bVVrmS{w&BKGWv&2LlbvJx_H-n8&N~SR!D@j;sN2G44D;P%S zQW`^Ph|3{iI}nmfhBMmWymk`>aE0**2(t zIojrQxfJY`PGDW_R538A4x0b&z;Gm#RO+OM6=Q7yq7hlFu!bs^o;(s5&yx)~*DVN4^2} zeBoH@aa4cng*ST5Rtq({{JCw1=L*BJg5bf$6?i!tqe($Om=(_q3%HDyZ$Eoy?h9bH zTyYdS*^1M6H>8KHc}M%)NCmSTvNckXY)0Q=!>#*eVr#mduJk0`Rnvv`!1u!dUR2Sq ztJKz4iy3C4ZRqB^wzzyMR{+eWS!V)MP(#(s6|qQPyoYJPK<%0tS$LN@+9RT@Q-udu zwrZ64%RG+`{6tl!l3G?N1vxRDkS7m1o}(@*FhX3+^Qm+BK3dR{#e8VU--ZyTbdKnr zS#fcoz^24rJ=|ruo7d|e{d51L>s*-I#$g~#Jt&cuB0F*0c=G>$=y7)eid1}^o4IKk zJAOqVfZhGF>+P+HH4upPzPjoui{D#UvlaGgTPwop%aq<&frFV6`UZfv>X{czgNy|s-Fms(h--rY3ZYSECoBE6N%7GE)d?kK*1{tlcG zLyR@h0qlQD9V0vrFN}{5#~|K;bx0s6=vpGX_ua9G=^f?qO>$qpz1k# z=p&nRK^!#TNOc434mx*8FzQke2T_Rg>Gib1GlSl+jaIyLDV^&qI`ML7 z*}Zo0s+?;|Zs#)#m|x*Wdr>PYhwyBSFbf?%LBmTW%UWXA#KouP*4zfhY#3Qy&)L`E z_f6%PJbSim&{*+#j+GAY6?Af{gQJLP*HsK9RaYWOQ86-3t z)&73e2{Q=0^CGCwMDf*Pcqq^lIsOLlP!Z9HxuVax9IZ+7{rq5lWvPju_OgA>KIH!# z<>{ruN~)?4DzHuNMYQ7Q!Up?RTJ3SR#IlJN;aL*28|Lxq(?PD_!z-Vf<>PCznFa^N zpfYGIO^zcM@e+2ACUT~(U9jI&30a1qw%0336YVkOrc9rWPMESMYt4&AxZyn8VlUO|{+uU|PSx~3p&l2!@pXRv zOTBfT5IVv4`NH~a_+rVv95-^jOd4$9(cGC;#%3knAgU?1qP5V8oh)m>KKgCeJZKv1Pcp^p9h zykg#;sDwv|7^<_sQj&(`&msva1e zLeh?-wy;Bl(A%o5*1TruO-N!q5(!Fq|326Q2TjFgipY$LN@9pr^&{S)1J6HWdAmg0 z3q*kfy+7tcTlY1)EowPv5ySX|%I9c+WEAd9P6ZxPslm$Ua;6|QWk^R_${U0tylr#B z-(Y{vgW~|lb64k?(CQ3Nqi&56T2m>-1Chb%MlALjCG2ymwq8%qm>s#G@C@~$D1XfA zH@$Nf?+_DjS&hb1&4c$y<4R*{>t(7gB8`|WUdzPIFg2NLhNU$#V`-Wz4tM!L03$*t zB&kyD#m!NLR>~aYz_1C-0fc6ntN|4w;x^h(q&jz|LtZ5;C z@;00!Zt)Yy{F@v){NMq>A}@($g4&w7)D(Uz3malBf`@J*9*uHru~>7EAP*KKUE~@w z7n(sD@+)Cl{rBHL;Eq53{-J9NbcqLZxISb8GtaMuaf}i<&xQ!rLt$m+lhRB?r!W&m zkIt2m`i;#h&Rh8P<$GmEMZelnFg7P8oM)?EbM!dD-1Z!`fGmYU61^vpykT zd-AbI`K{KnUK;1Fqh1>rVo>wkghiWK_y5vB!g@tIUG!-0*UF^{OV=5IiA!eNZ>?7~ zxW#P8(A+{NCn$&7(}GpVR=sS#qwKD>dN%QKiBGPxrGgj;^Yk)F0;uRL(Sp0aTjP(M z&do=zvagVJ82AhadQi-D4|K54{V44yTik;?--FzRT|Qf;MaBcYF6vFG*VGP|f4nmu z>rjKsh%3ydA>ta$#Y;pmJIh^W-2DmD(|`mmd<%`NhBwme8oAQTM!FJf?5p(G=ztBU zq$KK*h20rR8waa+}#z?Eh*ldfcq$ZkY5aJnG6(aGdLN!n$t<5z#OOaIJsI=5!oV?#K zGSRTeY(+^Hme0|DH?sVnHI%9%)@N%k7w!5y*G6QN9J&H8D4kh{UXV9urw^r zP8U4TI;*z%bh{?@Xz82mz>{@yqdZA8(|+8X(V%SOQ8`zdYU7`!hEgaNCCxWCDOKS# z7PdD_0uiZDcm{fn2-a11Kb4}UAHz-WZ80^s1!2nJQ^`YmHh%c6Uc^vfoK0%;FHw$@mX_k>&$)qW4k2%1Oa8@%K%N)4J9jpV;>i5G| zw40?*A~O;N6woF4WsiNc@7RTEire?j0rWP^6=sx$V2UisaIi{@wP4yBsm2m>m*9n& zHfGI#vjR70p)y)v-kv);#!Us-cewIVOSp`3b?}_Y{+fO#f-;a_HAH7Egk&kw@*`(| zxI?zwvp6`|aMPBV_9>kS%#go7IVy*+O||sC3%OKtpHVLphtcJ|;3%HzQ7UClBQh^G z-`~PQH0Fgw(?6c?S`QbPoa9APOIU5bLi`dn2S(P{JCTp5t+9%q1X(w$(_akg_~Z0nxt;K^6~rab z;upJmMS^@WS6b@i8yCM+f_(snPdIh(pdrGe0<9l}EE;a3yk?w$ zV2X_byqpF!Ho(>%-+U0F`9$`)h2WVBr}qwI;y{GqQ@JPK>)6uut?qR`=Rsco_<>%!?}JI;C^kQvKq-W3+B(8BdI3W(}`nC$&IHk#^I$s~)2aT7I#IFpV#T;{s5!6!MrQ+xSLbHx;-yR>hG*K<| zV8(HA4AWo**m5GyjJ0%zZuytCPcb+YJQhVCxYf$~8`34hYy#7adxc-5{JyTV!8z@aHXgI7%#xc-U1t0Xj*_XYu=)U z@3_Lje6esO8b`}g-l|noK2Nd;)w3j-NT@HK2}ozqmQZjetTES;^v`Ijm$@cvFb?ac z_Hdki$Lr;EGAZ;#p9%^@x$CCAvZ}e%7SX!gT2HNERq35QfqHi5OSW?ZEToh1AXLQ7 z${eH!W|NIZ&4|S})uHi2zF@Nj8NSa0pH&ejPmN?t`G}R zWL-|oof>aK^e!xrBO@!}D1J;dS&uY{EfW9_m`mohGIHB7ODN3{?i%-v&yj^s<30Fvk8#sA%otHvz$)>;8W7HPpGR?)yHU97$=GNDxD>by~vlkaci=Rw^ImD@l@|*bz-r~O6r@+ss^Kb z9~pk)t<8 z-4xV9#{ZZbQi*Ia1ow;c>>y@BANzi9XlpT!e!~{L{d+?}eBap9QGxaD7eleuegkHM z?%Td}$nOo4Shlakbd<6QPZGh4j7SoOvXou?4miwLl@H41QowtL2}9n@qy{>hu*jtI zXiPtUd!-VYki`l;FhrQ2yQ=n!XF->f@*?gPw58Z##WipMJ5ugMl@#qrjy$qAp9Pgo zX!%D3KN+1-o)A1wrfIpBO%5$BN3PzL&@?W{$??mKaRTJmt8W@yfRWQ@MGf)1Gl{<&Pv%SlE- zZWNEA{<S1a$UD>HFnIIEN-zU6}}3;flHqdjN(1p9P41Sdew` zviAak6iL%J)lLC4sFX%`r%xoNgGGr+N6tPZPXpl&E?2D9s>j4lg691FQUVgu&k<1k zZT!|ljwE=KX>tPiif*I%`4zie7h`8N2@}R1nUPGAd?|x$pAGODy6P+h*j{bWT!se1!0)}xE;>{$!OGbnJ{ws2Tu zg`T4|ah!_l=sZgCKf6Xd7I@4DME)KZ2pE8WtH(Z{M78Z=_gbk8LCt5|RQto0PI=g| z?z`4HSUTvGy6XpXQndNDVx?11Ax`(0GoDDx4dpp@*2m#*JLInYV3$;~qKmrVMU4w+9b$lZ>xsIDYjB6GKcDpO!Twc4xx!xS&x^;4eJ zWJvhyM5fW6>zmSnU-{9>JBPTd{q`xL`O~o6g&?kd*1PN8+Urgi+Ger){f8CseFTAV zTS&*cZ{@#INEgQ3(}T43!JS%5!(2LMuXMX2b*Xvm3-j<2ezp7SN1KrLAC!%L@XmDzQRtk}#Dc z!|H=6SS1L|sf zgk^QD3_cyuXU!|q^t(H|t2@KAYGrSx9{ku;C4JZp=Cr>=dw#UOLVBWeegFGcn%*~Z z2vKl~?*rU^Z1FQl{MUAApJrcyxD_s5d-tD@h z-s6@gBcrL2D)+p-QD>E|n~1ZXvR2XL$}j5_$c|hsOn80E3$$#{o=zh`w_s1wVL*Ff zIE>cG!NgEjO(J~MB8v4n#LEn1;2)BY@1go*`Sdhq4|c_2Q;L{eZIq>*A@vJa%!O_o z(Sa2%JOs{Ym@Tu3RM|N!xonmIazM+Jmfqd)uAesg>QZxkV>=6c;*G<}t~TbJce|hp zK)q|DMSj+VH7u%fwaihchrnsEp4Biw5h5+7;(nMV{0j!0A!g#L#4kC9k$uEDb?l9` zNu`wP;Wr4rFx)LQ9raQ^+kqW+sd$WE`19ZYhBoH?{Iv%Lc1ws%W;Flm*FCU7d=Wo>&W47} z$;y7Nnl3!_w&H%PRQbyO-Zq|vJe%aaGa7<^i#ysqybrW=BSl}mB|_jUk6Y2UWe^vbe( zznhD(0BPC({b9SBIUSC%^Q1H)r5KTfwMK43Z}vt&FSs_=K$?CeVl*a$GevRSb^&9BI=Ydx>BL`dnUOgB-u6TUtW#5nuXNNJ2H1cyyXhpVMN;e#iXtAS>T8PI zO_Xj=?D07fA00@{sHfhUff6$%k)BIu&2JNWveGWjD(!Mk_kAes6$-(6H|gTSLW2(z zh^3N)a>KM2Gr}`2ZN$Ho#qEF_Cw8;*b#QA2nU*- zM%0~wK;}m2)995227f)EX6KRm3@1{9_;7^2SHt!Pr*g9 zr{6j;;B)YF5Y=VWwK<>CX1&}UKbQw$gtfNeL}X(H!6>UQHOV7|^W5~7JDBBx){ukj z0X@xvM?*->ng};iBBzUOQ)b&L?OvG2Q>qcM%w)m~j!&+^3tkO}%(;n#?SkM>-djF6 zT2qL8NJyB{v~T~a#QBh{aNPk{DWd;=;T~7lZnHu?qyz8R=cY$?-;~ZF!rf;^!?pXR zg!zWSUhJ%XKG!R!q8?_-4N|$8&E_e63}mleO<@Mp@ji9Awt($3vEKnU>RnJzuKQp* z9darfk@$gH(hjn5e{1yHX)kC8u`+b!(G*jznhzrJ9s8{j#zCu|(izy*UH3k`%ey1k zDgka1>5w-XGXsL1ZLtiI96V$ZXN}bF2A4?Ydkw$v{!C%Ett0PH?NpfPk1bl zXk(0ik3N}0Z4}$YF?dc^a>*a;um!GxIcw48C~1)`qwqNC00kX0(+ZLR%u>nO>^ocg zg+H*qXD@}TeT@$^OGeFyHjeMVeHX5^#1TN9Xi@yBu*JFNMCYwX_fXDI+Vw_*>RduY zhUVIY+R_W3uSp4!46FTacBHSDc@|$WyP=Ef$qn-AMzm*Iuq4U?{~N#IDRYgb3!{-bgMT4sF`rY ztOd=hzny#ZhXKT2s^4%7)6MJRFCFyb^{qDAo%$E0&O|x;M1#e({{3MilOu}16iT64 zfId%w7juneAPhRwC_HDgKED{;AjQ0YoS@F4c$p=08odfu0;OZF=9+=-G}h!-ya@|L z8~sG#?-T_xRzPIEl8PiahbBKJ#byuk>eu%1$ny#Boy`v3UbcMPyM-+U> zkb(x?X@gte@~5Babct>tAZOL|FOu9-fWsbxaL61ub<2}wpHcVrt@3deYpQka+0GO6 z8Y6s7t>dB@SszWnhi}1m7Q)WGuDNWVyZm+zp5V=iL&2WufJc>`%5mgoH>2jjlEq>< zzVsdmZ1YC;PCBRVu>L;8FKO_7=yUbnKWb;cRBB$+csA40LHbM>){4C^Y7U0RZ8$*vJASyQ%w?N zvDPj^bWEae*o!3p615=-X9uCn~YXeE#pkT z^#7;p3>VYJfgmg!$(FFONgyHZ`#v%7x-f*b=&SlJzc!4YjbPw1f0tXLIvWDC&jTh;m{Sp!YvyK!?IJ18+8n0NbHfhQ? zuQ}>1)!!B8PResk>g3I+m2O<3Gl?DQQ@dML(|yIu*`2E%0Btg=are=oL-jH$-_3Zxid^ZsIxgBIQ1`D7-}k+2T~w zb+4}3LEQ82!S)+h(kUiyNr1W;wl`d?<%ah@Mzg2VnW-Q?S+ zr{LM$;4|8O{_cnh+|XG+{{CG-%ChP1wk(gI*SfwQ$YdHgVy>lVgK4LwD6IQ~ZX#3( zayiJST&T$61a<|&iPbGZc7<<{d`SwLBL&M;f9)J9?}Lk}Hd=!-T6D(OQ-(DpmmYiM zV)7Ojz4B`6F7pLvOFN<=m!=<6NV8|;*R8uXeuz(DbUN1Zx4zMcAFhq9e7!)X+Rz!k z;mCt?nNw{#1A1pg6h+O4%_}VBR+}5e$)CxlTG}nEW@@Keh~_eBwC+I`lbp?htlt`T z-8ASXImI!qR((a>R6#*qro`;F!azcN!O{qosW2%Vc(Q@C=DMSefK{#nb70$v-tucq zK-UKTD|_4|7J`Zmk)1*H~TuKQ?m za{@X332|Yim>qY-vvAgfuZbm~sYsLEH zqVCcC>^L3Jo7iPz`4J^IGhAq(tKdHp^PANE-FtnwzlH#s#=7l4waO0CP1SyFU(7PM zfp)cn`V33yx+Q9QcQv?(Py!nor4>Ey#uisC=%5`f8e;Uv%YrVDhNRjEW5p^-GrQmV z9F!6zI-Jznu1l8Zc!Lglm5Uc_kC&iXOk|KqOX_B;wtMBrsicCHN^p(2hhZG+Tc^j<`JIfgMarhA zmMM2Kx>AfF4I?-Q;E|Wd#v+lz#~dkwFO%r zQ0o`7)OXk^8o+Eb9Koioo>8EI>@s=xI=I`2KtbFGqjk#cCbJuR-CW{Y6i%DTMayel*o*x#O2XyjVJjADviDWEYGoiAkSaP{ z#By#qc)n`utA(fGKHxk0yqMbe>N@GGm*T5ArG&#^?k| z21~O~qo0cZ<)810SNMEdc44iqpFYw4eySjABK@tw_VaEVVIO-ls1So_j<=21!JhhV zF^i)B8?;J|B68eNs|DNUs`ukU*d>k6H;Li!c_`AV5zag|!;UtSZQcv1X7Yrix)PCP zpKy|n4s^;E{sW z+?S?VgJbU->rr|;7Ry<1-h-l*&AAwQoW)t(+%0k6_r<-t_N2J|jnN4Ii@a!UUJszk zo%f~Q13t>B=*~xOZFd>6j9tl_P0QR#kaIYKEY87=`Ax|c`kvUIYtEYz0+MZEd2F!I z7yImr!uxDqf&MISLuxdXxuieKePv_uKm?NLB|9edR-)( zqIinnEBrCL>1dI9*eda0mR>VB?TcBAtl^Y;OJ9h>eITMZFZ;l(dsgE`MxY=bv@{k({rY3eP5!5nsx@#L>=l7bA{3T7)0}KQK%q1RVdfjoagms-WTY&`LCaxdL6a0I zloxef^=qqQo$^95)*#b!c7R8*m9BZL3RA(fYn5@lAR1YKYR-FYffhad&)2U^W}t$h z&_t|zD7y40*^F;$IbBqE0`IuPzOd)iden20yr#p0f@DjS;H&^ae?ren`ZxeeHs_uU zpBxQlW&JQW!+f5};uFSc|5;;nGw@`VsM2HRd?qx4m`!~Y9=&y5T!shB>+vgC61DSy!2*1EL#K92?Q7f{Tw8o~U; zzL_CNcP*KX39YhB1Mt^V*VTUbslP^)@ZmXDwjUWmrjDDb2^kvcmEvV>l}K>({c4~f6VV?OI;dMZdI!1 zW0rERQ(dF))0IVSMO6O=hKzmz9iTW`Zc|fgozA1IJorJU6*)1LDhG|r>CO?;i=}xe{tG(8LR`|s*=`+Ur&ttu ziz1T|JcYeUAm$+Aoel?m^kuksXm0xyvv+D5WYRE}m@v2gbRumek?@vN2Ns*?;3I)?vtWliK zQHU*~tqxcRbpj(7%aiBYQ2eRCho9kblVD9BK5sWRh1BzGW65M}!7 z&!0cvcV#b0E6x2cu4Rfl4Jy!qIXmv@MSE98|4`LQh2N@(^dNgDsQ7q z+>)zJ#Q^snf<*^i(vZ*k&NOilob#b^*62`Q4{UkUI2wmRnk^_bv`A?};y#Q4D394o zaHK@>SW6zx(4JA(66SLwcevhKSj?7#&}Z76LIv_W0pu**I>RI0LhSoyt~as#E6mUT z*<7P4>-ETXV{_jC zy1nZZc9=iL@#CYkSih7{?w?<3Zmq4lNq>+<1!bUKr==H)ija=@@L-3+_W2s}KN_f@ zgeC^lK)^ht3f|4Fv&WOB+}!;46Ok!%18oF6LWkNi(CsL z)gscGkwy(|7*y0mOh?VMG_c;c9519=>>GcCbWHn?tus+>6bXVTM}xWrLbheE75@JZ zUGk`=(P(F5cEgfvjE&*Pi-0TL9v_j*y ztn!lM=_PN9~q#`o0j=Je}J$+3o)vMymx0KURK1%goMLws~X)6N$H7Jna zS=F^XUR??>|171^s}rr!T!+<|h>F#C7n1yDLZMr7;lw=N=6 zBApOf!!Y6`bmPj#-R~tM@qWwiFR5CqGI1ByMPFJ70hz6v+LTsAk?^)?+rYp;mR3T# zpx`Qb(Qtg4b(j@+kwXgIyFR0sMot6nx;`RF6gVz}BzuE1JUy1p$-X>5Nu^7sp?6Af z^Y8z8JbRJRc$F1ec7$6{gSEf+lPMqlox-kR#PWN;s9{g9>~jB6gFO{9zXgC+V#D5= zYWBK+c)`{@Fg+a)S=?TF7K{WctAMjZh{B{)*Q_XZ!!@!L)EFDftXKqke_GBY+onhk zuAAa2hH~~^IEhP4kz;@ydA&kk1v=VgxWu@cJ)}*-nt&REtBq>*KeXV+mX0V7?e`bA%fNIf+JQ4`lB_Uz zreBz@C5{0G-BJ^$jOtKOWMoT&xMldW!!~rQ=+`5<)%|`BISL;+pT#K8b?2XxB0&^1 zEj?fYz1doqr20{4xwmG%@gH&L+^3^Z?r#SXI4GE|VW6GgsagvME$ZSPFSUduAI142 zzMH0#QuzgxTytkn8`2XDqqQ4%En6;XLv9hxE!6VZ+@3=IPB{ukBX+LOZ)*NaV&FmN zJjGEo=?I4hxXWk#T31pjbx>S?9@8_XR(@T7U-`mJXzu#;94%QI+t0C`hL|VP3A3hK zU3oPtU-W5yf{o=fgp9I}G}YRUBi!y=e&e%t5zhH?#8S#^twf#1E1moNN@B?`$04$r z&cM=vYz*ZU{X+M@zbA!KLh}oaa}txx*>{pu8z2g*9!C?FD69CUN-TEh^U1-;Z#X? zxHpa4X58hZO>}Wz+hzVb*{drE3O6B0@^K}_gGk99V`TtySvFEnRpMSYJE=6P@Rq~N z&W-0d$IeY9Q~~!9bL1jH7jW{5cQ23&twxLL;&62*SPCNKh^nxf)k@;3mzp(XzDBL` zOgZXn6Oa&& zR}qg(KS0Q6L>s}5E1&I635Tq*UtiUIL?GpVYG5%?-XDYt3$WI=+hS?TZYt3&v$)P@xO^rAE|Xw7I_*LWh5nI=NhwIUQXdKTh|LO%93n zW4XMxz|BW)(_|jI=F2&qubC@%`EqVVU#6|WyXxu?w8jbN?u2@569x|+$N?^Xn-BP+ z8mn5RTu-B_rkm*Eyz`)+G^+BK$#*`loZV7Zv{jt*iL1FFrHEz~e&4EjV%|+0t5e|W zG#TF+@w_FF(dRU(Q#sc&)1&5E5e4~^IsKK0QXA&|W<(xjXDj&P=#cEhbIa78H`=X> zLU^VV$ZIda6gwf1a3XwS+k4OZ15nDxUW*?a`WX!_wl8r?jY=q zE8=c(tc7P}()%ED&b;0Ko_#dHI@iIOR?Z~(T6zKFp@}{wtj6Y<2fzwkE4_!=``7pH zJF)gtV_iyEg-8g|Mz-b?LeU~QFN?Rfc1(eo!3XOVZQdKYft5Wqt`U`hM%l&IGN$2o zsfJzgBxT&p0tE^|QM4kIoLT)SZo;b*O({gNDz3Q%A*(bgNr9QxG0^=p%CW*9mV=NH z)DNc;c`O=@wv^2}ELecREN1odg~G^Co$L~7lC-;9tF+*%sUPOD$`r}G#(+@-Dtd5m zQ?*kWpU8Qs;M&F;KcC9GO{uXzBRGlLr(4XgNt?WJ=FN$+Cdc0#R12L&G>0_KADA1H zkM%9NwPaWSS(7FDv;0pgx0+~+ehHtFYCJv0-{4Lv9)h4tIh{SRUt* ziNR1&&szRsXiTHEjA)~xmFA-7Za-o}$Q7bte;pM$$e(yQdw@m5LO)0R&$Pu&S69hP7h>+W2D8UA~} z6AO9Yi|@8XP-Q*D%TP1{0m}Dn-JZW2Q;a6kh}Q?I@m|C;3OV3dzm^n>Gscet$&q6%t9E z=9ohF{md45;s^fnd~PvNX5IBJc5is^YiwZW8h6j}bj0$4BPsoH+^N~x2EnTOYiF)e zWgp&qYgH*LkDc(U?AW1FsiFvbwjAFeMXG}V9F?8Hh<3;GvY!-_DjvY!!Z&JMoFu1G zq>^^hqX`*mORtvZa$|^3c7le7INnAK&A!;HSM9eoQ64pOChJK=W4dkF{8Lmm%r#;{ zE9#NU-Geqop|l(P50ffw$i1mde{k8W-K|?CF1bU9-8(hfv)lQ~BDuBR`?Zp=t!($EyZP&yZI)1S~gZ z`D`90F4l9Krqv{7E2U6n)PkQ z(Ud06PWn)~c?uoaA3o#EE|i0eXs(F|&us=2-6Uec0E`53G`XtrKvyaj5f?jzhD;v( zT*#`%-7){}bMXLysHUfwDNCOv>l1dt{@I3>>FQbEYYdk&4F!Syi-mh1kaftb=Q z5wuX4K)J+Y$*Dd@CLKYN%vmsH)z&qpH&7^`gvdZ7+@ux=+9Ug9I2ulxo+X~4BjwO6 zj`cIIV>iAPyiRIw>E2EDV&@&3WQn^u$c{0&H9y;;hX0#WGMS)?x!EP$#-B-Hr9mX? z7!@K21~#6el^ZyIN!g^-7b=wPNEi0tMsqcD0W%qw>z2$RuqLc;8NE=S-X;yH-rY6=nHyzP(>;BLfyi0+I+>7W7|;qpJZE7Y@w*C7rx78%pJ4fmu#IC68w+u zW5qyxH_I|DS6>F!uux+r4Bu6MznHINu=iY(9$3DRPKAS$oWGYw81l_M{J~7yd~okOW%HoRgpTyE`XwT3Xq5Ym*GOJsl~!x%GZ~&z4fViDLs-Pl~D%uvG27i(hytC>|5f1eE!5r{?VPDuh29- z_L?$Xey1#nH$3GrE#Zv!nEEJtI^VoIZ#xI*G&RmA7|4*G3?JshFHQM`txo$Gaop}p zadr&@>{Om(~Idsn)|+5>r6wqdy(HU@TP8G@iOlB^GuuYuOhE)Kis zhryHVOj(bmMZ4`uvYvbHug6Tbb$k+qX=;$f0iZdM!SZK>RZrJK0md--{evjNMDzx# zFF_m!qI+wdo27mxWdl;_r-&B_DMa<%sHDPOKC$J9}UW3PhUC=DF#lhecK>HV`?UymPnTBCB3w-Hn3UHQL!(xif6g>1VSb1fByIiQt$ zy*Jd@BSgdQx*?>%bxfB}eH~T_QZ3X^n45J?yb#iz>2ql17PM^O;4{TGUNk)wipYj5 zuyxMTZq44-d1JXyBdl&pKxC8B&IZuvIYhH#i?w=nm2B~z*js8_C`Zo{RwL{0C{NEV zL~8h)8*OdArv_7;Y%V4D=Q{N1YSd$oEJmGBcOJD4C66hrqD0M;u`$X&L+p&p4Tj@*fVUUn-zR zxgJeI`9qd;$}aF^q-qUx7>@I4LCCB!FJY)cwF zbGS_(Y&|QySjoYUst-j~&MItn2uF|u$&grbQK8cEFH2qAf|;QLq*x4IDpFwkEIP}2 zESa=Gl*SS%&!c`*$@H=;qylKhWFYR_?$OS8B$Rx=eqQS6H5E_AgUqZ9C~ff}T})<#@E0TJuv`mwmNN`PE~OB<^A> zsNi|j&+9xYiVBT0c3AMkNg+1$Aw;sq>NC~d7I(<;wS^8ZvNb8`fP-Usb??emk`nrE zA}~=e)eJKS5M|oT&&pA}s;J7CL@hP9z(GWpt@3?utoAs|39QxfrBRivyKU_)#E^DVi|}mAKdmRrXKfry>7biF z1sHWn(*TON49UBFH93t5N7E;wV;a4@A4$X0uPS;@ICQ~u!+HFXEhRf;M@$dISM**?T@7rSu&vDI9hW$+;+}29kGRGN5E59h>jsnjbHVCkDq5?YGAE&^S&yD2wyv)B?j)|R;xBLdh;a_GQA1zted=le$d(B zkW_%H#LPKwdusWWms-Bx(L`0uJ1FIX4o>Uc&Etf5rclHd9)#zA~C8) z7x&?+t0mM!RTDowRuJpY9+Dg5^U3Rp>Y`$VC0E#ZdV%31vgc(N0aORtTIiDzB_3B* zle9gvAbm}gksAtMz7Bka#SnvP<~7dld4|63^tMv%>+0`G|2$jOj%>Qu)ynrcZDkgJ+a)VyW&Xa|-{0+SbOxA85%`neUs~Cs zeWj7-PUVzjQ!+K(RV|5@B#fHn^7}uuvKlk9sB*dd{m<;c);+_keE&8jmg=^eX`Pkk zh9jw6uLb~Uu3<;wbLM(JH`MdjLTVZ_DG=IF&vURJF&?s5R$s+zOzjM^)i;=5KVkJ~`o^A&?M_7d5% z?NUpW{cs%hZs^h`$bDwpgZ}ccGq&O%@}*@9kF)LR|FE8a^Zr9#tn@P+H>sg{apgMh~(Ei!1V!34k(%Q|`tC)1Uay)m=X$XnLJt&E$ z3&l8rW+(FCi1FeIV|23*a@4ZVqI`L5bhYA1m!{(8GGxqkbXwoZit;>vN3KCX_b>otlR84A_ zH{~RGr%nJh3;AY?T}%E;9;ach?VLBfwf_wMvM?UOvzdZUWO5~dM=VR!pz2*n}BP6z4%nzSG+1{ zZc?hf(q>($^>ATVE9=Gfw=8f=Yi?IHxGKO+?nQU5zJ?7*g_)jPe4)vr7b`(V*%HOe z*1TGb-Wk$|EW-P@dcWB)A#K7f8`ZM7S(zJe!IQ0BL=urY&c&k`trN$|f@@fIr>NT) z245W^g3zUJ#TN=N&2T{}p}%dk{6(Er+YR4c8;zdX-xFU;=?kp8+;Zbjt@2;i0!!y5 z6;^FsuZl-P<{|CCR}QZU8s(|y{!I-XJ5_7VjZz@FQoWrDJw=?TJ~g}S!nb`@kO0=*OeeD z*^-fLFtEHTQv3fO`aIn|lI-l=d#g6dk^}<1GdK6rR z6TfQIOy@JXsts`!mtudP#?T?0_sRcYFkP|#;deC;;dG-@^v^9I)vZ&iPMYd)@im2U zN`5UiZIK-sCA2iqiI>#EtC=^t*aK89(*Qn@JD4$pjel8~%upLq(>dYh|HYN`xMCcC zl9X}pw^<7%IDNn8H;lsdjrZQ*(yGaCPeW-riG8b3EO>V>N^2iaarx9Jw=HBYxefcf zq5vwPUfkcv%G-|Cmzlmt|G6_?VV6jXYfN;9$36I=0?R^@P-cLl+yJcDsBAJB&rxa( zB^?na6ceF}+jg|M5i+gM&)qm0N*LVq=VP5|tLq-(Gb-|<(p?1HMpDp()f#JfN&eUX$T%u+ zO2nF2xn?|(Js6JgOc8B{VkQpS=Nt9Pk_fHy774J%8BEh4#8qV^Lvnve$$;}V$+1qK z6(>)Gcvbxpl;ZU(rB;mF?v*)psYL?Tx->U&!!T@?D2vi;LYrCe42H})sAEwtn+Q47 zqfqUXk#zOOlFk^EIrxu@G_s5*bTT6J)*5(LEp53G(iT|AEU&4HFRvQ`Q>I;TDu}YA zQ}_!S)G)TiH@W{ zuNDHaa;iQPmtn*#6x@}IX8^9)0DBDaOLdnYgE*R%8C@-=054@L&(0SGdUVDrS!_uS z4lsJ36<=9B>?3i~pyz^OLio}uW2`GtVzZ(P--~ju^m0p@FgjXByI=As3Cmi5`0tRL zo~0Ccf*#!c^cUVbe@U9@Zmz8^hx{FdJACkz$M-8=@YGC(9)L7jeByKJD?s#P z7fANmxpYDIxmymmlR~TySu~TbEoJ#;a0|4a`*u`SbNLj}_^WgKRzdoyzf zjICkTpQvRiEyVY`5LKD61lBu?FD;ev{`{DkXhWg4Z;oIGu2Q3LR`vLy2Gd}5fJOnq z>UdySc9czF!_6#qqg6~dwgz~LfOzZIS*~FX9der=!;Y+k1kdn|H6yPPLu2VSD*bXQ zj)gDHEaetlk2GLgK9sq1sZ)*sXCWBosJ4Orr_4pL$<7@4hZ*)!&Y^D+`E-)Q7OS#N zgXAe`l%3#S&jj7v*rR7argWBItY`6Yp;}@3f0Bn0Ew%k|_=2yWSs4{`uX~B)!50^} zY4}v;05YA}xzH*Qv+CeX>#C!;97XK?Q*C&S=6Z%YNd92RncbMxk^)p})+WP#{Ly6h zv5F0i))DXtBpR5Z$VAO6Q*rHXzPL(8^3g*rH`~p1ezO42Y)#cM17~T-Nc)1184c%g zFPIa|aHG`-RsYkCvDD=RTK8?{et7kuK?`x9>beCKo3a^Y+TF)5EsoLhvUSFA`vqLb z>RR1-lr#biL&`^8kdidAjOy$wc&O#nJ6j z$%!w{Jw0U=-CTyon+#I!8d_{&E#aE!Ea3P%d2F#rnYSyF`*sGa4B^4&+zFig-od8E zJAspb&1mGM)7oGRu zZA-^TD07zL$pBx$v~PF*2%$OVvO01iQp)p*YGy};-9*8gqIj)EHI${5PvshBFqTcp zUY|D0<`0`O4IKU2cc$2R!za}E^EZ064?*%|i&|jg?o3hsChc2coS^Ep&O)VST@<#{ zRn9Oq)vV4qsdM7(M)G2T%*<%Y;7Z#C#v16w2?JTRyHY1zf$*xl`UKpj2!4zjjQG=p z0AQ<<#Bri=Efzl%0m-gPG-3sYUI|HWasJ+q_qOB0XJkscGo@O{_b6lDvYAPl{Y*jg zSVHZcFGi2O8pnZInCT{pp0)SpoE~4n z*i`^rs>&MhYQjff9Ctq?!hZc}oiWGJ=2cceG9Lw=gs6c+Z=1es+^iycj@9n{#z(_I17*u%jY8`tmd#qs2<9SlH2n|m9p>SgVE z`#o_EmnQi#R(4F&rCUGyd|Ovq1}gPf-|P8^G9DcQ_q3sLxB=T{Fdu`m`rtrpseIo^ z&SD)*xX1;`t@%wbJRVK~r8M+2H_p}MkM;|39BtokTorO>b`^o{JrW5IVR={I30+!Q zj{pE507*naREt_v*eLf#JGE&DO)n$R>olyl>*XH3Bv?MkV9jc2g%-wu&T-p6PwQH( z!3AH^K+sRTafj3Q=pFZGG$&2`>;PEUq7o(AqLNrYU}cr76)X#DSrbOgR)xu#G-I%( zEzk&blxf5TnjjjM*yBE^k>wWxL^68QYMbh3geJ?%_3^0SDYhTP{zPs`#NhgP*I-w1 z2ikLg=E1C#L1jkqFTrc1|4>k#DKHjJI+G!3IOm@`5*>P*>x8UQq;6;4P>e%yF20R- zp0vr{sJtR6%Wr0Ph=EEbkBV6JrbyEg11@r<>j-zq;2(UoKt0Vlj18<81{cM|uLKrQ zZQTMsa)k2wJIP7G}d0rOI zKU=ZapVXrymVN{veB;4npqly-0uo@hs4^=_dJOu+;hQ&zC{qz<;z6+fe(# z$+}X5AAFZ#5(^*XBqbbDn(@s3-alMQS4f}3k^YfJcI+-z|$_v3I~awhjt)(EbtVNa&N34Q)SBPP}bb zFcDUxCZ#sdZ(KB{PWP{|Ix_dL#hg%vq`tH3-ce%+zsgELh+=o$k1D9L1uyh&Rng2} z&pkl3Y;$^4RkHzoo)*M_@InaAfBPzJOIP_sFKY+G^SE)&y6-0%7i&OPkge?T4L{E_DoiAw)o0} z4vS~Ng(T@jRacy#40CXnjcm7{J+xu35_f@PJTAzS(qJo41&R{(>?5lmawa7yuIwME zl&B3_>E7PS?ZVg}d&ZFGEBNBs0g@{%t@yGF{Kp(qtNoS%86TV+2XcJGXTfv~Ey<&N z)a%Je1X7h1N1&dp*VP2rCbfES8kc*gO#9R{%VUe$_~29-dts~Pwo+b!m3%Nbn0dpJ zPc`r)vwT;UN3XxU%gQN!k@5U$mDw%BFR!-z_M&&JN+G7ET5Dt0X6geRl~N~s0~yG; zu=j{ZOtx2y?eRcmG&=rzK*p7%XrEH%mD8RaQz04$JfVxu9MV8=2nU_-{*`N6i!8m6 zGccXRPVqub+mUgEPByVm8K$ZONO`E5&blmvFnOpLVFX&8GHy@XSQ&+T!eMPT(V>M7 zxt?hmmt>=JdsQxF`*+vda1TRH;6Hr9%|>;FT@JnMZ4BeBBS32GtgZg`n5iMfsi!K| z*mCBiJf>T7IPKiRiFGYVio-15OFFH@F$1j4&*Le@@%!bK3X&|__*&;os!@*bTzdHy z%_}5}AWkLi|7Yu5wA9v_C2SkZmcV0gHv2!Y^8OEcRF{@zCRtfY<^nS?4z2F4`idH1 zOG5Y^JiSpXT|(t0c8P=AJ@OUmS2(bb9a?_GNn9&!c77%^P{aEi@H!6y<;Eh329ac{ zvA&69z-5DnMl|O~tyAD%Et^?Z+XsI?L~6!d`t!!EM|oyLm&Ky{`a=ZA_I`t2QB-8f zm}IFH6#D&G9t?l@kP4DWhO7U;ZHju;_a{Kms%gi2CsUfc;H;i-hhlrz(h`)5kVtz* zJ=C^x6d;3ld5EVahP3e)^`DrGGZ}E?&v4(cN~Ke2x3q!(jnJN>YRVLh@8y*gERpb& zf9T4C6gxHQERGkuen3iy7?dUfa}dp299Wd%OwJ(!B)nuU9YFxolCa<^d#%1vFYa21 zDOcfLMhe0-N5?z1{pg}oBIL(03k2EA;~muLgzjS&We9cYp@HK>K*F+ZR)x>(x|kP!bhlJOqkOT750pH6aE&iqIzBXeOKO}ZW%lx}Ep@h( znM{Y1LLww5!*L4TS!IcsqPwA7H&2AA#iBC__Er?in<{%xu$$3F;zp~t4C*pbCQnktKosWzR^ zEex93WZ!RI35QfmJ6_gyBdLS!K{)h}RM}Ye-nI7S>BZXvz&bpLz>k>o>7_^&4${Uw zVxqb2sE-8qBz1ILCcYFgQi-uOJ{K(yHn|LpD^e6td5EklUkfL_YQZb#az z2+T`Zn66dN5c8$Q%Uud@3Kl~bVH5>H$L>q7*Wo7e(2sBP)xcU>UF%CKU(^*jd&%lq z{~|*E#(u2d6VUF%k%sz3a=uK!TQ0+T<$XjNP`)~?zH*O;-^s?gT&z^5l&oLHuFCOq zKk(}mK~-oNo`#F43FnmtNfVd=4;0-i?kv53o_=*K=kZCK-uYRY>8suX|4T!QgC}7B z{P}E8s#8nP6J5JG$oDA0bwfctR4p-7LQlJJneDP!6@`6j{St7BPpGRfdw#&E1IG}? z&h?@`UJP4k(khITVME%8u-L_?0*r%DEPc}B^L{8a0nPEKY^8(1DOiynhok*0K+bUA zV)40;XtK$MLRXm(3YBmgsE-ewGw)H1%%o61%b5v$W+y!I#PDIOJH9@eOXt*b6mk&NZB2ydz8;vqO%fcBelj>V$Gp{&?VP+(~BvS+W!qF zQLse?Eu~>GVxugMLu5U~%)GQ@;hXqbOIs?FUgd<}CB(>0t4#;%tce(=*gT);{?&xJ z$cgzJ1}UPcNyU&&>CU#(Gv2!b2O8GHlw|g?k!C>44z|M{0Y@Ku3puedU$OQjHWH)g z#@#^8zqdW{{pJC`LZGBv@_5*-wqe$WO$%Gi2KvWMv4~d!JZniT!S>H>iX}2d+br=n zBg7&J8UExSJu*zvExn4zKIux~*4E?^A8f=HTLh_;PTcy1S}vcIPtV%&dT_!7Ltc-{ z{VHDmE{^xrj7NvZp;Nr@N-xnthySH?^2lBpGfw3y9Olb?8at?x;~$2+=N@R$;Db&G z9y)H;`jx`h3$unVw{A!L@8wWk!p^S+?)MufG_fZcpH}I=7?L{t#$O~~YwiGx7eR1e z)6da$?n4h^=^KwDN0)kz+RNFbpGTjF;7I$W<%R`VodS+w&8QN?&DsySNZQH=-6OH9>D%OYMNU zszrfBhYE~_B7nh{RR7AkFzV^PVFirpO4b!V1AAg+10KvRJl+TE@%HAr7tUXLdfC4{ z-Y=MXc&8Blii#mK)924ILrIM){^F8$-^Ul&TQ7>GbPz~y#Vb)HrK)e!RsEP;T6F&G z$4fq3BrK;EOvI)ejXw(TzPr4M!DaVvc7fG=8`AI1`MxOZJK!7m!~H8;*@H$U{``(K zq}LW|b8*bG4{E{&{3W^(JT?VG8 z6-vxibjKpBC8xs0$A=`tTTzxGNd;^gawG>Y&S$7y#JP)8m6m^2XI7D1;lWG;qja~V;XI@zEZtr*8gNyQXJJ+pFF3^|uvT>T+ z$*PjNk}s2OIb;rt#pEh(+mYj*8Xar$K$|1e&X{C^hO|fimO_GbpA_gg5j4rFiE`!g zZNhSpMQ+w~%Vf3KxBL$>1ONM1ek7`+en{fbx#A|dbA(KVb6LeRdUvkOXW=&WF^4bR z+lpGEu?SY?q*{Y(LOyOzd?Fx=p8-zwBq7+pwY{zXb`p~^rbIbegy=AHb8`HJ%*rIAE4iVkYloT3cf`-m8hTos z6W>Jy1ShgZb>hmA0Bla6Z!MN?$wA<_?t|GT7iTlzYwA^Qjo1gellTu0S@}h2QVe2(VsIPh<8B zz9n{(sIZ?uwHA~8af~8Ifx(F555QSFxzc%XZ%XA8ZpY#T6LR8nalFPX)i9HnaY)$7 z@Kg)yyn}k!fWs=~h`1bN1{%^q7KqqXEMHtr?@gzjcZs%Z;Z%6B3MB5kHob7RpCL=5 zCMfk?^>JavTxwme%`b>zu}$W)#4te8v3x!>g{2Vb2}u^p*BHX%?24yVWbAjr3Fcl+%M!VVEkz00zVE5+b1jgnU*;KlUu6Z{t&~7W1o z_Y?ZOnFDNmD@g&(cQ25~m~U{P!vI1a8cS`b!_vpo+1kW3w)!seu}8i@*ws(wm3?z% z=y$^ne3WC zhIIfg>nk-1-9GYzNg4B$1tYa$-#N21h^_wGwliM1e%dwwI*Hr`T8==B!bW$eCK|mb z5`NLrB6$HZ4Fo(Ziij9!0xRJWejUlx6ju%lXol#4xVUqFP@Nb7mE(5s|;M09Mla zT3k(K>ttuVhR1S0Epv>n=kU9GpBoe0$>tPlmkqF*TClLjs#8B_56+U%Q%b;da8XfI zvB$%c3n3e>1tkoT^8elf7ABbV&5kF$c{2w?)Z-rmKLUV!3bAg17by`3FIs8>AbnmL{KvZ86m&KzLaKl!rv%7YCYdD59+~=gh zLvtMz?%pWhP3sbYY%-|huHClJFLxt1^=0X7`r%4ilXUj~^Wqu!(!ioTH>K%rIEe-p z5z}Euxc0#k%X8&xwE|6ZGr-R?_PWxq+1e-Wngy~Aiy;^AaC(C@kYb~3*;C)g$Omhpta!Z+ zzORUgYna1t($ys~xEn8Da)~cVjQJNh>r{h%lSHB&FJDj-Idn@tL7=r^im)lI-fCm{ zITSY&Ig~~Q#fdpUe*+@wp3fylb0t<`!NdytRm-&WX>K@w4C!(-(rz+@tRa3zQ&!&v zjB}z%);aBdu={bF$lRJGnja8Ebh^UxbJ!3CO!+ef!nFXuSX<4E!sPkby@17E5G*sJ zXoH{jjWpmP*ZR97k^pqFT=udN`sAd&I> z-qcN^XZ?S^&PBIzTnVC-OiHAsNR!nCV)*|*^s=j}Ny?es1s0ge_!T=*v%9NK@vgQd zHr;hPUqDAHpLip)gS+&Jx@4|$j}w6pwc6Kr1`!*!Dz!s`74G^j>`h6nozP)5d7IFn zt@#Leuj-phhcD+krF;k_enhWZa=XNF9`IqRo?2Y2s_v zbsC3b+6;AtQM>UqED|YioA6onI5A0^!g39KW!!c&333d@w)-lcb0npK=6uK*wr5+^ zveJ{@eqPxTY*TER!by8k$0fM8*VwQrGZ`cVuCAcsUL(pliExm29txIWN?vEJ*&+6 zTzgh1<0AA12JC+AaTvC8B{{5E#5EzBQ#)cgcQv2q7@s^$xTU^mj>3UNybXR19`f8j zbG^-riYjaLLS%{$MdBnm7SBI?=k24zoF)JUGvU33M~|xcXlf=L>Y|7+Vd!vqrzXqQ z;1lu$pG~@iqeF^r66pLZlyBf)`0(_@uCqb|>RsQMBJc@tym!UFTgULXG=@)hN9h0G zEG{3i=YH$3e&jjaV;_cFhmou?=*eyei6KWKgnv6L+{9Hk(8zFvx!pS7TIJfYe52#& zZ+Pvaj5F#{SW2Cd4-~+M1C*d|3FV_^c4npcZvRCot%9=%V~fe`cr&TC+a5eap`=-~ zU&En5P}#BS6pQk@^dpgdV+gKD?Y2%gz2YWYcwe?M1>s^#>7Y6HoV>ZSrr1W$wH=*y zr10)mtpm#8zS;a5uhS;V`;~~-s4wPvUqo{x?Pw=MR9R)eUPLg>GaODk2pk?OSTEMrx# z+P;&0`gE0)y47dBHlMdvT&Su`I%JVenPUUo^*a&`7~ zv!7Pv^jSIzWqGt$u8Fa?$-Q9f)zbj<^5k#y%AQAmBT}x-O??+?^-=gbSZ_khx{wSze;x{gbnRUbtrn|m zzS6#tDd{6>*B0YKx}V?pD@a-lH2wDRbF0A-3kpu|+~$aOS)kKib=S_$IBFC6opd6} z-xGp{hv-AZ_n7<^(BUbyn$C1Ob#ljP4p1v6HvIh#R{YLdQ)|C?y^ds9sbh!qH`!R) z47&B-U$4uoJ-Y=bWwZRgE~FaNGO+`LWtm7xK}aUpdcTjX?Q8-|%P7&c-qeRVZJ%rd z?@9P4fT_fEzP2N&->*+{qTQP?sf+d?o zGq7mE{J9XxmSE4Y3l`kmleQb&k)7A!t~nD0%i*gaN1-;H6i%kexMbx zPU;&ukMl$GPEM?;IIh138>QA1Sm&t3xc~;R(uA3u(n1m#W``OVOX;Rv+dx`f_!6<= z*%VmRDB)hTvqVj<(fLyMyDXl|YtcS`W>tP^j)<1lwAKB(ixkWA5GZ_iRddyE4 zfK>UcX>N4shi1x*IudS@K?cq*VGIWJNKl?}CI9fv_9Aq&Ju<+VXn8fjRpcUPa5>L5 z6vnr$rc**Y_gn*gy-0~QyZ8+BQEIwqjr!tSVSZ$?xTy3(s31Qs$;FwO?C$1B>#x22 zGjkSka3Qm!Y18Sto)C}mo_4FVS3TV7g(9n!#M2FMUZrNlOkrx?hqn5UCv5f z!?G}o0pi!r`t5L|oJWW4M;Yz~U=UKNj$~acQvNK><7RhYdz9O>c4)5GUu4Sg+vO$uOpDM>9EHk^ZMWa=^Yq5@>|MM^Hb@(SV(rPddv~ zl)|t(77#R*@8@^%p1LS{p$zovc8xUiFS}cLj(y6EfgU_dZ5hMDY#3=QfqWye$I`ME zhGE3E`P+>+!j;18_F?jGW*>dipj zLM_I6*9P72R^f5BOn2^nqR}i94aZoZWfXGS+Us zemk$!K+VU_?RmXbece{d(Wct6c&dN72-Hf-Rv?BuCx#f+3Y;5et)7wWIsv(K#>)uG zcnGHb@&Hjyy&HduoGQC8*xVmqz#OS5;r%wLZ@D zRrZyDu!nkOJkMko$Rrmo1WrOk`)1nSh3hrBZ7GnDR2V|5d*JH(=YRiD(eyw)bwo4e z&P!><8ub%FK7V|cOyiH>RaEJ!l0Djr*N78bjk+zEO{^5({CyeIBm- z@_nvomxNs|vLD%yn{=?E9Ed0fvES7wSI;)IpBG1BV($K`udhi&{Vqn?pOdyymmaAvSsdFh1&Dj1A09Qv`)HA79hukH&J$vuw zt64vg$Kl@7twT0$r$mnA{V@+=9rmX~AAPH+JrJ* zp-m3=WTjrG|F(d>7wZv6lJnrV9)Za1am(FIYhV(UvVqmypk-Y@7d{l*LBPpUJfy+b z+l9)mb^vj?%P=n237;BwgEJBM%ZMbqT7QE%kewabV=75kD>(HrY_D<1*I}F?H>KQQ%rpcn%%90!Q_xr4+l!1g)AtSkW zJFgQJXEU&eCF7zF0fS`&R(pW@$Mferj_tIY*i%Sb&HRUm-8&u(SrAr-@xsXUz>F7S zsTBaM+8EonbnVTb!)(FboVEF~XvO1tABTy$Y&}rlf~!{4>l{NKOTk*&w&yCd2=c{R z7!WO?v-uleJ5V^2{rA{jEIx^X+zR{*aN4kImq3d%nr5(=aU-mFqYhR0B2pzdcdo_G zo-=M(o(7KrA=s+4%MOn?2N(p$Nx=$C!xPFMPH3Db*ek~mm=IM25dZ)n07*naR4yZQPx70G|R6HOR}<@PRv>ah$}YqrjAm>)!mFV=JQwIhqy55JVKgqGX>^X*>=L z8X3Dg_tmMwjPXdz?9NtckAY`kE)Tslo`7WT;V7dJXR4lrr-sXo#A+jQ>Fmjbh6s~?1JP*(k=#3FXY3suUhUkoSGOL=~20t@oi!()!6vHJR= zS@_u^CLBa5$Rt}#NY?Fb%g_$X5?qhkk>?Grub(R7%8wdFDv%?o6q85gITfLM!O+W+ zl;!+OXI$!dK>-^3@Y$PLPPmuWS3jQJkgfb@S9pQOQQUnryMvmNF|jIvV^wdT`A4)C za=De@0_OJZMQQ9}i-ZlzKJQAO0flvARQ5(RJEK2$!Ss47z}?RiZrk1aS~!fj#s=S7 z$7Xa5<36|VLGv%d#yT|0Vg2nS`qyP_7|gmiIL6R*_m&kGuiT4x_?5^s_QgGPAPhF) zzoRcd0+v4GhJ?20aY!MogBUH3@elU{M?(fWuer#)X8%%~+y~p6G)ZLbl#bQlRfh)$ z*S~#JT%2-K4;cTK-g9RLa|v=An0P}UG1s=&x^I)GK#2UI=m9p>ZO~GS$aKAcbbP;1 zzu>Y#@ja$C?WW$p*@%-u~Iq zfNxS`C3`u+#>6i~2bxMPSsks9eV!hk#n54t;)wteJ4smGKfp1YSXL*Sh?{B2;vOY zQhgnzImXez;F**Blb6Sm>y@a~&74aXYnO|7lQQZle*x;4p*hk+mk6@f0%y}qXL(ug zVfN|Cy8QI4I50 zwb=DMSJ^O$6A#TP{Hh3JLFc4>R*T%VA?W7m!ZNC<>CtbCKP=D(&MmjNo3Tq-6nTu< za1dC^#3u&>`VeMuHa_Jrjdzl`7Lz%6JEu@Ehvb-UK96wNO{K~Avv05Y)Yatk?k&1i zZn7PnIm@+?Dfwc_&E+2}({r$VR?N%9wJVtE5~4fjUQ3laU-8<)4PCVJU+C2*+oSVS zt^Xb*fAT0l7Si3f>pIcSag~~IyB!tsbzIIAx_jyB^gn8F`*}3$y;_K)-hUMH959rV z==k}AC9nTgZY_qfG)o2~j9P#uK5E}L#LD4Ed&WR^o{MTIwxqb$#zK~k((ye?&ezwb z?W_IHdI9Ijuq zmIxc11mvnsHz^vd+YmF$HHLmJ!)Jt=h;Sj%uh6jxfvnX6+G%{nTszxz5FV`sght(2 zu?+FTix$07K!$cUG7Ezy=JvS+zLIlYTxb?VXO>IbKU1-YU6XNni?EWGiR!#XF!>qU z^RN^1ET{c`(m)$eIZvKtu?|6rg~VJyNyUOof+n@llYTlB)NQc4*K7lNNylO_Uqodi zUed`6O)+04PgX$k%+u>NECy6^E@NndhsmNV2jbZs=z@ov0-}MPUpPA1Du6!h^6`l*DSaS6sn{G_?~ zAVt+&P`%s8L(nP)HS|!kFrHCX??2@3LE8!g)$|T6EvHkz=V#i&XPOZwC{B96>~w<+ zI9~$TdjM6q-#?^S*R`xFPWqrfrAs^8s&G%?xax=3Kgg^<%ioUpnAYp3oF?TCs zF&fRlnnbtJLVoL8;)k7pAG1u3b@xrLX+7|!Mwc=`F$i9FZlovgWF-wvj<-2w$(4&l%s?K zS=J_Q-el&=By>F}u<~Ar!GRJZD3EkeNCrN_^xXj{kf8|ul`pn;v>ik9DKT^bw3PR( zc*0z}bFZejz|Jb&Q?bKpGJMko5^cB-&G2tY3yN|q9X4-GLl^3zLw%X{mu|39fqkru zoIG4?nHy{_A*Z?a2-)aJNZ+QZzJ6@ElCmcH#3Ldl(Vs|uJg7PLzS=!7BIiu*R}-b) zbdYHevgSOs2;oWY+%WzMmWA8<7)8{wDkti64w#0aFm)ofj2>)ve<%l!T3p$cLi&7T zIhEfB^^sV~B{rKej1}AQ^!VDy8$I#a%z3oynf1*V92aeyt@gKpv675I+rb z=6L$%Ry7!sUok)@$9ZaJm&Icfl&DC?&_FkGCUDC+pAJqTTmeV3l^5f@_aGfsnDf?Sd38KTr?jZ!Phu70RZNo^lfKh$!y z)Zym933;j9>DJbh38B5@%)};oq_)jvgbu3m5i7jTn)!y%p#Jtw)zb0WHaLlEbwvq= zl>0t2@E3j}(5Xso9UmAwBQqEQ5Q**bHnZD(ATOA|-LtwV{)S8R}I( zl}|){jvicYtDZq1#Vgor@qjtVoSg0T&|e|&D}9jjb6k%YQaj-|Q>>fb-$Neon6*L@ zFanT|q-{|2F|8L$@EG3U4k67Owx)x8OL~H0-cLp z!fA^^H&7+QLV{9Gfk1ul;Ds3Pt$oBC0W)SChUHw+k66+fzlGQa@+Jk%aP5RJnb^uH zAkPzJ+4XLAN3$t!aLK*{o(a|D^-kXWsUevnN?=^NG+0ZTB=?mpdTA~2*Y}eR5H5F8 zNg&9p+<*qLI{4Xpj)de`n&Q?Ka{LN{1nU`h$(lnu?BRyJEfF7+!}Z|hr4)F)-GZ;I zEv5WX;%wbaavTHn7%2zePY%W*)c(>lQ=hc2|NZw|v@;zeeXlHJYq-U9LoR=9F`Of| zvXFwY$N&0%hP2B>=bPQo5_vxf?D)2f+oHUPrHw?6TfHy`GE16OLb$FFK_E3DG>;+n z7@RX+JhLpEsGjMz8Ye{vE;xwbGw;~-dOE%=@#1tL)Z(u=OzCFa_Zb=;+U}|0qNO&7 z@gio&USZ^RqLj2Rc~-bKyv@WhbqQs3@A{N3YYMmjM|^tv*FR3d%YAZv-@~OIRh2Gc zs}u0tHNhPvD~H6|hQ@U9CH=9_u9yAunoj=lnW=EHA#GKGagykrbztcj3FkPrYSO z|E`=tMG+ge-;NMD_y_eb&CfWwBN1yfARKEKLrIKcgiY7ZZf;>(S&-l|omp4w{$`%N zv#?Mu_QcNjAa)rIU#+kYu4rp}i`_7J&h_6Nc&rU2Z>KT|brneqR8C6EOqEIsJnu1lS7Pdy7M#`4lodrvQdjwOYTEZYE}3` zt+kF_!622~jQX0nM1G~-vISdoE^%{%)y}_f=Xa&%zkpVYw`PYwD1cD;4l1>3RfBCw zqDMiKPdXsjf2gtC>KZ7mQDGb|WzJO^(bW8(H;QFLxIAizs=jT}y|u*bx%P@Tfg7T$ zb)XR+EQH4xwR#D9Mi!2Zl{`vC9r3;{%k~$Y<8Kj=zyC9f@wOOKA%T=|9o*_JZn+G_ zQX113nCUoSM5R*2wDe1bz3o${z)+DW#W3TD^#%Wm3MXY9_k63dal%wxz0AH@qm?Oz z8)IFIU$N9)d_zSjH+A&BOP=lS> zOB?@7zTKiIrMYUa+Tu${t*tg?+~`xsOwL6FtjW2sX^L!y<%?at=O=;dFWESb90Hn? zG1+AS^#<2y$^rnD&lKTwvMtxNe$I0*iAE>DxeH$S3elJCnBfj}b#A_{Yvpbh-C97M-pZB7c~Luml4W2$sX&5obsZGD!6D&tG4Jn9dBNMsyyS3qcsIY8oScRGbU<0KT zyW3#{Jz5r|;qiVwwjmHzBx%)8ICcaBL;8HcKnxvn{Z?py*EB2gVfNM;f@u_3!YFFJ z-q`Aihskn3ED!RjCw`KG3h%P_+DgkA_l`_Pe7Qn^1#H%`@n zi~?#$5=%@!z`vx1WH8rBBXmufTjdB&nB7B;qPCCJMG z)Cf87*t{`vqf8NsfZEt1lPD1OeAGw>Xr!K&4?zL+6G~L9K6*mN7O4;#UV|3Bhz;0ee997%ZuZYl2JlLTluq|E$HYpHL~KD+dR1j@h|Oxu z6f+YADfPBCzH(>%pRF@pZyeWwD790TBBkTG<9ze}4|-J#NXqViGabkADiA=`DTM`x zUM!weZ)>*N$f9^AR-8**o68`o%}Ls^Q5Q`FogdXS7m%Qp8i0@(<-cIxQt}2diP8^$m}rz8dmD&}W2%O*W(Hr-l7^KE%iR?<`Ti&74hn0JNL{2tN21z+nv7%qB91@9nsR=xIyx~V|h%_1x>cs zwfkh4FksWsGWkMHd7i>)j*NTQc4r873~Ayh6|l=Sd!5P?Md$4;pvv8;fZF3p zPu9_iK!vXD`uh`mX=P1Zze7d#arO5{5>`7y@SW(k;bMdj2iy-d++C-TLadD)#xRkR zl_H=R?%m9==qjVv(shlb!%iMw9qFk#?i7tV&+2yTH(uWsOa_cMYpg=dg6{lw3LOK7 zT0fVBE-d$>5oNt4B}ltn<{I(k<8(Kj&ka}M&CxPr^ceUUZAwNOXHEN=0Zg5KDZsV4 zDG`K$mvBCku)?1Is!f(C82{Tp1Zx^KK4t2G6htIo4UVjRC<4g9O8@$ofsck|^okDf zUlLR!+QwM>8VpU%G1}H45R}~B%BmF7Cb#yZxl&&a5#+QryokOx<`TptfM!@(VA+cH zV{$GsL775o@&PC)s1Nm;qoXKs@?uW+|1u&V;`wZniQow4o%38wW{u}%k>{B{PcO@Z?Q94)7`YK zR%)_nH6Kk9bIO1I4C|rM&Jl46!2W3Sf*Uk{xj^KPEpW}&J{>;fPW#nSQZy}y)>X35kY3F!UI(<6*K;~I zLO70d5@%Ac(^ZETwg2EnW{RD=>_lOTvuH)SUJt$l8{?BPW8Y34Db^^a9XGG)aoww{ z8uPS1nOzwOXl#t-_w~trI^)tYIn9z`4PD>4LawwByUuff8!d5ak7^pmlwN!qcJ8V1 z)8~KBoUM(zp4$S0(`cb-*I8T7;icfuiip5whF7n74M=ZCXRu~ZV;G6JkQFP@s^HK! zhhv}z*s*82d)ZlDzxktFKTffI(Porzbc@Q_HB0f!uApAN+V4jR2XqT+k@4`Yl=wb& zy6i_$s3}@vhZ{uX*%m0ukH3q6DZpP`SDOT7I#VoMWzgmQu|z6zfe$I3d+4=oGb&GN zwqncuIjS^{COm!^(kzDbm)*0)p94k42j{ z_hAFW?Wn?A6WidgM<2cRAiu5?s^o&!VQBb@6kq8Bm^ZEel@U6^89a#)aH|Z#gM((Z za|C+0RhF;aO1?4HYz9Fa+%X0k+TN5=Cv~4pQ-k8=TIF+jnexr_Gv(YS2R5ZO-_%;I zH~hCk?$hfJMHD-%7JA?5;LbFzr>xhtr*0xG5X7`zmFRFF4{FWx_Y`bl zQ?0tXU`U)fi-y(6sb3os4fgXY!N4_RfJ_knPk{xH*}w< ztdp6*ld^>o>2-f&*nUSPogC!`+xB;^yn9FQTD_s%K`Ya{o8X zbze#NVFVuxeF-WscX=+(V9BWE9O}ao?AEyNrRJ3hDjudQj4Ed)_F+k}MD^%s^;r-+Wm zzWwnC449|;P@X%AxDF}2OP^Q6t*^rbY_zmo&-Jwk@|nYWNz&{UNTEaw7%^kxj{DV{ zGzSEn|C|dEO~Jrp;EGH(3Ra7bU;142p)Cuf^3_U48Lhd^JIb+7yosXo zo8GEa*X84<={-mHt^IAu7jFaTI>%1$9OnBfcWJVKZ!Y6>gI?V+&21n4p}<}m$YV5e zbaYPb-1bJ%s$E}WGkOPP=Ew-TAv2nBw)e;tuG_lADpV`Q?)k%%b(4X=tHx3-xnm5^ zsd66MVRaQ;6~1+b^(Yld*gB1kB)-;it}VfuWKIuCXS90K*_2|Os)~-|244I%e1?+< z!G4M~{*%rFeeVvDGm0%h7P~C35H(+g_5frG@F><;jFU0KeNyWLbjHyg+ejzv{`x%_ z;DeBc7Z$@@;7+?jb)T%gT@WXy$Xn_hYJl*9-`8<$JA_leh|C=Us-O|+U>>3tzBB}r zHaT_j=;Flr!blvDtn=I$iKw4ymApsEqy>oO{xE?`nZiU{D!!IaoRe8}{#UnLVjw9( z=0ch?XYi(BoH?*3&eyZ#T-cmhs>Hky=HVikIOW4CDwS?TTOr?|!z8gHnBZP_%#m6e zv!%2u`Or8l)CatrL%$K^oYt)~5GIg5UHKfXvTFkLNc8hW9tf4JJIF87_3qlFDQTg# z(k66husDS)NM5AT;vy%eU*z34bNOmK|X-DnhR zODBg$LueJi773}M(t3|E*Xd_wVrId(#Iq+kIuqa}HCYaaQF&9sWe{>Kri7&`uqqe- zBJ9aE>}a_Sk(+dbBD_gC-N?%hk8k8te}P6e1c~$+pd0eq=Et?H*M(+lr){zaZ=2&J z48o_h8UNn;YfCxqe!G1C1La9f;|)a;qO{nRwkMEV>Ts>}Yg(3k8z8hhU>l!e*&YqlC7^tA$%m+E1`+DCHd2vW(KX{;fSqz z=96F=mSV6BLjkn-Lpa3(1gfjo(J`PfqXX`sZ$2qyhSBJ%f7rqv`}91w-F@eV5a7HZ z`d~j0Xrz#XoeSOH9Rq7cDs|hz{9hQFGWE+;DUp*w2{t@LS7!~{<+P34YhSlbUlQ=8 zw$~Ghz+`$n>Bp5Oi?ZyEjUKA%i1qM)C;EDIlW;^K7;(XP`S+PpS3G(i&*R{utocc{ zH^3=7?0^-NcdlTEowuZ|h=+GZ`<%4OSxGhQ7ogPUoW3UEjy99uu85wbwb<_md5+=r?1I<$>Bu7%fQ_DN_o&H8GW zAKycmel;bZ-HETpWzb5DCAKb4kn3gKuYx4`2qqnmdb0F#wJ!JmwUMmxJZgT=kF?C~ zm1&y2bdef{-&$><*QldYSFB4`C>c)4FKBKw&Nrh@wf5%sHZbb%o2BM+%KDkOkefws zqbRNf%%(cm5aFiHZnA)D-cn>Lw&2N95YwH29gM5IG#=$Tt6e^t{o9eEc8V!BwzXNV zQ+}O&Z>N%c8}2s{6JBg_G59}S=eFIpjs#JV0!hwqC6@pIAOJ~3K~#XG$;diqtd;-& z&_Pvo<08*w`62N|wkd^;?ylO^OR$75f3CT@a=9EEfT8F)z1cQ8N3!^aC)zHnJKdMa$|y{T z4upG18mRM@Mw)Ufz2oNK7~|wp$&l562>T3<^o@yh(s~%Wu2RzR9R#POK}oF2<3_f! zw7{rL7oG}ulVLPEA-qOyL<`NR;}lNLzqMkRnALYMyMgTJ34F=((7z>#zD}hm@P8Cg znq2W_4ZW#dMw_YyvwC4=Hb6uD;+VXgOvspCe*Q`(?6^sjQ?jBTlZM5_d7;(TD>&VE z_4uCFMNgA38|rI0R);=|BCN@e2A!&(Vu|YqB^NGa41H1X&wTOfc#@^9MR|W?x`O5& zHM$M4Ro;^lM@3JLt+Aq>h7SXiA(dj@6~Rt5-2aFjUZ0bR)0NfRobn4-S&k^@{wOx(po4;c-zHM`!p9DnWuZmH69%G_EC!~ED=MU!4C@XV3) zi&|uqYDsW7wo|xPpEmCThV9zdGXAjq?VtbrW5))8t&vSwO6>Rdw>7gQG;7vBS1$B7 z7s$?M#>rx~Nir`r{j>;LcxdRs_Xi_j*5FjXYso`|CH7ZCgc@&T#(qEuH0Bu2RSC~N zRm?3HV6Scqw@Jxt#y8^;*}@zT;;(e;H-!g|GEpoA=NEKwh8>q9eSWafu7VkNex(BY^|jM-UjsLeg~#(o)mG)U+uc4$7=A{o z_R3_HI5&N~4XRT1GEa?66j-2(z;n1-ix#6(^838w#(abv4+P|gzmHSwdZkg zILeHr7kC}?H}W$N6IgSsU2$DVSti+R=58;(>83)1bIk-6$rWv>aa4Lt=%j4-RAyLM)1Hw~0&EO6rj?lvhb z<+lgQD^~y-!yB|;#|4bb;)X(hNop4_fmA8Bbr@{3;$w=2z+!X~w!$_?=JproPG%** zg?+F~Syz0c@;JxO56(o=IayT}aVTRGK~~8v{j8M?(8-F}YF~uUJWB z0)<6A-mNeSw6U)>RG1p2O@mY>AF!uw>A=}j=}oH4f@+PmWX9|gxvwqN4fKqPqG+55 zJks%lXDL2?!MxX6oom{Y?J#YrY7j_k3|A8|8%^3pQmCxVLi$=gAVKlKV0JiRgubLN z1x0-A9xtekxN@Gb6*lFz54@#%hJ5)CrE12A_VK-mL7N&o=Vt9S_1IVG*P~s~937a& z!=7JXO&#oj*LjdqgO1LIl#W`IBtC?dKuhg#=wx#Qc`F>n0fBZwv8%paZ2gq28kU^8 ziD<{VY7C0hcbtj}UDB`+ZvCFNoMRAuEp$Eg*h^NWV0OdgP-}DD)&8HrA^Ugw2q@|u zOuZ<3YebJ8M$I|hy$o^lbwt`kMD9w=HaSQGOV8Da!3C1X<1$0`#EMCRcD%jNbhWhbp{Sr80JUD#kiTDmYNM=QySZh)E7=_ zO1=D1q21xMwbmc^Zob5gXc?~e`{0>w3I{d50i-Jkt!{)3(tcD{17qSX!X z#J(=5pcp4OA-v&)${BErOjXtaf!KYbl|;c}0AYFXD@|Zu>GHxR%*nDQ&}=nth6jRt z2!GCT)*_58Wy!n%1T(RZ0J*y_^2SNlc2)<1ug%=r*07RHj zu2p`=le8*6)}}8eI?FG+3iXy64AfZd6k1)2>Eu%TFGCeu9a*^dn{etjjwxST%A2XI zm`S23HZ4Ie;tZMLOj=?dXMd1a#9=J&#Stm{i+HI35PXu5+{8ixEowC66T_I_C!4kaZv2-qvpS3M@fsVa9Fzwu6B-=IdZk|U<=0+aYXVYdmK|( znapR?ET0hzvpbii%=-E>YhY`5Wi3;`lt~bz5;lVKtXM<=zbe%6@%_)AT`^0VvU_;L zpQ=~mh(A;z|fXHSsR3h=)CeMnRz^k_MiQ9r&kZ5d6>wsOM=3;o7h{Uc> zlC900RdhyH3p`ScVxSLrOF8{74{hZMW>Mf+W#ZDbSIHp!{eAxz^vb*B>UgQ?wZlYq zl=^NXmU4h7c53COtm`^CF#!k5IlQqZc*!mg%EW=zd-ovI+56`2H{hOR9CfUs7K~poNg)i^Avf zbw)5w(3UNBB0|ma;>tg9x(U}+i_LU1><}hrN#E|HbF)|i~)OUUO_aFnE+~-nE)Pm$>fTaraC+_#@A)z&fxu$0$z!X#QXchO7L zkVXVpFN}n9M=N`y*49wa$`1Rf;UTw*MtJtj_zX7+#BCDl*zG@ii_E~I9BasuBuHwa z=o+E=h@PU^gd-O@B&Z6hr@WJ-&R>1t$|iY?1Gn3GoG@YyuV zVmYpCcONR9O;nAnB_nwWFbR9`&U*Y%mQqc9#K*|YDnHHF_bwoYt^gy9R_8T8OwqL} zwt-6L{ma#MEp!Uk4^n5};S`-y?bGR#x*Xl`+w?mqmAf`|8*_|0 zdi=+PH+))lL(h*2!+iF0saXRK2AeXo0dn{KKUiN~-f`~=`XGi>^yTmabe3st2(m@j z2NSoe(u!Ucp3e{l5;dO8ap3PcA)a^DU7Cjeu=86^W?u^xzN)ra-BRuo3H3vjLNmt- zsbshxc^TH1!O2xAKaCd~K6e8Ey%k=F#L zF4w`_nqFj4szC&;17#HrE=<9oSirS(olrn60AWCdMZ+*6g}G5gc|G7O`r)GajpU{G zVxwa@ix5|M-q2cOtT|aSFo(?d!7zr>P^;mk7CJeAL&RiG^0D!?U?b6`SdP!X?>E2g zS?d3V_3p{T@1mixQ5XZl5O5-S!_N%WF;kWj`uB2TAaWb~{MpeFpK$RRTM;ltV5cTp7 zmAE-KD^jj($!vmNvxyjIaK#*3;%4(d?T_cGTlMO>@Kp>PEBCoAgI5OrC}7vv#XC2h zYxI12^CubCS&i7vTp{UeJ=IUTq+P|^OP@yDmI~zS?C7u#snGrK8^NTFwR80~;b zumb(%(6-niR9!$yeP`c-z9{KK$$VNWp>3Z_i+SXRpf)9e-;%pYg7HE#1LJt7d}fD{ z%Nc@3*|OzA6NRNgcg6$({Ph{ml^S1gGlIby4?s3pivl~=i!vuds}{bW+UEO&$oU4L zvE1U>G6P0|zZ@_Ll~RdSBw1Ei!9oqqc{Qfh2O2tt8zSxSUE1LL);Re%VrfAsR-UAS zM)^M9H_02QziMlRV1I9tPRFzp{4hpc_5iU3KdFU3bNnS0rC1-xJ$|T-DZE5X{KoWicpv z_5iskps3KSB-`RJ;~?zjR`M{#!^N$Lqn4nJ%jIYl8a23 zk`P)>qX16|CBbs7tR5E4tFw4j2&0RY=Xm=H1kTcJl7!fv zqH$H{91S@K$n1J4H&$lg*&s}6z3$;XG6EYD>Jyz%1K3sMe!Twtxyq+}rl}}G8+{}S z0*6h!gHw-(p;9N+bW2Gl><9a6)zK-;w8g^!J;ywJ&~$}4^<4t#E6*`QK&V+MPuGAH#xVlg{>mGB`J4Db#j*v zF${;@ZP)g#AIj*XOuFfryPqJ-`9rbQ9rmkTD}FwXR?`7syz9F5oQC~)F&`5Yn`)b@ z5&PFHhuY5O2BBHvAOpBU-RK(c(ZshM67SWohX07F7tW(?*o}VG4RY?fY7fGj!kucQ zJS!8)d~p#DQa|qa$kzVs{=OWOn4?RVCe>pW6JFi-X36=XqdFWTU67TTv~|Gf9T%~z zP_$t8MYO_-Y@ocA*KcB=F({^#>HU3U0o*!EZgmk-kGR6EE(=U0lP>nbt09&sVOSGm zlDt4xjDmC7T4Z{O$ztxA^`~G5lC9n-$EBC|H;r)PE+#1VjM&9-00w5$ozze-ob`6H zlcOE&{bX$g?3Rg~R87B$H9{RTuNW|_rJ^Yq_7`=XN^8!Y!&c3_<&md_USR4BzjPPF z{hsfPyt@UnSR*7?W?d?dYJIA&C0_d5&9vy$|9d7V;=1&{#G65CHKrgYt(&1An^Jfg zP0>{pBF+T7&-Ibu;hhH(nT@te8t97Gr<4)Co6F>J^z+~O>$-=rrpXE>^f8xPk6Oq{ zVPIb&;oAE6=?c-RKSLT(3n(}j`C`qb3&x>)qe*syE*Mie03Si<7*0;76$e9!!Vw4< z!sWZkloilCG#HRcF?tMSP!LZAa=4q57V9MGv636`^#``mf+e!rt2Lf1K^hG0*nZm; zP-!*bXvSHr==*huBw! zLkO}p$or%fvPc_u)XA;W-5PJ4DL4!d^5!I>$#!+8`)Rv^v$0{koO4LMPmz51^`)~> z@TPN!+R7e~;bwa(PJy+{>UspNx?bOcxP+&{*_vW~|NwDK!ms;GYUXqz;S z{6klO*M8*+wu`i8o4)5_<0J;9(AVkmngn4!Imdf5qxh!m%8|e3gh15lMr1EKilahdzL3J<7?Znd!u!@Do9v zmG9lt2etj%m=088i+)90sw-=1^y6lld% zVfT{_Mau;TpCV>Q9$oy!YVi|#*dpCI#Y`Ej8a<)`T0{i6=EkVac{$aC| zo%%2Z&DqJqgix><9_s9v6X?;0|IOREHJPbib=E56(=wzV7VTHBeBOPsSJuHd^EeANC00 ztoGOW66aGqgE1o45M6Lh?G1#>b|1?ZIRG1zgCBI18wBh0s54{&qjM3}qK~qeQh}42 zEw68VqX)eu^zE_w?JU~Cz2(tFrB?`a83S7s30`*S=X$T+Cy#T(xH>?wel(*WY^WnX z`p{$^ifAhWYxofPK#p$F&pRDD=iGpyf1;u0<}Wu{2HhN9sQK8x?yXdQuPVz${%AjT!bUj&3g9<2JM&*)T}A2#&__8$U|lC+#9VK(J$HGOGo6_c9Q7Q zRueBs9bB^ljJ~0$>Y#$+0GS5fbt}W)oay3^*!FIJn`)~IYAu(;D9EZS{Z`QX8!O{X zY**^G4)L~C-=05-QnD_L%_Rpq$&G}9`;_o{>sHsT?_C6pM&oG4>FTcFb}{e#M4X9k9| zc-Nr*JvAzTr9CbY&E?I@D2yQKK|7g(0&76@0rpFB+-?PFe(LA2W6I~6g%S7T%3 z9`-0>byHouw3*ZPJhNU-StEi5V3S8_wRC{vGIqI?p!orXB_mA_&r_vVi8X;cWDfN` zr{m+aN87-SGxcM@jAA*$kENBoQn<1JpZ`szEzuG&_o2s{s7{h=H?+r8N)<;554)== zP6SF8vKm?_Mm4K;25W+Ss=Ht}$u=*^MSFHfH-%Q~Y@HVrW!S@BjrekJJs4_PJGMwJ zU@6x+Q+bFJ02wb9-WXOJ9eHMxiPQuQg3nq82dP7$zmZC;C&4L&Q=RBmk&1L`9HIyI z>a@eMzP?_6{=QCD!<{8(9-K{~BLH^7r@Q{eSXf(mEm$Xuu}X0md7Y7A4Yuse({z2E zy;4x7#T1Cnnl4>89TDCddMf^0?#e!TlmcxE?1DYYd+$0&TT+LmzFoH_m})@{-i9I{ z@`vuIhKwEOx5rSx8l{sza96+3rRO6|qWb}vJZ1{INVky+-Em0WwZ@sQg-Ew$zBMHs z*pw~ms%tmRKLuR#0qha=H)!#>J90%nVOV<};X||^&zj@;dYs0+@RwX|$RTuWP6xBp zRApzevyMt%op)knMecN5Qalt7ot81enH=dbNq0r|NJJvlY`M;PGwivs;LUcG*2flB zquj>4cETma?)=dAQKS^1YQy6i8T$fT~>9_iZbn&l{ju z7tt*k`PZ+E8h8pr1qwuZzX5ATq3uCMUYWCSd0sGsh8+5WJS8-61?DGek;Vm>%L0ut z3kuA?pk^(~XCSqCb_+@`?{c9-S6w=5IFRp4TCkkw5VzL>syck&Cf=@3Wa|Q|MObv` zcS>U)g7NL+x*+W6-&6fGPg)E6;6#Bo^vn1fB9uzarosV&-EFmy6ZD~Ko+1i~B(H=% z8J#u{MmqjwY20o)&~8;6tP$n;Dnml)(c3p{45s%v(XHWeUd{j9ejHt7f?6wSbUnAG zaJ*l(mrjB{*30c`1e06_%1?9NZlV2zk3b3<{vN)m`n%w!?YUs4r#5IA?Bq+xP-PmJ zSry$kN))NA`N;`*wjog!r91FeEKUYyjixfXREEoyrRgl0(iImBPmIbyapWz#SgElz zxwf*()DM^XJ@gR5sR&&-g=tn2GsM$lq+HOgPWI3QtXgqA+&|Mogu;LS`!^=OL&&SP zr)z+~Ip*H93W1U_x<<-UbUp0{i=lRmBj?yUO7I?m^ea`J%-u4J7B^w2+<6|kV@B_c z(5daR?tjp9!vxHJdKj#28`zw0UmW=ID0r$mi%&YXL})XY)Z204>kItp!Q|{LpQwiu%sNDTgk1-zS_IHg#wasc=1o{3R>?TETh9Ws1l zd=HP06y~PVRKA?bFEL2_B)AFr>w?zNX?oQV_^a6@&b&W0(N%<%+fS!0XAOt)1Ay7E zHRfX?Vw>aec?OvOC(vmZfi;rqBQQE28}+?VS;0g4|T}MV9Ry- zo2%73kl+5ML6Yz<#;AffC$_oWCr@lQ3wu^wBP8m?q$6`?@66*k7Q+oH20$)Xl6^`ZnYSt~B>1fh<)6ax(lQtt5Qlx4hpM?@_6b-n!b= zu?35MLH&7XoE3Y}FPM68QG9y}tU(b{4;9sNTgZs)5p>_{8+`cNqvZIuAD?g4(u=Yp zD0Qa(Yb!&SrDhlbyV;f7TJnlSCaH$Q%$ty}nATNO@vScNY1;0TY`-nD5{0_2b1!wy zT3C-_a!@KJN%j6_dOvydxG@|#4|s^9x_s)T6xGXZErnweS#hs}E5FgGh1Oi_;Q!dV z7VSoHB`81wVPl9xvNL!7|3k03s#+2x=giqmb{vcesMXc=*t^F+uMLAngI%99-u0r2 z0t8HyP~y&4dul6eLc=i9_m3N&psZ~4!kBl^NE1Y9I{qV#4-b;2gfY5Lh3Lhg0E4jw zIuK-_q816?Y@}CtB735a)0`ExJG*j8>}0w|P4YqJ&sO;g*xemPnzLW;iKj`{&|{ak zq$GxMs%DZC0O$v0I&l^a3NW$Q$D~SO`Jk3n5?+l}<SPJ*hO4vFj0eh1G5LQS;LlP#+J>H{w(|#<#A+ep>B+-{)YURb5^7AvZIB))Q^9E+Y|Dbx=dw7h%$ZDCB%8 zlUHZx&?C|MvFwZURZP3w1h30IM)(4Qhww{M(Q-A=x(4trVfnG+Si&VF&;`)f_=z?m zs|#4zo;h4Ii7BRzokz;DIB&{_srZ?d>|qEPLk$*Z`rvv2@fSV3KdiK!cy_ZgA<7Ic zerHAFE?z(c9A8;e@0liRi$ z$=FPnv6`pRmewm-hp%|l+1T?eW+{56}W-G?r zXuKg{K9eqVWo#V>Z8S(awjgD=Ul@tmxnSbMrxD&GwhPMbHwU*$<`*U#vD(DDoXYn1 z%r%6>Gm@&5xTclbDDkmQJnHqoRm}*UquROytVg*H&k1s6w0@jY`$7mZ^x!Ss$sJX6cR3~>|*8wk$v<*sCb4a<3vK1y@Zq0NnyKC z`oL_NcsRxg5wIU&~#x`%7bncnJK;Bb5#y2qbrguUd2Vx<15Lk$vH@5L|Hoy-r;?8hYoJK zke8)nH_JXhGz}^9#_9jzvwKuihz&SA=OIoU(CdmPz(zKKe5L3uiJ?^B>EVA?BJnbql zSNvkNXQ(!KUh&uUl64$=t?S?@U%2jo6%avVE;XWGUYNZk`NK z)_v3anh(`(Q&yJafB%dEZQN%VNg?zX2sI}2F!?zDK8NkZD{Y1h8^t|v%4?R+R*M&A z2cfqz53N*Pooi(7U^$A(BZLy@zAHU4%wlV?*rRm*vCcRr;tZKnV?`<0n;7v+N;H;+9>D$}za^m`51Vcvuze z5U8ROUcBh-S0zcneF~g3`?#g$7%Z;{Lgv)vunZKT!DVwd*_18wrIX#ytmy_ck!#?X z+4GDNZ9CW&#v!^)1O{9xmT0-*Bkcy*T)<$fppk5;OJA?Jx|m5fXjDf!PIFiK$j+f{ zl3Orglns8C0d18Zq8VaIq$97Vj`ZE4ed%LPFhFr>Bu}<%SGyuW9bcy_WnAy2b1JQ`TFO5iv>V0q}Wxv39?#^C!uqReAu-;7XS-U><*cjO=t# zbJUTthnTp>asAZi|E!DUuIIf`-ZMRr&+wY$^N7HPQh4D8@&er|g7A#< zMyvdoJeiPhESoB3GIA1ab-tA2(kx3xtPjg0aDySI%-QGu)$ZO(Xw+SUehf% zAzXOb^uk&$@)|XUxf>w2p15}ZwaRp_=x~8+0#v_`S(JsbVoIc6T{{{j!|qt>!+J_= ztG;&$o#BdHKB5r3#T_gIl}2x5ZJ{0L`_Lqi+FnB+)A}abl~n_gcl4ILpN@Oa?6)08 z#;Juk|UdxE2HZNzxnD?RdnC4bE9Eb@- zM{HI4IH7;hy{{sf!Kt>t8&Z9gcR3iV>xV}4JaQdi*r6?C>C2ylqQ#+tz{lblglp^Q z?r{TYZ259RPnENzIy@b!d+Zr8?`3kHEcY1ZmgRhyD(rUQd9?#Q@!7c(dV)=D<7n7= zn9&8!M-Slelr>2CDVj>#19|?%IRx;=auBaeex`{mWMnebvSvepYCc-gFKINST;!r* z1ZYFf4JpQRv;Ar2kTkzM4?UAwy{9h75Jm61<5?GRs2M z9R$*Q(2!T)(NlhiD{kJQ3TJ&tvO2-z5GKo?bX`&~prRAkP=&`VBU&w&>ZUxq>jxP) z^T;X=Aje%4yv5KIGWs5l>>FDEwpzVt= zJBl4_r5+FxLpTH>5RdG&hNPy?$4ILT*4Bq(yySv`K}@Sh<)!(W9@g$wK@am$Y6YM zL3?|#4=G)#bHRDWGA_Vv&|TR|x(Ye3EiRgDn3ld2Th!Xy>31o69%(hEgoIP0+R!pS zROYEE7p4A6V{STW!k)uq03l|Pw9gIQ@S?Nb*2fsau|xVh?4|v+nr1eSHVH1p(3H8% zz29Mikzl%EN+oDs3`8!q+8mzG(nd3Q(7;~GcbGFW=pFjeMkm?hN0b)TH$ zmVY_nFlq6{HUh=V*y=vrx*0`zXQ>zvJrCXllaj5VZkwCQ!Nu!fUzy|$g{Vb*gKdy9 z7I-$ihHPt@TR`e{PQV2)vE7Ufy&ueF4)CWY$1)7|FG1aUyWrXxhg`YMU4SISKv8y? zId})oQSG0@BdM*egx3bDyTwfghC`PodS+eR4)|vI&1NF*Z5J(IS+kg6i2x=lDn`$& zdx%wB@Z4Gc0)}wU=eR{rDKhMtOEwB}Vs*rPICFIuhPyrK!vP)^mB_Hk5%DNxfQSN$QznODq)67t*6@y)oC&B-wG$E0Qtx1f~VydQMSngJP;j4Pc%q zwSkdzjp>^(mn8_Usw|9P9xEn0HqXm(g5&hdM7rg_Utiy*y+!=eOU@QL(nHnNU~IOO z6KAYQDY8^Q8f6)~3O_k=RLk~R)N46j$+oKepoKb^su(ilQ9Nuk;6R~g1V7+BUL58E zl14P}i}8nyLDckHcr_h4@qcwu#@I2?X2mMF5KIPU0xQZ#c{H|q#Wnm_EW4KIba=JB zp*A|`h$}5C)(PFBK|&8@LJUtQmTz=*PhaZaF#;6Wg`O$LkaPMweoyp|VCp`S3kXo*&?Tz33gTGy6(LQtQ zO{*>jTP?A{?QgvXcG8@j^DT^U?Zm{~2{l7dW4lnV07*c$zrnjHhZ|0y;W={v-%2mf z9Vx9&c+HlaCqHn8VR*_)-{?4Cib#3zTO$w`O)g3&kuSaWApq<;nz{T*^ZtClTQ2qG z?nD*nJfzF3p0K()h|ngC60H)J+Ib?V&wQY_fihc*4c?)5J^yAK#)8{?{`+g=;!naZxhQWbMk6@bdcDrumtk+QS>3OHGc~4m;Ed~uI z8@jLAhh57;nbNvGZ4*GIx7+YN=i^NImTwm9(wpn}K!`6shZU5nfh!)Oj7&{Cf=*)@ z8l)!(h>mOZ>lHsD3jm5$9^w{r3@~(lROj>vS?Z)(=_bHYK=!&y;tN+}j+bL}rnDin zFJ-Yuu!!Z1WrAVm_?o0N002$Cs;e~3nkPX62Eg7Oq}#31lj!K{&^u~`s8dS zK7?A;`t79pKB;E&%BACa*H+nn>5=2|+PmTs?>sGxT!CNs|IOe~`PIPM{psZVBsUoT zwFW*i04t1Uo-AjV(b$o{Q!KNWW#8nrKrY+D%|?)1J|+TFhwJcMXkwPI-V-8MLJoeK zcCU;kj8?`vPBb9=rQv^h@4sE^TdfNO&5`-Kz9cp5Q(w>L_{yNL@=#o!2+FC4O71P@ z>z?)n1hKwE3GchblwPWIdQpJ?x_j<~+q*9M;6FNIKlW2W8xSAUo4Nr$Pe@I@9PtRW z%N|l1sZGrB9M6WBMODrvG8B@-oDEs-pXI#+wuLQP=(P#m1MiV@AW)ruaF^c_*17ieLdC?bD8hYF_0AtZ zGYOCbNRB9_h{y#Y8C@}6pl7&k5#I+=;-ID#-7p5#tZ#gwMN}C2JIIAS96!+7v6k2&>sN{A@CtL-+0X zRBfC|%RJ94m`FC|dI@`;HW+?m=1uGq!%SgfT;TvS@`l#KDtFdV-U3BebH(YFP?nx4CY^4+A~P=r&XfE~F3-Z$Kte{f zunNoNE)JE4z*hB!qgQVsT$M(md?L)0RBn;8h!YJKM@Ppw5enr?iWCp%CzT%1V< zh#Ex7Ys$Uk_jwk(_S{L?jea9?*rb%62p#MCi)Z&Yx$_RVY__38a^d=vgqVI+K(GDW zw6hTJ(+UXM25eJ|<<cO?TFjU_@BYTf0ec0&aNP5DZa6?VYG z?Fat`Fhux+uE+tvXPoud8}!H@S!89ts+p1tE{6xrvy&81kRj;LEHC%w-$B+-e5 zI=D1j5J%NtfBt-ZI$B9`W;WQ|-fGiKSz#6_AmFZS^n{^k;vi@ z@+NN5q`pPrh{S0ojGp$^dtcq=j{cO6!lEcJ^Naa5MQJ!vs@6SJsTTsTuQ;q{)6RMT zP4;nv2iR7Zb+|s2&0k2%zy9|kf$m^jU68)bt=1ro4I_-WaE|nvOx6?)I^^t=1fg2ZYLV{5x5;4yT`MrO$tbm` zw;0`GEbS3~29Nnhr|@-9!9*VleHIqG=NlHn7z#r$U8`cPp;v&BQ5aFKGU_|*MO1a2 zmCJBdXgy7^M1H7u8^{2;u}G)uJU79WmbCTj>xF)^Bfk9wCS&99oTU>@Fdehk@0puf z>{h9c;@6hgAhV?h5|E_T0y|T ziE|KNNlu-wk(9hiO0~_Fgw49GdSRnC7j=R{XcieY8k}`k2o3@`bALA_kpzdyr`EEJ zO*$j^#;)RhoWsZ4+)k4$yQf$Z`!+2-b@KL)P=}rC97v@lD3p=aXK|IL!Zhe=h{Q|+ zf;Bklb#|b@7L*7Veq)TJ0D^I(h}{|0xwnaX=TR5@F0+TURV+ z)y79+66U=YA740ZJ_QHzb5x0DqM+v597umceZ@w&R(gddph2c>SJ}gt*w#ucc9B@h z0mK$C>pwY!NGk^k^LNgW6IQ{ID$h za?M?EYgujD-211PB)6h1?{8Sw9ZaSB+>{&dw7E;9zbK_aFCv%lX{dbcInyr3dP=}u zTc~i8M<3~rPdUD6UH`$V?3GdL`X6)Ye{XZ2hTSjx$z#OBzlwEw4pn?Pbo2*>PL6gQ zr|)U^s;nRMex}mb*(9{U+8bg$e2yF4bUrvqp7nY!IH1hY@=x{fjV>JA31<+&bh z(GJ%dj90?rq$s3m@(83QLD1s#;K=#$a8_p7i5?nmH#@%tT#ipJc4@`ogV2a@Drv|K zag|MQab(#NWK(}xB?Z?&kl)Y8jd}AQFbN}hu-2~Y?Y3!!a;;_XhUh;dC|TWV2Us7X z7VzPQdFr6#KD492HDA$350DTiQZYWnf1G$vs+i~X+h zmTFa0Z;g)#(#Zhdow2MHc9Bk;#ke-CwTym!l7YeUd4G$#{pMU>39R4${O_yQ*suDz z^$Fn5pxOx_v|8X=f!{7ZV-zaAys2H7<#1Ofk)&*XzTL&fa(*;4+xb**J-u6!#V7l6 z8QpY-#~OO6?UaaY{l+r(O`;$4VDCXfYPmf2R-iQ0gqqM%l;AS@|2uj&yU5DdTKCZdv z+h(;NN6_=f_hUwt#fyPELEL~)rny13GJ&=@)@iOFrIc<(HpPl%oXpqv*`n5xzqNpw zFW_GX%IYj-?w2~8T>)eZigzu&W5vuty(^cYd?yLp_<)FRD(3+%0sN^9}UNwQpb z5D6prh@z+>^v>KIsKlX*PO7G}XcIQ&aGby@T47x2A(-m*?!erW&_ zl4bfOQs}YFb8d_v!G(<9JuOpPq9{dSilwU(?(2^;#Y`sRiy(tjl*}FkTs+sq_N^1ly9M& z$$1ZN)G9m6o;|EO%JEH?!=DcQ?47$~51B6)tD^DE@6ty*o#}pOppi0!iLxZA>K+Ys z{g$5>PI6C824=>^Nhb`Y9N!7-;#T>Mp}@i2v=*JY#JmvkI@Ry$Clvt;{~AP+(^7)c zO%N9KWo#}=+uS$*mGh8tIWW-li@>Wkz-G=5<}1z#Sd-BVhHJ%e&{1$DJ1B|%ne1&z zq{Kb(iL9{5&EevXDhJ@bx3fA)dxt;!d+lDN#@^4pDdhl)>NPk|C2w{AoYSi~Ix6=1 zk|+4DUiSZlond>UI1+>f2#^ehIL>YI!p`2!huz7HjftJ1>F%nxEU+@eVw-l5XY5k%9YW?O6$wjoqIqtfkUq4D zKC?AdGU(b5xZ8Hs7Lt!~dUVX6*w6E=-Rd00rSvWjUOoDrnD?oN=S0FiH)F*UYN{=be^cW&nH#JmevD~g{@1mQnfrn zYKLbe5gPmPn59fcps_m)AlCrT;yl{IX0!%NjoR zlVIflxzj8XBOd za_=BrR0__u+V($1=N_-=pL~#z(K@&5k&U>zl7Ye^t1rnBD z+0NH9r~&cfsQ{6CK0V*cuP8uk%u;>A{xiE_Ap2Aq+6J2)&s0=VCat3OvXBryG-Y*x%EpaugOYdIOZOT}r&&a_8NV-Id z7$unzTp_hG)^V}CrmBb{+3p3QcxhJxeG6Sby!Kt+3kPFeFRROInCu115yCZy_YIEq zVq*%gkwO=d)tf~aK`xzYJ9Vqy@XES;8%bZ!@U8y7`H=dq*t4Z7*1%(R6(q=UMGbm1 zFj~GAU}s1AtSqG#!{DidEv^EU?%_j`^Ep%!TcG5IIB zEioAJM*wXg3eXm&>@;_PB-3V9 zcPlOU&q?{wVDa__sItRZvwEV$mj4dlM$7`b3bpODEQkHrI4>?OFXdeZ2x&~ zsSJD-d-gc9UoSOk$29%>+a6ac*%)=srZ@4O!Hzb6i@e|FNXCk(|1-dtmlN%<%`WzY zlz~cX&bG6Wb+M*3tQL95OAgi2ZUvEr6DjAhZrj*HN4qw+2u%Eb*rci%22vD8l}EvJW-H7{$-eTqt8M5Fg@dP#n+u zFnb)PjNCck8kxt5ubS2nD?h7RkaC4Y%hp@F-C8I}jfrv2l}z-~0t=Rvx{8xh2ygI- zuvX+%=qtC%E*?@YLOHd_`M$jkEo*@zuXNEvD~cyIN7EYKnC03ZNKL_t)pkxp`6^_;C&XR{w5zvLa(6_)Opx_X}dL&bWR z$*P@(x@q@#DWILn2X47$8a_CoV?uh&EyFU^ScMR42uHG98uk!shGPr)%~+MrA$LI& zk_fsXooldp7jjW^bNNMm6F0Y*C+M)iO+p%y`C4rxY+<~ZF^5vNPGdd~Mt*$mN2$<8 z$HGkYKmefis3$R%8&VRIXctdVIE?sARUu_p7-=Vydp#8kbPU$-?p_vczj^|uta@lG z`SP7W*;NWKUix`%!_UuV{vt`Tw$gx`2#aE>FnrrFwwd~CX}Hw6vJqdSOJD^#N*Uf+8xJWNcCJf#Zi{02Ab6n=|QUt7ow<8lUNvaee4nRg{=5h_5WPhpMNjC)fK44Z$Y^XlD=z`VWd&=a}ni3+4TY1tmgOa z^9=Q)q$^6fVq!h)GS~8VYpku zg(0EQ_ab!{*@Wn3OAEU}k!6*}OuO^(OYGHbMKYH#8O6X$9H3WwI|0 zY;%u6lVS$(S&KNp{xoyI43^1v~^hHVe~*L-*BMVRNS(K)a7!+!b!XAuO-PL;yESscj+( zC{xf(5Y%jXWr?2#m_>xvO`*Bfmvd|JwlxO;pTGZr`ZbS&v~p_E2;zqZPEiaGTSaqr zC@zO=q>xTUr*Ei|s#6x8AJss#36CQ3YN`Bs3Yf^f@?zXNY2Oepnr6FQco|h;ZTGX( zkl;}}bD$8%=(4Y=>Wchspni#U^T=^CeNEh=5@j{|${Iy6xbn;cK$g$Kw)t3t4N}y=QkkF|K?x0@ zH&29ZNl)d1=bURIMPppyXU6Bxq!KYO*jtapAL|@CdY~S`X>yIV@AtJKU9uTcrCWAG zjlWsCV{WvxK`K!*JzDui;E;j6!B6sxbd)?$;VPNhgZ$)OQDQ*ZH}HF?Kb9q3sCzK5FMM+ zR<5m7!#8yckVldzY&>GIMWypS2F!xX6@4@Em4)M4lXeo)VO0e?T(kY|=ktkh!Qr$* z3)sV9wx&~Mu@vCvVfQMOG4mwN4zdaSl0*@Df7qqsn_*~^6~cpUdomFAww=f|MsDwM*fds* z$s{S2TbuIyeA?TMWI%ShrVxJ~Y_*Z$B=n^QQM>8Vk|(N3g@Ii-*jr2`hQF#5NA)H= zGfvH6y+DI*slEV&WQ7Crer?!sVj9GGGK>w1=L*Tk49H44BOF{VDyNXiv$AnTP$0{F zk>rEW%Tzg{v{2Cj9a)-g{#c95ub79$1QAY#j$JY1qF6YMN{{f6hea+SwW~hs)nt3A z`2Uu&6SRsX)kA=!T7;qL*>n6nZ%JwqO-5M3qXlJ+FzW(`=nO8e+6LoVEKSn22K~m>SbPz(@^uOH0Ai>z} zW04$C`;HmWc=u&F7-tZ`6DR6;)1`tla zLge7SUwM&py*C?T>x99T_fg9t6_yG!s&2T7)GKC_qnU>7W^09Rmy>sk+b|?BOq{uI z>E$04iM%_o!5r2ONM3$Z{)s)tFdQ2tyq3rNEcF+|*K!5_wQ;YN)`VVo*Ksz3QqE@e zoqvBVKG6Ef^V^=dVQp-cxK!mu6lac=QU5kAmWT6avjbUmMqGgHmyc4{%=RIejUz!6BmoK#Dbg~XmCFDBp^NG60ZB=@t*fir zOJZ48B!+{T>3)sUihfq>SDVrX8EkDsYfWZ^3kjQ7*Bjyrz)r@A&-P)P{TTixI+kif zj$W^OZU=!CnX8 zG+s7c$kA}m_*qUA5SYta*X>E!Rf3Q}L$lZ$3MIKSk^%zzMIzd=QEjpmB{1+7L?T+T zP^;=-OQauqdROo}FZ+-N)wJ6*gk7l{*_sYbg{2Ot*A`RGQUH`Ue#t0Yl_unfqY zsk-hF(Nq*rApW&2jX}dQ0`xZr!{#W$qpw2)Wse+S4-8R&CHLzGLa%|4t@=AKuqD7A zfSx3Tgo1J_q>ynl&BATFxVi1wRjx-XG7a6W1LuV_#uK?J6r?cbOG{X2aKMm9MGpo) z!a*kJoKlH46;GK5F&{H$6K4XvBZlgo$Fz$P)m^f0pr zcT&=FmBV6;RkYyh*hdDw-!tV45L+e{yWZu!J zaIYOOv;hlf&Kt;yfur5d^v!9Rh-tPsf`v-0rT%ZDNoj??s($a|SHkIy5Det=Sz^7p zYgdBKO~eJQ?*?I4XW*+9!l&6%Af8*WA7)J?yJ&l2E7BWnLFP2JLPIhJSIe~M+IOs0 z3cyD)uwy z`gboJE}JK4eUPVx!yVSTmlg=6)ovnHrZ8&9x?j+52K=N7sJ?%y}()5N|lj44Y@Aq_z##Qnxs2cx-G3FX7xA_QO71 zb}`oI@aEzn4WrP=J|G=AKjpp?X5C(jiXxk^4?;)zW+mEHMW8#!vC33!kr*W%w1S}; zM~Zue*>;#||B1RPX6aLW@cC2hGQbHR`Xo7UDz=`9R&;u;&kBGVtZ-&KR30ZWKlc zJLNI%y4HFD4GM>li<3iObi;+IBMj&DfivIu(Xm-N5=1_L&CjUxq^t|e#kMpAb3hh# z-*wGayUFL+yuEHJcan0exjBaupX2iC?+tF-4{wH_*LFDXk$&NG2T1yd3;|!d!O27+&MtI^Xc-6B?-rE zzSIAXUkgrWk@U-g?RL;dqTA?R8pR`G3GCu~y*iIw!g|>*3DEp^)7t%B593-u7Y{#d zW9hV8lAWe{$ALgV7|CLzUypZp%M^<-LJosUZDv)dznMHU2%}&7+O{#&sD5ph)dovr zsH}_)`P^E_UV=!AzeIspR?~6SB46txZ88bzO14+7k9=A-F_IZl@E)2ix|&r%BT zb({10e8S>vFKBx{7Rj1etFgs377FLUohhm5%9-YM5`n7zEAH^x1L`>0iy`=~U9?v!Vom1SJpcu1@9Fnw61Ycaxe-lr{g3FXVhM=Y%B zHe#Q_ceZ8l$fE2oHaq?snkovTEcDloF!u5z`}^d=JTf%!GHCvQPLI7qvJ(XFbO{a) zdo;{hQl5@cIU-FHoZ}cZK*AkUX$&r#!Bg-1kH#qHDb#~xgy+ZYb6O9HMIJabHbst` zetX|wdR=FLqHfYQrX?DL+Fluf``FgE#2dTZXKWhXe%uvcgOpgk8hgl#YT1AkX-_Hc zol|{9DBxAF>z=^rYj3#8@1H;4e9?^H^?7fth*n3xZ0E})Lp;g%pP%oWyMUq+dI#v4 zZsc82%seW8NP6sgN8zNwk{NkcLB~$a3DjC&+&ROHWCL*Uy3n-aHMMA}c6u4rRWlN) zZ`d-Ag(AQc`+8pq@HB?ie|G5=KR8?}h0AhQ)+`;K3Ae7jgU0QO9UBhZ|5R@D?4I|g zZsjPvXaa46ud(>*kNvM?K}F%PZT{J*G^0JqSAG2x9G)}n%>H*TwO=t z)*(%5H_ob8)u(k3!P~BP+)su|117^AAEDp{KA+i{si8Eoy{K!4WQW~stV1LB5~=L^ z0Q%8cS~2KU9&D%34?sQ|F3n9>R+#F2eelr&;(r&@8E@cK)qD45z^atEsI|s-=_qGr zcEpm%uQWlGmDGC1c>ezWn%x(;$4h!_=$Y5WVvw-gg+kh57fjw9x&?|R3p<3)d8(cD z_WYgY=TTy>d5o;V;@`Df=h;}1cDVbXdmc-VxQLwWmzCRWkR>S*_-)D~A6f3Ga3nwY6rXm_~C zlGeYHC~>TS4~%2|?9Cp`xwB;#LK6)>2dBYCa=tZIa*@||KX;`I=gC!ce^i8oAWOTdH2=XXmQZU@@Ex19?z+?nHF4lJw z5wPa0OOZ(*(ZjH!rFisGMUS`JHR`Tc+5_$SNL&lxF^X%D-P2)}Eh{PEe94_YS5vIf zS}~@^H`a7A6c;he^RM*qeK492I_Yyj!jVXE*>T0;lU4U4yXv$YejgKulO6cOvwRkG zy@e6~1%P?dR39~8;p4f$W@;&%W0Uq?{-x({LZk2!5fMJVFD#}nhXDVcoWs73^`pEy zC9+{A6;x)JwKfjRiN)Hk35JcC)l%?`dQNTB)3)S?UEzLEMIX{6>ebRBb5AxJU9bFcPN^HNQL$FfHQG&j2YsNh^L>PynTfAOm&-P$k$hI~Uv&xn&sT zYU6oKU5emGF}A%fKVz?y?*HAC4}|N}oF2a5-C$|Fad(;RRRiE$!R<_hloT zU(zSeg6(rWA-cu;^%_IC{7>zfri(3Q@v!IC)|ZOa&|;MwD|!iM9M-yZ&I&3!22$Y2 z`*i1Sgo{~6l9E)_;wGBKLt%;cwseU;$_s>6s?T;mo?!coE=(3JRA2c$nuKb~o`!Vb ziJM;5THNgc2xPY~o+vF8V=3zo{i#W$Yq29#1KVAzw%Cf++pm!+>({VNp1I&PfCyS! zGB2$7Sl}jRyG+-`o*6&H`fHO(6)SEQn}m3w1*8s3AAD|;;EwZiHFC63sSzItWOK=$ zQTK^rF+!g-GCR#ZA)Cnwg4i83#0TWP3#Nm-lAw=5twW7A#p@*U(R%k zM`Ym1+DiZpbLsrIu3~1;VG&5u{yT9zY-8Z82oRC7P--8G)=&0CmJumu1=U$e4o;i5 zN4&0o89M{*MsX#G3XniD1ji;Bd-MMv`czfj0vx~DowH|mXU0h!2h-~As$0~)mE`N< zNtdkVcDO<{k<;+pw!zjVH+?Auh3uy4_YmXU^Qs~^IXdw*_5v%TkPmoH3ZOkM^yj zrc2vnO~CPva^=@xtS12|2Cv%1vyo|<8jSKWV(9BxN)0#t@%`t|{W5yr&h~gzK(B1W zD7F_f5D!`je~=H-vk|^r?2j4hfQoItB=+kZTi-v8*r6mvI)O-%lnI%pX2GKet}MWk z?xTse%_Tg_-y3b+OMMyXmttqwmceb2W20;NOJY&Ru^)Xq5S1crHMAX-a$*jm=Sm|> z*)NCDk~NAJ1&ss9L!12!DG(5cHSbeb?plmAId;R(C2%3%q+P^_M-Yl4>Us;DQU*8{) z(~$(d7soP|6S(=Pe+sWiuV0nBhePeKu08Lc_h(&p_fa2h$2%Px?5Wwvjz5-Nkaa?z z1T!TmD}mH!gXm_Fu=3szcpct%XL<47yP9I8>Re-Lj6Hjz~t0<&HV3F|BQHB7~~m(${77>z>Xio(2}$TBVtW4``0u1b1BI z(p;qRGRk>`DtcMENqcwxZHFc8EHZOKFc7LGtxU#}OMyt(xiTjq2su`2BM{b2k)XY6+BOzP3=ois&|zw9 zYyQkZTSuAI3>!1HXoYdVN%kL-z`Ar@@*zabl+En6i`aV+%uf%GuDRk_% zB_`fNp`+&rkwJ(%H=*ms!wk=}Tsw=r3C$ErtG#dX`Z4aeiw5E4n~z1omNB$*&X0%7 zZ+HrU?rBt%qT!lg+Lvn9*US4>T6g?mFg#VU&fH=oWJ=98EoY}!1jST67tdJ{#r}aD zg7`~Od_}8bGDP7u0hwwL@~aL?=$=sPYm6t%PBN-$mH@XJ8^rHmD28v3FjGVa}I~2 z=j3&89H!}wJnPpi`>$2?Wk35;h5u7Z;p@cr|8J<@p)RNMk>S)TzcRLt?LOBDyB2(Z zaSq|j6V*}&KhqG)QE*n$L1mqHyRk%DhOK%>IBE9;7tZtLUY9PIxW-wMnwhvg94&5t zYfh2L6r)0Z@RDF6Z!!dGAo_Vt9ALXSICyLXaF@V+!~~0xV?=01zLf#AXN3J?PK$S0 zTCvAP?PKtLmynf|=my$0GAe6zW{YehEB7SBO~eLR-66@&+s_ldtZ|yJ1a2+$7lV>G zCtoRLs^uS?=~7GUwrSm2Te*3=vQi7y*x9?H7E&l~`Ni@1Jw39Pvsp;Z1cetW-SbD5 zqC|pZ(&x4Ax0bl)&&sO8h8>k@!K}LQ(FV|hCYf*0jv{Nf2BO#nF{~K15SdPxC1hIa zaRNx`F0%MDq%emTS8X2OS~2S9L;j;#40T?o3yb5n>ve~))faGTDmwj7!NI_ca?^<| zBO<*(nu+eC=yB0NUe>>52RHNdfk&tPIH{EKcn~7UuGwJH2&k&}_jz=e5_HSB;dRtz zss2*2Mej*!stDVAC>9;>i-F_@!x%YJddHhnGNi$1y@$^YTj`!A=IOL9R%OxDv;rnt zu%2gSkDk;J7>?Mq%}sFOTxorN3XV-~%TA1B2x+TIY;Cpt)uKf-S+%33OEH%c6k)Z_ zs)@aL>Mr$AWJN+xg+1>D{-Cd~`n&IMrVI+-e6b7#E7vv zBK@)=p`u7!nx5N5IvTuW#Ia0Mk~sPzm$VrdH_Mhi`gX(4RAC=%(1v3BXze4KMRej( zt@X=ogn9Ifxa+rg`=qRtLom=`)q3a)bC^zPKyM|-uZ0b1Tk(J|&cAUKzb#1N-%Ikp zCj^K8m~I%t`=xVuGx=^4=^W1bvS2r+{rh`CdRdU;-o=Ik!sHMyJh?U_zCNR!T9xy8 zK2f6ChSzJNM0qTG_br|R@A%obv4}e=ZCIiCUN{9P*fr<3**M=~wDgW04UXF#SxohN zzu{eE!6Q_Im6&Ved4skmdnQ&rzb#A${IQ@U;gdmwh9k$acvpE-=b4b_mF;V-(pv%s z8jLH!uvQJQP4wGA_>?iJhW#iKw}Dt-Oj>19%3!K}!IgsVnV-qtL1RPKdqrs)SA@m+2s_Tf;LnF{*rn;C@{HpTUy3r)bE17DfiHs9$F>h%TCgA>$c zy8-T~IhaOM7avht1fFipoVBX2W9Jvn^p+!01OuPl$z%*dM4 zj5q7iZ4=;TulhP!*h09OypI=$4^eiqnK1@^8)xfQT_23JOm^bSF}1|_`j|M_Ak;=Niv;If1_To!+oM6-Z zv_7tj&VWMkgexT`Q-RaaQTT-Cyh?T*hSvJo%v(Yu` zbEH`odua95Mv|tX$-2A7i?KN4%#lE8`sc`78kWwB z4?8@WTDQM6<2yk(lf46Q&34h@3JR=g8S7;yIKkqE@KQv$&;4nW(DY@);o^1v6&Tf zaxf1p>uf9y0Bz-ri?y>Wpv0`4;W+h3DloWn9zh|E1^qOvT z?gGz^?yI=^O`Gb^WO`%UZJ^>eW%UL29F7(4FZJEmLm{79bo;~UUHD;`c1v*kvwgpP zsL4Aa^N9BJmp-%>yW|$o;G++lSWHvzQ1ikoB#q*0zfZ*XD zP-ES0#lWRpwVmZ_b^|K%Vm6gNcDJ|LF&nFVvNRdjZZo(6MHp8g8)#AFWSBjr& zkBc-0R2;GuSMfQFEy}j1QI5+rKH==EZW_yO%te~ovj4GcP*MO~REkZv` zL@wGMH>E)K)i2>1HruXuisj0&IfPT{O|ylDXAG}Lom`5^@C_m$3>WV(^?PFA^7E;B z*v{2uj>fc1-T7deZFXwauwOtqOCpbD$Bb*K2KQ5G{Zi5dIgdR~RmFhO7ONE=&qwXe zO|E0oFg)#gb_p^ZZy{D503%A{wHYSlbSQ$}}F&Ibx+QJT8`ekXp4977|*N=~rVh!6#{^#uCX(+%x z{`s7Um7e&FJ6j^qaxCYUNMHP}v&aRGrZbQ|}=s&g1+f#$aSFzS;GVVUV zqn4j1)O${Qcxz{0y-MLnmr(e1ll;H;!>^=E{I+kNQi}6ixBZfT9FDojuXsxR`4Yzi z<>V!1I0b_y^K#Rh4vG$q!xIBbDpvqYRZ@u{^qw14gE9=1bhI>iAy3hj9Ttjox#<0R z87|DXTUOztBYi~5h)4toao5{kkon+K@qKc#!L)mbhPE)SIk1B*?dtb8SH93fZwyLU zZrk^xl1T4>UwZ70oH0fG=4r84xE;>0L0 z?$0;gStgZvrldKE0l5;!m=*}Dw;9$eB>Ihzhy?>Y12(d;frR$Exv|9cQfsc8cCQWV znrczMBvCAcY9^#vJ$1Qxmb7|QVxc5g>rIiyQ6p-bQSTl{z8tC`{Ma|QE%B?#)O$QN zWU0NYOEPgYI~Z&{lW%Sl-e3gQNJVvEx=d`mL|JnxG*%yLVy-MtdXq0-P~tU?uB<`T zx5tty>J>!pCghp}tG}5nFt);o=vv}u#4?k7sw`GN#Z_*er;#98k^uM1Lrpfyj!bt+ zmcS7eJMAfmYBOaQRx?f1rXW!2mAlp{5_`C?A|cp?q8bkR$OaqDD|O0;xpXYyfmsaQ zn+)g#izvI;v-YqkZCLwWPgp}+Lr!V5B9PGXvKo^zjoNm$#D;EAPLWz=U^?zsHtR}= zV5{4z0*2tG-t3g?ZV>x&vVbPk)y~cZEdkt8Xk9I@QJAjDXVT>_;SmYOmQK3-U&DY+ zdIB|QQW|+JGR#JvoDGyc2R5n#+h%{KPo-!}WPw>lAa`DkV}`2c&?hJ39zGLxd2_!9 z#%Y#woU`r&(E};UbXvG>BJf;tNeG7&i|+PckL z^Zza;(%{p2@m~OIK$O25df!Hbj##Tpve9aIbb@5X%D90j?a>O@3d-dOR$_|z=zFS{ zUe{=o>d+rXDL93M2lY#(R<7VBhYW-7joE{k3`0nSt?;eX;o6r>pENr*OQX1a}la;`x>^a+(9&5GuT`(Z!Yz?<^M(C*-CRB1;RJW9e zZ0@0q4QqBTR=K^&l+e!FWO%myv0ebFj6ui1-vJcFLy7vPG|J_fGRj!Rp5|e2NMO1x zPZR@hVVV;4Yj8K;7JKlohiQC0ElE4pa@H_dGi_PDrxMO{M#2))hqGl61`pPBxq_-W zKjT>zBX6Y>m1#LNi|%scIiz9m;LyZ{3~SB@s-Phepn-jE9naz|r5pur$c+39(U>Vh zch_!g(sp*bo;&mJ$%|tM;~Wh&lJ|&E zr1)OXlLMSp6}ut$DqK%e`(Nb?d3A3Ihqi9NLji;97|yEl9kgg$@AuDtK2JhSai4qg z{V(gTjis^hy&^XdLaMWZi0Lqz92b2CBIH~eSt6=iX{?5+v$3`inrzbvnTCjpuO4%l zm5pebN;+9|XS>&_dYo`pI8P45vfA8o;XZk`qD51&OYW4b=$LOm7da;(>{zSdE;M_u zb>~xO*};q(lsm);pluF5>9cEQl~AdIC0(8S17F(Nr*#MH#0^&RT4oz!caF5HU{Q3* zyhLMomm!4%K5=)#zPG61c|iNCqU!LqXRO8et8_X1skZ(C@d&S(NKZ27-_RlB>$=1XHT!Y#{+$C|$r=nW%)7n2USniuGFZ%>R5>bN-tisjAd2@fACxyE80dKe4jp0FXInOh~4f<6ZUld>@3O}TgojHESm&Q;E?}h-v zral}yIsB~VQh-ORcnOIDnkDzEKCC_ESlm3b5R0vW>KL)`nZQ@>0TcNfK|=WXTl0*-r!E z_85V)|=VB|lq?W25D9&m|WYoQV^BKb4X- zzG_vzt@cu26+iUS=4q<3E#&e^)iTE_U4UAu^vA}{C?zr`W6lK6AlxTyea*kr1DA{L z%t5?@AEb(AF-$w6KyN{Rd%J6pdA)nOHizFs_47ufAldS^TJYRgqVBFWl0taJR;Btxj(gs}5=Qqwx5w$&lBd`6Ks^f_2_j>7 zN@ob;kwZ->?r|F(U3-3MD!3SSUTPXFl9J~2(p0fXw!pjUkqYEc!M-fkOh?{7Bk=G ztDIyAg$570JksqOtuy7n+pMmX<7@PJq!cR#(OV_{F&enBN98OXD!0uDyJdC)1XL=0 z%2`^!zgN>kyPYOc{HA)v@P^WdFKOHZP?F85aW4q7pe?t2l-5mUzC2Q`e()8mp)TJ7 zwcGR^nV(DhbqoI`9-dB}WVsB+wxdZG^K&~pGE2BoJ_GK#Twj!9Xp5}AMv;0Bqu-aQ zwGq0Tq_*pw?*UvN2HX->m*2VJg1Lk}$8770V-j3MI;%A7Aep`q6<*lep0o;}#e9wy zIusQp5!KQO#4DaX8x?~y$>nP)Jm$aicy%*#s{W=Nss$*Tr(Mh3?4Pu}$CPQv#5v?H zrm6<~>hV-7>=(vyz0HR((10$d55e7kHk`KjA4g1EGsmP~P6!5HK`Gas#iTP17Zukn zC%))kjc36SgxH=x2y~n#(>EEy{kFP|dQ#lUMd+?tC%KLH*hGrB26~ULav~dHRFE!(Mp%cd97x>i z3#R~ldtKF!Q|N^`xTq#=<+8N33-8P@6l={tHetEW`?vtXxy|(M#v%`%!DR*!T*u7r zmUc_VF?9J=%4koGX65APo2qv%^3Ctiy#)AWU2RUx!c`ZXoer4~FTWWkM~C&%jFbTZ>BWNNb0fyWlYv#xl7NXMYZj2io`|k(;S*h#AEE==n z;F&_0DwhJhHo``h%8MwYhG7lmVuyM5iW1I}2M%Q^nHZEdj~n?IkTPbLigj;CY>uJXDmP28gv)HwY(*TT-r>)ooCj)yn=O9`^&a1d0Wjo| z(jzLoi43dRQY=K4EWaA!v`2e8x>s4T91?A*e`oB2d71b;bgc8xhNNME<;NJW!fDDw zLlPK=g3B^T+mC2`2twvEYZS;E@K}?nCp7=7c4{6J%g@8eU2HSYl*w8MV$OB8?3m_K zA2#*6w)(vcgOb?wj>m3e@biEz3~l@B1=?xG(V^(6H!(G@zvY!>N!3YLbYqR7O@k{L zv;uy;QI3Naqe&424$*+qSeb;a;)l=Z`36g5pxz21t+O`2EMpKxK`dqEk5k`&Njnqe z#&INwg5m|}pe##nEByZ-y2ztIQnsgOcPAz$V%lz52hBoNWxl+;sf6-h$28d3Yp1W6 zlng`akDp3XK!2&dEFVT0!1zaYqkx%(F#E{iHovhKF60oycqSbanC0-{gXxhiKFM#h z!WXPh>-B%VXV1OmVRm*Uxw!T2QTZ*sbPfT4Tu?*kSX;Lnmhq-LwQ!l2K+92OuAA<) zG9+n+M7Lff<>VHd6U1MNR$~TjYhlbaw_CfgqBsgE632I;gS!O1)EI_C*$Io&#^#$| zaYacDCMSqruGN`ZW*L1fr{8)qv<=W&xsmfOVkD|FYX?ad5+k*CFD zQOKM<7uWMb0VW+|%}>U2y`?)VWOqHCPqpTuU#+zkTi^2;PG6MYD<;!Vbh6Se*UH$9 zQuks$4CV9v#2_VBO(X)N6x8av)LZxhDwT{qwYXf7R7*|p30@_Z7-R^-&4Yq7)Vhhq zZh9jBS1o7m0HV%hCZp1ftkNBOU}Pw80)l-p030w$iMh3OII)ntRr~Ydd>?7iCXAz~ zh@(O5AiDC%DkfQu76XS9t>!`vHP+!zybXL8*q?GqctS*JjI{`%W+U3UkMGV(4z^Jk zQmry_VV=XYi`T`GaXprxqo+tJwLn4vqM3BB<~+_H{zFL_lD1Wh^-Zn$g#=6^xrpW* z#?P;75^$^d5XUi;Yw-PRS(CjrnKSizh-jLK;N{!t5Z8fu4Oju6)jn?~Wn|kg&(VRe zhg%MvYL*GNM*vgpCcAD`v7-OEsrBSNx&C;_{IG_J?W2*1{K$;{Pn&fh9_jvE=mnOQ zCs^%bQ@9zFJ2rw0<^Lh}@y(@DkV(x?d5`7s;H`Fw$G49^@2b=uuyQ`!Up_tE}^ zN^j0BcWjQmpw#(p4|kiZ1Bg}?&M#}X8MljNdK^=P2V__8^g}ed*C_! z+Ux%GoYHwre_=&$=jkouaph?4Qzy1;uGh?^AEKE&b4c51cW^OYq|-m+H?jkXLV4va zLbv(BQB6bRoVQ!sax3|EMIU@1>T1MxmnZ*QDf4dZ938Q;-BQ|U!UUz>%g41$8#STJ zamLKzRU(_f7pHoLTY3@_ajFFrYuDv`JtI|N$*94fpPx+TrSk`--%o6J=lUH?GvY+O zUX1LH&!2Yf-WMb(Jz*QZcA$6IUrQ+Eh`@WUnrms6Q>fNQES=d6vr^IWTp!^nVY2`o zWE-ET5C(rSw{U9~Na(}_g&f(Q&-CQZoRDWe6uzcSO($F?w9#yVPi!1h(pr^G>3Hp^ z=6K$z;AZ=tN1Bi+kC?QA2;XzWKSe4Me0si_vFQlY8z#(i`7g<>AhOE>|)`f6+IE}ty0Tfop8plkrS1|;Sb8%ji zNIYaVG1BIhkc4S^EX{K>H(V@1A9q|9y@I!*7 zBYvI8JGDf_N&Zv@6oP%h-EIBOcc`Wub}0X>#nWtM-7!XwjjwUai$C#;XHXGmy_bvE zwPI0`EM+_jzaN`sRN5nR98}(qG&#LJ{(NvCE%;?WHE4(g%Dv;1hlVKW74tMPE%0!8 zeEfOSBHh;;nr}Cx=+%EDdujAy};vVS6g(Qo2b7h=|5(PHg(y$wdP_SSS*ysU^XRW+STZ7?< z=A`T52-npTrL;qrY)b-a<9N!u!-z9pm72%d%_&jD48c=ZyRYl{c?ZN98NO6weLb~H zfhPI75Q(uMv51zY1kDm*%$V<@?k*_t)<#37HM8V1L%1W>a#8EpO|_%0?eGG^)-no4 z#jP*HIZ=daC4bgh+I>DhwFyN5*7tF=D%rB_HYt8#ps0e(xh%@HKXslXC6-p1l7gqf zii<-4i6HY59$V!ZFzT;lA)B=`U5M4v*FA$zTIpshumMcUbJHznkE4yi$X@T}4nwO3|e7;QFnSO@qyNIC|R4{x;$fj&BzQ z73mRt0_dYGW57*NH0vMbUtnuI-~@hqzmVYd4#0=9Dnk6^^hPBB^NT>oX3V6W#N-h}nLIq0T7aRCI`}!pZq-{PDn7K>hZPB0Ht;`Ky>||twC)vS z^X3_J3>;g&T(dPl#}0@F7mCg#r^K8&#H3T3Onc4Y z%QLRKDA-BT?Rjo0v7vY!=&2I_;?41P7B5q9Rh!n@^)6q}Gg?ckk;_6?@B-T|*TK*l zam`B=RJKB>OYW6|E%|8&!)DbT}aXFG> z28W>?)dij;nmXsX3H?}pvtILuP;@-yOtRgSsNX7wJ&&}p$V=c8zrKA1aMOP@xgE*VoSyV>Z{YSd4w z8nbn3QkR8yrbHB?bxAFyx35Ll=|q$Eux=iY#DUZ*`*+g~d2zL_#)kR*@%Z!SLCf$P!yqmV?W|m+Y$K3sIx6I0(nr`*%i&w@t=huL zqy+KA>CTffoKu|Tnr2-|h^o`d5O%^L0}tKBIG#h`=f=k5%|NNlq%Pdb%e|iW&VjJN z+*X5pI`)BjUK%L=;@>n0C-Pd&OWe>m_LZ`s3+GKD?Q2n5na=;%l=890vhI4l=6VSv z%-c_XE}H4A_-maB44czgX=lVhRmSAx7IY|DERwQ`UUoxp2m5I3qcX3&~LpM;3a*UzqW-585|-n47Yt`FtJdptG1 zFsQIfcV7UW#&^Tb%=1EmcY0_(T_t!wzpmS}+7pCD8J=mPogn0)EXgO#tIbhyt?nbX_do%c@0J?DrJVh9=MUKPP`s*&0^HD|% zc#7#!=cGg>var%-U|59q$c~7x@@t4@x|rN`QG9TGZ+e@1@s9&vx_5FCzR`%oLU9m-6%MOkXx(LZUFdypZbO;4Ixy?U75&d|m z0)vOed9MJP2YG?~Wq6(x?s)7)^I$9bhF<-kaN`4OIZFHcTYcMv^$2)I{m=WygV7AN zGYO$L0b^63K@HVr$n!kCUlf^4!&N^`Yq*D$(e>>;T&(0Pa)=Gwk|+{W0Ku8i5E_rB z%cIw=4l|*4U!4_^mCLqW8A@C53Wnviuurxm1-@)3mAK?1T8djj3rEV|h?B2+tRLFI zW*GX(RXdaxxR+Mk<#)i;{7X^$QCIv!Y{E93=(l`@JT+RyfCz!~z3Bg-|N53s@!Qd3 zlc@Y3#?D5`Z5#)}q(n)irO27}*4dT!f6!xh10>~flD*nW?dCkT{4)jtbbq~F7sUgJ zvJI0jh;IK~eJ6UD#BNM*EZ(PR5^N1?9uU+1ZR8iCnX<@P_?|JXfK(@e+hA9z%FCxW z%py)*t&;7|OIwqauO1E@9JOZDApRXNl+x+suK=s$0rkGWp0$ToE~4pukDZafiV@6eaXk_t z+Ss}N*kYq|x5_U0I3G{6$cy`nExlwRx~hJ*AI}3(f&7VD!51jHsAt9#-G$m(kl3KD zKs=tbhq0b4Z8?+|%mi?xiMlg_J?^gqS|JQub7*Zae(G3E&GFD2;5}tqDbaqzTI(^MNbkcE>X@D|m zcv4b@SPb6Gu5HOH4w5;OwVD-QScAsd(HV@hyUmWYb`?j0-W;n<;KK5;}`dvM= znW5Ak-yD(Q$+{AR{jkCHO}MKcc01gK@)u-gq8N&jX=`og+Zd^!2hpSOF&Y+Zx>@Fe zCoMY3$|m}X9!!I^Xr^PC&ti3kni^kh9431^0IkLPt86svQqs*h0+y)B3R(v_ zky@;?BeS|h2p+KZ@)R zp$k-d``$&rkJwSAzJ$N+m0BXwFk-UUAKBaC<++q@9xIZmw`|s8biSad->l23!{Pks~n*W7||a= zs1MSxphIH01}OT0s%^4gATr=PLQVtXeew~dr$P&T?gs-C1cl5#_ugR`lG!K2B4S%j zDX$`Dx(M@A&ac3ih)>9rCNT-u{j!nmde%@gA~7jb%PVANyw@_$$9dfAVS~(RNpm%f zT5O)1k=ArB7P2VP6fjYTLW*^GI4Bs)^y}v1F00StJt*F1OD<+LSJ`JM#7XhA=TK?J zrBr1yOxPYO$G9K4{VO2TDukCQ#iGn$8*^Y(o?@G+>HjdR923m7_b7e)m5n1ZL=>gC zt8b_;bM3a*DCaAR;4KY_VM!5xTvuxJUUuvc_r;+};V=2><%!Lu=m{_x zY(~}@&o&vKI<$IfcdPxd!7H0M`$sc5%Y+Nchk(zz4KL7+G|4pICZlp3sSwhhiL{RK z7qg-eC)@ODNMAo->GsbLm!T=E(T)J3b4|7)mfwsIUF+y-=c-0X&8yz<+=&ah`1c>Z z80|P1>>E+#IhQu_Yvxs}he=cS(2u5qrC!BFeMx!QKbMp*j$RvN=MX+52nF9;ezWgf z!iD?j>aRfxZ+|Ho@o$TF_#Rj^RJ#0L{4Ch@H)Y?Fxbv`WeJ5#cBZ=Zum_%sf@bZWD z`D%M!Y(tD#-DdK&9cvoHm)oeg!!R^N)~1RX@cw4luq)Uk!WT&@!d*yEe7wx$dVR!j zwzGKE+FpS4_&V*CQ|{|BFLDp{cUOVIZ&-psFYKaI$5U}a-x+8*6T!~``Ph$V|f@_Jg zVaE16)NSV4CLfYOu{Kc;eNv)Dsg#6F&>QcI6D4C_eqlk4QqQvkceP6tee%@QIz;tc z9R8w&l_)NA@yrK2wYxd=ZF&?IiM^Wdn3}7_OC2stkW5iF{M5X(-`)l31@TS}NPUSL zo(3e&O}Q1IgYr1A@9S<9e-zu0FHAa>Z$`sMZSQaBdFG@rLxpH^0vCXut z&npaxsy6^zgG|48w8zrwHZoDbzMG0$1hgnqBLvoyHNL`5x}~J{$mcz-^L}hCFH=K| zz#44rjrULDI9m%^Yuzd=Keamw1~&M^aTNVB;8Q(gTDoc}EBq1-DaAlvjd0lpMZ!7+ zo1=S31dk}-Nd52M$>NZ1^zq2wF)a42o%=f-$sOL7x8 z%5S|>6rXx?>#%n_d1%pcA3=uCTBkp|fx=tm8*^|=xK4NfqgZ+9y25|yt3T+B-^ynA z9!dDgkQ@d?^|8Y2LDR&g>%u=Y6e!!wJ|!$^NWqXQp8c}(e6rie z`mIEYHf6mQ!3cE-l6~o85?YivZ&ORq`)_FVSX&bI&`Fg4; zo-@G?n4C$pknkTtsDc^mDe^KMzOUNr9w^f%a|j?adccq=#g@9{e9Du1uQxN2Q`k;| zo8XsuKu&$y1{6c!UoR-Hk%9}dGzQe9Yti?La9rbW?3zrUM^w6PmK~Q3E_DnsYEz7z zEM-y}&~8d~$OLQE-h0ctwcS{ys=qcVH`1FH9|lW?rrD14RY)1Ge}l8a@wl7lt6s!2v%H`3+s~0+u?fi zgJj`$y?zt#*|#dCIjl=dY%u=$It1Al>r^iY{rYw)!|(ajkVgc5p8d!lP|!+P&Fk&fcEr+FC-0||{6|_(DMwLk51U0#CiS)p=lx7p>P?)Slt(0m z@@zcGb(j{^7a42k=_k3uZvw>w55SM+G7KKuB&zLY-?dpo}B7wSruMb zbga?4ql83s&LCiyL60o3>1|rwkJ(^q86Nc%ywA*yu+r}kP%MAeNB=3s{ z(I4)3n7_X}uEt!!t0=683A4QzUCo^pS=zrA%Mt78Oyvy$k`2lny4yRuTge@1W}sXK zFHtDXb^iHu)W6YO{S13+XzV?5qh0H)l`eW`abeuSEDzns>BB`B{}m`chHC0n3-Jc8 z@Erx|Jh&BRb}v?_FN^2pLKosJlA5{0)gttctU~T{$(-Uv=lc^fF2*c5n5owBGs3qU zSwWvqo*zJ1QVYv4;RDVj1mGeP7v(V?grG_?wu9KQ1^H#NdiG)~XEXa?!z{>EeQHZ^ z7*@S%b5Jk$JG<87fx||;FTTj#qo1j@sMf+5>)xm=;B3T?tx2fxaEG&@gND_Y_$xKp zP6jaemr#>g*LFX1kN#E?gCYfSav+5RpbUlNE@s>n{_1gvhG<)NLF$9YT}n-zTjIS3 z)TUIgq0LmAB-E@z9;%BK@v*zk%h4I7^aH5>@*qj@UTiz#Bh>l1v%D=XPEMsGewjI^ z>CZZ31x$07%&svy@k7H!*H6n2POY&_JKu2_s}l|2?-Phzu( zUYg6|X%6lO_66XQ@<4Ysw0O9>e~dFXX2x%AFLW)CpDS>9Csw&VDf~7nVPHHA%BkyK zc?*BG{9YpP{t(UZc|?3=etd{2+=5#L-(}a`TlAYHb6E0)&(YdMM+Em&VMhiG_^S^U zOm9tTel!bFTZ@}4Om?+3F>`5|3>%Cy!3AGoEXEhsw#v8!SiXn5n8hKB;o&{47AL2N z){ilbUTw?NMEqgc>D2=Ki}?f)U$OB+tY9rl2cm1vgB+pEGzR#24@jZoxnq%gE*e+Y zUmeu!EcPTT?E#Yxs_TLJjegG(^~jDupfGN}9mH2^Fuj91Ez-D}KW&C%wB*6s^a@^u z>d*14LK8VE;*J&5W2~6*x}JbRq%H1=2QEX4>Gt)%w-AM~g% zBZ*vU>pS}=S(0F5j7HPbm-mkgM<7@y5txDTn{FZPEJ>V$lvmPmXae+v=d+18XFSOb z&LHF>SFbNTLnyM(W-~j`Xt!>K>udq&xSApz{cP2`4NoR4-uw3c_i-NU@R4?#a*=tH z_xm0c-Bn&so+?*qbaLm!Iv&8>Ut_BZ`Qs-?nMl269tNlggx}Yb$;fD#QFN*n{N4%6 zpcp?BUhODBnv|3TQnK6Gyj2DJy~ya%QBMH?)M~GcoM*yQ4ik@;aDKKgB{WA&-}Q!~ zRnKXU&>qZTdQBRp6BSnxl36q50NsIyUUyGj60H&nAiG`F--wBLm3nArA?A%?FY1%f zcV9&-h=E1Fy*g9F?TCck9u|vYp9g6u0hFcK}TWz!I zq@Ee5c#ip4@%R-LiI=FA-c~cgTxyr=rsjA%KOT#U-{t!E;X*0hkBqG|q2T3uTf+HQ zx4Pm3VZKpWSO`-_bp8_3~HNS2ndcFU27UFt9v>v9=K(zmebzBM+Q< zE3J?&?77v(3TKZ95W*mKp>c+sDT@_!?fbT$!2V~edfQNELtZA*aIXBtM^ zEi6T6tFl`(-U`o)3Yv7ZF2Nh5AY&tb->1T?80X8dPh-EkdGR72uPuo>69}X8%+(;T43$w#R~bOlEE=CN z{YI)04=kBcXL$9dQ$^R?6NUAz9f=M#EOkC8w%zi5cfP!uJN>yNNXe$lt^T#cVm6+8 z2+Iz43YqllE03m`fRdcD z2LjoAsO(|1#7#(HdTED!`*o^P^q$m3lfAA{?n&Zb01CS@(Dbz5%HFCs4s z{1(WaW$D3pkGWe)F4k6PC7sQjc~#P>Ni+i<*8x&I@pcnGb?JA@`}F`K@N3}l^Vj;xyK#VtUPnJp6FIHWjFob$-Pg?-lvu_ z+WJzyljKgNu9KzH@gplbrFrJvpU_eCcHFhkAcU0X!oX@tR`#3ggFHSFfs7l*2QdViJMdGqf_+8o6T> z?RXC_7bP5s^BbwU6~lW@DpKE>FKZRN%kN|%d_)^I~sdyX}}<%F9!jjl#l)2ZZ*@u zd;$*0W<`He%BCmH>%f$M(D+Qf^fQn7UqjliW|l4{eP(ZeZiK)6=@0fAUpC5y$FG<5 zhYmRXOUOK?zxIT$PnRUsgCCBXzQFmz>OH)qq8`>Uxj1@!(mWGD#!z|oJNZPNu607b zQ?$-C0A-Z?Pq|&#qiRDEpt=X+$=>CqKI_HZX~i_I+!K&oD`yIfG_JZuHyC8lsQCgC zb1;>bawDG#HHosML_4dk73GgmupUfBQaRpaxxq0ik_G7iMbR;H385x>NA?l9PNEt~ z2;2(Wnd%}qB|+$#98q++6b+&?thpef`gklN8=)9DOK6KUG7_&GcKmo;Nb5Sva#lln zlrya_k#UgdF{xVGuE#clJZZcPQM8NR?H0Q#vezEB(&a+xGn2=$f~&VOVn9cDN);1< zfL7u79J1W1zi*}OwoOTv?M2JS%RG8|d2N^Xhpf34r5Y~aLbvto+?KlSc3CvNC081+ zrF8Q?Ol%Q!RC^z7*BCl)*t=``K;VX<`pGp%i|2x)T-B?L1bcHLoW!#i&q=arw2uF+ z5CU)Ex@;SaV3j)kCdKYxH?!!(YMH`ygUR+hiUaQ=1&Gt!nUb4rfh@kZyk zuk(5DUY^xfLf*rKW?0^quGI(u$0Yj6bio#rX(Ah>Y7WGZ zm^fmAB(x;JQeAn62>{-#^Kowxtk@_wfpp0XQ{r+lG7Z~ksGFiE1G z$W1`Z(Zl9?@BGYuC3vTxnxkC+c{EJ~_Sk;m_RRP7p8KXr9zb*8A*8@r29s@h%{@_} zXCt-c{vxna@3Y*D)41*qsg=Dh7t1xFNll~!OU}zcLY88%s=!n}wD(AxXG{rQTFRuOh1thUMOk)y6&w2~lGH(}qL>o+} z(nX<(*g~`>y;7O&jjHPOg#@@TP2MtWv^8uRDWwr+jMvkSg=9jcR|u5mnHHlr9>67; zDTmXb^)oR;t}$xaP`Nj$FH2AlWef($8F~!_B5hU*Y{?nHZN*(8YkKoOFaYO`0;l7c z``Q{pdA}ZRu^ckc^AIrP70KU5#O)l`m$e$E^g@rWZ;cEi8%8=ENejHn!t1Z!FP?aw zsEMH?jYOcqQQmXVu!jM$i@aLvfTq-;)MJaQUQ*ic4@@4iR0Z~Wl3KLd9h z+$kWr;dj5jugq?;L$=UkfbPm}GI@>0)O#c<%Y6FJo9w*|E9`*H_dDoe>+7$R;CtN& zJ8iFcx6ErSvp>Q%VedUq+;UxF?p3_dJmz4xRG&f1k>BuSx^Ii(VcOi59o)QMnM^@D zsHs=tf0P+j6WSAe!BCH3iu{$7oYGIYa~(DH$>w6rbP=*+MP~ZmI^#&+g3+C5{-fc? zHzzb9b1D6wc@W*tBBrBtHXn+i>GLZU+j!XH1`Fd*L49&INj7LsQ-M$Q$rUBZL;Q)3 zhWv)R1skrHSUG&p<-;c!1`mJ?a1zwdLFD@6_ITt4WqVAtQ z&Vq-PnB=*w{4tq_WI$G*EE-F;=RIghwWtN89flH%H+pDtEKGYSv%Iy3(J8hbxWrb2 z7_>WC`f6Mi%Nt%EczRICLb9mFnWXATSkOL1#RQd2b2nPH`kf6U(l%BW71tJ&j#k*CD(YdycvV=3{G3lh7#HhtAwXkq|Xay%<|SXlT}r7 z`*`1K*zp<-(F4VgVw-y3EvT<`B0unE4NH!ir{$Iqx5zra>ps$SRe=Sy()&rth->T^ zYGSBkWw16GxUH+IrHBWMRzQfaU)`^eP|Kl7R66l3P%lNu5001BWNklxFmzBz2c6O!3mSzT`31r_pA1URj^N>fCiSGD=HR zq%w42thLOG1P+!@u_0+0`U=JJDE=g4fQ7Saqo~?d)dh<)=HgIw#r9bTk`4idorccs zIgDSi`mG_zodK65bce;s{ja}_7df84f8<>{+rd;_%r*-vf>0B0E9|o84W2CHO$M5} z?PFXLeltp?bF~z?`w{*OhAMc=0z zzEh<3Smr%xaYrEEp`xtTuKMhEx>U}euvF=jvg`NmGgRK`HM;019DnBWlwhv;6^)udKw(0S_EW|ornEZ(S^&qoNqNkaBXF`{xS1G&G)>EmMqsQc z*AE^~dW!*w95fQ2pSReHtfl-v48P@6Vcrq8g^vgHQy1-a#fBUh`I|w!#Go5qWh$FE zP`=!xu5zN0ZD@E6lVnm_D0ArEC^U%$?xakG32_wCa%0Yofn{$s7(rO4R3UWug~AMt zHvleTCePoPx|pNo&Cxq%YPRS5P|satWmZ6Hm=9x?6=ypEwd?XrMQlC2Jf7>}MJY5p z=p+0;N)O7zSOg(0(a4TUpD8gw~&Tz-=iqXq<6$(o^mL;i85`v~G(Gtg_2oFMGaja+8iX&1q z7OZDSDQWKA{b4Skl*a-~jZPtK$0XVX9(oorlI2rIAy#$ZxuTAQ zXtHt45ZR&Y&r=aC4n~P_3v2n1 zZ}X5tsj)uy?ao)THu7^#lOJv%b*5?!&}3Vg&;#0Qx}A4(dLO{`LEn@u14}5>c&UZi z5oL=pOWHLz>uqtufVj}IWIHf2lNicd;-;h_a;(NQ(e=@Ay@fV`psG+R-WyT(Ssm3Z z08%-&5p5$cPT%8KYqpUML=mqr6n_dI_VfQP^#0%$UE>GCxW_@@P(<+3h0M}tU=|03 zIaE*XjkoMU%aGa_K*yN6m)T|;HOE)ovnpWE4P<=)OX#?V;VCM<_||Taqcmcz2Fiqw zw9(*c@qBKtO&{}!UhW>UAK_VQnUmo7CfIF$NQ|yo2eCQ`k?~mDP6I5*m_mO+-pvuT z`|r-tfnoLS0=%)MH^gAzTY-oAVWeK}zC!XvLvw&R7@8;{7pnOVYk%6W^H{fCsPdWn7| zD*qdi`AH4EUopRqns@Y$^se%H-DDS89^Om!kpCjh+94|TXNnv)pHw2`IaJhjlbics zPkBj<3Gm{q;jmDZ!$u;c&z^iRH#I5GrqtM9-eA@qvX4xMXvHFjHH221H{75+!(+q zA~^2%I||=@R-Dn=R3nT*P2gJB)^e)Q-end{N~>68Fsuc(TpqAOxzwP?y+E49qQtPn zq_Fz|fe;G-n=}+j>V(8xw7vMNB%Mo@f3_Zt?kck;3tdc3@8#RVNQnBEilQsuQq71^ z1cb?)>p7%pBEgprS!DOJLb~yoypq@wOve`;B%A}}>9zwYM77epw7!4pvNGa~Lw-5b zEMMxmu~RJ~gM%UxuD5~jr&L;IWR)hIQ;q)#JBj)dAcMX{ene6bq;7gm4|7{McMjV)D{9*i-Dgh&&Mg@<&J z-k@hv8TPDrt^aLJc3^|u)r{mK+jNx961i0Bp4Yc+xEdseADxIU+mKpouzE)=8}<=T z%1#?EYa&EOLUS`f#uz5((2_^*xXl1wK%u|ifJJVQz94x(0onpB@1g`w*a4 zqtT(9|BE&Gd4&BBL+oKoe2hbUna&5#%JR_D5xSX9pQ9ETO;pm0d~5?!mUz&ntV@R| zVBI)I9^p`$y+y!3vYrW$pM(~GJZLk9-wM!8Vd@&v=8@aI_ zFK&$-xa|HP&uqsqxZU&QoCu&W7VgIJ47VAQj!d$ZugB9qEe%SliE=8O5|&HaE;`+6 z8uNU-iOit`gFAQ@0&CMd`Rx)zq=J`;0Mr8Xa?3mCP*t#?qsH97xljq#_suv>eLpm@ zH_k&`j6iP;&8W!2WUQpOG+Y!L3w0IcVt4tS(m{#|sa%Oxye}0lF?JE|MLi4)KyT3H z&kwi1Y+{uloN^S>@gRtF(Y9i`dXbfoFdFydNA+Wr^6hWC-v-{`TwE>nij}jnbd{%6 z#xJR}i^B@L(cW75f8;G92&>b$Td}?(Ge?l0a8e*Y#6QgQmEpK^1y_YT z|6rcX*|97|e1u+S+Xw4v+yb1mAl6j74bHQL*Pf9}p|y6|fBrBKvOQ}ltRDN!(8Kk| z9NT&(smo-&>hCY52={VBog*}g$1_@^$9`h3JUYm#r|WAZ)MT^;s?^QL?r;bV^!ogx zq=%LUR6o+_yT6wQ#c&udH1bPQyfvEdTh~`8)gFVfD}ZmG&iObec7r{2&ddWcgWn`?@?X5(oH&^o8BU1VW9Fp7t>?Q=Kk4O$DCsd#8F4=jj z@am%bK2G6g^ra0S$?M1OMZT8f#yQl?W-3YI8lQ_7CUyXab9wWZ2k?V;-H0$W+pj|S z<8974m7QiF?L1UoEF%wit+F6H1LpXA$XJwFi7|ABPh@~N4hM)@O zUQ|rZq!*;tuC4BzhQ~!=S!yEDS`XA8$MumV(OMfic!Ln~AVM5+8G3b`ER{n>Kt$$n zc*f=z*$u<)T4{()W>&9eMF=ivfN0Xt`2UQZVO!fc5QJr0vZch>384oM|Nn=cc4k&` zLPFaQyno0eiGK)6`}P|B#rP<*+VZE zrMVaJr6%|4Xsi@HK$p57h67t3Eo4I^gcY}b-7$!)ICGy2(pGU2qSBIuJJwX!>Ya)d z3SkLtiXTT|r6~wL(U?0=YN18qVgdte^CU!NQ(G6R$gD)#rWVnGy%ok7_x;bu`{g9h zFuzUWtz8)o+mn>iGDmaWdqGm6I%Rg_^)GE`j6Sx0t+&hNI_;in88p-G0JjIklYN?&I5o#DYm z(ICLQD^PSD+^d2MsTN?f8P!&Iy+J!vtFDcCY4FJw$*}E~y};4#urYZzE!q6LwJP4$ zp?1W`EE*We0C;p#V5dp4_H}@Ai-AX|bi2v2>aUgP=+xf&q)R@XGY7X8n_w-eZJ=+r zR9XecbaS=JzKFUB3lReCA>6@~+P>A#uOxvJ*jpvB4CmyLPsXB7jjaKR`-&+$G-M=7 zC2Lz{+=U@(K@J5gr-etP#vEskf^k2xYYBB^u_J;sUk-FuGBI4jg&$*-hl9%$aH#)m z$YgXj*KyVcC}(q&%o*}0 zGAO}Yn&&GseM@6VHu%HXGxn?qTx@LH_ml|OrKPu{ES>M6pkz-7a+U8a(-6~US%I4> zdFrF|+2`pT9ZyU%@``%$aWl12ee#Sfh0|eujqlfUhodiE>GPS?x4yx8JWX!gojvoI z&jIu>pgrH@HDWvO0&hgZ`ErLQ$Lq5j;cn_-1fAvJGgH zp3XQ9jw+5E6Ae(jC5CQy3b{KKTS7=^V6CM)L$hb&a7u0;yasD~ZN*#b@9k!GUYkYR zM%LIG+h7~uwAsfL2ap1mzDCEYznMa+{+;cS5yp^Yy5+{W?B6$Q7g6Lk4ua2APX~q* z+1wXaT*O8&+&4=~m6$_s)teZ}p@8jNB#5%=f+}ra^(O5Y^vJ<;n>ceaqbz7vyAh=b z(xRxi{w}50)&{zZ@RWn6Mt|jN_eUtkBdLHYUT0)f3UzCl4<} zY?o+mmkURUDUlo0+EusCt4>B|_2X^0ZB)|W#yyv&OTgGKs$+Dq73l_kuccU)vvAwi z3g6r=-_r2O4HX=@5=3TSDGke|QftFyI!l9ZxzVrFp@Pi4k#};_kHxH9L2v)(*bT<9 zIgT60noV_axj8-;16&5y7te<904F*N?JO|6Masrq+;VGaEY+90blOeD#nA^C7>cAe zu@Sm&$friH)9%EA`0B!NV|#j&^`3^pIJsL(pQ{dh;&A%Z99;1YdMjr7>gYi6)(M<1 zQ%;+aiBE6lO#SWTCMQD21Uu2|N968_24^y*$r-bYk6BPf9+1T^JWZVKZ5iga9*DDy zyZkW{GG*2^*LU^~*TjuCA7gt>PB_Q=q7s@lUhLb&qrI0G;eO%A`qnY@55W$<(jLRJ zLj1G5J}=qJ6Q%Df#PrjEqu=DsO%VP#p-%aD9FP_E_o4YyM{(Y_CmZ1KJPi>VDtbBY zfEqt^)-CoxaZAVdtsSQh{|Y3Z_y5rKdYl&fSt~_(NfvjQOJA^P=jT4Pa+gor+0<&*Zkma%I@OPdN0Cc%o9?z@`1cnN0RT@bvGL#+&$bSJ?i&53FaZN_Hw z^V?`1unN`Zv_L?;SxL6nr#_Wi(mbiQ^V|rVmWzhu^ExP8!Cvte&QZUEFS`LiSOux{ z8AUxcT06Pl4Qf?SD6mpy#Fq>Yo&LNrD5?;~v zmuqr&B5==c7i%sDk3m9AV!e&o=2RLo(i>Ac!1FW$4`@>jgJK7*rgNr{1&B%A%cw=j zMI=dbiwa|5prx{9@PUI$rBwpR84GZe?U&rLKU}9jM;A1ys3y7{^1@jn%VpWm8pJD9 z-5J3tS?MZn)+=+{_7Iol`x!eIjHAP$^+`?Q*noyC>ro5j*g``?%S%L_(%giT=)evp zLmr1m%vRq{(bGQ@^MQn&@>Wy@3}fUsEQp!qhe@x8+e7yoTlB=tlB%v=L@q8{FDQI( zs8;g{T4eZ_Y~K|}w;8#(`9d{x{ba6w?JHg0rr1LiMYsnv?ET|?q&sYmM+_;;+4y$( zfMKaVC$cu}-vKbo^j~0W&EcquV-a*zuR^1AKP#SqwL~7nboQF%n~Lp3Xg>saVHu5B zntP5{Dh+n=D92gcls5P4L}p_BaFNpXm_yW9v7UU>lv6rhx8hxn0fG-4V_xs!r}ZYh zh!Dmdd^one;VJtfys#s^_;@c{SKpq!IuE?6+N2HXBzY{rspRmyN`{x`10Ov9BFye+ z=jBz{V|eBR3lC{ku6m+(!`}!Al)a+p@%|PnYwL#kI|Z8BUL3Cl*MR$n(@oei5|9Ljx1{j~y2CZ$zUJL1)k?5q9ndNVE7ZoCc) zv$sFhU+bu!ui{CV6X`24O(^d-SaertzaU@Rc&v`LuwB7}V79?^@Ts%*vjws;HtOfI z(2<&bV;XMW3C2A@sTsN!3kc98fpao;6=N1D5*`u?kKwK0S*gDbKoz(oIYMG;`#;-+ zG~FtUQ7BNdBIlm#TWj)ll+sAauu;Rp#z^q%E>5FLOm;-EDiH6@^%|r%N&;Ht6LJ1l zFi-a4*&fIAo~eiI_M9;2exydGC1{qG8TH0=OD;RBclXcF(lkVf8klJ6(J??qsc94^ zaaIxm{km+nxTRunag<&f`Xq%sOu{;Iy*ldaFQGL4#&pumTFY@Sr_8r^@FUG*ELPg} zo;VE<^Fnki1T48fYMdGtbC!#nbz;##UK!=3d8jOMsg16!pwp|wlg0ZxPZs2!NUBW7 zu2o}5!tKy7Im^neWTE#06stALCi~rSbkCL=*vxs0&z4<>#i|SchsdjUbpC>JtzZQ^ z#HlMOL*z`dk#2H6rX%p|E8u#!nI6W&_NDF&w4zA&mbc8!70{1<%VX;AU8{Rf!V0nE z#~%6j@W7`UsPHfa|A#5{y%KucUbNDG*#*B6Oh1)r{rt;2j)uL>;fGB6zS$4=EB8)% zZb5KP((#(kJoT`I@S7YBSqax`Idaq5n}*GtE3cNvsKHw4BrCO#+v?c!5trrYpejI7 zegVpqw%u&NEVZ?zy}@o|x7>B#%-XuyKeL(`iVIH55#9|7Y3tts!s)!he6($6>l_o) z`)Kw-ZVrJIHhJFmhD)v`k=`Duq4p5kiGpoQjSjl@&d8X+g)rw;DF0QEPV(Z1znB9YRcvPTuyO1Q6i3E>d0 zCIeG+J)23k4B;6~Ru)rd+Jr2X;e1AxFiFw8M74uGa~7K79Gk9Qj<4*|AWRj8t*c-@ zh`Tv2G;E@Mr^}jz+pwa2K>;ojtwwjB)?fQqVqq{>s7O%)@*9M1JoHt%8|$+6MKUuQ z$eC!=D|htSXH4C6#E(oT7Z{&QgUI7bj-j`*N1mo-QRf5slnjQ#YT0|Bus~&mZ*aDbE%z9?ft?-pl>-B+eCeB;IRAgf&UU$R zTnD10L`kHr$nok{#pU;Z&`Y2jASFA_?Cy`*jKA#|Y@l&E^Hi2*m&$7Ev#m3GBXe;a z3dhB=s?_>>mXO5n$wZ$*E@sdQU8}jR1h?6%Z3VsqHlGr0^_x8orITy9gFuAvsXQ*> zHz(7neYyN$GG=q^G{k+eZvDMk#OYTvMje-iT71wSsE~i(V(QSC;pn^yzZ=Cn_+%ee zxE$ZiL+-9K50i}%J1u;2il6T3?hTJt#Le56JI0E+1j}KO9E+Tn5x;EyUNk)aau4cv z)+z53T2{xQ0f;8BR%O;J9qL_Il4LbWVg-eWAw=cpLnDs#6Qw5KxM^OJ=rw^NLpCN@YOS!Ut+}2Zu2&lm*Z2#lvY3&Ra`%$ev>2liJpd;^g=a zbh_@dFdB$Exdd2=znYSB9_D6p5?eUs_`LqC-1i-sM6AP1BS(xQVNn`Xh^NL@s$r_M z{=*iWio1WYlVbtHjFxa_GKb+dhc4!tgF=>d--|~nX>p%NnyksWR6Mg`nc40gl}v>n z7foUqktRjgxm5KbDUE6Xz9(ZQ+lhT7-G_vjU<&EL*kaVg1ecj7AoBt3NQ4g92K!?H=Ky(zhtH!&+Px<#2*FPX~vrgK@&^Y|?3@ z$MnH=VT6~wE4v}QE6e?i_usYY$IFCY*O)%t{~1)}Bk{uuQcnZ>y~GBd>GJ_%c|Os+ zw9}{lJuq{O->sX9-{nA+@Fr_%IiOVzyV@CA)W#ZQ#c!{(&8)?L9sO|UBie93iTP%N%eVud!P z&`Y|0A2*s8H49OVReE^^b7(8O7VE%FzWOX+oKS>^nb$;>Qt|o;Z-2y+EsT#%W#6S2 z4#+A{kLyO6zN_?oP)TB98*VH5Q`jO-=w>Nen#Dc`_bg<#uIeMX#fd(443O(NVzc&F zfx$t9x*TVQsAQ;(h7j}M5zaxdEf%qS0WC1!sU(RlZs=RcbNy6gi`&t_q*X$o66U`; z{uLKmF;g<`6_swjLoR3ISg5vUM;<2E+d44@PNE(WudKK%btLzJ!gK1r79jv9lK16| z5=`|>PR!C^q!BWByjV7@JEk2EX|Yj_jLOK4HUQ{ao_lx=~&3@_uo>n9@s`$SUufGW?+L-Xtn~G9h`FJH`B_1AHtF zA%Adi{T)lxhYEc5E%!NrzJ{?l7UNHC%ja6|_c@ibivOkA{ho{Yq1E1L%VFM3iLth=~Z%LaPS`ELlf-wq$|0wA0rT)(F_=q-7UFZeS=g2}2NRO23NP zxCX@)t9dzj=?p8WV1#tzT&_R3XEqSzo50D`+7yZ57+O51?VgnOq2(-)<i)$9Q|yHkBAn3*WWsY=~*XxwLBxv}E!*G^y0O>+|KtDjJqmZ4V=9mGfY+ zO4v;1jgK?sIXA5>lpFJ*-BR9}i7-n6Ad@AnEH zcXa<&*01@6)-rb``-kZoQux&y_Hhgxek;?#z0Ka`XoCA#Tw62)GglGq>kQ1y`Rg3| zvx)Ia-OgNE1xM{DT|@hTIx{Scfs?R;BLAA(0dB!*OT~gFj2xIn0gKeC1vsi;S|0l( z_ziqcw_1or@5)}%F4|V3kw}|Vw{Vu2;K#mcv8+n*xv#Y_Ynp9VKXLrg`n#(Sc~O5< zk@_b{ts-l!>qC+X#e%$Q9p3kK(VN!fNfCQd@yQbdjZg;#NufJ11+HT8W<|WVao=de z&4G>Q>pC$xF-lS}B0JIfkZs{f`^-8u)!g}vhOd_7`pgXPq|X;qWkRy{$AmN`i)vbL zqW`nIx~LCj4ve=p%M^Vw+Oa}BaQqD@w$sngs$sf(gX`;kr74Vbu!)~52VrG8SQh(? zWK5AYmRGlfvq)8X&GN)Cnqc@klawIvo0*i9HKR$^@1V;?{%&evtVY{O_gD`9Bx_e6 zPM(5=w&geF$zZ$G*+yb^#rBHU_Lc*SgnKSBnbF9g=kC-hBxBI$WCD(+t(h3bf`i23 z9O~4mxaYksRB1xE4Z+0ND{MLEt%MJK>Zs)qtvD2FHDRt4IgRK_jw#lw+>*3 zn3Fwm?rkcY1Z;Y?0sET!EDOP(SUbEgy|ZUG@r^1WxabHRl4pYe;@uz&Iw$YbTa)>0 zP!?bKYt6fu?p#ywM5Q{gt$hBSzB+Gc;B^XJ98XmH<^wgW3)`{=8 z0;O+4*pgfZQH3(XwH098$3rs_Fuhc<8aeaK!J_WfXAS0sUgjYTVZlyrRaq|#62!Vr zEvHOkz(kfH3GobHA3tDV)(X9?w!sWGA``V3?5nOO>l5?1v_GIR-NT5Z)U+}6SA&zV zqg3xoZ!6Zb#$%NgxTw09kxTSJ%OG2N<8(?bxR1jxm!t@*0lU}=Z)SvV*dpceq?QwL zbQkq>D^XIefHpZ+iD|7asSB=lIC+`}Uwy>}Z)OiY+y0St?+Stt)sLE$$%~zj#d^ra zsn5K1*sOB@?TNw@`SmO(hE@Y}>oCH`J+soqs9JVl0ul5r6C?No!Z0vqm+6( z>K)F8i5}U<<#H`rxic48hcC?=@I_x8w+^Ex7GqFtgG&Xio1=;$5A;jTbTUgF&8DPT zBa$_n^~ujn04DweKTYi47B%{UWr2|4%f)WFU1R9tCrh$3iRDo^INNrTih;+Hk+ z=Kv3d-D!5C&Gx2~;6#oH1`YIhYgXfzW>9^9jr9>Lc5*6dZvAm@F)Vz~6QYllV=`FR zq8X`^Eso2JtPiM|H87>dRmG-xw_-#E)7TCG%J_#q&_HnrG4jS)=uFVbk+)|p)M(M+ zr9J#w*+O{Vm_Ezl_pYUIT%b8GDjz*f;Z1|qBM$z)>*IxT_$wRf__sMJ#Qg=I8P1QW zZAfMAnt2FlC`ZI}H{%W5w|{e9cxl*UFOdYprNti}uaXfClMnA$$=PBA(TF^~3s6h9 z+?(m`JG@~J>3ir{Sxck|OSo1ym3ESgu<9CJVz2K9sQt~DsF2p97uFi_)GMrTO@Sm_hZ)hQ9fo@?X zhABkZ5)P!J%!w*85@pwDvW;q=oGSHFyjl>J+b$q#KqU#Kqt@JlQ>69QR%SxAodqmK23kod#*48CX3hN{Gsvb70Cci5tLmK^UcuKZpGBEGH;J!ynM_1&>zEA*)y&(ntA!vAx22Fh*gIuNB~k|Hfxit9U*O#lBwAF&I7lv1ai*O@y_b5kdlU4a00 z&#FktnpN*A)g-GMS0Ao&)oSx&H|~O40b`YEg?vhDTWQC7Saxu*a9ibZSof`Ep8M)- zRqm$h;yaliwa5LkJ#F7OKMkJDT8;HkB>Be* z^UYwM@>2~_#u|&E1}vTZv%|M>vAys%en$ITI!R?_r;P)e!q0dk&bg0`^Z*zJ+wP?a z^HEN;tVuAQJ zddFA(sf8Y#MDNfZKRwKkZsoK5taLbYc&l4`&mPgCQB?H{_jB4v`F6p}ng9J$yG=o= z5o#?Zrj+mvTN0$?xq$Q_D{Di0%jY4kpU!n5h&3s#jCK&ukvNoIr9gQFbjJ?6 zl5CbmSB=!aMay20u{2xa2|L;yRcWPP3bjd|aFSi|{vxzPl7Rr_D$)H-hqT#HGr1WT zu;}X2@sbeHSCiLTqBQ!bADy3QeMO%!2_($UMd*mt-LDJcTFNlkVF9<^m~q3L#U^c` zgHkR##k-iqF4zLu$S(y`etb=oJV(BteIq%cR2hLORA(AR7jSeWbPu9 zI%k(th3ff;#f4GKeu#PW7~OQgiS27P9z-=UZ>Mer&)+t%G4K5<#ZvE)ck~t^te~o# zd;jHXD{7$JwKUby+kx*t&@SRr6BSK0m32+rOP2Pg`kC3jdVqHIVW~2r6#QWU&eTvt zzSW1`^8n%GUihKGfcG0y8lsNjnKk?%J2PrLF&5LET^6**&R)H{uv;&P?}=^VtvxMi zSVldm=I_Oyo;kXb)NNFF6EiN@CY}112PA_=73y2PTx~vKw5#ytkWA{@LkmvjKAa7o z%h?m-cii_*pKpSr9&US*Fu$+AgB-bx!?A5w2+mc*UH@F{-((w)k%NB-ZW`hz{<7Z< zr^Yu7Z}nKirDy*x%^Go@mn$5)j{c^&@MLpr`*_EILuuUezW3G?)79WWw#500T*_t{GB zaY&j_D{k$}F-;Z0^Gn$fSiQ=o(^seLQKgo?R_V%+IUHoUi$S+6Q}MI!fPJ8%PLgQE zbHx|jKEg|vFKHDgsfdw%Ae2(_O_Cc45cAi1wFy$G*0~l$9VHYjSWAm&FE|3Hmk1s0 zv`tYJ#(2~cLB7(#!!wrTfoBe&kxBZxB|o*Y;>BsL0**J#1DyCA*kB^&rYnVX5 z3U2WU4|;1klxJmBHiZ%RqP)sl;^$i@CL@l(t6fxEMx`6dP$97$5*~B3QG7OHGzu`! z4|nRbAki95{Mw=S!E({SM64g|AmsNB5LBOv1y@oP>{-^pYSq4j9q&C zddw~;$CD5vUNI(_0Z7C&Rjv4{0*lsQDcu88AJ4;%Y)_fy*db!6S;b-U&+rK{7^|$; zL?ePunv@~$ff7p3193@~r8x7d=bVd=ia{YwSHI}}zeiU?gd`)>>vWYa0d_IvTLy?HK^?oZu)*gHKRKDj1hc|lW5UxC{py@Hmw~(cisY8wR+w}H4KJ6Od@|VVR z;B20pMc;{(b#v^*K}V7e=L7=%8<6qC;no)Io;7ET#eu&u9z0CkD+>Hv^U|Fe^NfqPf37 zIqzSu2_Q<0qFY1EmahQWcw7t@t*{@w(RFgum z~NdtEY@G*R_h^$&gzp*EqCxY2DsTjv1q)e`vPo<8{^QD>P~#|R?xd7`#5yehNz%miD?b) zeKrm>m$mk&lv+KXItI4Ro99`TaG({%JA;ucz9WwAi;5hhb*!Ufr8|tnpNCzA$lH?2 zvnK-;2VNmYy(UalRAx{Kf~Pm@#{nF zV3`hYmfV|Jldv>~<~f;;D{9Q|Nx-U7WgHCwkyA0D49_9B$2;_S8<=V;d(}5&9i+}= zM{`!r%H9e2A#0mGwz5Lg%F&ZryTT(m(YcuVJwI+2B2zitu)Xy}{8@NQk^~1cTp7(5 z>GMzAjXzT-d(3PIe~~C(c$Dv`j?4e`E4)KpesdvrD^Kyo*{ER~PCF+r?EvejeuxNf zevs4t^+%wIfEY%3{5YS`aht5){4ijXESWfKTErOPFj(W_5UoTMgt>_Ew^o!2#{bF` z8X>^@i{(_}gW4yg_`Y`dlwjbIKOx!PP>kvI`z4wml;9M_$NSl;mpF7=bA3oFi)SLG zTiQ6W`5fqHCv0Rk(H4W%PuMCJnJK5?i<(;LWbplL(qw_ckJg#K0pb|r%|VL(qn+(?}8~Q%<_a$JLc}Xlo#t` zDH=uQM595~U|LgO(N6%JF}aN~7~>g@tk&hi zZZ8iTZbmogFxnCrv>KPe(45!Lwf5?4>ghO`qCk(HecId3OY^qos7Z%|-OyFFCg1i^ zYcR%Vwvn_!xfGgRO%m=r#;CJ=i)X5SG~f$REdW)M>^15s>s4g*5swK>Z;Cch;DmfO zFo#4jNEFiC^O|T{R$sJM<=E3vJKZW)SC@L%iruRG_MD$IUAeyt#^MqA>qZbJ4TeGU zXGj)xt~1yx=&Gb|cicfwZcQ=#WH;bI3GJ1)oE@lTzCCMMQ|RkLX%;R=(Q$x!%_s;z ziLgyt>y~ z!u6t}OZw&q_L$%vm^D1zs-X+6uBIstdYruj_%*HF$o>5_ws%@RB`UW2z=43C-=9hB zyZoYkLy?mTBkixaYFiuEK7I){>V=%XVHP4)`%5zmB=r83_H}Rl-RCsDUf^?RI(_?y zz-EDPe33eZZxoVR^b(fJGG5)Bkt!qVnpUNii}&_xw=2MKS!=ZL;_QEP;!@ zOR!TGr!e1TWszWGzO2|4Ooi>ENucd`TMLz1ZYL_bt_A2?kzsW)9hgkr)=h20+;o$K zU8YEH76Kch2~TK{mO*@1fUd2hMIM4H-2$2*u zpG^h_R9Rw~Zw{)8g*ZLGVKff_Wz1%*eac9ERx7ZcH!Qd~6A(@LT&T{ps6J=#tuGER zvtHj}gOEk>E#ID)tgJR9oKnnnY)`r%6ygCh@GZLMIqUj>pJ{dU2KIJuE22|R{I@=b zVN_Arj#xWNlZy17!^1>IAMi=9O^inSKTikm@`{S^Lz~~er}431vgwc}fG-Av9&Vn0 zz;NKjE66*MJK1uwy##xxadrEKS#cF4y{)e`*YJ;Sq__1i{G(JW{OBM~>S{bkNR$x% zcqDjpn)qgX9t*i1+sCPQt-UcGSNNw1#0kIk4K#T|Z&&U{ zA(nEwOD8ozU1MKr^p#7wB1nVL5LC9B!+~W^HMz=56kBJ$;XqIIu$;`;8thG$@?Amk|9|LN>Xv340?Y1g)q7j85R#Bs zBdPoADOLlh`k}3>lg(psg7KqF#9CuQ;BRs0w$(F^)7?-f_WEYB-P~tX*W0vKNtP&Z z8`>d1tpeTEwjF_*c8mTRaR?SJbm-pwd+X{iU(Zxz^DZ9N5Q@MUs${F1sWp;067JHX zd5BhGUDD~hzD>N;iw~k<_R-?DloT%oQA2vGh^aZi3eHYqNFV4&T*z{a>VL0}G)wDJ zEPP7~DQ#k)qJ+Xm1Ho;R6gk?dw$a226Vf%M!et23Dbb1YWYW+FUcCs;vDnQlh#rQA zrxn`ni(6r@rAf~DhTKv-s`)KYNWJlCkrR>_@B zHA6am4XbnHlDC2T64d-W0OtH-IQVNs0^>oPWHCV|4S^jLih3H+W`dFotH7a6(k7o^ z8U1H)H&`wu@Cy)%^ue?sXJ*)HE@MXwIkk$MR-p3K;UoG@S^Lu;mA~tjzvWa8-+Ht} zk80++*Czmw<&!AwN#Nk)y0=5RyO~(zQLN?fy|I~%*6{P89H4N!Sxr1bf0k%!8IOW+p zPA5kj8Eb#9u>EWm1#qh#(qPi#`+mdX(xJ>2h2XPcV|Yxac{T!;jY*GB9OseszVC1Q z1}zlaN090Agz6otx8M86hjS;7TYR6OX7a|{I%-pSZ7afyJkn^|?{E>h^>~NPX{z_t zC)K9&!cVf0+{xTeaR#O%%AQ|5d@7Qy#O4rfi4Y@JxtoS8*m_+HL$=lH{XVgOwX;Lm z+@_d16E6~j3p^v@g6v?HX^$3+J*?V@PDk*&1SSZl)1$}s{sRD)I-!%Wf~o7OR{v|^ zsQ|E3NhlTL%f~;SiC%HiXNZU&{4r|v%JcSy(?v;A0#v^Y1WuB#Fo2+~CW?k2s)c7J zNtNX_Lf=aZ_!4@rC$@y}Ta5KGJ;2iR?GGxl}^gx#FaZ5msQQw_O6eO2u zoI}PJPT$0n3Bu5Zz?||mL+ySj(y19BmLm;34LGa?9G85d#t{-H4G*m3bB#tj=qDuw zS%Z{z6xnt&AaYyuS-t>N)~CQmm7Y7=?Msh%4H?;o4}9W3jg{qTD#1T)Y3+ZL{;YKt zOj}{|`~ut272fh=c(r_vWB4rddZ@yw-s;IROExB$kJceZGFi`K4Gylws@>_gEUnW#)lvLUNGSMlH3QVGX6iEBKu5Q0n^r4ZJ5m_bd64xM z_M~mw+~p&t!Lp&MNuw=sVZSTDjYm(r+ASN&_~ujNqa3ZqzOtLy?*Jf9R-0Fg`*Xg> z0`xQ+!W)E4UdG*s?9%JX3`F<(1`rE>Ie>bCfwoT8Z7*JQ{n&tE0*bu9^F7B_P-qwT z=*DsC{uUyPHy$PA1P3>n^ZUm>A=YA=iOvucYJ(S9AiH*`qb-o?eIxGDiuI-uf9R`c zL0~7t(fm{Ew7-vlXXTMR4(cwavtG1|1py>jbl*3!xKgbROA^4*a8g$!JP9)*=wvFc zs@}2N=FEh6R9rGK?L>}6v8l2q*@#UW2ErWTvg3`kK+c_PcdKojGu zayZ{4m|BI&4YRj4d*Y2;_nOamo3L4IUPn!hEQ=} zPhD)I{U7bSwjA*B0q*fe96_cyZ1VChN6>S{5}m4nhrTe`gwM*dM1733+tRhD2zv4 zwzYOis&!lam>|Ot-L9QmeE@QtjNz|hh0Lr+H--XRDAL`mxdIQ6DVh!EJaN!_-?w|O z*t%_{91W<=p+D}+G8siy%2%N)rM4T-d2w z@zAE&8cz)b9*nW;Iyqa^fuZPwZ~NriU+ca@5$t92rV)^5t%k=3E?o9GV$TXNd|epn z9G|=2hM|}b{AryQge3)?in9Xme43;+bIIhcc7haW7Efu+^i2pywp*;W2>6L~x~SdQ zZ+gnTHWINS1+T>tTTWI6u2~T(K}1stAO>^d3suwsDQ3#g#fRQu73%bD^@H95ed~x6a>Oe_u=hWk2P05J$U@S3Ou!%fbF%MB``)H}5 z3KjLK2y>P+?0NOHPwf3{M+gjF)Dh@B_<>bE_p2ua#A&KZJ8C`Yik5F{&vDXtxD)^1 zpDaxxe=e<`Qz=Bgt-GHEXCM(&eO7^Gz<3Ow%4&FmZk*B zAD14DuWOF|b$v4<@cYN++zqE-hzX>&_xMMqtp z)Uy@dZ&vYc6Yj6=AaNfi;2p6ys;LnUJ^S$(x0ncUnXYE=txB*4l*Y7-IpV5VUv4=H zv2?bfa?JxKLyNNcwE?(i9=55kjS&8zBcozkYqqO7{?|zd?d3}Sn3BX4ULO@D=ouSo zNIbm)7t?^bbnV76yD}NsUO<#dOAxXuxL_KAzLD85NJ^R`8QtCFR0{)-_)fVGGLzzN#gN*WbYd*>@7_-1d02$b%Wel{@CJC&xI(%s-ZV8f?6 z2$MqP8?xdOny#GJUU~#Cy0%M3>9wo|?oVR7C3M{Y$e5Gk#*3c;k5eJeScHNHLvnP( z2V96Uw>XL>=J%JvXKT*zWxBBAp2kD~4-|(aWDx%Pl@v{s!ArEZUcL*Y1Cbb!lBYQ< z{=mGF44CwX@0#n&wL`awQw}LxpI*FP@^ylrJEzsyACe*tgGQ>Ejem($j$v)k`XIp( zQ>P*NGRy!Y_^KsS!^MY?VzpsD*=I2Q>MJd`=ABdIc?*2Mhh=~lehp!s_Tag*k}J?k zXFE?)vc8}cKQY$&YgadvIvtii&)z$WB32&Bq8-M~NcZ=nwB0o3nm3>JS_@T8{#%b``RK{) zD}95z+rRG{&X;hy_5%{-yM!aJ6GI4&Gocmo?S`|g50uv_9NZ>i@|CJ0Vd1#jA0H4w zMS?+{jE5Okc$6)VM4T#8hP)teYt3D&?UikWE~I)WKOD=LZ5t; zx~-m2Y>U>!pjAL5-43N)ec7mU_JAX+vJPQp^=nvcBW5ZjV_lgC0a**QM+A#|o|Ir8 z>}P$$Z~B7M4rA1QVipY*G}TOLw`6{_Z(BUy0j+qlTB}!FsCqR3!zPukTyPe`lhJHK zEryBlg=W?SG1>BS_OO5}x-8-x$zQ%=FN$4b++Yb96(-;%?Mi7^z)JOXZe2{xq$C9S zvS{N9oXcn~u(|$qU2eUtWIyx~A%xCZvcSil(upN3DdA`PzHzMt4+Z?Am06#OFDX%fTaUA$KctS1CVU z`I4`h%rXkcVz>VqTr&^_eZY_%Y9R-tP)sa5Y3b5;a((+JffofYrh9Mk9L+cR>@g&JWp5+q#i-hWt zV3DrnA55YDxv?G=r*%@5GYq;1Ib{9Rq1n|%PS1gS(~1wH-{6q!=RI$2^8J!sQkoeO zx<~2TvtLjUm0KIxTnnK4VfqaOGHVA0w8FOeD8SaxS_Ou}*y4di?{_l@?H{{=p3(7I z2!PX{-6A}xuXnw;iYBWyek1Y14^EvScbD z4#4i)RlmLpP5@dxE5nV1dAC-u2W^_$l->5hYpJx@u1J2cN;c(57>Rpbfqd>h_#>Y3ohArk2D3d$unx29l16P-G7G%F0|+8B0g zUa|Iq*H=W+?``T>!@D!0__#}H>}1e6GW43e*NB)e2!aA8@_O+cUPEoR;HLdlgk~*| zuW!D!wx2+U)9A?2gx8VOF+I$vzDc)J2jp$5g6lOPSbYhq z^l)V&sSqA)DHk=G&8DR$;R<7kD$U&>D&{-z`S+7rZ7-uU>n50TMVN_COKth3O<{A? zAs=}9CoQtvah5p@ZRHdckUlLNQ_pq?Fn{{4cqa1we(pL-e>{cOjdu)v(^qroKPhq}Gwj6| zk@r?jA2!f7Rt8#WTN?Yg8J-^ij+L#v*R$KhO5s$tkF79~NQ<8KzJ;jHB03M}TenyV^DxV`=X~lNE4nh&|YNKLA}oqQ5yjbYotS!=(FaSb=yX)Y5Dak*OOxxn&85 z6pNUW!Bk{wg2XL!n{feCV67mprAK@F#+%F|{hE?y{EvaD`s+?C;R*?e7By?P7E3AoLR`P!Z@QC$pP zyE7*}xt7Swq~BnG>OZe0(@sH_P$N@2CfMNFVtBcJn(7z{g?45W2ST?If~Ori+j;D* zO%<9jpDb{LKaIF&%YUcdHQpn#)% z9cPgKq}3ERXZ_1+i8Mv8??SnoRQbU>N+(|BlRkTp@7nSoV?%t^o6dnpQQ57Vyysf` zPpehS=PK)-H_{S|*IPNAVt``ifY^*X0cV)qWXZeW~tWrw(X@@zv=!W7A?HGu)x04 zu%c2c!%BC zzbfkju%&$?Yu>%PPM%Ach~qP1S_vz#>9R_d#t7ewt__On(u8o9P>bnaqJAwYip_0pEj6`d>62}kO^BS)yRfL~sqs&a^ z@4TeB@MDo%s;i#6u-6_wIOelMr5{}SkJ*LDrX%+0r@G`*A+7(iZUe8^kl8<>aoF?b zEC;yMH_t5TcQ_D9Kd8y+sAx;)BG>fxQqQ!ogEKsJz|bRPOhPj-N!u}>?8J7TZy?MD zkT$z6|G0F-XT87Q%jukSc!LF@KKn!Gl6)RFgVtVqyxks>_9DZX22D3}HhoV^r z2x~t^-2A%hWtku9Mb7K?V6Lv|i#6(Zo-Mz4og!^1RAo|Cr3?WFBs z(pXIi^9r$JZz4?b!&M5d1=9XZLPaR0)-pehY7C)v=FSXo0CsVzZV;0kcB*$~HF_b@ zZ@Ay(os1FQ<|0(cACl`&T@`5sg;Z_97laybShuQm>zeNHq!lQk2*y-<0T2}fZA9?Brfjx z$`=n6rY);WZ*$%xt53dg#vP}K6af)#GfT{4ykI~cL4c6`=l(p?IzaPnk3N;R?mB&* z&HDY9etM~GKNq1jekaX-2yUCe(nYb5!4RXN&zdSppQ^%94cx^e{jQM8If?hQluXai z9n7fc$x+f9cGEY=iqp&I`k!agKKlH&*!u5f?h%1?DDnghLW`!zbWT7%W>8G&3k_D{ z@bh=akd%7QI%NpDef`Yv@=v<LeUV3P}pt$x1Jia3Ws zJ%Nyc|Lx}$v+=?Lq#4F`DOXnxBnL6;fLc!=d)XVfYd$y+!K4ngG%+IneC(+-ElR@= zl_44U9HCeX|Fixx2EvT5SN5c0DT{O>&vaBH+Mv2R1qAM#Wf8iF-Lgpvx7`&%53ws+ z_|>Lb!7FhEPP=L_94jq0ByfOW-ECkoGG=!pso8TaQ&+lRzY+LLyQk8uWQHW@rDUL` zM*q$R?HHGUt6|WEaTL{OZi{#_b~?s~+S_{jwHKPZ(;b_=n0dwa#l2)hd7L9DG55SL z&e=zmO;H_uiPqCc-UDjT1u^z+F4DtDi|h*kS3o{$FuF~7e0jN0$DEkx7gBJ1CSA}* zb^% zG{#!++?9L)UP06F7nc-$yC+yHd~Kq*<)}VABoldLp`ghLAq3`G7H_22_lZaJSyPC= zFC0dH9z}QRuHRW_Q+fhxO6iaFPw6D@{RU~}Bg3z;ll;R`hW}oGOFIdCRxuyWD7YyQ zBk1?`$4#Eip(mgAwnJWss(v8l_S?KjKV&~N{|Fik6jJYV7ql+jN8U-vBCPVTfZ*gD zC+oX4s0P>=faK699fd`jtXLaX6I|`()Y1u%k{~+MU2iv2JP!pqfl7o%DDd7e-v*;s zE?T>_W?O17OhLC>5puP3LXG4-ojubur2^trTW7r3;iJJcfP_gCTBCC6@0NFcgOVE0 zYXAO=SlsXOSl)4ZSc5{9!kuf+80O_cpAz=Cy2y5X#SNc8qIj4)X?026-XHIU4jo~n z5*lTRkU>)cS^;&0wdXnP&zt9=l<0V+8XMD-c9S$bn*p&!2g{~F0}0Dq$JIjp%HAjH z{5X+BJ=Cm}FMD&D30>Y)S5Cdb-zdf_1KUAkX!g^lvLz+76EZ+0CbfFG^;Q!mcbp#r z^$){Jt}QLEhT|n*8?i>D`DCRG+cP1WNhKnN_F@Z4H2?FFw1*6F0zA4XnyI=rd9^@d zkH?EBAGG8bj;{knT%Ft`DMz4hgerM@Qd1UJ8izo-P*?^#ynr&Y3%@YSK6hHQJQA%{ zBbpcWx5fi&gd1T?oa4G&++`F&g>7qHQ&XS?OeEkGQ}aAE6v)^mGIw5K_?#n{!xOOz zWF`<~k$@5(bB1t@7;bHnuaKzuJBy3vBrUXR*)3oG8TfIkdT%Wl&Lp1^hpa`I^n3`{ zYLmtkuHor`4sK;qvZN_>yqy-**O`Ky72i}kK80k{S-X+eG301Eq_y{Ip>(naeJP>- zA9PXYjNjXu&cx;u>Y`@y2}8xWYk)&H6>FS!_Wep|QxZJZ9lu3Y>AI%dy%fb96kP$xRB$J{+ zWJ+!mY}>V(DVaRskg3y6vRj=HKgbFCC^pc~eoF>y^M8Vn#FDc#-s;?1jC~i?aTB1B>K6_(IJiZMDA_$tO z&vLb#+aEt~gIi0h4;qW-@!7yN)aW+K9FUyXt3kMz#p zY5yiaS^jk?C;oOc1buVseCpt_V!Hr%61~n7u5{QZ*>^a2D?gc$u8&G;b-7BJe4&rD zz{hSgjFh_5wA=o&sYz$qKRy<%0qZg^ip3Jje&xbG zL6(MlKkiy)>Fvdo=Kv#pNpm@`&k^hELPk+dofqzLwNkLCZQv*1r;9mwpnI+&X=XPG z@AqXWk(6O5H`5K|djJ}n^%9!6p%KA2NS z>cQqa*BCAr)CaqKSdVwi6L!s5JTLMOwY3EXpphT~HiwIw^Mbhz$0upoH26rp> zq{>M>Oj?qBHAw32)vR5=aJl`s#mrhJ+wwgStKXbTS;x2c8)Ri&ZgT_^=ipWj{u&(B z{#}&PwGCi9zfm9ASN6ShYgO&Cb!?y*s@AaS1pkNpcY}ay7-9q=-t}zENwt8<+u6*9 zaN}iNpBo$_pX8$kFd5qlm}&Ba=pY>_x>9#>>^p1ffg0ge>Q1E;DF512$<@w=wk%OiZCn%QWGMW)E&?bX&S?YjI-^D-yFFc*l8W&EtGV08oQfcEGc?~CmY zb!V!E+(lqn#SCr5M%14BB{wvtgb2CHLsZk#@em4vcD0_Uj@0;T*4kCmf@K~mDlp+| z+*fj_74nK9GD|B;CjgH?QpmsewWePS030QmUAY**H77%bi7-j`$Em?LVtzZ3$M%Yn zN&p#TR`Us(>EaCDsS7+y+-av=JfJ)f4!;r1Q<5|67g+XCI%`hkJ3Fa<>aZ>Q+@>X* zrEVr03EPIZru|`2NG7f(S5Qg&RI~{_jx9@^ZL%1IWRTC|ZAbACF7i9@%9~vdefp%< z4xgoZu+DVThNMU(g!BuV27oHY6D_0nIAz~1+L6l8J+#X;AQt8V%DKa2!64B^3XLARjj(g6VAKiSv8C*K&O+OnTG#E_ zO*S;|^7<@U$o@BKRSd^)=SZ%R?ug__@g-ZDgKD%~jGQ%1P<~N7Z^0iZ`{UuFRAe~C*Ru@0ckxbbW5N(}#PcO6FFX2@5l=0V(YpGT~VuQr9e~i8_QnsyWO%XBAwB8N;aop#9ZCQG(Wu7~=p8!2la+b9GU6UHbOOy~!P&%^^=lQN&55Ket zyH32AMP3`$iF#>M>57UM&2qC!fK{dHC3fVMeOZPA1@_-2Yr-EoNmKUpOrALjB@&TVt zF~%5Qn^rhbRvsRh0V{6XY$r00IRH_poTCRF1teqw&k5BZRoHjVTE4Wu6^pM)oF%g< zkB};1O=vjCPK-_a30#Hh#ArkL$}k)j;FLOe9o;Sa0j&0UBDvM2wU3V#pXZunC+imLvd%gL71Pqnlg^-H1tY!lq*NuQ`y!SX*E&^B zrB@@YAG-tus^}uwt5HP2T#U|i9Fq8wbry4+fM@*?*+EJpEe|5K2fxv2zAL>$9(k_o(60ifXNbzadRNo|(+FHK!;t zOC+Ev`0OI)O7J+P>fDTi%_PE&CI3KMZ8~3#vn`%W$z^*R@HWXNSK|baw?EyNlyhnC zAp(}#M?R3-q-%hA98(JtLjqnFPnvB66CVv)VqmT^X!jCxxJmvwJgWML$o7aqrpbgSQ|?DnRU{t zyF)Fkewp8OU^v>%Y{Bw~vkHUcmOA1!QWSc_vDN?u<7%~r2&jhL^|e)KHIND-slgp}9@}#KjEABkF3)q+!v8SvyyMDU~JqmW)8z zm1d2CxmKxlSa*Y+~gJD5J+8>bfEh|IIdYwAzZfz^ng1Nn1s9ABA*4&^dV;gtJ zFu_`REd|QKlBfsy*&MQ$>>Xy4DO0yJnS7>=!pqIO92p-kHPVb&!KBv5}iC*9&(@A&@bWqo>pPqM_`G5c4YLiIS{#k9?R(q*BZc;iS`>B5=x{h_EFLIky z6Wk{mQsY}aNyxc5)VT?V_{j}t2VCf`NkR&g5`|Ski)$n1<1D(UAy~er`MGkRM{(9v zLTOnS<#McRGOgBec3%W;QPM9>?v0q-vZfek2=?))uL5(FT?#H!$^wUz$j&4QNt1`s z_%WE%dN!4ydsWxm24)7 z&Mnp<%a?6>uCQgyXD0_!1rEyB%j=4Lu`9HLVwH?lb(G-D*kWVXY*m}r-E3JC&pS6D z)p7MO>FbVMLDO3M`@KJ8Ofkr4kR@S9*_Oh=mu!tJkD0b%i=m!`DH;D_thyYio`=KL zHJ~~b6Ir;P{$?3c*RxJj`cG1Sb?LG;ul#ZJq8KO7H`G|Q?3nj7(uojg8$byK zYk9-k+(0=<&6sg(-@LgN%@cf0f-Ni4H&t{wk4r1GG_pV6hwM||n<|9i1O`<)@_^mT ze0%@-e(NkmmyI`eTI;_xw=hsAxyvy2d9amxIV`lv z(G2@&*z7df)_;G|YEDloEovyIi(>gyJicA|_^O};-v?LvFAz;WgnmOHuqD>bS;Q9Mf}n44&Ty&r=ot{?h>s&1tL4k zV`}~vs(e~@#O?uP%9XU!v}l2USUVdXw{;x|%ZcPjv14b~y;x)4|3RSwf4L=B+3)EQxq;p>Z&5aGo=& zj_|F>(h_C&SBGFDsWNyu7??{(t+MNIOM(~f5)KLagSyYAUYXEnQAZ&r5GPLg>o`_} z(AX7Bq?68Zm97PWHZhmE0lpJo){zJ1hoz2QpmpUtsWF2S7r{|Ql9Cxgs7OPpMTVIi z4y4ltsxsvr4PN@Oj-$NLV=mM zOVuUfYE>w(D{R4ARnPJA38PJrq2ghVBAE;p#G|h;l~}WSX!o%TeqZxy(RM38vse&N zq?4GgqWathb)n00?{E%h}a=nW(<7-hw6h%u{ z0Jch-bB@I!iuSMvKh6~L9b-KiG_EHAv?MC)Myb~wMctE{gqnQ4a$@d`&}yA(t2Upc zoo=|?#wytgs@akEi&*+)i=QNPuJD0soJy03h?cbGLKd!M@VzWe{t$D2cg3(9UYx3& zRqw3c*=EE$AJ9vIGNJXGBBht_c-X3j5>9diL(ch?I;pv4Hb^UeDJie>*^`0n9~HQ> zk@KJQ!r|EZzqj=KvEKQxjedP*Q#yh;ewvuSkz(a)2J+Vb#TQgc;|MAtyjPy(v+2f< zTj;~*&iUljhUD$13zOsm+KyR(&|R5G;}GE0tWD@vQjuV=e#=l-oV(goiA&hX;@XIc z=vlpuV@)H*|KC6Kz+oM|IVcOmZE$qnKl?`!P#+t7t+gyDeqem*q zF)WVj*lM9J*8$tyTk2MALA8pDT2R9m&<19F>FkIJFQhIUV^Z6#yf2f^7s_C+o?Pu5 zavQjW%YgX7Tm0DC&6w%%$hMIMvcU+!s3y_Tby*=y)r6u|v~SRen%17p{L3}$MQKad z$0b%ObM5Gi^g&NW9%B5E!EE1INr+Tf-I_h8h1hF{*LyF1b?=essCpKstrLDeui6(< z_!P*px_W8>*3FvWdv*3@Ujqa0A|A#D_wo6Be*XH@qKx^z$jB}xdp6u7;u6##ETi)0 z^Ld9*`>ESyd8l8%{`dK~FpJ7`+C6ZNZ0R+xLI5A1pAY60`|wvu)R(?g2$!W7x{15k zz=D@IO0QVW(2{Ud$`Fp8fyg!(zr4jIW=HL~4!SpxXOqmpDvVE*aSHp`qNa3~=sL$< zVku76d9gkvqx7~gjZi(jyCly^CgJ%dRYuUtq-gXbyPki zTvVkiIi+1Q(dY?bgQ^VOSoP2l((q#Jh-O^bZ+ZsQYkkfJpWw}7bW5w{9F@%VaZfa| z6;>8|+EdE)dTFFhWOi&7?9wp17=LT53X7As1A#he=m0`3Y(1QT{|>1YFXwhqX9>j4 z_V?5gO=^5?;1|KB4kaM_ZTA z;S?1&>{!C4yTzrdRo;eOF>g_rr{$^r75qoj;P6`3jIns&hFsLb)b7^gNWe6<0U@4GWcdR&zahAQUn2w}Q&toUc(u9I0 z)j8n_3arw$qf($XE>IQ5YC#q)lFGq4!(OebiKcrf!9pZmV@{*5nI~a>NZU%@ zO*!oBLR~kD3pAV3CI@;r=vd0u@@)5WpDRQumj)dYLMkL~6nQ71aW0L@C1g(|G*FR9 zt0)P>Ye037r}y=h{1RzRbM(x5WqxR5dhb0(7aLjZ8?~K|Gy`!eeSLgdhW&-Dt5xwF z=vJzBCqrzxTrFON@y!0Pf;ZctuZ@CfEF;k4a)*wY!({_@Ui2v-ADG@69gJT+*FmjK z7ZhLuqaiFW#*w;ex5-QhQcB#%RBG%Kf3!h-=}q}=GT#tsM?zkc0I` zw_-jMkB1%#yg%==%&HGWzN3^Xl^q1b3p&G@0#hH`fUZyzk222<$-x{nM(iTws5|JGc43A)GgK zf3?aD?<~;yjqIt;j^B@*PjQ{M=3I6#f*r`;*x2TIn$pgz>_@9NSyly>_BImI+(4Pf z(8JvwjM1&S_U+sCVeG}Nm@Zvb{qd}mUtI)>NhsZlx^sczk~>_!*Q8=X(eSL2Rv6$N z4|$Oogsn+U2pXJ5lNuu4_X3hxj|CdElqQ*BCmXv+EXB}~ zlLc3NP%LDZu}7~&09c>4ra8BYc^w=ln`sx=p!kcZlXGl>xeQZOh+;SW|ofvo%3B}Cka)~#zWd~%F?_H*RSneZ+)C4A=zQO@g)`A5u-e+5PE+C z&AGJK4OrV*Z%d6ws8eTyCF@0=xI*3LW_nKa5<5)EF#L2hnRHuQw?q*Qro@-t*b!T) z`9M5x_Qh!Q#M?k9lhF~|ei&*fi|oU#f@3z2T%>Ael^GSooABaJ{6FprCn7#&RNLr5 z6w=o=3Ne&mqg_XEuJ3?V;Pu!*mc1aYy3~TJ1DT_9`F$)l%?~9+OMC)$tM{}C`%rqk z_h@&O5cZHDiQeL?^dm))Z)2KS$AU&3_ND!n9mj)~ona(M=&+(8l#$9~Ht-Od>5f{>Ms$j>{L4I_g>c~hkhs@owsfFZzF$}rlXWr1^w!HiE-Z#HqDV~aU8P{+J8CS z>r%uMUW4*lg7iNM@9ZAYTGn-46uG^uvo>`? zo0MW8_8pZ%GwOC2(pKH(Z`ty8vM639r8iM^+-du|=t6iL2jN@UPYn$d6f*B z%$waRCeGrD=ejXo&Br*EeyM|KIIN+(D&vgF+x8i5S7mw6`+=E!DM#Y%OKPq-%HXv= zdV5J4IFg5m*o9C5ggF^-`J zyB0%YFtnCge$pkv-h*;R;;>uY3zNrL2e6_ZKtDf(i>Y~phq3#{fKz~ z4(?XjySXuQJ6#&}#)<91>|90hfw>?RZ(<*E_|55}xaU*9shy;=cf-2ODFKZr7=~{A zT01xG2n1{H#$_BBQ_xADEE?$H|Fm6ebK^J;ByCb6BbBs1@04Bs|3CDIZUCelJCCWm z`LH!RNgUa6)I_5nZTgiqr8~M6M4u%SYlF&Vhs%gpwypR39$BL+@D|rT)D=nn*dJGn zwkwJp#H4#;<}(@(U^0r(Rcph11M0^uFKB5KEZz4_>xi`WSKdPGI$UBf-Idvn=xB16 zD}Wy}wQqF-cg{Q79fEFW8&I{c!e6+*uJY)qfI+UcSA@!EuDcH9m1=N`po-g(R6$lK z;bI20j+w>Vh^6#-n$Te6(OJ-lSGaF8tK-R12iTkJ@u78Q+9Y{%QE36E8FFcX4JugC zz@K7Tn-Y3rfpKKe99zDS>RM}J6h{O92KduO1yj<^xJ=W!#Kl?;it3^Lw@PC$mEz=p zY`f;FQzMTZ?XWp<;L$g8x?FmFuMcL0S6(<;Pia|V>XA+!-O+o7jY;yNoUE+Y3l4!-a8OlmhTKps!2y@qSJpjj0U48D3tt-Vr${Q)K7X(r_)I36>C{d% zYeqE;!}3`l>SaEkJ(k48VruKaHngvX1zbP0Dgjl4>N?_8DEn)oIV&Nib-P`N?a+r_ z);e8yVmO~KHT1>0C97x!9 zQcLwF0Q@@E;q2_<%IDQ*K~G3W>`%EJAsp4w&$8uy9qn1K`Dp4D&&2ksn)feLC!xCC zhTV7x;YaxUMajW;UmoW7lH_5>{EmpVrRmeoG|&+9BLQ;9lTZ&sZAmW*9LC&)A-O5% z&nD%kAd?cFy0+}j_D+&zCy2LjJYT{R;|&W}jh|fi>%K+~luOoDA=&w^x|@_Pz{efU ze=$j5##VMeUOA)&B(bcb zQK9(iMOuX^HddRAsI_R;5p7onDZI3qUb~X0^~x4~g?x=-)d$zRN|Uvtu-w+ZWkt_~ zaMYp`n&rYb{oux$Bwi%%wps&4(^174L)S#eCDKaQGKBdX1(nre%tW!Mu*uCpwn{5} zverJ;u4=bMam-G*^^}gKl)>K9{`q>3)hos={I&;F;@Dw>EaxtdGAP=1#I_=FLnr58 z>I*sPoPgX5fzY-8;dE*0 zErFgb4<)aIhc}rzm*n-y=4zrJHn1!;avfKw9{zDYsZVDz^&558wsz$nT82h8_UMvV z`|4E-#ZKR<{XHiw4C1!RT0jwvY-#K7vzjIi`|bguX(&Gs zQk9}O;`>=Mr~No$;wSY|H+bf~jWHn>*IoI9lOe22%=M)+e%@;|FzT1VI>iM634A>i zRi#-{7_&JJ>6eF_X;CI)Ou88VGSJdbk(GQCTc=?1cq?O>lD38Dma85M0Y2T(w`gPU z57Dx|X*!$_9mT)czJ6BUzTZIp&QWARCT}1xe}8G;P|>|+s^b|0pnBS2cXe*X8IOcIis@Ik3Amx0{F<$jWhA`` zF+Lu6-gy<*X}d+rc%1cs7`Mk`-*&x_2Chh@+81f%5vq6>|I)UWSu?024|(SAL1Kpx zxpG(D?u^IiwkcX?V>aSfB@ZZLLK|_=B_>dpj~W=iouz}f%=_c!tgHBS<#92hyCy=D zrIFXQWlxjk&toa}E2K%yfi1jx0>cG~PfAPw8g9ipUmrWJN}fNq+PT!D51YrQY96DQ znEObn6zom-nZgRTvkc;}-zSLi+4jz#;v}8FF>@WtVdyoNF=hh!(0;b6RC2Y@?Dtpz zEY=Z10jh|)Qawfh<_jlJEwdwD=W;!PR^7F_ulMMu2o{0}7=X;Y7tLuVW(`BbKp``k za;a)dZr@n^E=5IFTFI1;xkJ|fPXG#w=QSj^xGKq&RI_NbH9|Jl@6O(g6t znTZgt$&(tJ(LM_CI7Y+XsjD_5c#sml63gVFP(kHQwI@iQ&S&jd0^X`>3>UAV*g}fK z`&5S|Lt=d7G-Oc(8lXQu^!qEj&mlg+8bE~Q(;h|9l~E-B`Sa(`KLBVj(jy&>%uXwH5nd6j|^$>K>6xH>_%zC-!D)^kEC=|9eu9zUaY?8lvX$B3*r%6~-P{Q{y zS}!8O-WYlM2x=C`Z_X3OtX(e20w^w*I@A}25?-8s-neQoenNp$8PvWSME<@j8 zIEe+NN|!98zqG9)<)BTOZ5)L8Cqljyad$?`Zw{3M=(=IyTedaET@1wSFDuTB(q%vt zRfBH4Hh_-}3Z>qN$sMxFt;om{tZVqPY#_upQCEut76FtfI^1UCYP6Eq{62z{vm{oR zA|~S^^D+&)q^EDY)EjIrA4c3W#&5|=Y|rO<-+TS61j_lj6EH>uSK zfH#egKUL4G?zAvTTN~m}7F>}mS(<@RXD5nrkuD29sR!6vg0WU54o}D$@dRrx=4A{e znj?Vi%1#q=ng6VbBZ%j~f6#qIB{leD@hRict5-ROE-uzX4=>Q|VU)#@k5-i%u<_D= zu2{AsB-7Mc?nw&D#hVm8*%}+~6kf4*FHC8OM=KfvTI(}<1rMJZ{Y>3DE58YHD6ve| z8VC+cjBb*WimtfIk1I!-F~|TepQhheu1Qa3BW%}^r#nD z7=Ld({_*vWSt@S{@Z-NKtJ6jEynT8F9wa(zeyZL$MsBK90<1o`%4#hGu97`#V2PmCS-B?*KuXn)SL-#V%jM!PgYQ|D zf-96^%gJoLZ4q~8%R8tV=)uH8c`sNAqcJf>gkK2$$l1`XQ+!DUtMm|gwEWX&YPU#8qC^%{`1rxb^#x+>;wmz$(wTCkpxLBK!GNx+W;Xl!* zN*q+{Qhk!H_CkB(a=jSI0v;zik|vdpv5&zD5seg|G%ZY5%uuYstsMCEi1Ik|fhJ$h z$`B7sPgQ+Msj|pO7;Cj(A$uFW2i2FvmPcZAI<;1qhRttnnOj7o3$Ik8LWtB|oYJ?p z$}T6PTukUZ6PeY|k+j}Hgi@YMWCcWnuc*51fjUt2i)G1 zmoVmWJj=}8VLI^6&T}5#60b;e8iy~5{}Z(|CqGZnnx)pjGf`ObW-SqxunKnz{b~9e~C2z}uk^-23#V16fTe2M2h0rMFwpm+$N?lj3F^l+R2;OK= zlG%8UwX&$)6i6o4(g?@@KedCL~wdcE5ZqrI88+m>zB ziVb&ht%YccAmJdP?Nx)g;&tt84#dkuXZx9CxBSf6LauUgAQwJBbXi5LNnOm4M_qHb zx(nsohQW0+BT;ug$d6%{{c~uiBPnwtuxn;tW@w*akZQW=CJ`EqYN?{z#9;l*5MLDv zOrbNiJO$yyp#`gn(bhJ;;z0@Ma;sz*nZ9{J3Cnk&Qb4W2y?9U?5mL`cPPIoJ>Ww<~ zrXv;w5PbskG@(%Hsrjj3+oy*jck5=tst%-S?05@0e@glKnSPDDslFz|M>Ks?)U4{bej+o=W*AOeP?jFFV5nI;yhIEa z@3--c=n1^mF`J2s`rV=7M$!@2FeGsXh_GZ#EXywF8<+KZjUY4uzwH(t_jReTyNV8J zQy7}rfQybl89p;7;G=pQ?;v)W{1xw>uTY?Rz<<1--K3)&uY&<2P^LUpc z2lf^gi|P^yce>ryjAX4gem@>t&v*VWZ`ZcmIF3U}iYr(?DGGA=n}vINXd34 zz1zF<&^7Lk9a$HG2RIi~8}Tkgj(yo8VW`dMFnc5h3zTRQes%^>6@yBrM+uZ9&x-DD zx!T0eGKRI)>=5XE4$Bf}^c&mP7<&n;26uNEOJFP-UOmaPFCT12?yP}&)?d2 zTMk;n?j}uQ8OD_^+Pu+y@=e=w0(zSsTb{YQnTdvB4W(_tiJED&Ymmk|@_zJB*DnNP zHk-v2hO@WD$Gv6~Wj*bacr{BsyNa4U_+V!c?4(}2mrj8YS46u*>!ETJ4m z79T`QOq&u8ast=vWTC-k#^D&)M&~EQH?b4tho%ZSww|HqRjdfY_1qiPV)}6!p|1I3 z!e{H`94U)~kioVlD(Z&HmDsw&AXnt*q9zO>{ZrX2`GuX;`$^}2J2iea%l?@?^>ze4ROkI?2;x|lvez?@)RRDz zD7-s1qu{5`{dAKxA7>oeCj&_gpWW_0wc+LYZ0fum-QX6#@mOZ7gizF*$RR*{D=l~C zMYV#mnHe$=9mDH*t0LFQ+g(PjQScXh6lHP@C9?QaN!d}AZ3eh)<#2(wRKwA+q3VX3 zbyNw5jx|PhZZ@8^yqUKHYH$p?Ggn>y2BAUB>naW2tX|NtwpcaJSDWQ)TpJt~lH>v& zZ&|luttWuCCL)&%y7QnxCF03idvr$nG2eBRvmhgf|-4m4JiAFoK%W?n z))K_zGfe+66W8Kf@&8W~7x|0Qho`CYx@HK9{gq%~wUuso_xt<%OB^LX)ZUuZCPV4S zn%CeCA&@M)!xaLWw8!rJ=m~b!tyX^iYl54mICOk{i?POZGKG;HdG! z5yL-`w|;x7!Vg^MFd(+kiiMklB^=d6&zDppcybH$7u6z}Ke4UGFjo z#d?yhqw1)HMpXi# zdv?t)N;VlNm9a8Hl)CWiY$Q4h|20{+_Y4BmJ$~j*x!$MmLp0yfxWW3^1slNttE+>Z z;J%E7C&_5ocN9yPn7A=a!h>xfEtGxkKncHQI2F%4qZjSor%xaX;m=ZbwQGe|->=Ig z(O;|1f#`J)8EehEtfHU0%3;v@KJRC!g!fyO(W)a|Qt0#fVBJA_!%TnXj63H?BUJ~+ z{V)XxFUC-VRX9H+dA$fr=-CFXcUL5qz+9HNOv#GO)Od~AZB_Yxt6W4mKz>`wb+NlP zW}jj+F4FmKX5CT|pNi~r@w_}%@@laz{Ap(nC|YWc3>mfxH*UU6a(HbQNnW%D2bk zwy_;m?)>dmbh0Gd%hd9Em2jhs8009iruxv z`;8jHREmk2bjVh3YXimVj);d(R_tAOpYd(L0?JdsB47?oVKQTnlcp#L-z!=0j+qXY zKm#7#uB-OgBblv57*#7C*#O2jr49mttY^40cC^$X7~DdFT0E(S=M$Lml-$bW1d5bt zepBQN^7&=8wA)I<-h$NX>ui#&M3baBxCyiPL4FvZwwoqNUIS7YZ9J`Yn72;aP@b$p zYP>H&;YEpmL4sIHEx1(sJSm@xxzgVMPZF;@lgHj8$GAt?xCRIex7m6MO!1PtfZ_Or z$f)gp`?we(ow@dgNvSgd>>fNTg&kt_o%Pj0|BJ?};Dllr_dVwUL8&2!=Ed~| zCk$ThWk-e1bbeDc->kx#t^Mj}#Jg*^-rL`MmR=C^csklQJOv#dan zSNoa$-mgJR3Wqd@E>M@d_rh4B20^k$F6Px$AZ6jwRrR|hMNR$aljVpg?|sG%~3rIjGn&+qTgPfzt@)UH@pQF}YAZ2aOA zEG6*fF1ry44@^20eF|@zygfd2peM(i7Lp8CE$E8mpREulghZH$^vN2?QYeR%3HRt` zze|I&jY3#|}w; z&JA-jEL>)T-kOg_E<$`^O*OhY3>4eJ*mA$#@_8y{tO8<(Nxhx@JB`kMe^BTZwfBva zMM*P-fyQ|-@E@1(9OpcmVwAxP@uvg)(^6aV-^0v5D~Xrj{{-a?HSL*2C(n84tK>RNdHjW6nO=&%rQ!_F2Wz;UAEGY9P7|Z?!x(m+e${^W!H~w zDb7aD*N2d$MX`HZw0L&5Ip2LLa&!YrdEt<#xE7heQthhQTos*HGg}(j3Rc!+51bq5 z1*OTEIMx@Cc`_mwRD(rDvzS)4DRB=_mE{yk`ZfP8rxYbK5EB{iv?j|MX7 z41#$7Bm3+ubNhibFO`;kIQ=p*)lP=hYW{A@nw$y>x23mP3lGRHwu^e(1U*zmTm=d0 zBk9F&tDO_yKnS(sDJh1GQbi68Jf|ubqonpNvH?_!dk0@emuB&);LSk+` z7LEGbUU51xhw|As4xV%mlgSX5`7%=Ro2{s&4N);mIr}mvtrbhea6m zzny10uH=1N-Fv{V(!4KcjEgO4*bqNPz;iO!s5HxK6B;QaY=URi3|ET@xrvj*`!wVb zYTZuL7h2OuLh1$DJL7=FGatZ-cNpf~IV0H-bz70YQP0fvL$X(~TRK^yl(r2fRuCgr zV`nyIM{^9d(OXq+C%BWK{*Lr#?=hNZb?Rb2>EzHmwDpA9(n$dN*w`-gj%vGyvfe*` z{_OmcOZ-%S|GdUg%K!ISuLU9g<>7I7+0bqmI-Bf!3}|>CWgLDGb>kwx2{YU?!v+xw z3au>n&-c>6ygmmTHQ=@l?~)hxDay{ou2`Lw9^b0M<8dnu65bf~wh9)h`&~rw;;0K# zrE`G&;aOob2h=_sz9hewUH0nct?%m-E)bg(=?=AYdkS!rJC2+lTC#mW=g zQE61eb?uU<9KoiRC^fP`>46`gNJ5gNX`%Z9b}0)6;oG^YW{vP~-mYyqbzF(cMv^7$ zn91QGRQ~@%N8M|6OC}DzXPqj7UuZ0#Xww z+nR@5U6ahh&fkN@C5JZ)j$#c;^r@6x|Tx2at^UN!Rz%O5pG>BgMo@A2^TL>>;Qm61#02V z8U#%PlKkCGskQ{=m#ya^57k55zcJ*ipG)-7F~7_hX69g@BB7&T)C|LvTX*;O)0$Vi zn5&!0f){MmQB8fSmUctuFe;y6;(E9$pO^2P$3zCQ-SOKl9i(WAbt^2tb{&QA2eRN3 zX83Q^C!MLu>?1WP|6=%;Lx|8H(!pOn+XDEO{-GePjI12es>2ye&64i-PA?xO=Tpiv zTrhz>8%)^H9pLclAq*S7p^!&L|I4w!LLdf}phQt7h=Zi$O9n|>W4GJKDideBZ`jKO zm|n5>C1y4hMPHTo#XQj#1;JlC>7Y|l=QC8j1#*3@au9=%#%;^kS+}xiNVBF)^?0_T z&ZbJ8{j@8H>()Q0i5Iyjd#^X7)kQ)kA)f-GQ^erBX`itDRkp_#pm{EK+K~dE5)LV~!{T>Dz*I^%sKuER4VA4@ToHz=) z(F=p6$5k`_7fsQGZbdO=nC3>E=|K1tjqQ+2mHd@p;%Ps<-3+E2FJK{9K`eahmfhqQ zS5K!dgX+n0v?`3Z7NgjS%V95!Ruk{xPt4u0%R7dSjF)BlcxO&BIO*u|7G!>DCpNm( zRzyI=Z_2dhK|T!%y6d-iGopqz0K0ksH{@L$u4o~K+?sV17bmBq20}ZukZt|1ro0D&UI(Pa zCZClTb^as_YOKEMxd_GrRA8^R<78r=Z#|5jY7#K8$wBi=;;|QCF$&`cVe%6VnRw+y zA!Z%?kB5Kn*#o%yce@dbl``QKHTpFCQVD0_T|e#0;r|k3zc>Y0x9#h&Prt-!2GQ>y zbtvJ~6eV2RcPi`O|2E;w+|<9?_pVW1{dLH8K>?bC!;io_@`>dG>GD~e%IDp`Q&}Su zTg(CP2Zu1 zG3izAZ#y<50td@=>Ubu<8Gbg9O;rbtx zV0yjMNU+2}Y@|}NzP9bQxu^X@i0uoo7oNANB}psdL-Mf6Xnlbm%(}14Cfpu(^l!}b zdP{b!3GZvMxGPs9Qv+s496XGqmr1UZRFv9|nAIT^UnIPO1yf=SKL=+oV)U;Cyj3})I}@@l?BEXGQ(n8xt3zW^K_-(f1(wJxEGN_>)X1bpB~pJtU)&Y z+c#2=^HBC)bB{pQ3s8;breYD3eIGT&QVrGjD{Z<*Ja0AX-D8P3_jdGlRQjFW`TYFe z3LYUH>*!~RWdzjaZpY*J{;)iUg3p z2eE5T*=#bX*sFyyP06-v+7#wBKa=QXo`*=Bq5KZhG^9RQ$-}S*hib7{n(Ul?7uCeB ztEM&2-O(I<`jU%Ae57VqqBqH;)fR^tN0XI;>{Ou3N7;1NvpI^2C3q`gd?Z;-siqFf z`I4(oI+EhRz4N<~zdURB&Er-M{OS=k?mz;CT>8pVsdr)Sdl~ncT90u?p~uzW3H-7x zT7Sq$0e&ONeI@Npv+5qdF$;%NMe;X|J6(?Q^Yns#^DOz}*lq8Bl=5P64nI!H@Y2;( zy$lC`#Z-RX4&||<{UJZ@uYTHFn9e!gVBrgJR4i!J7-$b3!utx0x9$@u{VkpA|JIG= zN244MK=<>*-w*rzJCcjNbf>W2Q0J`%BVp-fowd%3Xh)#!k-BtSN7U!%eY~ckIzq(w__>h7K-DQ~G>qfP zcEG)ZW%ziKfJQyHLr1rfS&dRsf3!7vFIJ&pDd3h^n^=)*T?TR05TJr3U3nm+2m@@3ER+KcqN!~@ikaMlQBuX1{O&ooH z+$joECYGD2nP*6U+AM~8$yP4encvJ z-5niRorpv&#zkXlLWdQNj7H|<_3eLGYd)|buL}wdV@0_z#Y+=RGeY7dHi1&PB@!B1Wf;34LqgtJKLh2HOC1)D6q8&5?8 z4%5 zjVmP3^1ha>cV64Hs?mYQp4AkVy~W7+QX)oaDkfLtxPw%?uNjF7WFn&3uV_q!F-FYNK4uMFos4!aOHB z_sg^uva5x>u||7L-4m^FdKy)A-B)O`v^s2?%KpMPmAL&<46sizNwJ+8ShcLT%931` zouSywOH=bQc(vlbhnkq;6P|+MEl~*MuQK^^ZPn!ON!13DD@N}8@T1zT7ki)3>=U3^ zf)qxi#A&Ay-($fa_pKCJJrsMugKxZcxsuJd)lM)S>5|dgMHJtIe=j zW}B&zz%7Sl`?m^J?k@YWP02V`H8Jx#ZYdqE8e6Ivewb+G#YfHrTOf1~2~qhnpygTO zI*@*mrPS!c-oPbv_0vVwP_a^IZT&^u&krlUrDPdkjGyh=EeNUcDV`n*w-+8l?Dh?U z&Jc((DeIzSv7W_d%hhJaH#qjuDEsUa0UJKu3jDap6lf z9Cd+w3JnCTDw-HQ!M$XNJBiIn^Q+tCwOyX~)jUEU4;Yzr_U@wNo`Rs$ z_e6=aHi7!HSD@~u+=4pcp~yRpNiUlI>8Aj87~1J$M}d^V5Oz+e^whSWWmb1FYqf#Y zVlxW@w2YGA?UFOySJpvn zl}9j1K_NdQ+gbJR)|~{T0eH1?wBfr?;$W|wLZk!dcYNQh9=kbKn zB?ZO9iP&^VQ7d$ekKVZV9LLrR_Yapk;9Xti|1WV@+T^y514)~d$dMw&>koF#|No&& zpc^3NV`h@KuQv6Lsl?G?%LLKr$qBZvQYO|E}< z+MnLw;Pw6Y6YCyQ9FD^XAMO{@0hQ6y9ZKCZFuuQtR&6fTD*_Fc%9nYH=$!LGj2?r` zU0XR5kI5Jp5r)J_LhZ6wWb)}6ENi`H-d5>+_uIbTVx1M5760Gcg0YKc7`C!|J}=fh zhR|KW$(JrgoUrzLWXO>6a9RsW(ajvpDT8(u+x@;9O(|!qfwn^dJ*sB&u1AoxqejG!tOW6Iw^x}moEK==c| zV;j#JAzL>Jzs>`ft9DTt!EO`WvH@3OwxHG4XHS#}D-%xcCJp1Zz-%qc0i5kg?Wzm_ zA=oQS7ujQ^fu-6T*Ll$C7Mn1;NEkbp6rQxY^8gTbLQSnO?|r7;bVxlU^8>LC=g8rD zweE)J0HfCvT8m!l#&O@~DIFWGpHq|mks8Sk__M+ozVxUQP9LUP$a=xTepQzHv{4FJvkt|)ZgWiCUxxY`&P(7%m?8A-Q;chQs#h6k$ zP!-Ws=zXs@smv)xrwj?rN(j=@fv&Ams`yq`d3`inWzHfm+ErE*5r4#55w0bA$w zl_{*mGmbW=?N}ypaF6Fq7fuNmM$-^7rOmIfT^tNIjF*$D??#O* zslTE-M!^1A{=e*N%29e*;Skd_S-dQKiLV}BJ5efR@xNUbYwlA_DW+y-=y@&v&ub=n znvU)Of8uVvw1zgB$Ax0-_`3>FH3M)W%PcaQB&B0G2biQC18L2Ok;RneNLO_ns zJk6*^(E5E#7k(i1d7>$XA9a-B=!rc{rT@NxEUA2d`R;}=ALq>9fz5Ak`Z1R|)px0h z&weK3E-Qpu!p|gTN2kcwQH(+8EE3g=0x_mga_)=q^O0a@>smKfd}Q8{;d?O!tY$2< zHbH*A-LC6Z0A)QhTDrV*T&fb4h@f5STIG>kBqLrTjbuT--8J34FhI{(GmB!!?e|+Z zxFgbMgWEG8R8uOeZuh#Qx6XwMyaMYe7Fd1fO0HcLENKj4riI+0ylxt)D4M9a@8Z05 zy;;(e&Vr@I6?k0koF-v#yV%f94`QbxLBrRLE+H~3M-l|u@C{be%1|g;Z(#z0x$eF* z3sUwRBOSP4;%xye91H6)$|$P~gT!Y9vuvTCSu5dmU95f13_((Pl=CtJRve>)C<&VT zt1xh)H1^;Z$uJ9lrwbcD6>&_eTtd2n z93;#BJ(&i${mu#Os*lOj9f*Ea-D@nNug9 zA54Sym_Ee8STeKQU9s%>WVjR?@7mnMXw(2PO6Lt|y74*H5T5ir9#;~Mh7L2bJ|7vd z8pnNzbD+G~I(K;7Jg@oR*MWCs%6taG9KJ|73jbmP(htN-;aH?WS;_H_k{DjcNd3$h z^6&!uY#>FWEDrOAmu717{E{*soB;N8{Tl2C4ogG^y8(y73;Mj@ zR#CuKBn5~v=>B=ji}>-HV_?>~?X>7`iY&POD*`xO^%pg5WM3|x4$HK(rEi&HSntuc zo^h2=?6zqSZC@Kn49Kk|(>C07y+NA2uv-N}r}c$0@O?et?kZB)u`}aEYh24i$1tkSNR)4C@WjVj-*ndDwD! zh>lE!-|+gS}th_fY2%= zYmTgP`*qE_o5Y)JqdaB2d#MbEm8v+E-v`5(_hJ4j>Ms&`@EV({8llXJ5ABF8WJ;^G zk!7dFw5np_y?PX`3>PbHCA-a}>1NF0zdHY#sI;?nkOhDRKX_Qe=#D{jll9ktOlQNpC3s zql*1f46AR&yDND!Yk!q#m(sRl3ElcGk76EC}P-`)mTY8 zz9o}e3%aq^6L`0&reqZU$a$ak9gQ2#dAfcK_X2K`!C$mbGB>Z6m?JO5)mj(6>$K6@6 z=`-Ch#2yUZ)r+_kXXA^t!+w6=jyY@k*TcaLx>(~~S{JU)Vk4O3Y&g=W<%29FmK8Yh zSWYo;}55?n<90I!A7S(Y4y&^JFe_O&OY z+q562e_bd)&lbtFt@ur{~1OqWMDE%H9}%a{l7rIfEq>jTjIT*k`i@>kEnE0IzL!Fny3&^V#$W57I%gj`;4;`@ygVvDldJk4>a7ib(%G-F zu3mJHT0Fn*Jy#3r^6f6ce=kBiE|ROD*1=Mq)@)h1K?yZ_Pjx;j_)gTdu^p|_daM0+zb;8#wZMQ*;^B8d~wIyx#Zgj$+)Gjdi51z+nv7^u&Mn#;9xbdx&+MD~)E>qiUDRMPqd>Sp1hc{y znAV#y*5IOE$9#m{eE~m>SSBj!w<}Fcrg#>3DNm@qBq}DF!fm~{| z9Q%>SsUGZr$`b%5O2(j@Zy>e47&Zyu7iG)UC83NaQGjrz>vf!)<9B>rVYn6BQrIZ6?7Y016FrDgyVB=zc`W|3ja_j+lGTyTiCsh<_YGx()%YLwj-4o8J^xm z@<9p@Jgnf_*U5=o-1R=pGxYC20i~f2sKQfb-3tf9v3O(c$WH+Sx%BQT{4t4Y(CCJL zUU@fDJbsNK>;2b1E5BVbhL?$wV;~2-(Mta`DU+1kcg|k( zCA^nV4e{%`l7=!5_Kk&o#`(9Pv}ux-QW=Ob3oRlqk}}llN_*A54p&_Z-4mx_h7d5fumsFvIfqm9eNBTU6=jdVLIpB|t-Y1k_UoJ4T3v@`$Q2^Dx)ab^ zI>Yt%@2eA|jEFr1KfT%-)B_KlF_nEIojnu@Wb#}CRlx8rrTVIKa*(Zbl7^8bG|$)} z!s zr`_ewG=5?kVuhgtf%|6XW5V?rF5j?y3ag7_zGEprRN!|KF{sDK*Uyk(;n(p4(B+w% zF8$C3Q9TR7>O4pzZ@u1VU6%r{Ny#G6WS?o>3K~yy+J07ct%9?9dn6y)l!`m4XjbGf zybW9e{-*m9H${F z&p27_FJbvuW(9UNz(I2Y9ow1OQpi@H2;NngTJBMaif8fS>r+-EC>yeC(D;b*tmRbC z0{MiE6k_Phc%1M4))L4So^Bjhijcx13$%TQS-o4}0?m$ang4*%t`j?x3kE*y0Rz=( zCRCqK?p7}7^V4H)1TSjPX(t!4CSzHjVvxnM4eP(7&qc?swK%bcoMCJOlB!Ir8vr_N zttUt(;?ns?bYvJ|Lu-Y*G)rdk5D4-NiHdDCw5d6LZAVirtVV7E!?2eu*g?44RqgE? z)e>rOt#1Xh#>BAAIfKIWA-KVq5h=Qw+8T|$8%1vXX-NqDb?w}vYX0kQi41J(W~!0j zQ~_Y;MqtuW_F^T!jd7-Ysx4<2lrZy$4jZp4e%~^gAdC`RT3+UsskvZ86mJHtI!8tY zV1(h?=;eCMHs7-w@bra`0;k|O&(!J0x5p1x701cW!xz|QJ81)P)j)KNzqO(F{av;F zLgNvK+9hd*FV=n{eO=DJSt7=S%scYyDXvT%5raRlpWMHEWaiK(0-+DY%zYuM_5Wzk z!TAQnp4yEf(NA>}u=_X9Ti(&J&-)L*_9}l4B@misJV^dtbX`S@@1ZIuk*tfg2k$uw&cfca^;B(+4F zp(UPS+sZopn!jTyFj68!D3y8)--2ngsb$jRnE)?z(~_YlEKJ!(`8@!axl9h zQl0ITstG4+UCcf-w&Zl748y^ySr1f&YTp;M`5+NBe*o$+0IdjGE#qAFwtLPE*TRve6^Yy zDjuiIDN7|#w{6%zdWCQD=K?B>(j?C4h59H)I&mZXO3W$5fV;OS*2K*4>g)hhLdMmpgEob*c{dP2sl`(xXk6N_ahuK7Q2ukV$ zxO=V9{t1ab30ko3k^XR4{vb7?@xFINr>^e3Uli~Ai&DO!QU7$zr?B!^`%_qR&Oh#& zqi5~_vo6I~tP3*3Zt#CH{Mv5JHxnUk_vQ62gW_Z+Q<@I6h?9gmSx7GL%BG_+xL746 zQYyC3bb1H}S%%;l{HavD9@q^()U0~(Z{>E_MqiVyh`;pX4u^?ix)~lrT%|8IX)2=i zFQ&-)X`B1OHNgN9Tz>j4#wT_EOhC%PGu zM=+arv@L!;mr_~?akj+L*SxZ5m#$@BnPRA(h^|*XOBQrtlR~*pa0R87TqaK)kcA(f z606el0Rk~rr@B{9skr4+5p=<Zn_~QUAmoahHPnc zUrm6`o}?g*^omAMDoXgO);96j;?}{zpescst#1`X8<-aQ`0e3 zL8a~-GNeEPVEI!F1}+~aRj)FaYo?b$s6+kubO-vK7Uo~WmJfV0{V~5K`JOLq zDcEK2U*#kH@E;Jij$R{l#y3BIqTT7XCNIvy?RKl*zuSE@^Ijforc_La2CVz2U3d8- z`Ysf^8|CT#5Sp>^6r}Vn+f5w#^#-g?S}#3vPeeU2Q@QL%|C`d-6m?~nEoENQTk|bB zh1o45#WXM004X@U?a=EBt)Fc|QM3;#?rRUwI@Wc264fXrKT4xfb2k5IL7;s)_J&w?scRXV_jEN?(J0KdNPAmkYJ%%yr8~qF99t#)yOIq`LsNvcwBLi z7R%0AZ5J2QfWjJ_meIDsE}bN+%g?VAQ>JDN%Yj-H?&TH>*zI152=?qQ4-hQp>)*eI z%AP9<@egjpB9SWj^844&-MIS^rI-!`MFxsr5Yfu6_!#sJkBC)AL ze!Vq*`HLjWjm6Z&}4!H%Gf;%UnGIy!P#SX~Npk^i<{! zed10;H5GbsW$3OrGzQEeCO<$dHEdjBAh}(yw=Tyfh}Hc@wo9AaPN6-EkkP_hU%?wX zm_-NTyAv4ovhsuEE*3<*H=U+W3eZUzp?CVkJt^z6+H-#Y&-Hv^`IBiyrSAspS5Um> zmv>hqlnrVxK06rVV;{mt2wt?H^eTROX<)vGiJ9zu)2Bk{+8r+M_X)(G#7FTvSyUpk zXk^$pZ#Vv@5}IV4JI_WtHe(6_sUrZ)j8)ZNICF39Cg8N}j%6t;Ll|VRSZo6Glv$a| zG*8tagVMY5#XUg`*tWS?GZq9Jo|D%v_LZnRTdA-LrE?Wq zE{li|=gY+uK3LMs(c`%X{inFA|mqh>Fvb3%vt+NfzytHBt5*IG$ zWp>-G(Jd{ZrQ>DU=NVEYCoV#oGb$D6Wy!q&3ODRb`hZ}b*fr0u1~RN$ShWG$5d;mf zrRK}50uf9YW<3ceYpu5_w*ZkEIqCBL1XEW4F`P2=b{HA=R^)VQ&+16td?WKt3gkOP zP1@kPs8B#Rz(KxpGpg)J@z8}ajMSjin1|gLDtN`dl;D_5FRI$HX|_?90%jdtV+Bxl za1E3TadVJ&obBx-qAok3AJZ{c#^mkPDrCUr$TPz78jh4U%U3LZ8_c`4JLb=!uZvl_ z3*T+(F&b;XDn;&9XA9!$E#+3-a^pKiOxEDDYFo$H{kX4PdfMGLIv>)EU}Y7aT?3wt zOqRSab$Wr8;>O;$>{eGD28yqO-~(mc>6MzOB%di!+wc_?s+IXB&+j>6x;W{P&u?ce z`JZRUa-zecxtAj`eLOVw`k-@|w$hFJ90JIg1Ok zh_Xapi#z&sf3DmjC8{j9bZE`KWe)E(6r!k_Ig1p9qF@3VCp`g_&p z2p`xe&sz(y%*&b@EWIocSRu5)B!G@n>w~zZJd5}zxj~0^1STQYP{87mz`V3;GxoQv zOz@;*6N$-RB z=E8w+aF$ePdH@GsV0}>|mAeD1t?sj%Yq=96b)fh(4H0%=9YlMM!F?pVx*2|oA%hO< zt14Y|ukoC+y3_R2$U<|06QkwG!Ib_wtPYIc?WnBjVDmXa=xw#cHf zhxa1<`I6fkY;bZL*#FDgxh^-3<4_osNePTR%4Gb*sl5M#u5brsIdQsoc4}&?tK*Ae z3j}b^cOvLsjnF=h@66Na!-JBypC)UIqAhfutRWQkc1&j}?5k=sci9AF^O5(-!^uX5 zD2Cv$s1Y5TpikQ18=IyL7SqnPBSelvgf5-$cx@{+7V!=MXYJ9DxOBQnJ=re5*!{k; zn*Qc7@i?{2ul2T_)#}J|J+)n(Jl8j%=~wp9;Leew^K1FOZa=;d7$(aexzgd`BnBRs zW$kCuvo%$sJfT!WT8qlZM1pIiG!`fl(nm_G_VslmWivwx%l#rxDBDF2nWMi+IeGh! zXo6hh2cunZG{C&jU7A&+z1lLcM=sz5`p7mvzi_2o*CxD8(|5^HSrUplFajYB z$y@?Tzo-p(7tN}={oSu$7L?4^aay2?W7@+Ir7h+(0Pk`HphuqWcd}vgz>bqSEK8@S zuGqBJDFLUWt@L!?r_BSZiU|7Ke{WKQDD&ape`Lt%!p|OLN_*7V0FV3`#-S}nzpqzI z{F!Z+Se-sm8|s?0T5Lq+@Mdg)}Yvn+aSbU&tPa(gYe;-V9q$NLx04XW2o%Z=?G z+&t&cX7A!ta(7YIO9|;mZ=(q6Tt6E|iZfI1S6RK=_}j5$y^W@~`5`$qkBJR%;>hho z0G)#=HMbUi+y*}x75^-?dR<)w&zZ_j;(0+^{b*SJ@ui+oG{va%(=_1w@$%w+zarZ6pb5T9~a*4boc)J`Xt+q zI*8>a&5jYIC26JEG&y|5YeyY#S+9)OxnB!=RU7rVdk0ZzeTko6w<}?PY6At#NWm!U zBrGE7d(+35YBmKyh_$Gg9|>T+st~KM!mHu`QQSg`g2HCGBEVjvg&KP~#}Ev$7G@kX zEJLbuk!V~NltCA56gA;=c(CIR*m;5;^i~M8>7IEGT3Yibux&>|yXd^sC*&e885Dz5 zMoi)>NMcBO(yjTox0AV8cD7cejZqCpEn?A_L%KGt$;b{N3W+I)>ohmP6|jE?-#62w z>sERH#iNO_snVfFzzImB=t&7aCUvzsQOX6!Nm2op>}ThFr6-xtMjGBKz8ahDa_y!p zE>yUNXYx>(PY+x#BvmNzmA0S+4+5I+Z$&e2xwx?(D(2Z! z1+dpXv_W2XbH8jeY@vMxN2>_cCSkSeg`rgJ{D{p zx-*x^(roa_+vW5c)a;5 z`4*+zz#0ECAC?BO-Jm;XQLm}#)%uzTE~eSAfmuv6hF!1cTZvvtq*Y_Y#PY$xI!(5< zx@6l6Fd;GaI#q?W$ZZnorKlLT7`!s+ABa@RT<7cis-(#-Fbk9jpMqg&v#1cG2aGK^pyw3nge`r44TOZl^LptNtZo|lea}pm3c!f zeM6m1iZ2~wqx+6TD&^6^*+Hm%?qUHKXqm-&+Ou&l+8NH02bRq*$@P9EJVq-Yl6)xg zW8b@?q$b(kDJlNrrYlui`xUnMG8D^U(sGBWo}rVSL29&dS)mk7!LE4}O_#hvHxom= z8NS(eo6w3chw03&JsP-_i*Fn`9sshNHf1Myn1w%$PD{-m1YSZT_lJ^`CR=@a4=qI= z4V<~IxOn75ogJc#_D9OXi1C16p(iCrT4^WPBn2l)@&uW4=|n@A=Zip}JzQ`e2K0~} z(sIe@7IN|8!DTW7rQZQWL^H-+S8Z8o>kMc>{aSq13Qg_#vwR zo>43jUMZbV3)7z$b@)a4-!uJF!=sVvPg;_{W?AM~XL|4-{6Q^4qbj^eu0kPDi1FpEubUHu_f3#F>g7>0LFr zsETk#OqI0KB>>cC8M}|uz)36lsv-hvBJLfLRD3!h; z+!UecvcT{ciS$@7gbl5yuQQ=Gvtj`>P6&l8B{kaUB^%A4IpJu35Vq#>jlX!&JsJ&` zz4PC2EX3_voSMbCA=qMbWU<5G@m3D2gM_@Z`W^FUpkMW7=W@Ct!k0uD^lKEo*qu~! zigN9EW=HC>xK-&L+5NQF`=&3e*V;$XXb*%kLp?SP&zVIW00N8p=hDTWG}|;*=FB}b zQ1M-eaFL$akK(?ag}jgOaq)#_1i_}rdRJ8&^{L0m)*Htf##EJ<_0g@I=hC7WPWgM- zwR**(H0^?I1wHXLwvL;@9>Zv*N@=K*&Gxn7tWLAm(}j4-=ImoytY@54D#U2M(n9Kc zYk4XaTGP0^D*Ra^g=E*D=4{*Aa}2Y=pJmz*X0}?Bqe@XMnMGiO0&Pg#+2nb^>dlT# zvj-Nk4^!eN0^@zq3QC4>K+AP#?U*Y$=O2B%5b7V2 z+I0($wCBB1xV7cg2KG-U(thI_>_5=|%K4OZVb*^9Vh0REyLf8yjq?E?48dhuk308h znc!>&j<(-jo@HsknR*?MJNOQrsP2Dk_AA8K6LR!W{!`kJg9y|9vZmU8NdbG0`= zcZxw$$c0mzsXuO_LDY7v5u<~J$)(IBX{8%{VK*v41~CNwd~7XO)i`^md()}b{^Rt8 zTld@7>e#<^p7$pvrghrESV%TBA_S9$nbg{aIz{1N(tj;pm-O%KU8bZZPDZ?nZy7yC zOM(@Oh`;zN))Xr#07*bcJ+#}M-@bjP_YT<`B#^&)ZIMwVrx|5hf+sA-Qb=BaqxYN?^X7zF*X+WnTxc+IIg7;L7 z+rYQf+vol5jo|y86}??ym5zb%0kOLVK(Y#W9}VE+Px@P~aU}9m2$1jZ)%`a;VXw`L zWlTwqTZ~;}>eS5hVNB#qAJPUY0F_I!Nr#0?nUZ1?>LF?FHH^cP)2t-viKoREWm)m% z!o_T|UHFbOg*-_2OV{p=fgJR%FOv(ELxZ)+>>*8AUU9X) z@E0-};q-^e;_(~BH*bN6|MbvZrjLI5<#+g|olgdr$5rr)Cz%dm-6UJ|q2YH$S9gWp z3T&1^VKi`hJ1u*!H=cDeZJEP}%2lEeq_t$vD$jr$^B?67P*y#5Yi~<|4EI}U-0e0x zc_UBERu)c~j909{g+q4vWchwm!Es&p(y!emt!}5)TOKX@eSIf}wWydS)tFBQ5@t98 zEeJPBQ*@eiHyiT(F$NPQb zNrK~rZhJB338am7nO>!bgbmdw60M^aT4_KqWW}h4PKzh1^VqNH*jacYw1^0>gomHg z6yo#B9h+%aQT0ia*3dvVg|G^Im>D8y)l^NF*#u*=8Gf&uSE6d5r^NE;s{PeAZ}EZZ z{4t4VR-kZhU(IVMNbw2XSJZU~l1Qz0O*Sk8dxdw&a8yRfN*FG;TbWOKXy|3MEg_ED zmCDeATYa(**Ktoh&yfWsPZ!rib<-^0a^4C@7@;=#`a9%zn|a-{^hJ6!_@m8x-omCX<*>613B=QSm!dFr1wp3w2BqUoFB_47Yl z!@ufPIp5$LMD^=4=!XaB0R6i_L4Nt$ueZMrN08?*fu(B&ld8ebPRld1HV*>_nL3eQ zba~t}Qi~j!6#HXt*LQ_P{*Se@?Q#>zp|Hwb1*O2idf9W@C;$J4E_xRjyPfQ2 zKFlQ3-F9q)O47a0ZR-T5BYCV-Vmq97Qer>u5?>@J53PtgrBjczywe@^v(>(TueJ~7 z=`;--k}M@Ay!2el#{S(>1;S+k>T)mb=tJ7b!eJn>R9K{{ipgfXpJI_o__of) zmR>||s)o4)z3sa9cd(5xFL$Y@zFFIBo8mg4$AYsFn|g8j&ijCHfO~1F9*#-Pz7R)# zy}5P@hSG!Vqph#WTP5NspXMrCvl=H7%qq?$PwFqaluX9@z3#QV>YJoCDyL$mkjO6i zmKfgU8e3^S<0bIqm`43oK_1-=LlDI^_VnjPoin?6a5o#;jnZ8ap4PjEme?+R@25|& zrjx@dLcZYuUO=J0Z@0LA@@r+jP&cy6^Ns)FapC&d;g%%0a2c7{=qd!c*@QrDk=B^> zzhE|g^a^E0Nfu@@;=;mM$fB2r0ha11;R+7RgTt)( z#S^E1cm{E3ZZB(>NzS|XJ;Z$88^$`(1bI+*Ew{iFDMz-9{mwhp#v$L|Td4VJ5nnJGV5MNvU}TxQu~T8qb(Quyo&oj{2>5&3z9(54bM9jZv_R6h_8ZtTKT1&b3jLM0--}_D zLC0D?Tf5YFFyB(5@1#wmty6pqWk&$M&Iy>kh+SB~g0$AJgXa=(mqVZLr?fH88|3%d zqpu;2w)bj%*E$gO4RbaL3eBpaYoN|4BwUc?DeT?-Ogr2jT{>+Dr}n(V5WcnNLUPNHX?n#sIf z{v-?3ZQJ}(EXKOl0T+tVU*^6d{HDgbm~$D@hF*5z*li8WHM1YOW-GKhz?SZnrt951 zYH7OXg$KqW+*VYoOxM*11wNwgU1z;*Vc<4uS?eq+_RocRvFNWr=e~Atl@Ac2Uqjaz z>lo17y0SCo1Gt~7#$GiFkNd#R8${I>Nnw~Dvu6%OGNG>adiD6*@Shs!8mmq>%hX*D z=2~dowjj-g^&Sr2zX`5JE5R7$?&nJ>Qy3hP9Q$=tskPT8eKqU~{z29)grYgVDj1kk;0@_RmlFHzFG%f`7mfZycbWoAMfE;U(~NnJ5K%hY_k2L z0Dmxx{y$_FT5j8qC0f^A2?_Sv*7v08f=qBfd!!%Y+}^2r%j%H zRNi5lTG)Mf#jV_pHr)q?c+HQsb%Q>e=nMV%LetS&>&?qEM`udYOku25QESh5C6>(q# z{SQhFllu=6j1%#G#~$V}uaUIicIm8+C~4u)YOSX%bLq%rTpQ3}{+9hzID(6>C2rQj zlhjOH9TRQ4U#tluDdkIpJ;U}|F(njzNoU(3<*>_9sjN-elq$`xnu9zHVU!72v)gnm zTM_NtA{iT={(!C+5!Gv4#qE)wRdm=io2Ve{|#R@)nHDMU5|JOJh&BJX_J~ zl*DH3)jiSmi{*QA0(O5ls4C$cH`sj_Vrr{?jb8?L-oW!+-dAVGDewL*Q^Cj;Er+7t z%awTcq^Rxv4@%DXH(l@R3YlMr(k>jkFSKMm&LQEmeKn8o!Rgg|`5VDihfiOTi#*@) z#KD567yBH`ye<0|D4g+yG_Jjh7=(F#$77>Kpd&Tpu5t{vq>2p=?bfhC>1WQmd5#A5 zTY_9Mk0}tUj_)}NM3baZ?-1>=|5{uvZ{2p;z6@ps++pGv_#UIHJJiu^=*XoU|6kLkP+PuYy3(zzX)a`@z> zhm++jc5JV|MJ3V&R7AxUmW?^Yd^TVkr3_MIqib6##I*9AG@>CS%FT>P6U(Lz0U@xC z%EN2qnJZzIQstqL1-3IW-Zwa#;;$cw{vg;H(sT{Vo{asF&V|Q7Tzh}X*lI#|$)Q)Gj1sWLeO9xyK5_Gq|rK8cpC(%XiSDP ze#NR5dRgoar4_=-9IP8@!-v^=qe|#+%cW@Cg0bm5Ohp+FvkYcTk9c~p_y%R+~*m9N=p}vM+v*p zGBmHy%*F>`XHKt9Tq-T&j)Eg)!~m*KMP4o~Q0)m&9Cw5DH9S~%~l zfn@>%6Z%4tbw)i%g)Y^^hX;L~k5!EP9DO51FMJ*jTje$=R(`}zD4?)(4ZfYw5#*ug zZtvEf@IM%N$B%tSZ>OiqqWmbe5MHI#pS#l^7?u644e5tQ_;O0{;eo{|6=_O@`dNWx zTP)x{Q-)u@j?epp{_=p)IO9*3gp>iq*}#phK@4pyJYPi-TXFD0C#&hS6w_P@B3jaf z_A*?gBcjNj+e-2)VOTcSBT<*iR$?(4k+6w9xT3z6Hn|zMqAMC2`Hvl@^t`jG+cIiT z+a&)M^|#8!V!!K5FQWu2Ox%ofT0~#wf(D`Ln&{9Y$^rr((k#ZbZ;u5n&W^~|)PQfB z1Tyf6SJ)k^qsaJ2?DxC<=@E`gM$1gYj0bbDf*SapL}M;XlZ$~96xW7D&7dvEbov%bQZuH0-7rMnG=2ySusSzP zd#t`BrZd%KIe}_n3ZAEnS&^0@8~)C7Y472gak)`d`-~b+bp@*t38XIBUxwQq!8KS$ z#PIob7VAnsdORPv=2zXmj6c3(aJ+nc9;mJG(|8XXFF_(gM@CX2g6X+IJ+#NuwJC-% zYm8}0AX&#UvgU+C3`z%Jf;Z;iBcGp)_Tz*hb{lFk5=rZo#N|zbs}LeJ?Wx>xJ{AQBtLUum@ez7$BGT zqaym~8pL!|G2$Ft-l5+{62Z@7=g$IYud3FMgWmmX*5$`&TevL1a1MTa`4_c>pbztY ze{kcrc0S)7=j!0P`aFl;PH_`{Qd`#c6i;~yfIxV+BydxXsm8z~i;IYU7&N((fr7fb zy)ezQq!jT?v9S$TxB}YB>;AFqO>apxP=qiwwu2?=ARW)~SYW0t16uq<({Ml7> z;YxY6z%y_kq8_Qrn3;+P;n=FQt=r?lEjo4WX{(dw`W>5$VVO&SD#U%#6=e9gv~7M_ zF`z!rf-(vWf<1Rj_vQRB(e^}-z3<2NV+u>hv>yK?bTD{w7L896o>bb42i>WsSha3m zpSzSrBnC!>kZUA>!o;z{Ck|;7r|;>6=URvl!wPg$a2h`_tY8j-zVDDeHEU2q>|-qJ z-g+2B9_M54jX6nHb6r_NM*`oYA7>ssg1~YH4S@^+3xe$7mBM};S|_O;eb{ZP8LKwA ziLI+hZAW9AVw zOQN1vM6+OXdvFiNlpHCZI=F#!WBI#*++fla9Xm62TovI_?CU&v;q7TWp9{xHs4=`S z$WGu)vJRG&VvqSRo>H$^+<#Z4qW#D>l)_OHjlbX5SIu5%{$Hgax=bkOFyHuFau@TB z_X}?kbEg9z}v2u{o0{5hH3U2QzM zWlKEFM!Zr=mG@srT-uCg4)pn#x>wS+j59i8Rh9Wt3WQ}PilQ33Q1#__ zntT~6k7(*^O!X)rj1puxx32tFaeO)}h#l%~>QpfGpE}QDlP0(@kvZ$qc7B}ikEL-i zB-ay<+$QcE=>ehH!W<>2pqv(|C^Ab1tDXd_QbD<)fav&;9PMkcuh8v<1Z+u%HT*mZ z!ml4DHx>Y~S?QwMal_c2vC6nr?VGLd5_xbDttn`7{V2YW*+UW7UqWN#vka02F|mwW zmLfGU>k^|Klb~lX9aD`>sfv?E_O9X%o2k)qg)|44vkrp>Nc3K^U*PI5S!Ba#hM-cX z5Ft>wAYbj+!XV)Us4@7vl>eRWTOtNOX_c9Q*p;7k~gG%8`3{1r3$3FLU% zU-VtR-2Nwjvu_1MzMM((m9P7z1|YG(ps_I)V6vj%oCO*HV|`oGeoym85y8jegW8`m zqc0M&q&F_T6yx65WkZI&p63%^HPiz7O@M%hxBq)VTx&O1q?C9qgVN|3MTNIJkGWT*XUZb z&~U5E-q0K`yts^t7CIu8fxp4lZ~eQ(auI{L!yWUj8_~v!T6N}rzQ=x=mbELU5hHgr zUW{mQ-gX&ndaD*qK!k8LXw-o+pF1iB<@pvKy9&dIv0X-kZ8qx09|4*5$*}l(jH>4W zvz3-}zR7BEw) zn|gNsr2CY>cjZz8Ni}9C1x5rj>+N3ln$3NvfgQ{)uS^+K2c;Vd8&x;m61LzL1|GEx zddr~8l%LeW1{_}mk)A`3XmYWvslMaSTuXgU<(1Qv;^+8S$ZEg)eSwSCU_t%YWmZFJ zugj&K%v%0$laC-Et^JVe`AVG|eJH703EEpQ8dlxi)KA0cJ`$sSYLcIgNot&5pnX$t zi#(TWW&fS73O%1UO0ayhFG0%gsU*t?Z#oTMFQWkQqzy*bd;S1=aclW80jFE%&e>Bp4QUj6+t=bJXQx2;VZKz ztQr%XC~(|$(@Lc*X9&}xw%(71p5;%CB=Ll%RtY204K0hRDp$@l%xPH@T@T4Iq8$g0 z*pF99#U21Uw^AmZrn3taX_qE986axg@x#kKp}42?dT3k~@C}fLOLLJXub~ynzA_q) z-953(@C&!R-I1nE%w4rA5H$11MCDj7NrC> z6(+MyX;E7&=1+$~l~8_U9$7wcPic9N3_qpZ1s`ui))7n!{xFMaLR-?Qr30JZl5HG^`bxJui0HH;|FDEEoDJ+17qpnYD@ zkLfwoYVjeL{yFfr8;7F>Udjat?Kt4<)ZwpvVmT}3<1Pzfy6NkyaNH5)@-m|-Gvyf* zd&^O&X4ETXQY~?zlsJRQQM7XZ1t?L}MbGm#zH(j$6sDVoZ8K{6kf`b5{kro)IU2lYZ0 z+YY(liR84vr0`>zkl{wF3j{7a+F~q8{GTiNiJTOKRc0e~Dvw>Iaga1U+8?8ujyGIN zkiD1GL%7sUv%i==0xOERgx{u5{basZx#^AK+THi<6D*V^opSBQ+sA!YNHpJmU>H&u zhE8zaNJ>!$3l_{C1Pp2p-7c0e0bh@2@|JGePtuR|UH7CTRV@!(Fu9m;)w8{H{wV>y zxhsa_Z4{A{5r5?NZ1Wh{;)8+DBaCUS)I3`Ws`9f%O$53-@I};n zy9)3UWPDE;ZZ8QNPh|A^a^Wrog4{{IVV>)IUh)53e*dXMj>+^>H{QFPDZrJmSmSlh z<(5dO-#QJgwP%8T$718otLvcmhXmINmi;uZuFXu1pyl|KVRq}jehkGpTEN1pIgo}< z8sg~&kE7Qmx{~0fUyu9Oye+AUE9BSXabGp^ovF#J^CjbrlK9WW@p{}DaSKdgz4LLV z6nB60&#MI7Rv|oj@dP)1!XQLV=4;k7_Zvz?aB^uE)`~!eQS2P$H=|W?KZbsuB7Nqu zy-7ub0y*TN6^%V!*BlgNoI5cy^I1H;{?gM5u2W-(AiT$cG1K>UV2i;L? zw^s;eE94bT^^f9nq~ie**uJxSA0dncIdgyYbN!o-myD_x>?>}4s&r@D@GrcOGjV98T0kz4I@wHhr`>ra-;FoV6>|HH~f2j6KD49N|H*!#q2D3h& zb{y-#$IEe{Mlz(aYfhdnf8U_j7jj_QCZ0fzOMrlUt**8a1@7CL#At)q&+GoRr2Qzs zM8YcN@px?P5rt$T$`G_59eQ~-$f!151c^;5By|z$Qbmk}NF1yPu3b8zZTmO_LP^kt zY1V=b)6BDoYPo9O7~4CRswgqjoY+K~vK7f-Bt$~XR)Vq^(wbD^W2P>lU{NEfVes_s zmc3GTgV=2la3T_gWTQ*`6TVPQag3_|xWQ_U6 zu)kj#73jNwLCq^hjfHHjr%9`(NtwrKzZ)=1j>*)$X-x`#A+ep&GZ zB;PyWS01sHPgx2K%DA(sL~OZFpzOb&GIaR*9l=+B(gU{7jq}{8_d?_q`UAEK4#7sT{WDdGCzjAYT%HFoj=PMDWAyWD!7g({XcUM=|<(7d;RuCn9r{ zuSet6=W`K5Zylor#5jri1(mc!%H~z?R75Xp;Vtr9xdgA<^K+A_J5N}7e?8|)Z3^M8 zEjgOu+2vj?2SXO037fXjTsbQXPz#*A(EXQepSm%{qk#`>_heT_hpD8U+U~*;=_YJo z!o}Wd_RC~utVmzNK#z|Qf$&oDGB*_R;Ep6nc2b(rJfi}0p|ZkF!9-XemrJrU)4(5+ z+P!7@DS!=g(^fH_PlpJ4X8myvnwNz#vWX!Q@@#l+l%;A96VXixd|XH5a1EGaPeWYO zGatX)UAZI%A!j%9RKrT-bK$CC@{j`otEreRxhNeMOey8(9)N!0L#iqWPqyJ0PfJ^_ z=41*7X0=+91P?}6f0r)|w6NiXTxa)Ei7pDFXSFA2Cjsq!2VIs?vc)+7?l!A>t`VG? zbp4v7kv!q~+@Oz99<^COi+F|y7RW4vgLGZyY@ukFR;X`VzUHaEcDNpU)ZsQgJtE_K z*s349=&u*Re-Zrmx1L$}-8T1^_9uKPCe!atn11YswU`T>Ks{D1!Zs2_A0pEi;^~4-JUnxYX@7A z3f+B)TG97%LZo{U{}2sWNS2*fhm4}+L_!``s|m=2&g{IZ47C&k5`sX6b1)D)Y>M>~ ztryA^X3rum3rSvM5DuCDn*HceVhD@*UDWuV?mnJ!TV#kHS-a&??sv-@ECsVOnXJ<+ z9xwYnMjCYL-Hbg31k+llGLywsX_5z5H6qB~tLhI$^deRZ#U{qK@CrgmNkQ_c*grAkjX z1@t)$>wYiL1F-$5kVg8JXFMx~vL48dA~e>U3QHKEggO&NCV6V zuy;Rv1Zu!nrySJ?o-GpA&2`^{)9SwA*$A4L4oj1K*p;(y=$zb^?RH<=Z7;2*?v;ib zE#Xv^JMD&7Zb;k8|M)?jvBn^9hbU^`!T_&{9J`dKv~9XErB9>UMahfA2+JxOWF8x@ z>mvAQ{vo1c+}Kk>;Y~MXK?6r3l3seRj$J|3LfR^lUtDP3i0k<8a&{{%+CCR)n!j$@9<;e#Z8|wy&Vefx0*UJ!7-=Pn9r_^(Tx}BJuX@DqE zOM1Ocd(mLHsvD*cz9EeVyj;_~+o8sepyMt!>f5OC)oKT>|0OSNk*jZ8+jsKeIZl1{MZh8Q0e;$6djD^7Hp@#o z>~LR=qu}nHpNgK})>VMtH_!ba$+7m1?CYBQlLxVOxZs=D5AW8+*uOPJ*&2b+gr}D_ z&@J;plQ>6^BpzGluh--9Z|mLVpIB=;hU}&5g|)fx*-Y!=w$ewu5e4hE-4_x&@BJ9v z#(4tz`T5a2&45Z!*`ABQ5)syq!jTA-Ju>2ZF=I?`vNq9?w6G`1th-!zMXMqyy}7r$ zRmi>&CNhQEbM}vnbdgoqBHXdfsC&muhE!Zy6`CLPmq2xUk#&Phs2Zv(N;cT?g;f%k z1D1*w85zpz0Gxoc%${!Mdj_M87-y8wV10-MCAM?n@@8c1ewp|!qK9vZ^z5cAx*Yr2 zC`RS9MsD5b3M6N5ZlA##mzH%<=ur)a!)jQV+zTD9&`#Vf^T=8W_udH*Mi=r7p|0{& zMay{ORkU;_(~KoemRE_}jZTK)`{9N+A*MVz*mzhPipb=Uhs(WcEV%19xpp&76sry?THMGe zn%ji0x?O(hJUoYby;fVmC@)g8Fzoojs&2!BTrMf0m;$!98^vU~QaMik-RJoVZ=T$W zolX{_QL}!&TLcx%gBY7<(%LNtXa`=`B`>$m4%wR1U!l#14|me#1{3vhspp(2JXC=^ zJW5%Oho{sAOqN|R)BWPl>e8h|Q}DGQijy*)pl8Wq1c$oK8@^GUkr!Z@V8XT8asx)r5C3;MA%Q>yO8)f-Q? zv~xjY5tfu_7{@xO`#eoNXdd*_i|I}zu_v)3&OQRXAVyBZQZ*JUm%bV5qoQReGF7en zp`k3-+q54PIDl!GD9XXaZahf0N$bl2Z4K|KZK76cTDE=5j6Bz4Wz`3T z8A1R~MoYZb>Z9p}uc;WOYrq+DGhstypGSAd!N6K^*=lTPr^M)Db+H5r&9=J+*E%^p zk`|y;uzC~<$Nzg8%OIq`oteMWNdhN|tUlCFp&%@GyTnlZ-%mnZ2 zd2%wqn=v)Kq(!IuQjFA}?PX#yTwRzga{c9DPAF#gx95FZsez+{M#|uodL+^0QiUn^8*200c%WP=qdwSJQ<#P2 z&MF-~vt)UhxM$<7aG9o}+D)qBDRQ@KY69tMOSye~EIqW@D0ztNlG2$ND!r2askoGw zr`-09b|i--3WpY^sp^q_{kCc!y}!c6%tgp)l9=5Uvg-v4{`3x!f3@ZvG58a;QRZU^ z!N&0AeM6v=3l7zIy{+TMDlxLPAuZ_8Rk>^iev;!1{}k!ey0JST(ewDOhpZQFtsRs| zA$3{zVm=8E9KDG?^aUw$!O2EEIoQ8h`}^~FOdcsL0n+2WG|i{AxvB;x`~xj-j882LlNW{CaW|NX{3!g%qqr8%~ZEMVTgWN71HwflS+~2fI*YW z`*IZ+bBX|l5Gbj4*ayMJqnx}*=XeMy!^SsZdoH*NxJoUpmeQN&&^2W=xczCsnRX4e zp!A8VmZ2QMkV5<1>ZR-KfhysRvCE_hlOh*+SW4sBnfj=vNt*5S6T?6g(rwc*^YB{9 zpvTrQ0~>^HcV0>0%YiI7`**M#>bxrWNHG7CB!XX*?q5F|XPWWdtZnT#`su%H`uPs} zZoF+RDV{EZ)pHigqIkY|P=TEcH-?exma|Rf=8|Gy z!$r0304_y3+m(06+7F``fuQVtFUhjXO-0MXOKK8ir|6{476EiG6AzK8saU9uE|T*g zULUQevSwvtQ8&CL-1y<9(@PYzNragq9@J48Y?-)Pj|B>rerzNHBR2BV?+g17bj>uuA5 zkLRXDE=zvE<8jbW5o7+D$Xgpk){G!HOgq@(%%LDnKHg-~kf>Ly>vWm+VO=$fjsV^0 z%O!Un0wWSMnafV=KJt{)J7yhrK&f)xt>yydTp@0SuNHXZA+M43s~w|<=(2#X2C_+Y z!xkiLS%1@{Oo(aXNW%dH$ydAcivFHLT*ChHr}kJ3 z>kz{AU)qgF|7ahq7cpudimL56=CJf9>W5B z82yHX^r{GYnOIU{>0y~@5PTyp{liJ||Czhe=C*kp3^}9(M5;6%?~Fb9|37qzlc0|r z&Az+a4{fHgEnAWa0?&oN4{`XU>8#I|ogWul_!fIiF9E$Wga-HuI`42=KS15_>4pcM z(XF4ILjNJPC(C}R-yntqGpcOeo`BiBatpLo{j#rS7Eu$SpR2~^v3B_Jv8u}=Wq2Cd zLSd?VE1*=vzg2SpwVhRy?!CaN2r4cx;o!s5o^h;_>R0(Jw1q*9t7X%n`mVOQo7jCCCV}~#g=&t@ z<~vE{;kJ@(go>}LV%F|KAgFLM_!xLDWIVG`xzpBAZ~|3PH|KlSLpM!c;B`DTSD1A= zu~)p zoD`H5JF55hlUgss0^{PZiMh<^A{$)~Zc~fDC)Mn}2{oEUy>DlVvbuD0>AMkXm{3HA zsKTAoslCL>M;XctmQclIBz~LMaz4+!{<^tkDOT&r+@%L~QJkCEXUM}Yza?v}h+`i8LpsyFtl3?R>Z0B`QHSiSJuC8ch^> zs~jf}2S>7Siotx}2j_~Oib-imBb15SI^o}B1lpXpKTX?!zbKaY%Ub(;&e&*w^8Kv? zN+;yd@BTG;c_^Mn-IHW;di9>%`R}E}2AQSN00Wl#ic4oJ72wlAZf>D!as|V5tJI@a z6VV#2+b)FS?Q&hk1dEk96ZekWhT0Jx$971wsft@H>U^w7Z&Am}qEsxcxJuI1XnU$o ze!6`e#r%v@1R=J{BaW8ZRkCZc(t^yTF}rLX{?;kv7WGtDfuvE5!Wrh)hxYI0aHlcEs>)rOWQOh+GT9_zrAM#!y$aM= z#j1Is*qHdJK-@^2)YR^?^~%Y@VTl=xrXNa^xBF6m<%6E>DlD1=XM^F=-Signv3IzxyRRhp z$>La2S#rWe43nKUF^WT0_wItuWJCj zkQRBq+4+1IZV7P5%6f`bK5fq639$Jc&yF(Volo-X$@JgYJWmzA|KM*G`o9)bK@w?a z<lFdamy!8-I`6 zt&f~k{>!u>Rld@8xm9$8lqE@5F`80)D%9LRjgYr|B|hf1>TlQuu7F&u&Wrc z;G9|ySa^hy#efpiX>5L;eoOTgvNbq`3w?0R^dQEdnHaQkD~VQdsy>kky^_2f<+-*k z$gTEtAd&a94?Uf0C~pBL%V_|tIBvR0Hx@n}YX{f{8|Hx$VL=Pa9UFbSR1a?=eFzQQ zO;Gh!_=jm3E`@g{Y;+>tP=gB$REdCeZ&URekHHtu{fo0Usdgh&G}s&WX+4Wt|FGZM){9to+~GR20QCRRL9B#Xj8V6C+Q?+c==q6SUwK&kb~4|{IYI<19>-8n zv$cxxB4eLrcF%P9+r5NYnIK#D;saWLgbYthl49jkWf?&%a^zD4z{pn_k~ zsE12LpH0uM1DfBNFV(%Fsqeg#rUiP>!j7GFfcroI({d){JJ8keKI3DS;N;(^!@B6y>_CM zM*-x1e!X6G3LqG^B`F~+<~qUtwEcwDn)FoiwC!J4Uv{~I9o)sw>%8)`K~d4<=-`f6 zX8DC_NU4hH_7YshibLx$`X(H|!5p`M%DfCeUn5~LB}0kQz&k^R}MT;{V>?=73fM!g(M- zf;&-J+E2%aU7!?1Yfqp}6m|;B#c9qFz|uML*!qoqpZcSNSTvHMDZQJ{%_5~^WxMC3 zW(Wr_N>s8;DT}vbqwN@jbmbNdo+ZTP|4oEP*^rV^n|{j;*45qEbL{&P6BQ$o6}soqn4!n3c_>g)22-h!B`R^X zqU0~5q1dPH9`_KWBEdtM{M@1AH81Nq#`~k%x8nc4`ogOZcc%f_Urzzx=kswGaNZY= z9x}x~+g=)8P`2#bGbiT_pzlxHm&#d%h74b%`@P*ZJ@)N`s{%6BNqgtxxG+OXIL@oN zFDqfnf`sSRAYYDcZS}X6SS9nYm&WzBF_D+^cxXG0>&Eqw7Riv6SvEO$o9k{hwU`k& zw6|8&QTytOZagXBO4{2hWz4LwTyZ828L})13d;FNFlw9lD($UMi z5b4rniNbssVPdf%NJTxg5p8f8@g+;_vvTfrzus=^`Fz$zOp|}560AL42&(|2Y*PXW z)oEwxn9wi2tuaDE4=HaP4T2TD#M+f=i@PyP{ln?HsZbX+pFS6Hr)QDcLG$@PPtNN` z=&iBv=|sWX?`;)YaNbij>@PS&(pM&9W>6kipMzo-r%*gHQI<`;a@TnELRF$Xh-IPi zoWWE+KAkSTWad>L#v#!6R(#lFd$AxpW7=H!yLlSV6dWJd7}LD(lFh@IM)*t% zRFpyrSxYcf@XyDg#V0d)LovThcaRyt!^|D>_`QGbU$U+q-s+&G_8W% zOL+9X+^E!h+rfyaSDx%6as7*i9Uk5R4iPpye%!zLL8~sATvd1OcDLKdMN!+GRY}T@ z=9y~ybNl!>G`m2pq0k*5Vc(ec+?Fb#F^dT3B1v~r9M@e-nS8)2zY1GAZwD)rO1Cc7 z$7}R1Bk&>;S{XG7001BWNklVtoo>XLzld@ywuecB<4$YA(mt zvk0?YbABNidU>xOV6TSadMuQb6wIZ<>SOJi7OphYvAUqfN1sU@R^}coP?BCPX61Af)u*{T~tM3kC^Gyhs58Oj_yrmm9m8v15l$wqy4qii+J3MXvu zrj7j@u3SBp7%9oPJRDGLu-@N2;Ncl9D2<*0d`w>Y#9V_6-N)I>t>yg|f;7k`PYASV zW7j?fb3kdu{2=Var#=u*Sb3pDg0Tz347zhB+AX24Ob%$tuf@sr`BV+V-Q?zBLcC{o zN!?)!zrbpHKKYAPneIf$z?{FkHv3sP{1Q}wpLVhIlxq6L9;1QvkVr8Q-0^#th{40F1Au;1l1YtjDPb#}4k>u40^hTG@fW z)x6t{3$yBVb}7NYesfXa*EQE`)8drfVaIeFR|g~-gY+W^`wQaZd)cGwkA}x7r)$`*rS-UELxhn z6c!v}KW3gA+0;_hKz2Yy#vv=sJ-kbGL;EzDv55LsE@^d&k!RfP6zp4yMC!I2oj02W zOcNxOe#EVNqh<>o+Jan4&ruBD3R&UVl$<=dR`!MIBiKG72*ujo`w$l+Pu4Pe*p?#H zMhHXDp=8CMoC0ktefWI@6V~xwJLJg%4nmFYYG22HRgtUNOpqs_3M7X>3wj&cn@oY5 zPfph&NY2;YcFIDUl0G*j``Rw6lsU2Te+K(#R=ssstKR9`c2yR4fOt zZ8A>0HYA5!f%S`e@m+TA8n`Ul@kaKkgA|K9g7lEcS ze)%_X*P`4gu0$J00`2adhUc9g`+XGc|+ig7l4uK<$@`@Cb^g-@)T*$+}8fjP{O>L)VQ zi#p5LDL&4!a6;y(aDn|e`>)d2ONgPmIB-p2pJv<3iij6NfURa(`^rx_5%h$yubyru z9CI-(O(~VuUfex8UTw-DACP)Nxpt%i@qzYFY6tk~Ku6M?0-l;eE~m{XFCs-Oz!cdU zs3;cg3-f1b_;XyrNzZj{keAI(yCW@-u!B8pN!g*YCF0LTEvo99fG(e&IUdoIICNL~ z4ODzxrYRS*T4p9PWeqmb4q__UaQXq8tX)|zF`PBg-m`ZS%r$=q`4XH-vK&!tL@tL| zAfT@}R2&9Zv!eM;hX17j7iDPmy%MAaU50)Zm8Pv!3`Leq-qH{se%~l!8*^}Wz^*b_ zni4lf8PF^<#Kr34L+!CXe*N|LUmQhfeRkFSXd6D7sh}bsnNZb6*4nC05$(_|Bl;j5 z4=#%qj+`tRuxbsXQ_h^0oo@72U@1`C_{hXI0JTJ>*JNWz?B6gOy zYJ{PU>gj+v&wB;l782SNcE&2iQ_AbwWsS=v*gEc|eVsd^5R*l5F)K$As*c(orGMil z5w>}>sz@I~W?w3DbL5tEA=4+xua~1pubEAr#Z!_ex{0$3OX|G6%&aMTGiB~hHVl==dR{f>(vM>W(gno@0K?MUqfAI6FnNU439Rbf%#IB!GJ zHo_cXh_Eo>nvlf^JA)OIjfuq_diIUv-(!tdl{i=JM=O{foGA-ku4ADP z>ifs0&$;jK>9xbj`s#AKTl@1{;VO@d@5y;vRt|fo{xW$S z?+}w=@g&$*sw}MA-y2s=D%kUmb+v8Ga1jOXZjZ;rv?;}}gb>TJzYqa3a;;(z%quz- zakE*Lz@RcOOju^?EDiA`PV}}PEjvP0W3Cb5`+N0ArPA@jmc!!L^k#E_q^W?0yJOm@y)X{qA}>5X z=0#=gV5qF9RE5gRo*8i29I!x;u&eNf6bK7jPLngL_&_oY<__;&%7vH06x3ph=86li zoo<;V3js^~CU2(K@#@R(q#Hek!FW}Eq)wjaATpT@*hjzCg7=ex#`#ghBek7yVk;|HLxJgkd<@zBX zhN4Gg10|UfdqB}3R*;mQL{r|;RlAbEWJb}dpOSJYdZ>E4Sva%_nD)~0@yypwBEjoV zP!3$ID4H*0?PJl749MhD3*bP0pLBI3%*bZF;P9Z}j=gziE1hdsF=40g`a2c0}msL4G3=TUDC_k(P{boS1P2P@!GX zq)yvTu##ynSL%Wih(({ryk@K*zZWT$4WXWgEYgFqnxwK-!91wZwBowln~jEat4UN8 z^eys>WQKUPn5KZf)*kNrarCOC?5_c;Xa#DxlH;Vf=aP6Q9Ef^Vauu(T|Nt5@9gb7Sy5+w#%KI3a({J3#IFpOz34B zf|KJ#yRiWvE#K1cVpe}uR0XfS@=_76^c$K|1Xm1)FzWph_K4-O1YOtsh7!*B8gCyx z9uOX4!k<(rIHl2kU2OIx;Z0ui;M2xuq}?~qa(LMVTcs4tzrNMlk4 zhdFRKcpHer;jj68%}bu<*P=5wBPh#K;Nm*KF%*Le;eNo(X$lL2;AtnCkj62x__V9BJ!a>Li#@jfHk!G zT#G3jOw?|9A=RA0_kF1Ru*+`D>Gp&=u)RqT;Xy~-^xiC|jn;mQ_Vuw(??T?oQFOcU z)o(@n9)3tWCRp>0kfOYvr?|m z=?+hZcehrC#Gq+;0Gyle=l3W?t2qy_uEKww=51T%nFqjBs-~IcKcrG3>nxi80(GtD zlBH)o&&2z}%r!crPK`6%~6dFE-(RALd)6=n76VRDGDnPDtmUmZs4IV-Q1akVCv3{c-l^6V1f z4ucg%GwOIEq0hvSW5AvyWLQh8wToS@i{5`NUg=8)4{m5)TmvV)13x-b-y z7Jvq5P_^Wi1bq&iZ1MTn;QXE8UIN=-0@@rJbtvbVKaCfsZZWO(V4EOiqhxx`4tZ7#hfn>5C$cN+|*CEc}Aelz0sP;siN8Lvkk^9lN3yrDQ_3)wLd zg%E3kzw9h}YucljSO{g>I@P)v@Q$zY!|y5L6)sRBjo|=ANSo)=gq5us_K917btl zJCajRAOE=}Zl@pjcbv+c%Xu8OK4vb>w)=BDudC&L1$+Q+$|3e*9tD-ibT@aA{CYCb z4K*dSok1N%+e#`EkFHcQQ~9@WgM=H>32PE|@qTXIm(bxOA@5UA&)~!<7syn;7i?zP zi%{0WrcwB1(iGMzi4h{d|8Kue?6l>KWON=?U`9i`##ZiABiK1MPeKF?F^}ZOC=DWk z8`ji=TbtwR5d_dHr%mlU6}+O6h~d~BMxRBa%ab)Ji5tNh)!giEAf9TbY|64`x&8X+F?M)Lz;0Z9#>t3eC*IfX-|6~X7PGi{FZSS_cn_B(OlK}qI)c4gv<{6$g6#y>5w-ri+_VPSy z`N6A=%K7tyV?{pg0`G(oC7+%k=tMH3jZy8)ZDYx(g^6MUXR(IfADou`!I6e{J8&gg z5IHoncNC-E{r998=JHCiQz3G(EXg*&-O{NeCik>+T0SK_o&Hi+2T?U4)2pG3Y{5j9 z(WAIwQ5f+yH9(UCgCy)-oFxb`u?4hb`l^q||CqbBCC6x(SOY@*TVu4k5lAtR1!LL>o7(}WA#ax{E)qj==Xqx$XH&JPA& z!&_$$11y>S=FDb+U`$aTq7-W$l=^Jzh!(=|;I`lHeVfNCPJ zXT#byxE{!<_1N!SQawZr)p;m zZkWhC)B1k>hs1Y}ANy$DZm#S`2qvyhUKs@QKV zY_-whc$pS9?NG-h0p*3PIEWeMGO^zK>r9+_u&$F5p28us>WVxsEkS{OH^eiG`oc@q zs9?(AYck`+_E;LJSEc)lVhH6DBgwa}E>luZ;>s}*PWILd&$*_XrtZIcwG|J{!)@z6L1l+_=Q182) zZcXUml)SWhRIxSaEjJ(pYmlZqLQ$$r(HCHsbK zTO`}a&NJ21>$W6AOG37MTf0kUOL8Ke5T@8_;gmgN79klXN`wOk3pR7hbj0I!?nw(- z9sP~5m)VU;O7gp;`~{nLQdo1ht7daKHkfS4>x+6hX_kX^r4>ZASRE`e!aXY_R_P^6 z*ovToqj_?M3#h{$c;J$k$k4*~(};@__S3hU>axcT5L!lrOI;x35<_ctJ~F5Nb)1H5 zEEOf2413Qbw{gmsMO0zYb^IE7z}=w~%JT)yr5SnG6D#TY85TF)$$iDRj+0M21j{SL zyE5kdn9>d#nm?mEh97~}Q_df-{@>K#kK!Ie43mlurdVI^Z2+E~ik&eEB@6Cbd50nk zdIe1IN;V#hrX4RA{;%WkA`~&j6Lz#DFcm%4N__Oj!=jUW>e1$VE&l)_>M(%Qzf6azi3f^;T@V`VN<-`NMl3JaOqgDam~wRxpri}T zgz#)(53^i!Nd<(u*4(u=!^vsvAJ<@{)1IPbVFs;!{XS`U2y}x~HZ+KAF>qk?y+?lW zhA~RQG~u!>+4xD-bW6-J37K54lj#h_r@=fv47EkF)kM2D$e$ciOc;IEd|b1kDD3Wd za_;u_;ncNMyk{BbQ3Giyw51QK_D=K)rzVcidSobdV$+0S&>+2t_E9KH!^t+fYlGU( z33HyJn@>VCTF)jWb3#>jArNJ;4G%$R%VfezL!JWR$(7k?`M6*jGi4`C5nH!eE#et5 z&l{utevWfw;T*-~cu5UDNe1*_sAirSCH1y7R=FJ7k$%eb6A9I!(XNoyUl1HW>_xGu zn{imc;k$q)u}b2-dAh|rt65NcN{2swgKryIwg0H)^ZSQ2sv2NVFqa=lw0%(@e_P+$ zTY$O+zt~tkc@6#F5<0kvbhdXILs~em?t1UVZ7+!N%Er%x$@e?8h= zTM`aez)N2lNkTRChet8a@5%lh(}i;sI+|a_N0H%fD!8s!GQ9+L&f-#-^h8`XS4p$G zt&nNU$M)bE@2<0BuXuE*HWFd z&5ZG(3SVwx+AU>ns~19lSgw3@Fe+%{#5Bx_PBz06JI;Q;-VQ!)VVTKC#7+bO?ySMj zqAOJ;q7~29!%AsTV-<}%Yr*56QXVD-cq6MljHeww?Q;hE3t0GBJ&8LBF+6FZ{tGGc zn;;9}gYeSVQ#=l)fn-xcKqE4g4d3k za26Fr6Y1X=3)yG7qTl}IxG#nV2=6p3|W;p^J z2Hy);^+EFphauz02AlQ+c`&@~JczX^{A))*E2AtaRbfhlX5|`6|jt@r_$;xJZcBT{WIL`t&O6ohphZeg;gq-=6?^sh;OD6 zf2odsp^Sc>(r63Uai>1$#+2ZHmj{0oQ2`YYb`og#u54PSg^=?YxVWv0V6MOdg(2~u zh0HqoI@+PL1LE?}{hvFL(#W!A!ruG3NTL$8k*RSk2}r0NMy`3W&;!W{ni3b5d#`M% zElXJs*k5_OR5fub({km&cw}UcQ5I=dPErSJd0VxMc+oj09;WJtpe~1!S7_96Yog%N ztJu8X3+yj4wTM;`km+mbRO;SY!%d%btatX^bWqda0K8n6a=IZt8Fuqwtma(X6BzFz=Az_F=|{qBl!lP4uV~Svb_Kve;AAcOSGhSc9*qIs_D`6& zfL(3+#nPIIkDpg%Ut++wAgh!&`l5K<>f>e^{`@1nXV%%iN9K>}Rrt|C{Hd!l7(yIz zS$mi-4l0R|Jj?$WKl0eM)0;0IS zoF?X4MYO}9eYvRnl?)+yji{U|@+2$2v@*w&xor69yprfR?HQ$#j;6(8{+cn}iWW*g zn{hNgzJbF>(Gw|A)A>ME3 z9|63QpxERhzR)J3d1#^eKp+Y#Ku`B+lgYIRlgE(vSUoa`b|e6bUCGOt_C68W=jCom zMj>+&)MDECvSau4f(lWFpa=#gggR=o08Y~}OU$x;$HgP!Zq8%G$a zxmIbH(_g=SeM<3cc&61Yy?yjCJ=?Fiy1E}uf38Tlxr8PYNz-#f=*VNF*o{7P1EFp0 zl*_2aw_RG!_3?JFp*=O1citW?RAye}24CO=yt+^;5DRJGG;G6E|L&w%eX~YpBSriB z{liYWooafBF|XVX!sOgIl@F~Jp^u{CgziUp0RcMJ9tS6u;gANa3cfP=ZO_9BH6BX$ z{EutKrfczIjBNNrka$PJg)nNC_p^gP+bVo5tR7fpB`>$-KjU|e4~1KAoEGN$P&#yv zbzJj6Wg3mm8sUwo=Z&PZuxxiyS`lNsaEV*VgM;FN?<}?=-%WDh*w$&gFCvYiMk3eA zWRfLj8Bzgr&ABWf+N^pPM`_utUN?%MlR;tKI%wn%$+;#J>#Q=V`y>kDNvf7N)Afstiyy=kH0L2za2@gyLhGGfHeI1*eDSRE zId!;72USrIOwtkLJVY`dSgzGx1hV@Up|nGrwH#CQE}Gpf>=kDt+dF5abr9Y#a5+Og zT_0>vVZARk#B0Pz(7ONm_sJ~K4qFZ&?P+wjxgF3^t9XLC5}PS0i7$PBr(6mpt~e^h zkj@$#?!{!eOuHLB3N1HV;u%rh4zxMHnbN>fN`eutIsI?!K1x%2!_+R-!KPv@;-*^X z;!(m5l@W4bjBK&&ssAx|ZOe_~K(xUUv|>h#%Ma_y|9|MxSG52qo=mc}d6=nOzy{ko z>h5!4KDG9>nQcAB2xBwcnnYe@YN1K%^%N=MMj0!S=^RB?o|l|N6*UQnt~ppM7nWIWp7X!-ZjU(-ChpYZw?AT zw*r4=$N(Q`ALf_4lTg2ftsD-j_{!g5{FuCE#qlu&rK1ArGt|<6w*L)X>`W1zE4*?$ zYW2{dSH#a-Ia(nP%MR7zOSpau0i=+oFhyh(CX+*S|-TrGPsSFr7S^k%Qy0qM;1w7gt$MEm?#T5 z7D}|-@>pNa1!gx*gIuP6`B*lidpfjTn(b>k(@7?NRWbzeRHlL!$Asc0qElfaTc7T7 zJ3Cw#+2XKfbC%~FSQ&|=+dk0BoyDG(?6bPo++|L(co-G)Fky;!jXs*x04&W6s?BUs zcQMG?B}q9a%5##QdAS|NV=d%2=_B%V-B{8w#Hn~5M@Zli$Cv0qVTKrD0%3>}?EM)B z7{`l-V<)Yoyhe%eEn@_?!V<>_nu+h;s7%ggvY(l}e*yS@yBO&~38#B>R$%_vP(PSY4^a{9cs}StoeMw@Q-Q zD?1&yjj89q@vcc^Nin0!W2D((tql+`jAm%}iH-H-B)OAuT~m;!R1T^J-39bmD)T0v z{_^Z3Hf2ugJ55sSH)=;X|EMY3Tfv<#zE8$aXYLI@g)85DVEL&GqwhLx{V<^6KX?KM zT!+KnV}sF!AdwM>i`05&NTs5;t}De4Zbv@0x_EdzRs_o+tm0Xz4eITC5eqY6D~o3b zajv!^S^lJO*LkIRGP2W=SF}Xx+NxdPa#18l)UjUJUQ)3atk6q|b;CLmfhJ`M9Jy?# zL8-xqu1zaAD&bA*&OU?vlp$Dj8*1}Oy1g#9p9{;FFpg=$T|Ri6MvX(OI_cyxl-2Eo zHmvf!#;K<=gMvDVr@27@tvy``+y3zIB595=Pi~(*6;rU9hsB&s5lrf~0;GVbd@N+C zU?7$47aHa?-MF(j9IK|=Z5(f@&5hmZQ4SeHNRbJZF28Qx z123?nHBXkFP^{{l!e30LCysFuR#>Cv1%<{b(Ss#rfjYlLzt%vh09hb+8Z4Q}#=qlj zj23M{eJVX)?$Ag|l=1j?On?${j@&>kD1(A6`WbJ_-!}e3&2>I8jqu-|p47s8J~l1-}`Xz8r-B_{~VtMfXAZDd^2>{hqVs7rNT(6j4 zv6mt@*lOLCq((HXB^#_e$$}o@hD9_iDKBePduRbuDVEpw_xpn-#M{x!gQ?Qoc&>Rn z(^kT+|492<=}3Ga;VnUKT^H6BlMaX^N@84DG^l}!vFrOot6OuqU>9hqT+5)X-a#AS zK4#%&GPi(-!N$&GyU^j&+8c=a!IKzmNYh%HNn7 zUxEXYp+ac}(Wb8Dz+F);>G;+waiw0DIQ_Jnq}hVnHCCQ-ncO&QZ`*87O9$GMdz!e4 zxO5(Lr!I?uZ44SKB}StA=md=v;RlJ<+4`OmT9G!&u{50%_Bjk^m|!O;nlQ1ia`;vt z%%8d_@9V$lQn}M7?5^!e9zot|5yOz^srEQKh4)KiVR!;BN)~y_912JS9n1M=ieUVS z?MSzxg)(_9JG;oUUd7H=f=boC8}rh{JwpuA+sfW6h`SYISQP@6^pUx{%(ff)PZd;V zFy@Z5N|cO7U8OEow@US*R6(trgFDVrFfY`B=2#_xZ1K(@R}RTp5XBHrrU%VL%BC>V z1i(!0(V+FQqKFs2DQoqspsDTZ+0%OvVV^rH<_`=719W#)M~z_II1^a;D((msC8Yxoa$9EM5%IRyIRIO0habtG1rCQbwhg@2FV< z7deHEfH$>Cbj+TSIOHfe(zTN0*)}IgXP`>j3L>?UnC1d6>#o&&xav5G+A)a zpv>;!Q4xYuNpQ#H(oNb3!5YgdTjB5Oy+hY_GU&pm&4Xm|g>? zS;27DJhn#-o|w=P0$!J*oU46a7P8=Tn^?&D9HJR zON2bY_uUd%Umq0)Amz}Vk(Czgt;{7%g}KttM1VxrQMocO6Zo>vGdFtcRy%X?B4}F; zgn9L&f_lknW3~N8_|t-&gKBkorCiuwOR^1D(fRVX=Jgc!Tdi#SXDim%A^@$kVB%2^ zIi&r$BBhv#mSr!^EmP3RZ7BAbeLV{trD!FljF*>{@mHy07?RU?EE+8z!SV+iW=Mb6 z*3^v78Opah2X+L z51N;3CXI@wT20EswDrlc&2Eh*J0uP0O-7|MXGwLVvLDK8;YA|vrc|EP>eXH!JF%A7 zQN#PxEF5->3ALV=%&JG8c-DKlOnvr5N^ay>PK9u75boQvk__z3^>X5*qcXi+n$;9^ z?O#)1g&_M76A?!fUUyRE>Cs6+?_}XhWYO}x(1K*9VTb2X{C`*S9hYGjLwEW%{6xOu z86_<)>9jxo)d2e5F!&R9;uoV5pYG(-Eva z`b7+D4ht#5CpCW;D*VwtOf0uZE_4O*nPei=_AQNq?^KVV_MmwJOp!wO$2$*mD^G~G znwf%=B%@H;(pl4JrD4s5hJZ z!lzoPYi`Dr!XVONs47%I%4+)I_5FPTH^wlVNv=B44lLwE@os}E35CF2oOf1huet9C zDWpl%#N6*H+2D&eTXaT%@iGlVKC>J(h`(OA)?o*Zd|9rcEYTh+J!v%%431ln&c|Ei z@7JWEE#3&lYOC}qAxt^H%E{C1^84-Je9O0RUT8bDD=F@Gw$1`k1($2e`ub{##_1Yb z=y&86RPm5xz`Jg__}<8A+rOyyjQw zwVgI^B@XG*aK;L7E@yR$+6J%195%N1{2kp`(Rf!L$xwuS^=8gkF2{`xPTyt`4tnXH z#w*jIyVsIcR=<9|{rdfzgN!Gubt6njEvxg3012`qW6d1o!UhYD_I_OVrqD%mNf>p%Cs=Hb=9YR<^pWGf#-7vgf&)F?MBK^?W}fK7!qawW}N#hkSEHyK6cO8iT)sc0&6gQ4AJ@TGLZii zxL-M zodvs@3DZ0e<{@wueXxWI^8mSW%}d8}!A$iuMg87c$t0P9)VjVeOvOSeink+0!6cR- z+Sz6GFaInL%7doQI@ty*V_LaZU_59Kwvz|(=P7S+eS@cSF z%Qy_4LfW##B?qk-Rjtx&*zT!?*`r6z`$j`EYfT*^OsR~0N6xfEvC;%HQk4HOIuq(> zR!P_l7%ZI8$U*~&uEc2=85q_S?7Q6+PYW6^7B*D2x1mnyjrr`nDKAUO35i! z=l!KW9j4PNdQJv7`(i7~_*c|nmYHv^oRLIm%hDlhLGwSEBb2E01&t;mSrT`w36lqg z>viFDU9#GG;CjloHhast|y;7D*ykX>%O;S zbIHtXZFtC}fHDGuTYdUmlABxU4^9NG)zn#Hj?v)jB@AYRbyP~8(rY%Bk;WukC^3(Y zh{EKVNaDVnR9}lV^kxnpqw&(C;* z&m0A8f+u}*V(4{JgDkN(8Hr$40OEw*tFD|4-gIr>tnnsxV)n&~jjX=C0#m?(U6GZ7 zzXZheXm#nfAC5Vdh&9HsoJad=@2w(&R-B(4L3~Yu)ljIHm;Vr`^j7)%b{cXlmihZx z$nf{fcmKmFvDuM0>&#?F+LLw@qTNjKVFV6J*`yP^x$qCrJlk1UQVC5vrVCdW95b3lk0%k{9{N!XNmS4fj(JTxA4!ag+7_?<60zQrCK;D- z9gcj$rFRa*HYgpJ&_kQ3ktZs54o)$^IY#xU!lKa^4Z`4Az@-an1Mn$MP;r3aHq)RD zg&+m_GT5k%N99vwZQy}jU$$ zajiq}?dWz)#&{N3SJI2@vGGh2pc6HcylW6j^ZB2TF-9egA3x70HQ5R!ZRGHVfKs@t zbroY|NIyS*{@^T$((d2v5Gm}xK$`WCb1`+=&u!`3+r~ORCjUIa>Cf^ltJ=iU?!do^ z)m^03A&#Y1HS8xr(ly)q&}x$Pvo8->yx7^E#?A}ViRb#)EBw<9a?{*2A(<}9+SSEmPDSeD%4thPq*6y&=5H4@y=v;I{6H?83s~7hvN!1H z`a#g#gUqqXDl`sb1HCTcV0zm_AQo2i(zU}tv>ujVdsWPOFi4K8#zQ3;nn6d6%HiO~ z4L5?Cv@vRC!4}$;xKGJt#iIyS3KMx)`c;h1#_u(0c73gnX)4BaZ9F0H8hgtJ6e31+ zd!udjrjjz^4vh{+2M=a%f&@?=Pc!4rv8YbwebV|ja}mkiwu>j)9^V^0Fx+fff#*@; z7AWv}ObSeow;yNDmlX~*Go#PJ3)+w3@NP(8ke5y56LLGBZxpYzJ&1uwij!-sBD8j& zya(XfD0i}HY<0wu*HwL*4GPden+M!)OyY;nOpL=xw5q{bf>k3(BQ(0&lEISMQFB;` z+}rv!yYHAGN*xA(34rz;F!7v$>#OY-a3G5HlwoCRSqHMT zLf0&;tOQi!$anj9nK=dtTjzxigcIXTjq!EGCus&RYNtRZtysio@MK`_u8Ry^x5`}5 zzS0J@Y(&idP3^9QBoN% zPw-%3E3o44DX?yN-CH#zDGr|2Bq2Vm%ML216211Bi-mJYmM{n3{WzC|<_cfh=HbAQ zS4=J?D-NuD2v`d-dv~YFQrpHFOg1R}`1e}CMaWIbos1kjYOYe;)&??>D{>iE21uDD)3gro`HH(H>e@@vP2}T$g08t@EyrkgEYse4(7*| zkH!2fVqB3l3Ckqf2G7^6TBC)Qe76_Oc912{zqzhwE_CR*bA5eMW;0Wmpo zD9s5T)PJ+Zm-u8YzjD82hG|_(?TDWCD}N>iJ`^r#y;ggJz&b7F?hw-nubDd*W~;LD z6VCtvLLvRpo@or?+==O)nQW&c6cG3;iww73?Bq&VQB^zVAYO_#Q0(&^UD6ocN zi!Owp)T9D}1qT7susFTfyd+09`w-EtB|%6AgY5@c@^r!_ha@9mRa?}dm|N)!o%oL+ z^wDuz&db=`P5#eJb*^6R-IOF5SRuMArI&^B>#%!B15-v@Aa6ywfP2^kHhGkcDE8p2 zCTM)LcG1uh8jc_&vsahbPSOiIs0M2KiU`Lh0$PAWtmDD*(qVBfbNR+t;H^~Z z+TJ@%Av(>`mY~z_AArnX+9!Z!w!ZOX*rz;|HE^{K9)IIwgvS@|5n literal 746614 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⁣c+TBa2J>zI=Zy0-uM>fl2(R2O~fn` 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⋘d+Zi`STpkt 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¥~4lq4}81^wmR`UCGevxzg{340rX-=u^YTjM_G%O!g~?PY{LiaXc# zQVG%IvEy8YS$5E|FB>W8UVBBwW=5F_h#aWFfiiJzr0Jx&ciTLSjjxPmkQ3u8##Z*y zhYr{k$@U0$&Vdg-a7>THQ@Dd)3hR1IdsCMm?^sQs)weP!HZ^aBQ$xT}ffebS!j;6D zs}i6A(hN6J2D0sMs7QaArT}Zqn+AcT5`V&YgsG-WoZU9G+sFTx~ByEo9N)bV$j>%I5QXe>td_l%)}jfk~zj|{r5A!>55 zZEItG8`g#*^B9^|tZ~=xG0ETYGYuB}VSG}LbH(>>8?H7bpGoW(lsxfreNDUM^4 z@vsNfaU)D)sP`GqJ;YLvaz=wYgFigUR}p-3Uj&JfB0uokum+uw08_sPWC{vi|Q} z68O{k*4MwwUaZ{(EW_D3Cq474IOzrPqQA)u9I*BWP|DPR7)4)|MPfQ08kaq$dKh($ zA74iu&%qE_na@~@>g?@E$krUSS31AoGFeKD|7q^F93>z#C*gzMB7NKk_h@C`t7Z!^XXn}#a)4T-@Zf<&D%0>NfDKYt;hMh+sw(zbYucPCmk?jl#Im?YJJxM2P<;fs(t6%9Wx930Jd*v% zU)ja+=;qEez8_|Ly%2l+J@l-zT3+ei43*ZgXR}Yw@q~CO0dJ7*^D=9FPqEC7p>Fr- zN#1Y9x%TBrZVvh3;jMemm+$(PZS|~_5pz=T_Ey}25%0K?jQwtv_vd>N%#7^_&Y3u_ zZ}XA>K4{MW@7I5H314^WBGIew{&m|P|4JuuZyWaXwV}v~7EaASIPZVIq#c;5#pOjO ze!oR8dtuAMHfnMrGW>wy(MiFIa>2SvPIsU#Ey&L9v8V3SE?>Xl`!8uDmiKhTC>TFl zNaV7}T1p>ls*}Ca6I*`IFZB5N_tSs55hL}3kz?$E^WpTC^at0$r`^%DY+4cN7|@o! z>>!>c#OOL;X~P=pD1Yb?4~?w4m$>g}mBeq*w<2unT!`2O;*as>7O5xQ$4db8zn$;* zyvaxOB9YaWt03Q4;NHVWL*BXH6`w92G_cJU81>GuS+!7%r-gZ5y7hDPyvBdcXpf)k z{T}u+ESu58LIE+#+G~Sws^d`nMz9g4qPRkHA}E-k_$8RI7wd4uT~e11QU+nI6*;eg zigF(*&54M%kyb_uq6cg8HMo3GgS2M2!M~XcK=PrTjOnm(h)+4n>sEO8h2bQjP#uHN zBantMa%peM#gx&~u$yFAc$uJSKBhd9dn^)3sL6J*+CfNKD%J%siQLBl3d@$3rz zbSnXCm2O9{sH0JX?K)2sa|X)FiVP8GD zqkDrN$w0jUbz6s{<+?4HToV3p4=mj9kiddgs3l!1cl+XVka#I9vXGi^qOHiI$G}Kd zu)qp6z7rMJ)VWdnCi_l>;=1Ptm%ef)U!UAJ+&;?V4n%p2V-nvb1gshUvB+m`q>r^k z2?<`bP_WJ-1x9`Z4X%gRF2(cCJ=Vb`zQ6tI9`+FZ@qsy%^62gb1{Zb;e#T0Oxou~~ zX_ir&Q9OOM?5LAF9xzXF;uiXVv9y7f*%v#m`^MxFa>c#Oa0hGg0*^e;ast7KT(=>4 zb+J4CuHV#i9_NdsKLc20>?y1`cdJ;*{K|I$<6|@U@XS3GL=&z{_Y|2a7Mbu1H0qel z$3RE(k3}<&HjKjnnfDLN0~}Lp z?e!ao10|m&k@t@LP0+)&^rLeziWlD;DSCdinSe1?6$A{_omlB=cKQb*ITU(@aTHw? zg{6@KxM-47pX`_1Hf7U>P1aq?Zb)6g4);fLPlUCFvo$72Qjo5QhJQeObT7C<%~ni6f{A{nj?FqbEzI<90|u1OV{>Vv8?r9^Hldji#lTM zT*Pejo=QVBp%r7U*(*hP4{`0A16&U<3cP3d*T)Z@?8o!l(;N4F!H_dIVex_)nwgQF zT~BX`?Vd38@zgc<6n`t0mjrNYb|!Rh+$re4x|?_Xx?je)1NZ@ten##7>64Ca)^w@+ zx@|pWu{ERO_o_T@6lq#KNZ=P2$yfg)Xxp9JNJ0--@eKPyf*eHmr%zK3LYNK0+0Jj7^9tM#>UQWLrM%hALOoa%mrgZ%^xtP za>{}nE%J#LYboXIzLWLrAIVF}MX{rjM?Xs%Q2Qli>Ph!G(nm*9vL(m58eVh+>zJ>{ zbRT126s$3Rt|DewN(_w?rU*?s5$GF#ECHj6gOy&>bSS3W*_5N*m~?dmbb0UX1= zm-RB)?sdX#PrFMTtst61HQ2|?QRuZf+S&pgM41r;tFCVuc_oN~c!z0$tsq)C&H_C| zLoSTqXkMaDC5UT@2V;rgxT?yYo7#Dv%N@M2l_3gXc#>$n87e^>!Dw6?qiQJf+PSGA z%F;LEfKqLzpAzpPyZF+a3136i3ACdQ#N2Bz*t`d|@N5cAn}W1XwT-at+N(_Crj;nR zx=ODaT2*mSSl9NahC$cZD{Omp)KLbrO(UNXW{+ZquwqjY7f-X1IgEItj(wOJvdx3P zSIecUD8sdMGu;|mYiv*2I6*E+e%d z_v%VQ7%5!zgI~>n6ApdKHnxiu?plM)otl>-EvSp!w#WW&hbd#^Abz zv5VKZ=OgzDNxz6zUhLp*OG(&6$^@sTlDy-hkHVR`}yiWj&sAY_+WL!H;iT0H7DKMN1a*5j@>nUbV9h6x;xY^;98Mh z(a(-C?=bBT&_-TI)is-M17ySct01p{LE3K(IqB2wLJY>T!KJZvXJYWiyBKD?W;Td` z#joblxX3=RPiPVa#m;E$2QzBaz%#hQcp9n(p+OahtD~tZ3iPBasK!N0$;RE+EQ(}_JLnyiSvXWxYkd1ss*jOYpq!pWr81WR&_)C}#BM!s>A#|+n5LeYzMc@5q zDvkQQw5T?c7AV&_GbDcNcmJkao`0F;RH?)oQ4d$r+oM2KC5ANGw0|ud9i7c*4ONq; zBU{xU^EZYr#fUYpuY2vRDalK+`t>M84!h7pjF8Ctp6HcI*;fhqeac$nkLPk`{AACW zs7YCKWQsVdkBG#(j_r2w-afgfjk=u6`}6DMEVeR+6|`FH z#aTTf|5Cp;+M}@gvok(FV)`uaU_26D_y>e)_2@NGr%5w%D~2SF%!Q|>n=2Lx!^AeVcY@x z=o7!cC67JUR$kvpZ^>}F}L7XO4u`q%-?(7VF`260bbOjc$kga#P~g z{mqO<>h8PMlFM1f4IUP7>_7y99I8!K;os&Ddd zGfvPC#J9|_WsqMQxe+3o>!B%=dC`fwtd>M z;PEKmviz;~Sk&J6P1TI$*Z5QgK9l8V0cnoy0GL2$zn1nfXAx}Y#zfzCEpsAkI&!+_ zWF2RL&N+JKF^!L6B!XLJ&ZtK+k6@`1G1slMXH*=`7kq{;YcBkmNh}7xm&M@uCBHZ3 zt-0(WGVJB>m$O}7TV6rl+BZ)}>=AvLzcG~j;_vA{J^pxlhebG9@O4X4az43}t3B~S zI-YgGRR_*fjn?e#n-uH_DBK~yiU;2A;`&k6PqHwJTR&qF7`8k4ZDL*6wG3_&Zj_-QRLJv+}c(o+SyWorQ%Js{RPti&R4i_)u!i=48nI;xZP|%f1rvhH-y~x`-SrEs)pnrPzlZ*ZL zFaPG?+n)Shg)5Bt0nfeciD}Uhr}mO%6c3)!7@Zg1>ROe!SunLfx#8F-2SuJbn#ar+`=!nF_8=C@ao+84j<6P z6L9N8i0=8EV}C<)VBWnx${ibUuLc`YlMfuZYPeqCY`)&S=fi#bBiuWeGiGQnM?Jpo z?H&IdmN456&K;qlhElJdV2`(yajqQ-QD&a+l=1NAU~+@b;i=D&z>O%_JV9rNgdKCW zBh(9?H4e|H?+4M(?8j3y+gxn>arhQ}Qd=Y2#@%ji3To3HfyheD8jr}H;k;n(Z0f8r zqkGiU$=eAV&F=9d2@2SP+2<&=HV2jn=h;PC=8Po#J2VHO{FGu;azN4_yo6y)AHL`n zQu$!d?^}7~Ijon~FrME>_?FI8*bjStF1_8iymxl1_iyW?wZ#1R6b~1dq$Ph;Dz4@$ z9nWcowxyn@9X|uns{y!pc5Qz0)G!vmw>>W(nPNrZNOGtU5yv0Vw<^w`ePl#bdfh5V zM)cXO@W|_}tV?`;eLCUyg0UEE3r4+V#9QNR?yc=vxjm0>ZPoM^<8BMUleQWbmheN| zddp{!Vu!*lgyp(SSzxsX7~A#@2yHHC=t=YFvt|VsA98ni_f~?7zo@bB3p?5+_%KkQ$t|LjUM&FfPuZc0Qwa zx|bTaclLeg(jJ!Uv1t8O9%LpCD5xWsS4t~uAQk5@GPmnO@T<(F7;)wF<9+TB3^|mk z=NWM>o9M?MI#iEXRh(ZKhCePgHukaKgCW+}_->=_Pu>=`R4X;7i@ZSdMT}V3N^SU1 z>=G-{5+jSO_jfoVP{1*_-0LQhE#r^)FpC~-$jVVU1#a;dtq|>eXL;JXANGhlk~_|S z&RlVB_EQaN!83|(W9}pTQiA$=pVJ(@k$D`>S#r$8U)Z7Ke9%Per14Cm=^xmHgcB(G z_12ILA#kHqPf-mHWvD#Y?hc9@^ea5ZHKe(bF*vmeHv9{`6%4-- z)&sYgC6wd&{?l(l$G^d0&2fje63V6t+hKg@Loer7TkO%?;|kK8qn22S#(S%8#mr?- zjNI0*^VhvLBliMpyF@#$1J>TLVE?F>I->4XX8rW@UOvr!d!=uD^>OuXi#m(&UrbxK6cHXKReWtHrA>zEtvh`unT={H8c?ME}G6 z$2BCxujbB1K00r0Q})I6q1xHT5NX!bGR7F9=dy*|xn6GdDTlk+8Z+?0E&d8>4DnMYMQS%^DZy>DK_o|hP zzr5lX{dGjTn(5-?Ny{R{EgA^w<$<2g86rMC9@D;p6F#@Bi`imoIjqJYd_{ zv9rQ9t}^68XH2WVQthn}iNaXzh0nxfc=qM7j5nfu%eG|0e^gb zclvexVuAzRo_5cGo%!8l2N5h9--1-mKvQcIK&C=nkFR@sDL1hc$Yb*c?hPSv)^@*~ zr0fA}-P_I^BRcp1LE(v0d&_f2e1Jc?)1haDtc`7=*6_8_$uo-Yq%|;PKymM#*X_1i z)j92%ye?y%b;{6fzK)!AMT?i5>tw0DVD6%9f=G^|TJz%Bzhf;Na!uX~1N^X@5IY_i zq8UDe*htVBGOj6-)QMq*&TDk$=!9+8H90{iUATWWf*S7aV`pR~fpHCKCUvPcy#DW- z68IQ9$K$U2jlakmrKDV~?Q;Z-y8gUEhWu!~mjvG8Tl8rS{d!I=AuPTJ(}$0l;=X0k zwx0#-3**9`$9cPNc`sWvUw+0Jxvj3}i#f;88lA?#^3~n1G3Mu8^_90xV{sfD;d1Ux_76Tj4RTll#QN8{ZOUPJ+ z(#2n0N_JV+g^cCT*#CaYpLs1Kw@1WdRua-plVs<4WMC7i^swg+fQTu;iq3!cp}_w{q3| zv5$S!cyRGIwnG^)Xxr;%tzA(%_sYTj0l)EkclRVL++O5FJ);P({AWI7;V6_{^HQzz z$rJWZ?xQnQ+&Hd#26Vp&pSiE#?29*L`P)HV_qcBA_RawJg1tO5;;%)^wdj~Jr=1*U z8FD#E+0)R!DX=rB2!jJ9e5F;}C7z2yy_gk(SAD))@b2!G;klmiN9xbId6*0u3j4!4 zXOYg$-Hx2y+y!wq1-S~tqkF8@yzzU`Tw2RJRe~iRZD)k4DRrb4O}2k5CFaq=Ou%QQ zWQ`M&4N@E~V^4xYY{5J@@(^C+EIPvYLwY-NN8#I!sfc7`oD#~M_wut_ca_E8QWkH| zwJ65>$`<`xj?cvP))+_sB5*Hj373wigdDS%c)i`XQs$a3Mb|CyYg--NoR4#RR9>5JW)AS?`Is^9<#?~5E|1|F)L9Lo(y&L| z7g-VdvaCDc_R#nX^ieKm>@A+vw`^?QY7y7eep_m1%-n4Oc*ZOW2X-AS{<@EFP|FHp zxcIB5w$=$Q@PpKqwV~YwZB#KHu!I22KmnsztG( z$1MUAzSNFaz~qP7wpX|_;z^2B#JCUnWbyGuz8HW%Oz`u|-^r~Q{`CHzPXGG(e=R@S z?zJhw$n%!iEipZsYP_)z{n7)utS{Gx4JG8&Kb&ZlJ;q&%BDeO&0An0G@NbvC z3K+jx{z8=^Zhaj%$0p(|?aUR>_>OPwp!B?!`t!fW3_h>JUKE>=GLx7rJ=>pH*5qi!5{9q_l+5+o64sIQ_C!pP#)Pbw#QFSrD?>|lDXOl& z6jjP{pgob27|xkI%yqbw83{5R8B;j0uovzth2Vmj@BTx^J-tGr$m}&oj*-+!X#Q{C zHf2K84k1E9ITn1z^8V`=`K%@8%k^U$3HQ~?s`Icl1I9BNJBsHh>v452IZ!LIA8%uA zyUox>kT3llke=(PpWUao`?YZYA7$DaH=5_$!pF1Lzd!Dq2jPFw!XobvcTHPH87Zk3Q) zN1@M(22Po{Dd-I&IRn-jesss&REAz~o!xg&vLw zwih{WZsqqd1Ad?6Xt8&w)t^CdEk2I|cyXH+d{ggo1q#i6oDSo1(t0x|n*Gf8QjFn_ z<{wit2mLLMY0k{_vuvEhjbUTDfKCn+cjTwme&)lF)j5F^&D2Izn^SGuHDL# zi|Mna%xY=r?qlymQA3iGj({d>3=s1=ja&`)935v#Qk5ERmo0j>#MC4e_#(6Fj*KiD@`Zvr+3`U8Pzv@?g*YTVi?{z49n<~olNe|8zdbZVbIZhUMZAo^! zOHTj=pGC)nWD_XPGSnoA2*1YdpXd|=<`{)1I_*WzU7#o??v^)Z*%Nb^eiAf8qv21Q zXl?9*Nuhs*zXL78wWP_;F zUC&qdhAC>Bqnk&7Db`zRIYKp~J)ff**$Jz1RGmj8h&ZEeRZilp1ShVeDTnddFn`7!6M?Q!O}W;^bNSZ3gnFPm~^!fl`RpPe2(W%0ztnqfq)b{c|u@h+9V z7;6Vhws_!8tXuGvHflV+$XD9!$1}%A?K;aT-Ye2EE_0FrVjgt<=wyU&II(iAA8rMW55FAt{`6nI|376B z_+J<>P^*3)5cj=DTP=T#-`cO`fv@&JPWo$Y_)s*Ln_6zqyRS08I11F~U_o0g^=H4` zbnAPxWp!48#(NGiT=)g<`WJuw7;mj(XF&H?(b%R7n#DhhXT|`pNlSh_*RRm(9#lIBx0&{|+iBZ~J^A;?LLUlWjkR}m&t@7; z^Ncdjn|0kPYXd_KItPutBL^Ud>@G(Tb3B}`ML5lejDxv4Yij9)hp=72AyuGRst;%=^DrQjB&5Q zg?@PaaQ8tzQ^%*0WY(EMZ=Ah7t4Hy+GnWymrqoi7ZhPjkmGkj4<}%{usm{QEe)#G1 zD2sU5U~b_@j)2k|Qb(k~%?FC#VEVm69B}@+U0v{fk{n$8^#>&IOLD1Y`F81h2E7IJ za@%J)!0%*%S3dzkoE9!<{_E$z$Th;6`P1{?Gar;JncYe!qjR zey%(+ZfPXrQKuH#;#k|)(4;o*ZN>}bbx824j}n!o1D z@zn4+A8hu4eT)xlN89dyY(oQaXtTh^f_+!M$Z+>GdGVM0THB2D(8lf0KGeU;i2)10 zddp|G@flXA8C`JS%mXvfGv5Pro1tYL>hXT;L;P|Nzg)CA?W{oACF3tR%%ZOI_<5=0 zzESU04Zk6#;hwXFCMU_#WsP&>?_q(g!=-IWP>3m*>r=2H2qDd|CZH~Bx3?qz3gNqm zjY$p9IKvt|9=ai7&9*i`f=*!Az}yOH2&@o1CL~Pgwe_?cq7S^ntG>;j1cgZ_n?QiPuzR0xK~vbH%5qJvQeBR$drEvcd(31p zvG3A-tBvhhn()buetHAu>nt2|pTaTpb&mM0sru#h^Xcc8&!?}i&vJnuKB2UwZ@bxu zu)QsQTU40&t@pOf0oEmMWycI)()FR!kLPaw_{;j@TjvN$a~R_f*YMV)0jx*aZaX%`$>*lHCATJOg%1qs_gAEqul3VLfM` zdmxKC_nL6-+!OQJNj9_vvq9`>&SIa%vu7+bV`q$~%u)7K#;_@u+&+}Y=`6t) z`WtXm)2e0ap=TGYbYD#_Wb{~FrVhpQj%me>i=(|IXpSR(gml zEa23kg!XLD0&P1Bc1EC}R10I&68eaVYkl*s%i0=Y<61wldT-=6i}`z~zCljcsTa`v1Jk$dcj<%9bmYud>l*Th-%#HcRZ>iJG? z`HZseudX-x#BG(vF{4E|n;5JOk+9>6U)_`7Wi-6E^81~E{Juad&KcN$vB&EhE9^J; zEnu<87aVkds?8pmYM6c>*jR8rw0+voQ_mfjYCeK9o{dR4@Pc_Yi|~yx!HrTq<#mCS zr}*5^QH<+#P$Tfw!SoVVaLm=2=jfrYM|!BIp0+ZEimN;+^=#!h@l^BC35IZdRn93+ z=5FL&hpuP*kuO*VGS_q~Vc_oXkjO?f#$cfx?I446R`&JHa*kw0<(z{yt03a7xCWDC z;FcWjD0e2JZHhS!uXT;2vT;=b-M}i#Jm;0^>6X(C9GI%|JIG*HI3jgb<~LpXVqwUU$D1A9LB(>^Z?*V4vjTwXgEPMJo9B@&2*8 zCv4GBjtRFx8P`AWBOD{xegz&m%0G&i-vCAkA3pJ|)jtFFBXR7GzCXG-(wtyWPVa+_ z3&5ydUqE*8*Q0rW+%H=h%L<+Wi@#uVw|_PtF5~Tre&9p}qGJ(q|M(yW{g>0{m)}m` zzv6bqazp6{xhfd{o`L5>nn4@=TCs5!2m5$I6eRoNExzTwY%!agIRn(~D$n8wc^Mhk zKA4=C4lMM(S`xxuWLw<3tfwCyznA&_bo%w_*O=7w6{`j+S~D3OnigwaCA-D2UBbq8 z^jWCK+Ss-=+nfx>qlS+>?9(dysm$lSEd2W8F2*AUCC9BEeYQEQ9c})xPo0{dC^AC> zj~o9xzl^Ezlj&C9WI^T(5>FlNU3rGUU5xWUSD>w1LN{>7 z^ptbZ6YmN;l68hMb0>TlX828Wm}U*&--D|`8%6G-BO(~>W_U9u&sueQSgw@`_4`T2 znd5M_5v(Cu!hBBSTblRsLG+z`QBwbQiv7%MYqp8izI~>Lb;#}GeM^xc4z?IUMt+vz z`{h=Nqh!x9<*+#$V`HE8V=K{G*S)2=s7KYkWBEP0#ESha^o2do&~BysLL38b%b#YC zBiIj*hgw|CN48vTb-|DRR<0cXTd{H6)EmzW?dPm#XvlMnZ{a-8+}U6b)@Al_{bjDQ zr>&zLdkN1mdT}#o+=Ui%{`B&EdM_8T;jyiZY8=J4RQ2o*_px_I{@--E#7o-OD`Cb(Ohk^VRwb}ZZCfMbot-><@`SByzV ziY`QH%dJ|ou~>?sFXJtHh?^(}h6MO(g)n6$?@UxygYRFJh$c zE`z3B`?y6k_95H~`u+WTPad?eK~UU=(Pr_PSPLk{LTM;4DR{Kl^?{vt;8 z`siEhHUsq;z@EkPP1rh}KD^3zwz`V4bU`~ndSrd8`|{km>X^>$5chhqJ$!y-W9}Mm z)zbx~7Ip(K6hQyBIpy$ISAs3N+;ckma6I>j8w3OZx-Yv|e-i|;~% zdoI6YBdx8odMtqLEU?o!z%c;rOFo@&Nn7BB8KvM>C!YyoP5U*})WrHinwTDSwpak$ zS>OaC`HNzF4uRlp1|z)Vs8)xjO{qD8g`eF`TsEknw_vuBbK9AO8B?5d_+30WGrXQB zTSN2&y)A(tzdws?6o=YnUMdy&3e*yi`8drAyaN^Y3X^APjc}U?|O;1 zYHM$b+0ytJQSQgFalagSj0gGS$1#~g)_B~p2HOuKkL%6I8IQ}Wwd`zrZ`^7l;)v~i z=0aUAeW-H$x8|wO*8b7rOo?;Zr`NBizsUt`&zZCF77g_n@Aa+iWAW=|qZ~7`kLKKm z@BK7+UzTq*TK0DQ_O09v*}Xr(=J&e*j9PrF_iYR#mzOz1fF|E6ppCb?_}yQ-@T<|f zB!)JwHsul(`g+x`GTjM-*Q^V;4kP1Q)4GAlVIj5`8SGy^{|g{%d4Y<%cd`I>e|mg) zJUz*8upoMkUy)%0w7MV-q*oE5YQ4U=Jjz>ri@9Ji+8ltV1?enT?`j;zsoGm3P*z7Q zb188Pk1hg>T_;4@7P3dVodOov!@^9gL$B|Z{5gAUi~F86-Bu+m?0ne8T-atb$g*qh+OWKG|ulP;lZl|a`E$m#nY9{Nb>F0xno5~+uR#{Ry*-zoY}DgM9~f7~QJJncJV$wQ^pAe`FN>bJUN#hB=t6;lX|4 zFq<_zgUn$+_L!QZ@n{y#>y~}CfBu*SqseC?BJZ6)3w_%AP^0ROVI5U*t@vMFKFeP& zcc<^=LN?44E-n1l$~El)qgrw+E#KPqIm39kIG9OQ*xy^HM)(mbYh7zW6Avr|;DNNr!htTd>9vgXYP7rUvvBB#$+|1JoSIo~tE-E?h`PIzLsu4efBE{a zhzQEReff7FoDEk2BaWHW8o)E17OLgXP(~&*jmG1xoLl3RroN@bGp@?jf29|_Ff#7> zOvA{gU#>Rb%vp%$KKgQ9o`=Da6 zT*^N1#MqiVX?=h9q*wf|i@%IZv26>s0v|-@7k}d{=s!p-M)D#ZzxYd@Tiu=k%>Avz zGvN0~oDH~#>e&bV{;Pmv=Dq#Q_R5&{W~s*?l~Cupp8JZtc)_@u0xcCi71z8Wlr@w+ zd$J$H8Y*HA)E$NJ4(K=}CGS&JKo!h=x>7BDaSN&%PABUj<{jXUe1I&)zcSD=P#d0s zsEyE$acy8GYh0TbOuleNrzS>hNa{iuZ|e$|g`vH<#6)p_GqD85T)F-p{w=XN4JF$a z{v9zT8L+$31Q0l}&gIO|=U}Vu4BnV*s4;goZFFbCPUignE5SBpH&+QrGXEFr%AXA( ze)d?AEaGgY(!Xi(H)~gE@_~h*F2)V`C1jzG|NaiM%1@9z=db+rI6r4zxwm=TNNZ1g z_tqE@)Pdcjxr4p~l2eegbx<7)nW1V6N4#&u{gGkUkDL*v?O1AHy`8BZN&b<#&bZwh zYuL^-9?9I}k)sjyO!T5Yx-eHg&pDLT6dhw2mGyyh2T#wU*)%g^_t*%{=7GD zJ!U@7nd_Jl^s(Nq0PdToBFgS4XxqLG+VVC4@i8A4f87$UIG^O;!s2hpPbIPdyj=YY zCgoBFUHp}{Tdd{xG6b<)S)^Ev!G)^$ZQ3s{znorP^WU=k>(gIPe|-Fh6Mh01R|&t#a-DaR?2C!FQKhwQS&l>2V|0rKSz^$X| zMH%XtonCuz?4-JU_!;Kw@`JpLg089U0yXr{;8;?0QFVbDntR*>c?O_8nQNF`sdfcJ z6$nr^o`kx>cZ*bs-Ov5``jMIBYw+60fM%M`lLuLBS@#S&0>j#|AsgBxM`(lduxYRw zI&^Fp>`_ouMhM3FuDM4;;uj0PWA;gFHHMfxlqxQJi8TvZ&j{r+|%?C~?%y zk>c-%q0)fs*{uOe5)R@A;kfem-BastAuB3O5cVw2zr#>#4Qb{sZT@}f^Vij< zcpr&YJ-Y1=*?N1eti3#Qajm(+Y~Ww-XQVZCjrSe3(5kPOw-;AUb^&Ke_v}52d1mw0 zrVKgHldqkLfOH8D>)M_X%cPH(=gGw>wmxhGifs6 z)6e+Jdr`>kbNW_@nAxl6sCz>l<69t%|K0cSTdkOIJoI;V{gjk8L~Exi`Dw@71zh=y z+diZ1-#$1MP5_pv^!h|Dyul2H7xCb>&k_|c{)*QztWVOA|9U0x{psuTCyDaez{v9V zr=L&H^5frseD_EBT~=J>DcR&!(7rfQ-_5pw;V5H3&ey{k@_;>zVm`H&{JKO-ugtqN z^-5>(<4v5#<2hu6KP?)eXvX3)U~Cc>@18K%z}%mHdi=?e{O#-CQ?jZB@ufl^Ym4i( zA;x0S=7akl`dkPm*4Au;i$!hsci30uVK0Rb@)6%#bL+4U)sqF;fuJ({zAp;;IPTEX zXIO9LHUo2K!0vlw*8NRC(s_85o1n|FasHB1c77FaGvn;Jo6UC(vwGZ^HZgAsx`uf? zN&_YYg|Cd^>!kYP=gK5jTro?zpK2;&GoGe~CLlw)$5hD|x%~Uc4f$5CwXuO@Bm{X- z{Jx|8OvP6E9%^^kMT$cC>8nVHtJFD)cFG(nPa+`x$#k32l0OIjD`0I36c z2cRQDN$dA8T1Hs5Vk@~SuJLRs*?RsclBF?4=#V4gjkbk4N`lJo@+Bx-9_j*!I}TTyf{}wI`v>V<-+f9vejj>un7DjfS+Zty|0uqTf1$OHD{x*R5J!OPv&+37;zSZ zKKDPgZNYwrt9`#nM1E^n^jI5wzEBY@wvRTyMgcz}pWP8?QSiiNw&s}s*8jcCfbOl_ zXR+VuAC~xSp7*cv`{3@%_}Xk7ye}S1pC8$ANsnXBkL263HfFEko;Meh6E*1oKxw@$ zC~Et2Q;4TNmn5ID(HhX+U@E(J=R(3Bi^WMfJ;*WZM`P4lhZ`ZZ5Hy^$MAak{_~e19r)`hpDMPNa7?H8 zIEvn*YRtz-&N{a49m~`=;#S5!mhGrg{%~GPsNTG-eW#bF7gs+@dRaV9`SPrJtB>t# z5=<)gg2!d*^p<=`3M;jpB+EdcMD?`Sr=xo|QHWA*gpPg3ym>S9>w(YC(9 zz)~*l(v*Tf#q^>4Y{Lf+mXBG(=2f`GU$-KwR_$y1>GbLJ+tZ&V9(-X&AXuK{rlkM+ z`Cm`}^!`uoV1AG*f!((}${`GmY6OJy69EqITFG7sbzv4@^?lAagr)eyw| zA7t@Y3uB3k`?UAe;jG0>wvXTUMZq&3?#g!@A0Y)G2Nxu?$_`GK&_@GKq%4LAmeAY` z!!uyFyiTt_>)@NixAGQez;4x@`rR%dPwo&*4$Ph8Tf@0u7W8xtzroQZEuScF?I7%u z)CKBDR)Y-Y*gW8x2KYkaK2-%&!Q4`i_md3X!akS}3}4%eq2w#Vy|_r?0K{ z8qP-w%iL1Lm=>e=`xawI>RvtI1Qwr})=Pe? zd#i7Go}A5l%dK2o&Q@lCXFQ_Lx5YcEp}o~}jP0nl_Lz4Dr_Boft(@br;}O()j(K1% zosaEW$z$uI_1j$Y+H>b%n=WjPUti_(erf#S{=M|D!U1Jvb$L%{4SQR(=}ODiqi0LT zIA;GCB1Q}bq)WLi0COg`)`h*JwBb^CYRO5#`&>MpkR{C-7S9xmD?Gh3B*yQLix zw|`#VG0V3tc#!G3FXK`B_T7VAGyJTJakSPHrW{QR9GL| zR449^f~Yj2ZPje@?4ZKnF4pdc_002M$NklY}j70e@wLhKI0W@r--O4;0N;@h*h|c_-u=yg-l{k|pV>*0%&74iZ28kKY zj44mNb+I z`-reN!qbEGdFtpku8t^s%O0z!4`m}-ZEoWhuHU~$*qJagRa34@vDOZrv64nmN6G`N z;`t|q)L5v+Kes@O77F{WqfemCQfrL6OSX$-4s;eaQ@ec9$E~3MVfjs9pFmsX=bQiv zv%c77`?ift=;IWE2evcY#G%hNYcZ__Hi^RT{K~CtAKc=vj(dfy4aKhA?gscgr)8lc zyp6-c@4b9E0$T+CT#EqaTDAqd-&D=9vOZ#PD`Z*Y3r-hw5H^?|y^+ zHjmM?mAjnKGD19EpejS%Iho(lP3Ei*;Ej0mbCS0X45^Et3p9{)C-g8mhY{}_@PzQ@ z(3*e=B0$lfN0I&bL|`)%06voForY%eo&5Rmbu??k;*QdkO{R$}E~{*Nn+Zn8X5&U< zx2xS8Nx4M=0$3M;2RNA1)|oVLqcmU&I^wx6F=g&kz+8qUV=~?eO(rlSplM;xzq>a0 z2`ZE#;*50E({wJ@c5!xr3UZ<`VnQUMQj6u9)2=CsGmK#4 z*mA!t& zJ$;s+6#XI>6aL;ye*28R+T>>uD>S#VaR!17BijT0z!r4kB=rrLhU!}$-th*tXRv6r z{gM{4((AAORjb;)*JG9APQHQh>(jr%ycR3~x4xJ0>E-k3-?0cRQLX#ByTxXQ40UKi zKf+Z&wK0mfb66!_otiZLj2O!)JjBY_6b^MM(Vn z@$nC*KfV7)F@V&TxDOv}d=MMsa(>!a$6T;;(bv|*)6c%mE&Guy_}f>&yqEry3k3d|;MUfy^!e3FTHD3DI>JIL=E9i@C33CN8ML@1rFV9-+s+_O-3| zak#_=G-@xL-Y9uPO}|y=i9UjJtGa8^a*&QL+Ah%630~rmqccw@Y>%Kbq!^SpFh4ow z=74tc=W=Fk6(Nx;>So!hMh>Y-)D5hr3!UT)t>@^i!%ZY4hKX`2+^e98=@P115^7_e z1Yd`N@;DUsv+C$1I14(^$ow5CD3NtX$Xv*|5@+TlW12fQuw}*w#IuFpu=80-h1==k@xRy z)m6pbxZldI_|Yh`=H@=nmA8_Ib&ij|%hcNx@i#ENX1kZzwnxlujpYE^KIUk#jB&e^ z!Qx7oId)`f6{`lHkL$ly)TR7XJDR^|CPq0&@LP4aa~wai{Wm-A(L!7~6Jl90S9eIkvjp#~9IcU2&kscOqV- z9qwk@b4yxg1&bJe1#t8N~0;)61t-CmTSt7J+dk@WXxY?xi{75otd9 zn0+6kR&0{>AA zi08wy(?)*!Y@ZnVP}62{v7ZaRz@Tkotk1@wtvGk9XLrkIF8tD$!^gIszD^odkzM=JLR2{Y1doX=j z*ToW-C0)vMl~Yj>RdIz=*bNNBf?mpzT7rOyo%3bt5`BoAkTmR-RP~`s(c^aH+nBQ} zbR+lBKq@&BS7I2-w1PonAFCs7bb;caN}qfc$N?^7T}#k`H8HHv{fz=Q%mvr}oMf;` z*giZdlaJR{Vk|T6J9Zl|o^D@+&7BqJ=?9=bXlCo&0+??Z1G}gXElji|VK>T~{}U+! z?b6A_hGYXh|D-c4VKb8^1hD6mH#r%y);@MM#f^#%=1b>147!)@eRTCN(@=qailSEA zriFOajIlP`F8ND#8_Ul+LR-6+&Otk76w#-@&Kh!ry?W&Nys;|oXQ6@^6?*HvbPofb zdCsvdy}miw@Hw#ke3xVKdG@x**wSlpwr%s5>=tv0w*NHUD$KPnq0aB2BiW(8zi_Pm z5k1H;4Lyv&DC;qby@sRteWt#apG)8Bi##U^3&Fq0dJ-0cZRwrOYaW{&&sclTsBXUj zJT~ijw7h@7I!3NwGttGGxVTSySSt$8SSrIqzYoD^yCa~@Wi8(384oqwCeK#T>8h8z>^sB<>!kK4f8 zIf?!GzRzNBrBvpzcqdVyFS0Ouk6KdT4;8l#zi3IBXu%w6p#?q6m)j= zHex^Ce?0y1-RtQuU-dTK-a~{7Q4%&?UGv921ki@sF8JCue8eG!g?7x3-tHM5kMu1@ zSg*JBw(K_47|t?(<5w4aJNabp_vz`(a|A3mwMXRH%()1(I(a~B<}3xi-RzP!~ z*V=yn`f&OzFF@KWjeWM=E1J!GX}@HPg7E)XwzqeWK3f^TId}KnxOYv9pV?P(SXQ&0eFiY4=(KSn-no@?(r!O_~ ztS>y)!`|3?k2uz*Q(p~X(PMeT$XicmfOB2iSB{-0W=EDD1;F>%IDhG4**Ymeif9@6%pV#Ad(0F{jd*|*fYiF?)zt=x9H;NsJ*sE@P zJXUXR<)|50_t1`me8uWZs&+LF&sa?4QtpfSRKnpL3`<;w#EgktsC5x>!MSQ(`i0j$ z)N*(F%cuWtSkfkN`Y-j-@;^WS&(lAD_y=~g^}QL72P_($!L~i3-0GO`a11D zwXFS2ZElh?rJI_D+P6&mR3Yag8{1bDtyit1jR(K(Q&v2dqs(JHM{rvHp7u3p=+Sw@ z?3;nxcHTFC=a25+Vi{z{GZv`PuHdWTRHH(QWCN!9R z%^*Y2$?-M;xuA*-e4T}#K9m&v# z?L);nv>)zeF@{@uPllK?>@x$cai8{FUB}kF>!m2D(zu?`Kzv7b1Sid~~;uaYl zwDLp-eGh{fMU4sOwntAMfCh{YLvgGHBT{ft>2 z+g45;6}WX)cR)vt~w&E(O0TbL*C>wNL|u2ns6@w_+38;RFJzY(zwnH-C5-Uj&Fc5@1N zzTv)&QNNR`fS=_{78fge*j+6BP~tAFU7(?~=L27x_KKd0YyNzt$x_RPtRO+*xk`JP z=WbvocEr>DTjt=D)|dDQLCsDaHxyUCviG z5u&sg+Tw`o>0{>hYaL|>@nNrLZpI_P+85P_>QT83!+p7?BmM1P7Cx6f zMEJUf^}hAF3-5VHKt{I zo+BeKHHL7@guNrjyPq4s4UDywcXtn`$2+t*hx@sIFATaS^?MoZ5#wx~CnaaPTS`!B ztg2h#c7-?_0VE$-EQG+9D4nvo=jFD-UXaFqe&#KOvq=IY4!qLAhqvK>cZ-r86Sb;T zeLhJ~tVe5WOH9ncKDf$!>eW9vUS40^VlQq7?S7|osS!?=wbrR#HkWQGW{hjZxUx3b zU)ZGj!{hgh5f#aeX>HQS+Tv-mHBJ)`^56n6YhqSnX#l)HL%*o)Uas`Lm#-_}ieHo* z(mAF)>7-x=@wj*UyUvT-3NAUG28+@T23-QKV?B71FEKEmbHnEI!QWPkdp1UevksPh zVUru9z*H$m?9fMWR)%nM)n{Pc9BZSFzXor&)NWv9R4GSlsf5>D-9+8MTDFF-Ge;+^ zk<7S3=t+IcK(fs+E(9s*beps{uiNu~VEGd~xZSMf9y zQ&~U}w9@r8$k{-5!Wt~|+|Hv-O<2UDi5NV>!#L@zyhxwqcyT&SKI1NE@Z?vKr2Li~ZSM#$%ZoX>Gn; z_j+8tRb$alZ;2@1O^k?ort9!RYy7yRvi`YiBRQ@k$J17!*?V!iHI7ugcYF7bTge+=fYy4yv@%$ zFJQ&2jn0CefFw%Bdy;RY$X$!1#vd3@CsGaO4<38c?9>lkD0XtN(L_|hKN;JcIi^UD?A%YLpFHyAW06*~jUjYVIm z)a7?+BwuV8Og&rjVER7zB9fb-FX-)}ILfiSIFW z<{+%8xhE$vAe}&Xh&F1B>y62}!n#1QppHIx3-fGJD#{o-n5RO5)a)QbLHo4iHdjo# zJ$IH>j77%P!N}DRiyG*YD;Hw;EzFp6QM+t5PZ!Z}Ko{#iP=}@t$UY5QqR%DDn1%4&o9Kimz-uJ!d1>He2p!uV<)xHRJWH zxb@7ywPKcI)gH2#eE+5uJrs*ji$06pgI5Qma64g?C&6%el|FEKR$5WxYDizSO$%yy zxGtV#>DHNGyF2~*^lzu9m*2$hnLSgv<><=py2l0gGW6oc^v41b9WtbrG)A|_t1JSe zh2QGcD}iNc(zP{$Ov-P^qiwg2zna&E1WQ|jG|psS2;bd3$|CSTDsJ5a5N{uhvo^F@ ztQ}Vs##jHs&*f~7y}$b^zw`S^Qu$F?R!@-h_o(J;(h_RFUS*-qLwnOFK?$eOP9f=?y^YBb)(mX|dPN#sgL83vly4c5^E8n< zNS_$aqvN0~91ZI=4GpMWp@IF`b%DQN-khC$sGG%ty8@bwa{yLXfw2Qph&<4IE>Te) zb`Koc7_|{(n*AJ`g8Jw|JzP>f&A+3YdFp^Be|XZ)kEos^ALFd$K=)_vdi8Jq>#8=I zZPfY~Q6;S#6C-N4vd{i0+MdHUqMRxAY}36hD$d>4&&~g6{v1axdyY4>p%+?mJY`#3 zNe}yz{BmW;G_p^OVC_iqaX6avpT|D9&-K_x93QmRYGO-uE%qF~oUU`^&E<%-q!=LD zg*;#p-qi@PzHl zlNsxkQVg)^m5Hl$X)IeH2!bszI4rFAvFjybiD#v6is4hgji<%hY?~acm5V*C}_W4z=PZbHcjS&`Y zaCNZz=EXvTS=WpA7M-v!nr$X5>8~RZ$1ASZUK9J+cc;hGpWgj+`itCp8;j25TA?P& z`^bcv52(b0eJ~KG?K@d?y~6_Ra;xVUf&TvDCM2MdUp$q(I@9=_<*-I^bex&TZe{NIIOF0D4D`{yS6UB`&$>6;HO6yBuTk4u)HGv0 zXK)-mcS90~z#D~k=IDg=i%`OT+6odbl(U@ocO+|uHUT=$p=WT8Ow1^LNK6}?q(5R# zS~8B$+0M{Lv_?_)gFmxhFfD>J?jom+D}rLjrl6Q)a=$}U2V}CS3f(2djORqe$nI1b zaEB|>7j-)b1hOfpO}&|RFt7{W1*(jxBfbN|1b+Xh1c~eY%ggDb{PwR$`4+i!`&m2M zwjcKx8GfD?Mi7&$p*}_XF=%$!t77x^oHez1i*I=a;T(B8S~b)R%sUOHs6-PGPG38_SbUPd^sH>cwjkOy>Z0na+hr}J6WuP z^wo-}GVd`SstxmpT5FjZ4@}5Wi`wR6u2!CY_1koeMD=R6XXtCt->-XQHd@$g7=uH7;C79;xRKpt z%99(ij$5w`hE4n2hBi0aAMW0tetP)fbT5m|z91%!L!XPhw&s<;jA0En*-vC4^6u_g z_`gVf{xxa%d}>W@iHTL z+gUOHx(#qP!I}3#zHqX?^lw*H(2w7*EypmJe-NI_c-6LGd_m_5WEb=l%z42>;0#3? zpIS0uBc>t3A@GO_gGG*Wc)dc$9*L z7dem3%M30HJHe=q%%4r@v)58Hl(mm)v=~q$Z&2)ZTMco$KyG0L$ob5d5R=JiO=w@d zP>>Naq>J%Bh<_Cu#tqGd*V7Ji-pfNBH-<-%kJZ`u*v>{BtFKCxHIIv6X|vhTRvBnBI{GMthR*j#NTqaSM)E z)RQZXUq7F|KI8V!+l#Ve5n{O#SQf5uHLNZ@N4ZTJ`K4SLW7%(@gH6oEeqPR~XG$$r z7~XONi?Q=JfZYgjWiS?9Wx{b)uv^sCOMqRt=Vwc5*JPhrY~Q!3>f`-)0=zr@_30P0 z?*K<^t_>Tu9T$;^6_dp26~9kX`#;Vs0;oBKqfj>ejbC^Dv^y3KTMTt+j~UUfdAUMK zyT&s!m~#{EGBY!ri3;B=tB{G zTwT*q^NlIWF{v%*8RIUY)JU_P2Z@DnQFrk5lg` zzQ(Da#KwrcHAbO7Q%jD&Y)dtcZiPHIMwBwe<4h5Gw!PLkFZh<0{7Fk=fHZgKJTRS!}f53xD@QE;_IvjUHm;LjgfiGI81_pri^{P z(z`e8xNXs^;9@vzIt;&AzKuEZqp&T#3iw{WP?Fvny*V+H0HOzyScdmu2Hxu3GvId( zp$a;?srM0Fua-lU4UrCkH*N;xK&iamO_kxvd`lJ7pU2R3t{L8qdJu+EnQnj5tb&wh z>$8#Xo4&P`_P97s95Wm^H%t+}c&*kW8tcq+n8EN??*XZq5Y$1^N-i5yft}4&&{Hs< zO;&fJO9{>7&6v7}aTqWoDr0J=-xSoQwTPor4Dq+YN_#%ew^GzLOKyI9vgG1&3Sutq%dtHd+iy$N zFb_CJb7AQhwo&GD(&Ox2-JBfPIL0|60}B>{pJff^QPx}D$zy!> z#v|sbKaS}UJ2)T5rTMm*c|wkN5!yMwt}h_k?X0XmX;?qnc;Gi=*{0w2ZQC+FDQ=y8}mPc!%{9LD9FXxVbM$+SuRYj-jI zxpn#(3Wd(=1sQ@4a>V0>tvESwZYWHe%e8^-u#jul*E{e_j3de!b$gYc2N#Kpy8RmZ z0&z6;A>+&vwJESa$Z6|`Zyt$`tdXeUj%SDc?)eq|k5A91$LIC0eo_R}Y-IqceXZ$> zYZ5J=xUlPLV&jeJ?E$>IQ;ILyL0t0n*%j4;En#$UoYQou^|%rJDN|}`=ePTokN2&V zq2FRzY#uOJUk@Wb0rgk^_C#0=viB9QD~{2AJPyn1W33hKm@D>g>(^MzT5`EcOk*rL zX4*m~<_oRF9$O=~<{is^wB{}RVa(Wgj-6$)hnoD{(|_6e2t9eua2_r@>aE%FbFEl& zxx0ImwFSMjY%ABue2idw^lafP#oVp{?wRpU3?`YUG=$_2r3RS|vSdkEoJ|2Xd<}6Q zzQ@aoTx495EFaKs|D2w?SST93`{ZEDWBmwLYNruWh=`wiva}%76&2P*8l-SU3e&GGXosG0pw`(`G!IpHk z;2C`Qqg~JGXz3dqd&{XAIr=!Vd;FVU1kR4CZ$hpLbxq@_XsNi4na(pL98NJDuwiOC za&$m8BpwWb2$afs_^diR^r+zQxjSseU@9EOWtv7SthQ9<-NI(InZB8pKqhVm5I9gX z#}V8rBghbRaxw{kZneV1-!gk?39`)8Yx#S5ZHygtZ@i5eZ6o(co>=Qh?5MULywx*Hi{*rdS-d^t zITnMF{PyzXlKgPL{B-NFDX*ISwg9|y^ZX_YWIryy0URGTq=x-LUf9j`jC7Uj<(9wz zVEHXQ1o>e<-@qb^Rbbm-F=hR|S&z|$##g!h^A`i0({x#6LF?6BVQEK#w%4H9Fk0B? zv$Z1hnHX#9ZCed-{$37`OWCN|W3;7>6e$UOB}pmy#CHFzA58x#RR_N3l^?4C$4zk zS9JcmINZ>7C+teq1zNXr7ditP7<(pq+_Wd(p4f4v^$52k6d>26(@Uf(Rjy0GYLm7* z&#T8rjJB9zG%kb3iHBwPK2D;z9?&}gjk6rvKU&z){3EjiEhw4uZ^flC_Idu8hSFOp zwe~RSa6m14!N(kMXSM^(gcRI>^c5xImsR>=EQ&&4%ZO>XEz_Jf6K1s35-<#yVrUnr zmPLFO4!D-w7Dd8PRt^DVh+^!tx|Eg)lJup31W1N~`bch-VKbON0aK0ZaBM^jTS2ko zO8PbJMq($-L|m|WNwHDxsC&Ul$)wJR%a}5O71KDu*byT9<0(Y%K+pmm(}gMN&*8Z{ zVmctD4bt_Q!8%^t0WD7E`_SxrKBL-l9>p-ue;VRrTP?<>xUwh3?zNQ1mSfJLbGGsb zw#*cjq?u9+u&K3{HAX`_OYEb4YaR2=$c3>z$-jC*W}B^!w%#x*>?tm1vkbZRmY5vR z)=}lT=2-36;w|2nq0T_>Hts$JKhnuH30&mqU@1zsC$pO5FJkMl*OU_nuZ223#^kpi|xi!+zqfl)5%G% z?c?W~O6uB@4@VDG_*F{8z-m`cGhGC4I9jmjgr|AbQRn#jPD(_ zlOb79hgDW2k`yI$12;$|cQN?}PJeu4*=ZzmHZ?(6CnL{TQ%@shC#=D8CikVp7V;L% zXPS&P4P^Met|6-7UP+6M-2_Eu?~okBX$AuZ;ej^aDYpFf0Hl$u;Vvdw9HWcBALZ)b z_j2p!u*7|+rVVwjO$PeVkFmt$Y8&VOLd+q3{=Bzr4Ra{Yj||(%BfQ=7d9Syjm9wWd zHB*;+aoy_w`cr&Vsl!oZ9Dhv3Sc{rN3^kRmi?;# zL=wL7+BYzw!2UgVA7y|i4A_{5H@gYlceh;|tFY}=p{k2;h0Z9s^^2SMg&!H&HgaYj|Y|Ezw4i2CC8SQ&SdJ8eW_CDY8-pRYGB`&n{ zDnf9Iai5-qAnB#J1Y!&=bj@G$nG~63PC41)VNnH_;-aYDc`xg$770>HUL+NAqUUF6hL zzF!FTF9GVay5Q58_4&+;Z^*w~`|6bBpWG-NQb*5z4qfx*@Uac?vrC&3FVA?~$sd{c z=dOkg7J+d=@Pl}8B`|=PHSppE-fYJu6}-CWtGA5?UVnEP5xO7*=&Rdz~ zeRucX-Gch_>ytwXq*2;qs}b0R-z3tT7rOW zoncZ2Al>kh)~T_PgYMnwLA0A>8B;@4!`(SCov@9`7=|p_X#pVX7}QlvpgdMb%xuzk z!i0fH6CCp%-KT^k&*E^>j?kA&JU34+1BU5t9%RQG7+M-itd=m--WZl)x`64N;tRP7 z<_kU7zy~nabMNst>qc3jiJO$iubZO0hIW;d22#crD`xr__Wz3GO3!Jx{MFT#1XViQfdqEZ~CR=VgHyw}ZyRvvT|44IlOn>0<%eEvlj~ z%f;xsZ48XQF~mYM7JpIh1dD$^-oHP6CyUJw(yo`5zaEX;c(^@wA5}e3kJnFR5BdO% z2)Ohd95AYjQevCh$3?}QH@V-PagNaQ1fJi$K1>ke*?Y+P(FSRnJvpXehI0-FOp$pb zxy``kX5i?3Ue8tY#s|F>%@x-?4P zI%9SZVH<&tv7)i!8lH+=K!yKD+;_3!r&A#zFzn?L!`6oaGT0Yja3!_&SQwqJ`!yjx zL~Ad!rKo(~wl(F|m~_nKLPY+(8@X7=BLM>B(^00D8M?{p z75Y{`f6CGyyB}FrOkMkPgbekJA-2{#N?$E!%U2#-D>C)Z z*QZNro1Oc11@NR9#Y=hXka(2eV|>p39;1CD5VEjmYvy8<`tVGY4$8kRpq(}R^3rd* zck(0HC%OFnoJG^?m8oG~jt~etO149^_AEB%FWJl_lpve!{oMSvmb=my`4EcEy)4$s zRjSW24-aC)3^=p2@#aknYPOBZHGx7DGT=M0{9dfQ>2tSz79Vy5**E`i|3Ur+em(vD z<+HqP%`L(&+#4(RJHu}AR|q1x8!2~&T~Y+*-O9%{3Jlh{p*@>#gM{voomvrowz5;} z8Fbp|z#fI;A9oHYeNE^Lk{T(lb55^QRbwi9+{wTaLl4VAn2MH)>mV@;EfS;n^YbB6 zHj!=$(&5Z_PN!xgD?SSJ?`SrXL}8V=skkDNN!^VTmDRbCYtl#p8cLzjA0o84nlSIq z4lIbdY$sJbU(Y#msOn(0le9EMBP^KRpA!-Edb_1TTvD;oWSW;$)Sdfmde4+-)1q(p zY$>pFDE{0S^LG-&VXj|^t+=vOS)-DawP%A)5Aq=f{w_gWj|{~S8P{ge}s z>7Xh=s5^FhyKlvq(SB}ewZ>7-yq_uMPA#gfWUnb7@zwZeZGYy_y^uYqv_}c-wqF`W z52h5`vV*(MU-y!~4@Gpl9^td|+h#rnLA_&I5EVv{2P#9)UfpEwKjY>yriyc@^VT7SzW z3wsH8n_&~_rl3K6Z#73nH(V(C)=ArkKUegWau;=O;7W4L;4q}rN>enqbgMb+G2~)( zRt}8OAf^jEM-KhVC>TjRUiPPt?_7k}I)IF>jOkpn)R)HyG|j%)-wUcSF%7q!rQo<+ z9RmbwjBQlnD=y1WZ!1Y&yF?apVDb0+C;4J~WtBDz^*#M0LsfaJS84rv-p-*sK5lU= zJ_;7!i}Bj;!Q>*6|G6qWW}R8ucxYO&5W&y+7Q2n@gow@wt@=Gw|Q;{#<3@ z>4dd{{i0m_83Ru;z{eZOa-huzTi%Z)L*G-sm1%vSOg67sCKJEb7GM*#?DrA zem*-+e5-`tEYVqj9*)}G3R)I|@fPw~7J*&u`qGjbYs9eWY?2o>Zu=|?zjx2FP>fpk zF?nE}U-yP(pKyI(rH=>y$t|Prx&r|qob1Qw!dy(IJ?gCD0)kh7_`?D5gQl}BULd5@3G zwGbE1SPqpk(~^&;H^duFS5w{D2uFi5tr=i7Uv(j?uuVnk>Osh#?|?96{JX4Il&;eoR+zFw}qC)+rP?f zp+^h0D1PtPz4bnN=gNx9&2JWXMx)O8c@iSmHO|47(R1FeVLaD8uU?&RVaD~3L(b!t zZE(hzQ2H4YUvnyMyQ7YQYn${LdS=fV`LLhpc9@|u+3T2QXj5+rN>aBCl{~vALqDkN z{~)Wa)*~9a2^^Yp294I#g1CW%+4;>HM+F(Y)n?2iI&B!+mR5$$t{;7BVdzC_%0Y4` z(i&n#eiX51yr0W6li$yMtZiqV8VyWXZPmt|A*^;wyh)OG8r&Nb^>BjxKqX{aMGA zk4LoCl$Jrqaw$5FL7)4C_xV;^osSQ(V;o^D_L*}0-mS`9aRyxdi+??ZbJl~MgRvR4 zZ7t;-eW-H$xjnJocq^Sl4>jz`O%CYY!{f&bMrHCX@9k~viDeFst$$qO5zMu<4#yex zMmf)~epKNNpUwcz=fBGD0zb;_px?^{a^Fh1EdU?7CDT(y@F6_U1(61~=IQ=m(WN>) zRWDqw(!j;yqS1Eid(n9mT}3mAL#lOkicQ*o{_VdJbdg%FJx$&;`9)wzg7#>D7g0Kr zl(WyPeRHwIum%QiTjly$`S!`9TcMS4W1o=rtNdQ?$=wqgCnD@4S|f%ZoLVNX?CTq0 z_23z_n9Wz&adb}uH`sJ>SQW_Hvw(iO`*8aC^-JelTByR}FMhcgngcbG(H1DE`7L&| zo#BS*uzU@DZaX$GZ`Pfe>!Go<;*Z)#hD4qj+?tcR9Ji|r1T%*=zR-bV9bd`VUiN7k z%6rCCL%JOJlHw-i&eCL!)4fy{4q16at{E2-+e0 zXnvK(EJuuBeDG8=9(jC3q%G+f&3$F?U! zK9*M2RNFf{Wqin>J!a{9pBysqeM)Sl0(}ruFSlCB7l>vs?xIhtvD!R>NpZhX-eaHJA5fNiLZs zeS6cIJMoh&R)$bMte_SpmAFOfm~>xXmm;kgS?iRAGb}>p3&j=z`LMu>Sn>ppjU7%Z z!gCA17-g8x^|K45atmmgXM8CD(~YIxN7QZ?)zj_gj8H(IXzKww)d_o-6l)`D?bg_8v29;o9j*Pj!!d_Ft0MG-y}r-1;uw66 zsGl9$JieXcy|30P#c^&Jo5RHzVvnq?j&tR=IWe}ryogGXdF$wmQITI|NHeuLJxd!~ zLyYqMps}=3;bq!g@F^X8IKj8T zRu(q+p&9(e0x|&ri(3er6~JOh;P5MkfjJNvc&cg~Qgw5&!jBenfS$LIco_t{7q2l! zsAY{-_(sdkwe$Cj#cu-RZKeAs?FTve;1NP@S}X$;j>)b`$-=07SZ4Q9l7l@=ILAoxz3r7 zm_5c7t07*naR6}VqYb&KF$AXT~dn`ZMk5I0gf*EFRn5|sY!qKw7@I~FN zSm%od zEoavZWsg;GnRe&&Y!a7pmuDiy)>D?5;!k`+p3yvEG`aV)>}7~`wfjCJu5k}<|C~Pq z=B>z7_E;U7Q9m)Y_WkX?{FAmyPbF085zJ^knKfIZ6Z zy`KKV>F3Y?pEK=xqR^N`77*`F_%ZEwu_x#w91p!!=|U!zv*R|V;;X$u4am;g;o*b@ zShMKsHrO(b9eOZkT?p1WaHk%*68KdXd>>^YSeI$_nqw{kV=H66bkP}eC_T4JxY-ng z>xgMV(g*u;l`op$QznGpoxYPX$xjixn>=GN7)2L-|h^&wSD2b z^?G%BwsdEFZ@j|Y=qPaw-io{8y72r>RF)ol;-%7R>T`+lUx; zLpI9rOXcQ3&DZ^0$TMNO?Rz~P{_rGpjH05S(MO~ucTg9!1em3ho!_i67k!Y8`YnB9 z@=OT+JgOD%HbL0{kIcGf8%uIl89Bh}oS-JhPuhKXEOS4TjiQcA)dekCbJln%;f1^z zjWl5cv0aGXW;n-m-6Wc6vQ@4Fow9S|!mZSN*nC{rFcw$z+T7_xZ6b?&^WgX#73 zoqXi;aajQF2yhUlU|ovi*WzP;J#Op(si8S1^?Y7khzoljm9|1;*h|qlOB`e0Rps!< z*lJm0h1(R=GHhdvqf(uroe6lYjgPNlyLwp4$jxF4_ z#|lHvzI=IgdFvLak zzD?6;6j!W9<8Juw8CXsU*y=nEl324#2nJVL>Megu0eP|zZ84$8rC&{07Ldg~S+INe z@I#_(s=?(nV@=2-pZg?;wnea1Xu0J|%u{(%6ZX2n&Q~27dvQ(do%<%pqHzVV&w6!i zZeYajpF8p!Q!69rad^NSewA6G~7kIeZsX{qT}o!6)K`V`e>vE;)j@a6>X zV~#16d8)Y1uEi$I>dG2z)S27RV@qZGHKbdn3X3G`M_Ogm+g1k11JRAaP7^aPj~~vw zzrLmo(-C=v0dK(^V6L`P5T7&WY@5e5m29($VxW_^S7T>~3XRqWh*)=ZohCLus3-j5!4`m~K`~PR}O?xF*k}R>iWWKHHRd-K!3(#mF zNZ&?)^#6Z{072510fZThgwd#{r>mD&mCL=dNxdTxXnPEb%BGk=2fZw^oXN4oHvj*z!-!9v$k=9BY0{`(c(} z`aIKzk9EvnSsUEr@fx;KKGJ@APCWLy>CG*C+C8BXTbai7;S5&2k*bGTb?S+CEV3=c zKKWJo^+hv7i%sByaf1&4-{g( zbOsw-@rmEU_1}<3(=YV#fTdTKM){xWX0QOE00cj4aXKJuyWUsQ=o&+2F;Zd;ks$f)LS$AO{e0})k^;xbG zeth^BX#{IL@O~#-$jx1meN|X2;#L0c*3U>G{OY^ggf0$je@)ENsFA%rkPD&9Vid{^j0^dH)3PjjIgraJJkfmYgWMM>+CTL1&k|VI^xF% zZ3Q}lXedXia%|BqKkDKp_P5Hb;`b&sXgCdF9*uRwenZ@d?gUXenDEX~79EJe0Hb#% zV|QT7=TV~HZvN`$4IYdxbi{M6Lw&?Xeey6G->6iMIX?X;BY5o;Pc5mT2&E`!SCW-@ zF)rhxCdX7u=U&RlbWE#P*M!HC)Obe4K5W*~sLNDRmm7YGDo0(?+`}tJHNy2?v08Lp z7*}~VPpMoE?>QHC;4-$dM$NL$CoaZ&+-iCHSXmR#8=+f1j$)VM@cy>(y*AMFeT}%= z_S7tmhOHM1sm>^-q1gH?dF$a3t0xA2-mSVl7CjM^br=_<>WQ3wzqBxnvah$wWq$n? zx%W)92`m>-u05f4#Hhf%WMArDwWI&;q}Wwlv~!XN+6QT@eO{Vv8LB8~KTh7pMQ^!A zQ`MGGFyQeb&yS%Aya+O|oPjHhc}w7RCEm-5Ov2R$CW3442k7Z0-@psSOMnhcpR#Xv zpw^|APX9h&tUC7C<@tkSzYQ!c*_Y3u;rqkV2v+R42@GENleoCV`U+ck^AbdWVr7N1 zHXKIC!L?j5s8GaZE?u6LVP$G5GuJmK6vu>kxpxhH=&Yv8#ZAcyz&(DpJ9%uuBMK-eG_;?6<^y z6D2AHSzvANmR&~Mu&ajRpXOyZ@NUC3vwI=*oea^O@je9HO0B@gc9vU3Po6uR7Q^kZ zOFUgSEe2e6&osQWP=Bvh5HHqV3#_`PcXuw$n9h!+*AMl!v-X;2N1sRIygM@2dkdUO z0u}cBjLvZc)M@J?gt#xxIED?34RL?%bD%hm9;6&2SP6R^>zKbDYv|xp0^Iufr!RTz zh&kuN3V+dc3`6A!I@GMF46^GHd7wTmZ&AxL*0EV%R^{3mil_Pzy~R27{5a+#_Gez- z1E0fB+!3kg)#-IStr$6H3!AakER~;2a}GV7^)6%hS5RqwtkVqNz@CYh#>Ck7`j{7= zAsLlMyFEW*yNzDffKUCqw6}_7+!{B|F`m_IQvN=x6s0^r6T9p&=HA+W9L>?$XSo;; zm)+q)yXTXR%8tfZvM+V9N_y|S&IWLxbAJ%_yi4JQL1l;A&lFw2jSQpVdRYG{}7JZ+X0pKB56%c%(o4 zoyIVNS<>}8qrLASMO|K{5v%oiefT7o{C;@+AXf#;b-?l!+-JEuR~!Dg)wllo2fr7! z?sEb1jbSbs^oLa!`wV%iM>L4>Th@Ui4PWsnEZmeSd?i7y2!49_BK$A%#`py{#hG2A zQrSwpP`(>D-{lg)?l25FmXZgrhFS2_#98nQWTA<34DZ? zx%LbXG&`=EAMbOV_NenB_NXqV3fpPiDOm};!agsF%N_1dC49Mbzqwj=@`ux!Qay{tnH}nkF@Fr{6+|6L^TM%`zsA#jj|5}TCpZS(TF{T&pQ&$Sfe~E)eAiJ zNogEG8L7lIq>>c88gh+Kn;5yJUGqGL-}0=ovPPMEBqm)KM-X~!^SE=4$H8Y`?Tu@! zt+gesN5Pd+@?$)l_s3g0r?keW{4I|@w|YhUGbG*&teRK&=)=#W$vHJITYN(@YRl%H zzX|+dy&%!#_ei}rfG6*je|Y@!!*8$08o&$*Z&G}t z;#=*?30GgfF2A~pMjQ@`bW|N!lwY3Owxbst&4=+$p&sST;Pr=oXbFs0s_LPij}#U1 z^M2SdO*DPshrT$Dp=@h&k8|`E^;}UGUipmiRT{Lo5*Llx7one*rnR=+mnN{kWr0fv z-zQkp3>{!F#1bdrK~GlD;zL_Vdc*0k{^X5MuS%9%Qj4;DCq^2@dNuGTiRXQrQ~~Ug zbtjEuVmAhe$kZ)@m7i!~>eUkQYW7VM<*MC#s@!F^tMo6$@dhw5C;Git;jP6wTF*20 z!D$ebwnJ?%rbmcJ`}ga%MidALBoM%lZrZA57v{)tpBjSBk^trk~Dr~25=VT#)0_*%Fu6GKL`__UOUeWxW zR+1S&4U9#!yO!0()$m!hNd<=S3qImW#o1gx&57A+Wwu5^53`b0j4?JtEn_b|_WP`Q zkX1*s?Ay;H(U0i%MSB!c?Q1CD$5p6l_C?#LmHWs!Dbg4DG&(%L7uK&V?0 zKejIEmw2@P7Dwc}y?^^MpNUoS==aTb%+xl`dGQ&NQKg8>ygfE4(jE-8*<+b{-=4=_ zFvDj1Lg(%07^AKG)}-HNZlA){z;ch+H_!xrZvfxmHN!W8mg}|eCQ7O=S6m8>hqlph zfQUckcsr3%x^{N8ur&XI6)cw*Spbx2v@sGH6(*A2)kK<=XiVyx=as?YCBizMRT0gq z551(T`weR1udKVum`00blex2XPJxYmlN{8ShbFY9F5E zDg4g*xjQp0*8cg?)c1Sdu)LSRCd5&Ns0ub}bB4GOOM!KU=lz&GUfYjQv_#(6cE4R- zQMfC7@DTQJLA0LL=SnUWb`@rtpyIg5E;6S@G6x7T`fc~ZHjoq&k_472#?Cngcrr!T zbYnp+oJ|E<-hA|tW@&`zyoL+6!gd;Oh)j}6rq?8L6Q{>gn-cN{$cA_#1KN~-{nStsk!gB8a^V>?j+e+Yy%Nu)HHw%ux&ArGz18*4kfi>( zW{huCkN+`kt$2>BD5F?0PThJ79dgz|G3!{d&;7I9L(bVokE8ZksH84$VV5IGvFZr= zX&vSLcC`3*M_-F_mHTri)=``-kNp66K!?A6Vol8E#AdigZACp#zBdPrReLA1DpAWS zuXWC;*^)nQLCY(~W6>S6z9PRpKJ=E*X%qPVa(!HvjJN?;rk`*Z=0>hvllv zRUPkFSOfC(EHs*MxJ_4`@TyP zS2(shv}p`ZxcWLYf6>$xD`_Ch$`uh>k)pR;4Gf{Mr1^{WE#3w95pf8OYmU)){whu5 zk8(?D#1?)h*c_g}E3fcyIG@704m%a=5E~rmUiNz{h$>HMNNPPB|wqlO=*px zr1Q?Zw+djN`aO<=Uwj3CytCr^UNo8Ixx$WgPMM74I-+|@u!Ep1D$FJ>8V~EB$u>`SP%j3>%2{v= z$17w)THSoKD2-a9HP+4JoD)EjP%@q4qlR*+vsw@lf8Ea!w=!A7Ux|uhi@jmHA#NeZ zvTdOL+$&fWb{xmvSq?6z>4TdYp!xel`y;IaHqJ%38AT39++x>jDj(IY+t613cC__+ zkW8nI1;47Xt*0@1J)@1vwUk3YocS@gPB~t?M(?p9R=&R|X~j()@41CU{o|wesAxH- zM6&OU-7vO~p}ek-@q40KgT8%VuMBaZaTKfWrRTkk)`&w~n%3qW&%R{YY)g8F|jYNTWOhGxgCkzn3_AV(rtxs|r^FqaT6`?e2B^ zfI#`U*C5|oTwlW#mVBc{^yLN4w_c7R&qWnHka&{*S=ho{N!e#I14CpuG_vdYK;uAJ zn|fv$dC}kkAioErW1_WqO9yEAXj1u!^KfM;&M*+e*>QZ3Dx#69g??Nc!8gjiSk`hZ zp*rC=d1W=oZvvyqi>rZO^{pf!Iu$`B6PH+OGk>0hHv-^LeRs?5(G2> z<=xE=%f(Xk^a^0yE;~dZx}qa|G^BCm@RM8(jNdE9mC8TKO`b)S`YOB2}-NE=q!2B9b}%S*4C)5Xc=p-VZ`iZ)|M7czImqK3uh<0 z-X%L{~PdYF1h6Z zCwCG~^XpL+uw#th$#=p(;-dklskD#SJ~4nA<>1l|BWcr7x#vTMt;8$yeH_6wd*Ww3 znZPmBUyhZ=;pd+A5tGl+xe284m9n{NTGe99oS$>NMOj+r#&(>gktx5-EmeRxv@^@? zC}P_^GxJ94oI^=IB0?V})`s77PHv1$uGc4RGOSC?Vq55$4y|m=Wx(-A#ik1?*N^3U zXIr>=R(n0owX4OwC*Bg)9-LZ+DgHLLYS3<5zvj8dpO2V&nh`rOfUOaq6L;>1+4TFX zV-Rb6BxZjUB_GGEfjB3QQf#;6{pkfi3-I;f=cf;nA#>zP+ZWm1T9@qZ;0jTDZX_OZqpmIuy_DWZSIdelQlG>&oW=OC5+fCZ=P4Wa0I)4D+e5BVixG>e7# zB>MPm;wPElA8rjDt`?U0XYr4Q@K<#!cHhw!3WlqEwPs6or2wc>zK69$zEDbK0je#;!x$?uaha~=0Z3)`FWdY0F+{!KCNzNm?wTh}GIZp_(l8RMk0 z3T}lB>xRgI_h~tUlgP8Vz-NT8>|S%i>NF1dF1ef36li$!GaS?VA_?TBGWnOmoR(BW;kBBH%^b?f~>He z#$mGNVs9p60eSE6=;scp!gd-5$Wy@&#MNOMg&s{hjC)l&a644Cy^Vnkug?wmVZ7~x zc51|d;!EUD_-JHfGb=r>RdsUHkzn}3DrMwtkBwJq)mUwMEaQ0MSrvY#K+$s_IR_4M zZqC^bWZT9xj3Tabaz5qvH0Dv}oL0Q}Su|$+@(s zOQ^9u0)w?1!SlMb-}ZJpjal&$=QcURyLp};ON@W!-kRk}YrsmNI#!>V@yGGTvtB>@ ztm^2;@Qzv6qxx1PzrB2U_)(g`=;7Vdb_WgMdn(7gSpKiae@Gg@`Aa0+23pwbn+#Ok z20k8O;}IIb3oS#~&?F{+UV+Jj1)@>`qu*p6ROCsTfO3CcX#{+H`0@GIhd+P)N3VF7 zv}Nh@oE<8$V_f-#TPYo6BQIxSrTZbqK4S*YXtai_!exR+?g!~%+)@eM>L4#*5`W295h8o>M4Lf z3iVaKG4mNsW#vkWyeLME4(jiTb8(3#9P5l~YIPUkBH_$N)J`{btsimQzM%B# zQTOT9Uf=zVR)G6y`BI0N+lm^+dW-tZ|1HM;9&=oQx4JJ+iu*9^VSsq|)MgjCfqQj@ zXKV-lSSvu`xq;mf6@VtNG}}HP2FDRrXVj-JnmJlNmjn4MW$Z`uns-n`AI@+YQe(Gg z8X~843CU3ARhx*l@SWU|HSJ^k(;XZOZ_9cOUkNc}%!8sCkdv&{n9hcl;k z1>eFN!;UdOFJ%k;l&K^u@mjv>`tZRD*0oyL zCL@k?Q0I38J7^Zcs7M;vcF^D(sO zeO7hEV|d4`8PyyVqTSQ@Nt(bv$j@;;?|4T)E06aE@L84Zz zAKDnQYftq}$*v*6%LadX`RCVOMxgwrbK?qyuAdydKYjS{@Z-lnyom;|UUiDRkTI)d zS^135pta6us@9sox`)p2y$3T?C^S~FrsUspTWIOVO0!pTkh3^6W^q+8-lDLQ!d0m5 zw$Q*pgks%st&L!6z}EIvXfTUT;E9iyfQ3Z}zY-s=1eOPIaAk1m z^>%K zwC#}tw-eSTp)VT`8r3K`5>_7P81AofGdJA&xqrh^ z4>wXAV?H#!Hl=<<{Hb+W-qJD)#p_3fWm&t=-&TIW??Wo-sb$^1B-ye-MBGaDkk$B< z)aBHmhcm|9d(P?ci+zX7LCPCeMf&Dh9X1Ye1lvGPb zou09UQ>%Cn?)~Z@<8L7|?m5jRo|URUEAMSjCGT6jb5P+m&O4rMMMe2OD_ZB{Y`omV zHU}|a`xagcnhCS{Bp0}`349OPy*Geu|4gU;x5xkd@ISx)?LJ(-4*6OT6ts!(0L!su zA|E0y%`_2-EVSUl2uiiN+%QJgFbNGo=|*?H=5qT0GW3Kv?_8dN& z$y^H6O`E{1^IT7}(886s((pl)Xs%*Gh1)Vq(-${_{vh8_0sl#E@vIzKEup!)v?;OH zmi5D?tnVFJBUrDK4hu>Y!o9!SJV7uS+m;duUpUSlPsphJ_Te_LOWm%hkqDgN6_b*XhwL(cGlmQ3jVFj zxywIuIkR42XI%8OBOhf>6x7Fegoa~XJNVx4O9!oJ+$ zywHKPhQAVX@r!61z83Mi%!?Sk%ne@!n6lprPKE7Z%XnU+hfW;HbR0Lvp#669mv$Um z@tO{(dULIXk;@RPeimlb5#ws_6KcU_TXRZK9UzG4J|gJ|Hd0|N z&whVwSEwzG0^XchMw_ae3WhZ^LUU{Q;O+CV&&py*so8ibe(yZ4O|R8G>){;&O<>#( zn%UhlUTFX$BtC8#%D3nHlU%zP|51=Sqtxr3f0f(jJU;yP+-_=d@8DKD_|@DmVowWg zvjGrIG-;OMpES(SWJ4p(HlZ;M-8x)jxscMp3{6<*27O5IXl=o|rLZjvA@}&&fD#-W z*q~83f9t`-pG_PBqBZ|EHbjf7Yq45hU*uWV%Cn5mawYJqygA`2;14e!b3QHExv z&{$JgIodw9148s%u{%YyZs3IjPT}E})8XJEG=lY%jw^`Og9h}TL`TP^`3s-YoB}vv z##Qss4ZjyGBmBZw*qr}`bN)czJ)R^!R1Lobpk{HveirgdFiX5xMG-tsEH5L(`j}~S zY8y)puf~T)ieXmo)XWMTtF!Jw#n3&joMRCZ!>^$kD?;Nu7F)@>fLma}vcfKa_G=c5 zC$bO+w|IY$yE#@T2lwGd8se5M0U%BPl9)Coqcka{ahO575!u3z&<3mwh3 zQPk)|fOc+M%Zu1Y$Jk>$+k=hTehC+`(AuwlPp9%&hM8{4x5y|lj@P4=@j#`z)S}NC zCiUXc&PQsvvHmr)I2LA9@*QiIG-mUTdOT|H^BKe93aPIlk3C9jEZkSyk!@>?MKA|X z<8QsIjzv|{*3Z{fG8XlicFA{{cNT8hTb+9^anvL1ksymdy?hSu)W1k0`1rQJE;GCz zkN+D*z;5{$X;u9a+O|m2-eP-G1_s|WX@edv`nwQ>t0#ppWPGTljXG(W$s*$}Rt^3^ z$1E7(DKvfqr}Mpk(Pcn)FrsN`P2g+d3vblHmF$r4|Lrt^vCF~%to$}G+PqjtFY*Nf z+z$E!8n%+xGaA6*fg4?8U7>l4Mlf2twlYxy%&;iK$(a}{Pq=}%D1=6^*oO5cHj92R zT@Z2F7v`diTO=b!+zuM!#l}5gmX|MbY z+%qtH^O>yIOr9C>URvU*ye28vqbCmY z+oxTNz;Ier*;=_?X0%Zrx5Vw`d7PBS=PAdw++I03pMFeY6lEC8T(2>UzRr`aSEE{4 zq>*h~ZEM(Z=ZLOZwc@>vtds{UN14t!L!8vOP0YPs5%H`@nSDQ=dLOsj&MwX?o|UY( zHA+@>-rSsKM;FI!=tjjF*UtK*=-0e9gM0P%C;46ATV4&!?%=)F=S|1;B2BD+|L_kF z|MvB7_T{m>n(+3Gh8(77F=D6T=E>lr5sVYvaP_Y=$j~xFy9|vuwBf8#SNJ0k0AMe= z0GI9g=_k1j@J|n4UXrhNs(5)`3?ts{C)xxq7`!_5?@P~p54KA~ z52l%OO!ii&u^h&<&#l3kv7CuLS``a z1-IDjSXt-upDPJg*mM0CoG@`Xn)+wJ)+)o%_+yI-^IF_!`v+b!3yMlkCchfugB z^hf#0P4ow@-rgI)Cs+JW(yINt$KM|Q`t|3kr;pNb`-BE!VZ%}n&DmwmqXGOZ4~$?1 z`SPqyNqzZ+-vkasM=x_Cp=T!M62 z3&A50!UK}S8=P%yC=ssu^>6GoGmS6@^n6cimbreLV+cmIE#9SjDuC+N_VgaSEt}*1 z@S4GR`^xemh>$Wv5L8TJVkx2VzOelSgp?I|sXC&Q*Dy;AaZt6p+IHJqx$s zs>wne*v@+YuH;!^Yb+N$GwtcAp9XwEQQ%_YjwzHPX8GCl9dS{;&Tx~~W${sArx8Hy ztXFgFt23b3==QS^_BFA4FZF%mwHoEAsMT?6SQVg}dWFB7+2+z6@Y^|TfL6rYxIX+G z1oj{0XUjh3B5xRIo>O3wt1E{(UJf4ocwPW>PpLeeJJsD}8?zN%pUZKCaf?zUta({h z;wsO)8&%hiC1zn%tZ~jP_7=~Mdi)wbyDXt#<@mojI#*3kD<^%{bMTbAXKudGUg+7( zqDT9lb(l$epHmB&v^7U^CF(rH5${KJ5xqu!O&;d26nR@(vgqR-&F!dtPn4FsQ9X8N z>0FU>Pwe+mjh;wbI?N(mv?f2n`NIvG!0!#<)*hN5`z#Hre}4V+@YfIZ2Jo{SP?!Hc z%iD11r0E-SXo?97f6CDW_AO(5!^ZWecKEC>S4fl!<2qdl&62B8XV*NVLx#rR%nhZK zLY>|OPRhp=-f|NdIfQTCVz)>g<$_vi*y6U(vf{qV@9#d#6~ZrQ{yxe2)7vqJ-w%d- z*^O%>IN7b*C?->8z?Xebez0>GJV^;nY0*_ZtbLh;HLe=q>lMt1b-8+2G#KV<6oD-Zlho524dw|+-_v9B_|X_;Ij)VZfkBd1umTwj}{zJVZ3bcC5<`npB`EFU(Olbug4ME9v!|Ty-kJfRT6sKA_15&%f^!3U2UcE3)VfySOz)e3u+ zA13Hvqp(y<{cV_~>iPUM;M~-K7lEqhbUIwB4vwSA-`_FQY zu&P0_PO7MVTKN1yv9=Mbu7(BW*vi}yaLd6cv-dosjWSK8OmaN36dQBHFG-K^4B4n0 zuO-X1w>UXk&e_6f$v?}z=8kUIkGhp8$~c-1IqhRp(>Ka2bE;1(x4U;vnpb@tP_wQv zn(Gn7BetzL`*5LUb?CEcd5vW`UhFT{)^%>tq|#&aw&!hZe!_cJd=^1oHIo^2G#^8% zQ&;$?dsoRl#IO}(zZ}OsxDxp4+d zfxSNYJ;7C|O<=4_tW>cRhVC+GtClvD!GBRy7=eNxtaG71%MYrnts)U0YAbetR6hvH z$D_Y7oN_VOjVGm?1GlyP@cMCSRL5F0Q{QWpvC=YQd>m7y8lQDb^~dIQbj8_{k9m97 zzFh^dCv7EicDs1)!?UY{BYkWYwpU5$af<|C^7KGFP1B}uat@tvr-gJHa7gS_^i#n* z_e)U?fnk$(r5na*u3bDD*yLyP6aiP*kjO`{hB6=MB>Yo&q-P{kQ?+2hz?Q z2(c`CA5)Gpjc2;>7DnYIXoV z!wS1#18_rJ#w_jIGSF%-;=lZ~&Po6)uZ+af;Jh7MtcA}TDB*eg3K$U@gPqMo2wsdA znG`2xW0Wbj(MlF(yA?|t8#rFW)3L;RjOo}WmX&AY7KU@g7AQyU8Obah;?+j3Q8QE zE4p;Q$!`K9tDm2)Y0X~aWnPWmB+`F+{O5;X%dp_z*&nKaI%sjI(DyBNxVJ}>m}tm85l+0!Gg zTnsn=4H|FtDKvr4eDe%NL{0Neo4}|$tDEb*1r8d)UqUNbR*-y2fQ{eqTfB0MXk4L- z+d@BK?MZVMSK(UgoVmv}vKizyLp?%&7c~>y=(Q5A?iG%x2g%Yb#xJp~D|m4SMExQI zu|=@R=nuC@rxf?MUd0GPHssBX((u{~u|eYOgJSUNZuzX}`b>1rbgnb?LT&Omsx*Gi zW#Gi8!?A_Ua$CsCT(cUWnCgJZx2K9COsr{lfpi^ot5+1mxBDdpdj(V!yV!GL>T>n2 zG+2SN_6^tmt=|k>evTY0(jBOu6#QXW0AM>~KQGvJpsKDee2&W#&*p|v!LG39_y#z( zgZqv!6QJ~O=D~PEPPcqISdfCbXO+wBHEvlyAIHW%7*O3n+9AHF^BwUHn1s~sIX{hU zbCvE$VH0!eF?k`69Wih3*#>Asw2eEi@nOiHSLV60@+jdr9tkXRYwrJCvd=@?%Dfm= zvWTVe4En|~s)SSKv9htW%!N)_vhCS4jG|BF&8{LGAcx>m(F2U;#J@_bo-FjPtIyiHu&)3tKa8UK}U2`AAY_O;*gjz#rS3J5OAV= z1o4P%62>|OW}NdXsuDBfi2cX2Y5?DnAg)L}yJZ>fA(DHDVeUS_EAda^YGAq8ZZ33& zb_WgMvs27+-od~wIXlku4cO-FGlIjbbkSs!JMxCBfcX;OsJDUEG@++gFv6M|E*pG9 z7+p6Rpn<1fe)!vmPhbC09{&u^$s4@lf!HQ*0*S^XzF9i9X`QwXk3!Uq(6tGSy>UWr zV+kG9Mg=7Yxxc_g@1> zsZn#r*WWk0lim{x72y6JEJv4Fm(rl)QFRxCBS%r{`T)gt&gb6}HAPM$LLLn8(iAdULvzlBDdoN?saE z2r*~$emW2b)jJReRLaiDJ+n#!K^|8P2{EhVaPtrbVj58O@m;qMEx^d9v3*!Wbc7cy z8=wu5cba2*Dd{>G?SGJK6aMhopUu)X9_vW?`#K8i9xTW+CbZ=wrxvK z^ViP?QWUF=QK?QoAJK*Ne0@VSig79@=Toj@OJs^wzBY?%}tGKRo;>*8yu|N&Bu? zxY*>aPCn%NAdfGhah1RIffKHdTtu)$!--3uNZK@mu6%$Wu5#4h1r9$nEf%X>Y_ma8qg(c4j$tyAl{VzRfMHJqbOWq)9Cw z#9sG(yor!oTJJlDw|1urHRiybNn`()lV70(kI+9s1?< zE1&~c!cq$RLN+#A!+Kw33lZed&^c^P5}>hcRxMDx#WiRsLkt@{@Vm&~URZ7piLN}Q zAoUwprH&fCm&f#$Jl6hJW~}yG%;)OZ=lBaRv2;=IEMER&YX{c*(}PCS3~AsHJVTGLGZ&+(}0+q8yD;_ zEP)=5*THX)%nWMkmYg$!Ahvl6;gNlY%isV{bh0uWG3a#60MC`W25V#KXZ2Gy%L!-6@EiPEabaA;>6Eay3AyBWu4H3uzsn!!tZ zza0RMQYhdQSdq!V#BwNr7FYw&1=Vdpi|66tM``~4p1(I%Kx?z;D;;&efvb}JjoaA2 zMjp=lW5JY}uZsaPH{&Q(=9joJkDm#oc=0^8F0}jbmviHUdOas zQR){J>Ke8_j7s03yu^@FZaSxCjSo3L(V}i2$Fvp0=B2u|{F~)9R4tZL+@let*ox`7 zGrZW^*o%gU_S%+eQqFMO%eF?zoAGk{oMYNrx0!i+?0co#6}es1d0aW??C7rdI3uH0 z)acngNRQ>rCh#3}rM{0B@gE=mEH@5mT!|_x0gcMmhDwEM$*1$UuJnVP1nNot^1-0+ z@w=!%0Uy5!j8S>?tp^G9^GC7%)^=;$L{6)c6qnhP`*m=;b35X&UV-MHz#khy%p z0e-SATz2dagdOc*99Px_1SSl#$o z0!OP#%*pwb*GIM4V_C<1m%POaa1CJO#}E0}8s1`N_ZYKQ`5q(N6%!Xv)%c$Bl~^|8 zttN7FK^%HKI~3eBsA)izbbv39v)wejn`nu}7?Y_&k_FaerxiHnIw62*Pz0)k{ASpb z@*vDICeunaQZ39I+n{;_X@@9vz5}9RvXObi^2Va&oTumP;haeQei`tv)69F|`IP4= zP4HYY#wp+kOFmkewpk7nK_xoFWvGQ*C~Ay9zR3CQ^4V05nH#2Ar1R7QO|{adXVoQ% z@#^vPSQ`$hIvzFb{0N*{ZYfS#ugvwHj8eDC2x>j8h<8TIj zKFHf1N4>NW^=^taopi6)^iqDWT}==CvMfG_-+E1yF*Mq`k2IUx&s%xyjV{lhoH^c( zpdGQ@TaS|6(Mm86!)_zCrG_#>~y^26_3arUawgqmg1X33{=WvT&6%uBhjx6t38pws7IZ*fhO`a&@gJA2q;c znR1n?JbgAjlazQSEm5&WJS*wH^S;Llgta++aZCriVAr%`ZcDeqJ7&FwzE8e0rY^HC zrF~(KTAdyW9Gv4MMvZ5qWr+083psK#Z89~h@-&zD7Fh^L%w1V=TF8|rUee9JWH8{_82rZ3M+f>D>{CUl>|P_z*wKI=H? zPvhceMja|a3Ohf)i_+UMsrUlY&Q#(U8~91Iu=BP*%ay+$zmmf-FOo#Gvz@Ap^FGL8x! z_=qLf&-Aheetw5FGrn%r!rOV8IrZ|OU(zLxmv4QhxrO5~-vW(%{9{(k#EkLCMyLo?~4eA}|Lg@Ygw@sJBzXwPB?f@Y%^&0lDR^Ft^5Ah%kE&LS0w zZNZ~no*Aytlz$xFvMu8?UBy zUsV0j5my7hghucexmCfZmrtPqjHWQJ3J&zr{6!-eR|uzDSd;REtAnvX^(tX%1!-8f z;9#cTSO^qmVT)(vR>ox)>)@ZEzX%u8XyzukT|1k5}347c_Q zpq1hHNEDwsvE=Q|mm%&O*mOJ1|{{23S? zFQ4o}?N7vNl$*FYb9m9$T9>g0Yz82GF6&`}`=kMt;(_7u-Gy>+nf<_$^({ zeL0+1mZEtfr6XsEfHbZ!#_grKkyksZg@w;c=N?ApY_%{@mq22RRzy{ zr1%z+xKGfGq)5=8c{i(?DD_*-Ybj#pV=c2{;T((3`RE^~~Z7)N{iX5jAAa zCg2n5a4n_*RVuOIhe3ip9B;)*tL?1{3bqo74R=dWg6<~K0Q1`#)n!~@|M1OsAYVkD4RFt*v6?h?M!E0ByR~R&A+@>`!mY%Jm)C79sG_UF@h1BcE&)Q zht~ErF1?TF;wa+Tcusv5WiMrJAL3rE*k?T3i}`NH3VgwP46wf(@a z2$|+Pb!r9v)8jv__*33U1q3@0I~X6U>qqM`O^0X*^LJ>2?qbqV)1C7_ZglFLYqgaf*Q# zOm$OX_zq=g{+i+k*<;Ua1g-4F?>Yyeyd~;oMy|@em8T<^XkuE3&}NZRHp%rm>XV_| z10&Dm9-{gdWAK%3UFrTU=6<`JeARCk#bM7~X+Wt<@o+eO082c}T`2l&_G-<|Jx7~V z*Bp3f!qb2n{>8@?ZWD>FS(R*xaSbO=$Vu1BAgm&EJ)u!CCOz~PWXryw?Q=TI6IhT5lr@cjq zPx<#cq9*<^w+=);j=E>x&GWvs9^?G>#Oe|9xVI6vHN1yydIsJMjO|G8N8@|T_gLje ztMx_B1@QBmGycZCH-L}ryJ749@c75fW<8VhirN4GKmbWZK~z)`B3xaVHJH?7J*<%x z0~!k_+y;69z#I?U20Ao@W%3-Zywo{w53TBKg)YW8!Nj%N9Dxz{BY|gVg<0cw!oI6rU4cn&Ut?j9uaeY4SF(P|Xv}v@JN44iy(d{c?z&_&{&`5F zp6mKMV(K>OR;-6NT_Q2@cxXDd2b`OGjD}gv@t%k1NiZ7EG_XPnOU}zsP&kc6mzJGT z=QyRu1pREciMxGM#(pqZ4|5Po^Oz2}uROb~eC)dbA|s+j%xpp}KW0krj6D?y=RBqV8^0P54qur*@;k7`+d^<-NLPf zpYxTIM_!6#%PVb6&nU{y8*90hJ?7e}UaVm=qf!e$@6+nBh>_x%x3AG=VU*Y9`K0Hi zblEc1D$QZJ-@1ed9%8mHETpSU=P6e|iLD`)_$fj<_coBV)o&2x^MYlB8AiS>E z(ZCVe*1@K?qHk?{$`!xT@Wm~gL-SXz0>+iV`uGxV6&1=jf&iUp zc+)FgDXy_<+6%n~rMBx-;lh*|I@Y453*>QW0JHJ?6hTLm#ZHkR(Fc5|n{qtg(_TC0 zk1yOD!+UtAudBeV_QbefTG$9`eC=IV+bcauEm)Y-+@9`WN92fUFs^R(Zp9sOA211j zf6k6=E`E*%PR<>!$^;1WITg%cS8B=mM#ryz)CdkXv*452--tU zfV2H~N9F1Y#TTN>psGY9Rp5+c)$Cocrvl608~kL``5X5k#{rKt;W%L0r%GUqXKnQ1 z@Cz&_JwV2JtVhx@y91vA4jWdn*H{*fKYV_A_*riMJZCG#>6>X~FXP_L!l)E`t8Gz= zHO27rvVNKC?Y8JT0wi_m7B1zb&m<^2Hd<^(9YeeyYkW49Z@SuS&5`1$7OB>(bLrR% zd>IE+yy8u!QN2I6E1(thHErwHq{NBkWp1p~p6x||-PPL+pE1UE_Obr)jK}eEi=1;j zt{CBb53#@Y?7pID$NKi9xE=JLagklP8hBs)@4o@OuWpB|{_K9W7w3BDGvV-}^l|~O zbm-v&@C{>P;A-Emz=q;-MetL&;u0Kub3j|d;be2Y(s7AmF?wLXi&!j%l@gr%Kpenc+s9it z*;&9=Ot0?f4-z9bd?DjGC?{AA0BEM-bnaZ8M#esEX4F}({aUK~u)R$ET4a>hvF=)e zw2*?V_w{#V?>gW-IJ}0RB!}bQIU}~dM&grH$|~dfcd8=4jJ@o~WLa`I&j|x)+!9A* z-(+N5oiTM6Wf1qu+;Nb`Eu`IchaYs0;d?YgDswkO^9mjUd;|AdopcIDvqPW+ zvC;241Uwnu9OV=;jNLKkn44RUatgQw)+p-r`V2btyt7_4IKU4<)_{gU(xfh$_rzY) zu@Jq+-mHPK*VZEWMyTk0>Fk{R-rM2ppn2Ql82GXEQ}9(_`FQvH%Yg${&i3vSx?g!u zoT<&P()|5#ZT`l-p&N4$s^{eAyh$=)DnA4jtmxYiN*PKa*O1G?itVWMpm~9{R*?nHyXOU{z z+RXm~dKv7}IkAjyR4yYY#>p*A?!xmpot_8S)^$G%E}B^ z{-XH{9ek1DRo=vE8UE?z&!VBLTL^##yFil>Mn#A+S|-LTQ7{Hy>}AmAulh4>>gY&5 zMxGpbp4T=FaCM_D=NwCX<+=Q++#F-1c-Ax=5Nf?qwuS1pjrDozZsuNoPVDCE8VXtX ztgi7o>V;AIaTKFR|LA*5kB@V7q%!zJoa{>0Yp&08P>;np5EE3fCACs!`aFP}nqDyv zxyaL+%Suf2K2)%#-!f8}+XT8ycxG&Z4fq`=N_*2UXH(|x^ToZ@g1%#8c-UMp5ekajxe4lyp>_~QEFSNXBpLexAAj5##*!6 zma9f<&*WZHZ`&HF#nE~E8LY3g(#9dhQ9b)v{wbQ5?uoQ)k5AB^!n;CQzQi^?}LX0Ja7B$@yo-1eE7$Q|Kas71E?Mt z*dE~iAcx}%nr8B$GolI2G8Ynb7$s>vc)=~8%nZeyKzDlKEwt^@Ccunq6)s9WoDVR8#Vm@OzOfJWX8rKvv6| z{qy5<(7mO4R|tXb6fRiJwjgt8&}v^Mt=U_B1LcfHx#*HhamxpF^V>8rOKgE4ihLlN5@ zzed&&yOYwChMv#FMj!|A*BT5Z)u~Kys83!8Jcd}0FFHdypvG+COv>B?Zk#EwowsD_ z6yFHRTKRBYex5x-d)Py81UdvV68TManeE;nX#ee1OEP0}X>n@&RPWIIpp%2<+oA7w zfVDDiU9c#y(zvJj5@4?J4!659Ok*FNqw)LuFHdse0nc}H1jcS7DcvVFQ(HaPw*7@K zfG=n85qN4xVToVjQ9mEUCkh$6h2dqMCJ1>P!B^Tpt2Q}ampEqUbyF^}&5AWOj@f%Z zHND(}A(_2Vlqx6Z$8yffqqp|7*RJvNN_eYtX}kKDuVV8z@*aWQM)b`KDD&Nmp`R&zoLG{f+APMO4ptw!bmFdR%>Z)wTNK zi2e83)P3%k#BuD$`Bp8D*5{M-jXp~6tac@E3IF{H;Con2*fV%ty6uA;jDK3bk{MpI zi5#jlgNQ9tRbyjG_`(P?X=Xji6~WSZlSZ3d0lYM~0tSKT9}POWTJ!N4HXj~-{`jvR ze*64iC_QgP@Un<4oAX>5a@u}3$r)6!-l-$$w4e!$8zi?kpkdR!uJnCBBjRvvd$=0- z`QgK|yC1P0(GW%xSU#8ydqw7GFTw`DBOC~!nYCtWGow_pK8wIkib`6><98?VyT4&M zM&1^^Fc_k5{;ocSFjR0&Uv<*Ca#ho4QZW{}=?E>q7GkS-mfCL3JuY>%MkXNC%P$zIP%=HMW@X%i&JUWGWAfb79e8I8o%l?q1%tra z_v)>HSJ*Y*qx^lbIxiC6uhRU*t)FY5dOrO5xkE}w(?s(Z=g7JlAM<#&s6@lIMx?%L z!q~Qrb4}&=vw7-pG}M$+vNCN?c}?XTmQmO@e&!K+_FK)i#*gu9Gau72q?(6w__$qp zdBd9Y8|NJT5kUQQ!;2!Y=M7Rw)>{~+Txx`nGiP>buf z;0>j1Ya7MhB@iv%roPJ6z@J~`JC^c8<}dQbg@0c$;!P~Pk>S))en0r- zb7&63&Q2zD#zcx0SX9i0+WyZ_Y>DOYLB1q`2C!-+)}rn?h)@41Hqki7T>AG21+dlVQtGo@h5K1mpG+vQlmD%G(74hMtjIB+ zK*8SxxnSVhZS{u;*2%Rol)Qy-ZV}The3lA89^%2)v2TV#AHdZBZu1<%Tw)C+=%~YR zq^t!D_v6=5>XPnI39&!CZddjPd6F|6i1;nQPQv!Mj`kkSljlO&B+hgPnc@~8f=b0- zgW?M0 zY|qQMF*iT+ACEteVhn@Y9AiA=8Wn5U?5M`Jz51%_p}N@W8Z}wVLNU*IetnQj62j*@ ziq8x%tI-yTYP9scjCLu{=0;JsHI8Y=Nd30`nz4tOGse)jO2)L0#d*{h?EA9Xj&lTS zM7QR76k}As38^XtclUmt#u_j}nz(iFgM!_ETn^UL$YZ%=53rZ4hEPZWcG z5C^MZ3yK!F^7lm=oM@(jeg!R~HrLQ#LmNwP8lpDZbVCT}%%Ktd>_wbK@ z`j3IFPr zUU?wf&EMc?@kN@W+H>YddhdFad1J;P0gLo&G3UI&p5x?6#w+T%2p0bbV_TbIXiDQaqGw@3o@Pf^+cIDjt z^KgNN4Q^M0uv_G*=Wo{TD1#HRK5O3}#E1D=p=C8Y7;A>NFhUO3B~s6#E~$lnj8A_a zMRsO|?X}(xohEZ&v3jUs7;nt#4TI3|n;co8zN%2WvlN5sov0JkCIvPLrkqeec;CJ& zdnv#1B)a{fB!(l?hLeJ*opZrpB$OSxJ|3L1{i{#;=L*oNpP|NkqLzX2ab|CuVqEmng?u6E)_UW!-|7X7V+B^P@7Ql0GnT|2h%w@`S2y-+ zv)%||J+nVb9l^bYEqr1-T6aYme?F4)xVP`o0!`pAa+lQ~q@VIs`7G+a0o=7R@FL+0 zrpsWLQjZrzfrDx^s;Iy8jzfgtLmp&kD2q_9_!Xvb(a3{Lo53~@`lUu2FUEz!W!t6B zEGsE4PK>Vh9u5*i?JX3g5DDKXIi@=2&+%KtkKwB9^L$}d;`YzT_z5GLz@ZTgiS86s zAe2L&;$Toe+4MOPWs+PASN_Vizv?T}SKnYQkyM+%!7Q>>j`!wi)2~xy{qkCfbxkMc z*M0f-xKQgvHOA3d%u5Wy6dENo)zv+2c6hg*-a1p%|p3)0Io`i1zX3u9u9i|TZ6dqGvn>7$F6AUqodvh z{B7%PjRLH)4wzOkn}QP@21t1d<=t1~X2=C$J&U@e05h3I--KOiQDIZ-?ToENDC^k& zRAu5FCRDZ2gX{t@sBeg}s@Mmj-RYTex5@d6J}B&GKR@7o5==dU(;bY}VnR6Eud<4h z3cHS1F{l@Ny5w0tAo|0XXZe|<9Gd4^l;kQohq``*R*L22o*r5GzOEy7^w%4c>65}} zxf6$DEcG@_K zDCN}Wu_T_ElN#SN>QrnS&+1mOWS>=x;b&WTwx7IJizZ^*vQMk!XIn-e&}>H&W5G`K zjfyq4XY@VdcN^7flG}CbK5Ru+G2Ru;ZH#adgDZZ~2-e5fwJ8i)_=hyZ`V_*C zU>CxMO<7{fZ2p>_T0vuZ2?Puv;gzEQAl=@4Oop1q;Bs&AIl zsSrvWPduCMF#){RTjIPh?Tn{Wt>EDPS;%e8ZzWEOJ90McW83;b{0B^j6A1>)W}@Q& zN!)!=jat>Czc!9?+>C+aqQxo4vhf?>G69U-JWbxl=wWu4>l?^nkc}YkQJm)N=T?#}i;H>@3z*xneLF zV;R2<;%$CX@gkPhf~TYqY4{;o1tWQlGuor&@_e zSvrpB#@W7(2Yj%BUmT;Pvvrhj&1 z7M1xlUYi=X@Oa0p6{!cKN5{w2O9S^T?5!AX<##KtT%Jdob8@S9&XEeB35=dfy2%y5 z`UkN6r#dxzpUYN^;db@kU!tys6n2T2yZ3$w&s`6rq@FX^{aGvme&rNRBZA> z6$b)gR|_9HczHd^6`a!gmBugpK#Fe!d{ueS1A?|$AcG~Y76#CxoG^U+_{+n`=bs+F zy!?yEuGkPc9{0E*t|M<+W&6NgpW?h9_>q#tqRuMqe`g!(2vU16@bvMM!yo%R|TWArkO zBIkf#=GOVSq>fONXgpZOc-?Eo$kUj%EWP$QG{2Stbi|33j}iG>#GZm?d+S>nZH&26 z)EQA-x$W~wD~_@gYN|TB$g!u<0zv+c2PE=a}Pf8~Xa;T=ys3)h!%n z$Fb@8Zw-&SI&u~t{VM{lp7iH#if9(*p~Ry!m8EmlLvFdmIJw+p^kfLVGOy=pB6^U$J1sF?w$>H`U7S@?i7jWs>4~TmCtLMEnhjxHJtvKYFRN(Me4_+-PkyaZ~BPe zW@BE*E&Dx{9dUeY{x(uw2(AE5u3*A1@fc@d{z^JPo}k+0oR;xY9ysn^)S1 z@?oUPFygVaw}MkRm(DL}K4kiP`5oX7Pd^FsiY+||yTa$x09Gx5+hCTH~87_b5k5^iRaLt)W~)AufDf1z%&qDnQKoAf@x3 zXnejs`crgTC5;+GQ@ouH!gOv@%Pc!alL@Y8+(jq|;w}PN>VHqMT)!k%k5L)U-bcsq zqfplbQld{QwYuHXJXVup9%~6!B2$~mXlFp_HL;B4OVF(&> z90u57KwqVC0IpV~|)vWPTJF3%xXMff`mRtU|q{{N4b*gZ=iuKK;LW6xG*)9kv)H2YHJ=dI|bcS{l27uh)&D$%`u; zpXHXqI4s0mZwZZGc?C~5J9LyezBTYw9xph7cos%Au*G`PP;}!np5&(nBmRpa)bxk= zZRC)pJsC2Zz_RafY$d{V7Wf@S3Ks4EfAFR~8#U~ZZvr2H3K*JiLo^Y{4` zZ-3TQCT_43CFntl*0cHwlI#gG)mDnLz+NN~_9AFu(pE>qjro}2>l>v_*BG9;+Wbh` zEVYIN6U$N#ISuNNOjPRG`{ z{A!NHW7O?pxY~2>ucHbbDrMYVhB?#~9E2K$8%<7#AamI5qc5^Pt<338vkYe!V}DJG z?p8Pw=O;%`#dreq{21!KdnL?*qu7z;*b8-+dQ5`jjv#63#~~PR2%1~UKQbrgz*urO zVBVwZUG(VZIvydVbM4bObUobxfia%F(N~9`0o4w)L6!Zru;bwU7=yvK)k7V%n27Cf zKYa{85mqy@_*0EqK0E_U^-FU_kA1|ml2s3H1f`Zq?ngEKv+9szNJin$m!BnvdXcoQ z7fayPI7Ts=ltaFb?dRN9IokZqrHllUk`&%rvUW6e%q_bfxyFV4Q;QrZU&5XCay(mO zq&VXI7qre%Ih}h9)Aih#rj=n4Gu0!Xny}QXe`8J6qn64z!x(Rr#N4+#V?L#EZ&tc* z?YUIpJ=lz~$CkPnbt8xK{&CdOeD?UrwMYC>H%IC5tvXw_Tk?KSxhCV!CFgREbGryzkQ#VUJ5dKZvfxP{`{whPw|1ta+HGGIsd@!ZW^n+R(LSOkvr8| zwQ@)jUQ>Ed$CuZ$Sb~oSZY+%3PNNwd4vz>X3uWCv%H!knFDvVO!udbnS?&S#$+;6a z+j)h(wV{Unb>)T?(ms4nquEFxRWHu%kR7)q$3HZJ@y}L&(J*7Gg;Z7uJYbJoq6gAH z(~t1<6+wRnsWvvRQG4U8;pP0kNVtwU8jj}HhhkRuKwcN=jFT9?5T%N9joaW`VJKQydmDmk+-0)6n5)$dCM~BMsn%n_GlxH-#gWxO# zM7AAWpO&F66wNqh3THFu7~_PEZ~_p3*all~y7RS1QkI!xJaDTb~Mw-7{TW{nwy`HOoYqndl={em{6$+5Kcb+}wlH7b- z$7^^RSoDKNT!s5dqJ&zDDxdIs5U;O;vhw+l9aFy#Np6X7Py44lVlVA_&iCo2ph}%tI-Def+ z{p_$Pdd#un=4@!hhGwkz)>}ej|i>gO?%%kG2Yh&4unz4UA=H)W$d{>?9 zn)_vJCD01Nd3t`Zg1)OJ=SDS_r^a&oh;AQ&)(vrN#L}UX?*kfbVCROn<3u6*$r(AM z_+vh3-7Xfj#;{jRZ%%p@o=wo<&e(l;E7VGel(bizLlYTeee+tQbRG3vNg+-gd#(@h zo~oQ1&}8&9_|kmCWyyrR4b!5SwzI~flQWoo0pplF{&z+!70j&=D`xxIC5QXb+LmQs z)x)<`y#QXdE$H^M^m7k<_7T5%I0P?p>=GG1Pl>QfTE}>sby(jIC2-KP!G?A}zR20G zvV+W?Jk!&rL265?=gOu<-)axO$%uLTu@;j*bI)~ZQqxq*=4qxaNh(X{hUMc>uIl0$ z^{-nRMoPu|EtPJ~&7)CUHs{NGWBDRqC(pP3iiFSWB7oF3okQ94NS7j}OdaUV^GI`y z0;xLSKbuIOXYQS$|{wdarJIs zhlR?>Y|VQLF`)U2TR*e;yXLT%@`MUgR8%*PhDML+KXs*5aQt1<^# zv7RAaLBaQ0@lzb){SP02VE<|j>=_PQ*{kL$VGV$uU!y#jR#kFsa?(h{-xVn$UZ3}| zr4imoRJVkL)?3H^=};+WvD>f=cLg^K84PS^?yJnHx@IFL|kihOBa zlHGkh&I#J1vOH5t;ek5=VR9^n9ZoxA%hh)H+F_FW9p!X7?Nl@G!vhW@2-rQa@hOdv1xf?d?*`?RgoY%-u#)jdDbut2DCoT#sMlL#J+~QpIT@ zsD?ea5Nq!rhHsQ1Zd3cLa@;abnVVaWaQZRvlTx;^f*c_s&5<0=_g`s9gxo(lrlFM0 zHL~1ytU(+lF%P-*n1@^&9Bd;s&ruYk=lO_j z4}MGMR=(SQ+tOA(^JV2&%G~+hzh6Z53%}nA+)3tW#Qyuoe<((SKksZ>K>;rdY<%nF zxC%r@9b5@a8lyg>Ng}@`i>rXq1P-)}oatC@)$XVD$W(8mmJ9F3t(r?wT*>ub@OoD6riiDFKGX8+g$t3J3 zUY*cGK{T0lou|IQ8P75%(>{!Q);gFF&F?lv23Q);51L+gd7?4LT_Agnu5`M?*AA1t zl~6l6#JI6hbwe!{=hyqi@-t@=ush#PJ@Gu|ho$-Z)KP*IV|#9(xb^c{8*_>AbFM`b zYu5PCqKu)B_+H4VeiTyhMr@lGGD zz>N9=V+1GH%{g0n?eW>~rL0-z)*~I&_ed?T74pC7)2XmD%WaP@9s?Sd5!YF0w#j`r!G`3sqe(d-o-_`-z`J@64)_~~z} zhO2;~A^M@&i8Bdl0)PDB%HIL@8QlSmV!ADD0@rTe?M#MAse0d`fW(HYfu*&dSac(F z#D6 zVPrNJZNzg}fc^z441Q!7v4=osD&Md+Q5uK?Tcs)+VzsS3-%F0Q_$vHj*hOXqV3fVD z$o&!R!>?vB8LsMQ6-;!PL4i?O`>X%`MCNWk)P^NJQSH2(=%H^+;__Dr-%E&niBz%j3P$`9WU?&HGEc?P%SX+o~0}yA3ONZT1>(IG_~W4foXl zAn$X3^?Bx<)5?zZcYoVC=-;=pJuMM;O`|L;bBVWiWDFdE<7tmu<9nSJo!h4zn;TU} zgbw$AT`QL;_R&uYdLqny&*dWFo&n{&?Cv;AJmnq}_HNX>&$Gx4{va=$re8|7VNPX*p9U8~xA z1GrY18}M-$f`bvgN-_RJ^ijUe`63P2=r+)@uC+O9f41=9yI$j{31I1C^DhCF1M5X} zuEdQt_kmL) ziPWY|WJfl&z8X+OdlB0RZrjhx!~Gz=$*n05a?^3ev`GmbD@_J8%P7&e&*X1EX?8I0qPS&V6K2JGRy z@)@NG_$7xsoq4GAm@)X;iR&CNXpj(2g&*+&AOb1;sjc zU4`>8=~chr)Qu^rod?mDdT^|?TI9{&_^hhtopE~HYEp|}%O>}ga$;|mv*+iua`^1! z7I6v7G)>Ct!P4Z4y zX9eMxG{-a+@Jq6kSDq_3m3bc~Yn>@V%QRsh&phHg-BSV7@A!&}_k+Ec??WDm$?t#l zMozzPTA*INR{b#&Jx1=gx7x-CTYJ|$7!});Ba3y8%yPdu2l!>~e$REhx`c6H9INyG zIBS`=qwMoH1EbH=The+PUA4DV(F3vm%j1`a|L5VK9{$biuWb~p893x8-Oi~`%VCHCZtV?sbsuSsoqdt?`dBT%$L}+rwe@GM>zL1s zNA1!0`|;riiS>)d46!V7NRbgX<3#Ehcqg*WTSD!y@oY}-Vd03Uy<*K_S_lW1vTjy`} z2q`I_{gt_K4n*K5EZ)Y;jE?QMXKI<+dq0L@pYo*orUR-ZE&GY>YPPXf3B7Jv(~dFg zvvMWs`eg~e#Gqf6&*ky!+-64QHZdpF)VY6-^*KxJ$j?Vyz;oVKisR^hJ1^RK$jtkm za@`XXY%GU(Hm_QSH0B}K&N+r%qDJ*SM$5J(^BC{+85Jm3zsw!;KLcaT-$glDDE5XPLdg&Z8z*Pzk*il%RkejnDT@3*Hv+62ZD>Zv7P zNxk}gm4jy@_gT!hid=LCFg zeeXx((GXv~=yRVhZ&9Q@^d!ilpTHc?Ji}tVQLIH~W_nMI{SniW*+hjP^G?Pk)-bp@ z9eF2#zK2n(K)T#&dIdgA%e(pjXu;2UtO;>WfT-uU6TD$o-e0u{8bCFZLwxghr1|^v z*QbZS_@W={Az%G0!LUa|ELnnAZkm;}=~1KM3}ZXKTtByM`D@8M66yT>SrPbL#w&A) zSswS;l##Z%b9}W>TC%=#={4~5UOT3alQ zXDz$3?5KSib(@>|ZLg_qyjdEEYep>0Zx+@F&e0r3V;}REYmfRnvafURhSrjq);M(* z?p7pqzjetL=6UjROl9tQQCyFFb%yT^;OqBs)8ii>{`ByVa?RqeuX5F*XktNdLqkh{ z^OPJNgPthr6`%Si%iG~QV)$KQG(nUv6X}xSR>3$yu*NTD@(@0GXpZUaQw0Q$@R054 z^~1wYAOCW012|yw8*PYGnwCD1;Q1SRs^k_mhLfgoEBmi6pJn$fJ19}q16|a%;xy6k znF6Wot;gEy97CZs)@-07<BCJ= z?WmK7byj&2+}=RdjA1ftyhQNUMScSQKE2xtjP3Vx(%`CDSJOl{_mJPtbgH4BSue&~ zbxwtK?AKgP5`y`FJ!uV`0GR|W(@9PU6Qy2c<{{h>hY=&BD3$IQJ;HvJZg;yCU7Ue* z**bDJ{JY`t3blRgAxHA1DT&iO4bbK`q2f+BAI@{tS|Qujy%GQO}RD zo=H-E$)Cqf_3KEKs71}LEd@r+lK3-6^JUagd{nfI7Oyj#m8k6~My&dE?do5%*^Z^A zF$06xN3lxw<^4pD=Z%bIj(?yXM;b*jeWOMzHexxVtLFxJO?okU^)%lzwMQ#T{jr#6 z_3e-6)CH*6@)f82@9TN=Xz}~1&JD8tvs{t;Nv=mkGdJIgOl|CzMd5=Nh}e?Cp}T)! zg+{M1o^dE7PQ$H(@#2s;UZi6ZZjLLB=f|ZH37v;8kUu{B^uu30eERxN55Il-FL|iF z95l6~kB9gI1%O=fi{QhC$niM!-qY&p*3Z5Kg;>74d!as;#I;9VAV)@wK|mejGf***7rms|5APO8fX((fBT#(K}UVgE!v#aa~Dc# zRCLj$RJ6Ps=B^Y_!85mAK^+UI;S#T4&G_uRM^Zq**lrzDrEnFt#@zGF{O%#go_L)O zLoe={rqF@xCHwLFHMe3R67-5mZvo_TLQaCq9e@KT2OSh4ip+8dcf@7MeMsZgNm0fT zy#MoP7bgxl{FY3;=$)QW0ayA7XcdU_oxsDqr7|Jj2@vIC=D~bdMj}e8lH84vXGqjoZ+OB-Y9~qtVn6^wNdcpQ7iyEe_(X5857X?+HmKdqCb0U$^SVpRjvL&0`_m)+Uaq3Is2Ckbt+_RS zjjw^)9%107QIn|#uP25bIA8H~4r$oiCN1H|pKJ;$y2=|?+>f4CF1=_J)QjOxpB-`= z=X83k1qXP4{3@@5CkX{#6hJLCCA{-#g=xlAV=krTkv5Qy*yU&lP|%KnSZcJ5>5xRYMx{Rzun1v!K^_3(=&7aUp6nT!Ro?7?+D9CvQ-vEQm@BWJCW@xjYb^ z9|9!Exg*0ahT0TPh^rsJU$ZAHqNTdUBBViJ^o#3*PVK^BCOzIp0do>?|jh`njixi#x)_+mSU_@(`oztn4GT?$c64 zZ)>zsjKV7A?L60PjKVJFjH9ZO zY2O}=(EFZ)55!|gjHwsJJkk9y7h8ivkW&-BvgA=l11EpNTDJcE{>maNy~UcEfh zy+~%aH=n(B=6NrbSK)TC?9Jg`?M6Cq_nO0Z71vL4p#R&mUUldb$6G947T`xs;6;cJ zx!>2F*9Igb0-{uCV zAx3(aqheyl-+r<6q#58j)+XO<%aPf7%n`hWTr>Ro&%%JddXiK3RUzEGIy8hK zQ%pmK8qm`SSMzsbpaQJ0?TNZ^ONTfm>y}+f|6Aa->e0?GUg>S!8B)HEF7mrkm<{oa zgx@emqdE=IzJvjY?V@#|&h|Ywb3Z$ee*AvTJ!K#|Y$xn9!cBn6vjO-4;9_iKPRc(I z`f`rX=vY?skj^PW8ei%~)(TY)ESnVd?&i$#w7^bxa9ZTH0JdBl%<-Uk9^E9sT`;?h z@)U$K=ViCV(+F$SPtX^<-^*u0zkborR6Km`Jkjgq38zw>0}Ef8O*h1lTBJI?^EOsn z3LkkKjNKxraZH0a`FS?+IZ`wCO%0BU9?xK%a~MY|A-{x_>ZbG9wmmyyn<5{>I%b{5 zlFmz4|AyC7P$b1MwI-iqD(BqGJxw{r8sF=r^rPH+ul*TnY7x)(_>2+md&d0ET0_7; z3wuvxN8-tAGh(gLjarQ9k7=`B`>bgFKK54NTdMQ7luPgai}l_cz;QhqGrZwr!CbTb z{o`+P74Wa!&V0j{f11`llAs`RwENKd!xl1;rfsts2dWfK{@1>q5IC#vDyn7yBUZvu=EPL7T4ch!$w3J>s z@?;JbEme9X7TP0E(!KVh`gPoovTA=PSN`g%#xqu}Zj1~g>W@+NOdfMQpERuEt%nm^ zV8*C)Eq{6aZB==a-z|O&w?!8%`7Pn6M}3Q?A0M+CQL;k30Rk~w4dw(qj)}Lk7x@B) z{+5o`QQraQ))bj$h~43e;v2gP82i(wCx0%&?#9sCX0M2rubatyVG2R0n3cMhifja3 z$m1N=)p6Y0eyCKHVM1J7GE^uEE1)B6;#UJ$!Jv6o6zZfumNlpvaaynwVkAUX%&MT4 z<(uF$D<5o@x)=Wc?7i8NEIYCtmQ}UqbNY0j9_}EDG(KEXkK&8|{}W`=gN$a9C?jPO z#XIyJy3e$CRhF>exzZhD01=3xYA5!t0N}oSxx;~s9FP%NY{yLVSc>$+6((N){>wNx zV(2DZ6X{0HU7ZgYV;Dbrt50$0a=;i!F^~8<-g)NEdEW5K%kVa>FEQmq^O4Mr@7pK0 z`Ro2zz*BKEsU=Tb^9$3lJni?rgPM-ldI-^Bk2o29E(h}7IeZ6A9HnJz;U|vX(s~*J z8~RP{LtPtNj-~FU=3m&R5j78G>$1jX z;v02blUvR{`An|mcM0zj+j;Y`y~lZRzBH>hSakf`FL+Gvt=J6wx4R!tf9*DapWHs( zz1ugn8G3LVM2~J03qpI+KpXq9_`n@ot=QtTcHl=J`;qu80eJK;+q-__7cXyc6)RUBtkm3|4Bj z61C!}J4TJ%KDpaBvmkTXyb!Q!%}rpe7W~aASUvbPlKsc|*4r?X0qmBt{22w0r z)LcVxtrqeaL7y0_E6GdP*jDYi*0EZ!b}kI=v2*XfKp?TYFJ;`h+gcN9$a?%4vw6*o z|9M2mu=3|Ycb>z#(ZV&P61L{%dafP)zQh`1zGn5(`5N<(%w3R}L~8`iKx4B_6=16X z06+jqL_t(m^C+_P`c^8sTYIv3-~ zI6^Yddvw-VVjVr9p6AUn^tWw1&VSVH=bK?+ea#TfBJDQmUVRu~(RwzgQvmXAV%*P0h@uLsNIi8=42e|?m!{s7pXt&xgg3C&<8N#l; z`}y6Z_%Db%9hY>RQE%e(ev{Z)Lw|M~y{PZ}CJ3&Db1#9N0Gq$hckYI|sGT0Rew)N^ z=)#G^`CCEXo!-CwH5l9h&tIPt8@HRpuN=-Fz+2V8|g>p=@67o!k7y6~L1Fcm~uDU;0bbcEwVn{wa}~ zy;NV5s4i{k^~ro3FmJ4}A^gSt$wobH7tX86@9y5Y4Pm_bf2jqLbDX2b;5c#K>7<1T zZq4p~)qJ&l+K~F^j24z2Kfg~VF)6Q08zIk(s>w;57vbM=Mk5!Dq{;(jBTU1 z$`LyaV*zN-co;_%LzuYgNaiW&m)4PgiubM=W-&Yh5NHuJa}<`l%parZY;-ijyU<%~ zK0L_SK{;>CQ&3mUbIQPaqBDH36aMC_Ya?wRMUBPAmczAsu}t&Yk^iVGoF*RA3{Kk20+Ff5KHHO>gM@fJ8m=M^ojv^6q%nft@W39bhI%isJ5G4c@HlE^cQEOSImVO)4w zBmZJeY)(7Yv3`sG=kqTo{yqBZv3aep&-xZ24D^9aVvg-R_tMLJ*I%6Wa<<{$xV84J zyY;iKhuj>DDibqO?Vil*Gtb&%V^yKtvQ8NvIEdM3&IltdB(p*Plz=AH0H)(E!H z3CxES#xYe7akd&s9Q`_uw(-&)yNT!8yfz$7PrKdg>qgdcw&TccSgVIYXEPnq9Cfu= z;3T-pw2kr-FTBl;8@jw!Uv=^#Ts$|cl=y|R^RrY%B5*ppQvY_WzuN^z@ycqZR;!5ssy-JtXj3V$X}|-RMPjxR^yQ@ z#|Rq%+x5CPrV<+?Dd}_a&}LL5IZwT^FtS$bo)NTR^KrD<)*pW@W2*V7=~}q+m}yoZ zrcrtJl5{TL8nKjORC(%kZv4tAt&}-NyvF`Pt^j_GsU0{byk@}_x2XKzoqzHF`Chh% ztS4N}hL`O34$Oy!x1_NL-+4WMz85%b^up5rBBtB$J>&MXuJ`PIe-gj_dym};cLkzH z_^a%k6-=Jo;T~<=qV}Wfe)b-E4)Q{%#{y%+*yUy@2xHBHD=(45M{{fEHT~_!%{P1D z8%v3YtBKL2S(o{c8!YSUBR*HhoH?nBrx*UBy1^I|`)HZs5?sVrdo{vz= z>Iv<^zI=v5&X>`fm)pR~b>g2i4rePs?~oSwM+u`6*$T(XaMMUC;1xo98I+lvWJK$Z zC7r2t{dKT6h1LY>a2iAVCxj7!X`@G?^F*(W9y{T2R@(XtoX`}G8i&*tQx0XF<@AuP z9z@A;B9Eh8C$eq4B!kNe;#jhvo3NOHgXM42a0WT6(CFi@0xHf;S)sgTOit5hH#X)l zo{; zA*UdS3&)d6Lmt(GGwkIgp>+-c8B5A%edM&T6nRdoGHub9)~eH%YSAjmYnqS&$TCZe z?d{|0U;SJKYfm2KawMDfG!lLyKn!ceQX+Lp4lTKA7_y}pd@4(ZX?2Cl_t0*0!Mc7`LYJp*xC9 zI5s)#)o!wf3yjEd)vxIN6~VrZHv^F2C6sK4`i)Wi7BK$1eZOCQ{MX(`?SL>Yp?FyM zVy0%9>g*U&?J~(3o84|u`1|tw<%Mki`q^GKaBq!GT+Fw90|;*Nv-aTNfE6NhTE+-Z zO&?HJJKvo?8NF~SGy7bz96|kU2JKlJ2fmq;t4v$5U29*m&PR%Uw3HZ#k^1rZC%0zZ z)xqxX@%*FzQU<=5G3Uz}C6BLJ&dk@w$cz)SeAdJBB6)+_J00OEVD0S8^B-8bPMp6m z2!l4w5c7(96Jre3=!KGfGI5kRF#1eBGNSeK#GLHne8BM5jGMXX4|Bd{zb~<%$Hsg# z!sbR3#x#?~4yn|hN!@N%a!h$U(`Y0kU=4n@OLcz?mZ{(RX0c@k>|CK;E_H3$u3KY6 z>NcKZK!@$N+1GWGGz6f2X~o3MVJsd3i43>n#OCjJ?l*rwo-beSHGULHTca#A)dqlC zuRw4>v5dlwh41x4nT*(?RnHb{=EkDSLsu*DQAUa;#4EZaS47$>*@(QPO?mc`tQVoI zf*ODB%q6l=6ZXPP)pS5k=`CA|l~2~J+_tUloc2hrIsWI`Aa47Y=c$jbuFW&nq`iEK z*H(?cq+4bkvx2RkvB#nvn<7(59KZBiaXIUnZB3WsdI_?ZHKvypZQuNFHMZLozOMNp1QY<1{6Gl1u+Qz1@!#e}K(C}CMI_tB0(}7K2 zTu}&_-x!4*E|+ssCvcm;&d3{sv0PwbOWe1*dK;D)nH1@9q?FF9pU#io5L<@&ZNYh5 zFW1WE7u%8O;}1piF8%n3Yss-*fGo`kxnkSC{>Kx30|`FhNor+~I3d4$T_HkHuNG*D zl(C08tG623SlOI*o+mHWSR~WxFU&1&eEsA$gk}CD8^qqbUroMuzw^Cc!Pvrh$HX$9 z7pJweI|<6Y1rS~SD&R43I+iHZcsBEXBBMNLMd>{Mfz_o`o_&Kh%@qd~QE%)N?obK| zNu!xC5Vj4D2aaRc(CC~~P?%V%*RGqxX$H=WIOexB^&I6a>lT)KZae1{T#@G-EP~99 zAhe4e4RjJyhmM!`CPS?SFloFzKEqIpgs>WBI@+2wJ=l7h(V}l{W}r9EwA-Q1gbL9% zGoNujCk0iSs&bCEs?FHE6=E-ltAROX7+V|3gR}bPN#3tn3)>dvP%;%ute5x8_RHTf zVpP8#CvsFn$a{XqQbSsv^pgUs6}CE8>XCTXWtN_p>8H##rGZ{z3L_J{_Tw_^RzGWc zkxxG80V_)$f%Zt5#4DP-3<&B4t^HUY>vOimu#P#TFB`xm4CTFb?5o#)9DYnBmWA^z zF+vkcZ0xivBP@ElUH6vStN&ihkZYNB$R)k;jMj^e+e&loG>%k~vy;bWI0DQDVfjK37furVUBIzTd^5HKCsdxSF(z%KG&8_ z;G9Nz^4eDEC%5_g!EIp1C0-?n9y0z}e2k6z7K`?jz6B9->KeA(d~Aq}y;=l<5jI%i zk9J{wc2~1Y!6W$5eUSrm3$%Om-hU9)SAN7MFiwpurA=VTH&Ns2D(_Wk=Xjj&wV9Y! z36gv~(VTXdwarog6(ZuU6W! zdg}r55-PN@y?zU8J)(_#>gRg$=mxK}w6DG>!#n?$Qf3lsWtnDFY}s=QrfjX6Q9R1n z(^}setrx7`;ylf7a*x-m#k5w?~ahY|>*DIMb?lvDOb1G?L8iiWoe=pln zW4Am@#$tK;+v7ctXY3!O5BU&a>&akNA2^+C-W_~HsU_vGW=(LLbBlXrSPJ-D3_An@D3a*gL@a}fGRcX)H> zHj!{uCQHt%jX$r4wZvv$E(sPHpp~|;MTzT_+Y2^$9xt0==?m_5p4X2=wwYPkEVMIN z9zSOZwrm4!+hyyT=A+yA{gAo(7t2tJwD@Kg^Gh9TB3WCxqN#1E$$;^(U9)2z@>iI) zFof*1AaAHmV-lSIB8Sh<)9Lf&>UYf1+xt)MSmKJgm-G?$7Jm9-JiBurZn?&S7Bfs4 zYAYW(63c7-`F2&ApjQ%%9BnPci=VCB1)=QXG>9PXSsmVX5mjcn$pk6K|mRFCdt-Vx$`*-u@}UXgUbN$j<2`;)#nfH{fJog zTi5N#C-0NlOCN8kq<0kK@Zo!O#vG3m@=ymvDxsZfq@{g95XW8^1*N$<&y*ska8vq} zu{Pcux-6^tuIb8*+h`t>%VctXdB$KJzx+^n-ny=b&63Ykz%F+soA#57FCI-EvyF7_ z2HE#a|tK z@pyx&zT}f_j(T?pPqb=Gf&!;cvAEfDy z_jm734|noZfveY0 z2eg@^r5TyF=TL|&=B^n?rd{h?w6QD>usHN9FlLyxxSBRMVjs<;B^h5m z()i*dh=GkqT;Jo(R=l(U=; zto*W88RC{aV)!{$%nmnx~nrA_~vJ<@IZ$FQeK65#PP|UaOFwW0;D+6(@5# z#TLfU+G`(ad$g^-_r!5Dh(R*jo(b6Wpr^s?YA8)1Y}czj41w{Ketqw?)rR7Z-_vk-(c2 zi9q|5x72t85k9S}6@IfA<=I{G>wXPY6}Q&R3~-KQ^Iu3fpD`t|tYdv&A71dgzjEtm zaAMx2RwnT!a(PRe^G;bQayci)tlCdo@mCMPOfN*!n>@B8M(U<&aFH|SwYJdJ^f8uw z#%62bIX{1PkN?k(^~qfs{PALdN38o!D!%n`w1TkxFs_Xu5z2WcrQ)olnhr@6s${-m z@0~_Q75I9pnK8Kd+b!FXH{S}>tSzBiX=u3bI~N+mCIxaZi=>ymmcziaU>8S5C^+ZDiL^0+F?pYOh${>g2? zynp`aHdp1;%5P1U9Q!5fu>L{pI;c_XQjTTpV>cJuI=Bj$*KfiOdfaFkw<5vIUtCEm zw~%!=gvOhcC$|~wE-ill=DXA9$3LAuKmFNR#O3PcqL7z1F^c^dO*w0h2RO8S+^)vP zFE)M8Zqtew+T7|<8IX-kVXMs)XJwgR+5E*V#xbMzkLy}yTGnRx1}(n^fT_hT@#bym zGdCu3vK9<_7Vkxu#u<(>jF>&mgS2d4+x5JpmcYl>^jPN-%h)z=)6N)2ljG0H za(-*LnohXth`QEB(~h)O)9vt1fBFd27C6{r9rIGoI@Xu^f-ir%*~jNDzbQGo$ou#v z$gb)-tJT^z&8KEIwwc0{cWDj3>MQIm<({(d^(HwgU3@U*?WTW88PK(%t(N#@jo3Ba zVl{=)N5~X1*7rppTOY5#&v>@*dfNa#-fHWL2;UCHtx8J|R>--KP}}1B4&b-vBBi^i z*V#E?mu~`N16bx%e8wKcD>nUQ z?ga&DSi*Gy6yk=It4Z-WAF7R8seOzPKdE$D5_0#&HO;OF&4%Ob;ud|x@)7-o+-?Z|9Oyy;Q>kF2HGRphB=6%}IL1;CUGilyFn5zHW|^C= z5gi6x7;`~v!fwv0v3ae{O13Jh{j#z1+;!z-=U9VDVk{8W&nE52z`=q}A*l?c9_|9a zqf8m-6yJdcVndz`%YvuIX!VoC7Q9N^M!tVEs|;~JQk&daQ7k5y<#o1E5^f@xO&uGq zvsN48ZGgnFw)aEwt}$Lr-@4CrzIoEk-*(@8H(RpM*z{d;3EL;fIF-H67U&lH@Vz_y zr5+(E$!%1`Xbo-3N1L*Sh_LR(ht|t`^Zl!(w!(Ny@(?xMWA3Ms{Rn&x6c#=b^= zyOucWZB1+rBeI;vGNkQ(3*ne+mqq|do-HrUGf>)VWAX9ak#kf{U*ZS7wLNO&p>LJf zTK?1Rg)#PwavEDl)U~yd_UPaRW$AU&VVudE?MzxE*Uc-S~TTy5-&dozLyd?CXI zE4K3d?*qHd;Aj38FgAyAi)wdI>gR{M)7v*6Tpu#*3ilPd?XiN*m-8bcy!`92zG0VV z0ILgswQnlU-vs{k=~E^|u5zfPjiYP;E8L<~8nzUptq@V`!Df2Z%F3+qh^`(%T|3R* zf{4dMpL{H19w`GK#_l%W%`M*_pD+vVMXS3-v}^_gw^xbB(-#Nk4d*h9k#GAT8(w46g*)HtTJu^-@xw(e?bs%#4F_vxulNBBJ)K zcMPoCH4KiFKn?&iSdVMF$Qe^6o{DPUHQ4K&1DUeR}zbNb~2JK@Fd%+fTmEJKoe)yRY!3lZ;R7|JD}~64CDM`FtLBF+}wqRhdxU`jfUzVaYiX5I=u~Tc2#}=VJ?2*aVc~*;{AIi#{IZd5k zEwn{Ht@X6!Gy=ZjOt$)O!94|^0^t!Q&w{n*!m`e4ERU6kQCU=|K`*w8`=P}{@iVo$ zUC2`JDU-J97HezcINH|KlBnph>}eX&=f9T^_;Pe@zDIDVr?G6xd#u*iG0HgS%SOG- zI*z5SFFyD1+!o*QP`3@>!^{az>{z<_^2J?+``K--esX)P7R9H7(xS&_<^DolSNos) z&C_4DH{|I>`DMccR|4azUmU%k3m0T4a(%FD_&lGT4Stx|?H+&s?cbdK;ZOgu;4vHr zKViZI_pB~-DFK+cL1uvI;l$Yp?$*s9T2Cyc^ZUSTT_l@I}Hw;+u;admxP_vDJ z^09$7OJ0_f(xRp2T1>IB5|{F)yvrozcTl&1r3|*re zxu+@;M^oB{ii`$#j}U_$662xFWiTV6cHer(!05WZz%J<_nAvJFB6!6*j*G4|zG(z) zM%1x4jU!ltMm)mnu{h!!^hP%zIZH#ZA^UKq2nWP$eKxdf5p5q$L%?f8Y6%H^Hv3BNGE(5J{7U=%fXMEY&Ds9_lu)S>=e=EqrI%}Izq9CgnrZ}C!x&Rsx_r0RH$b!UuzuHrxI%Fwc2UR zTI8jiosw1=YKWRn8Op7t_GRWi4dc*9AXljHs9aWF+>gD5*5$J?9z~YR^2GAEZ?W3W z^R?NMB}JzaVvkwp;^iDKi8$uPXWm-!9;Ok>(9!~5-cxKXYk}v!Slilf^~Z76V=J?@ z*|$br! z5!h5h!OeajpPk=ZIZy^LPg9$~oYU#Bzdd~@Z2n?(+9EHC;5pVaDB!SV(Ue0TtkG4nl$cDc6F#pfY7_W4!5%(M^ab|?u`xswD3r}t zs<`#Xwn&Y^M$JraGNO%wnQ*g1V6&!emeIu6N2-}eaONKqMC7%jVkvkjh(~#S**r`R zN3re<(Mz$8!vQb}$%3qsaw{u(8m8FC>#*>Jh=V{cPM_5cc6&HF|0e!$Q4I)a#w5-# zsRufkFhlp?7VlqtdGEpq-(Q7sg@)RbmiDbxUTP6&hbTOdLP?BI`x>{kwC&VJB^GDf zj05ae9!5x=yw4PzMQdA;7NvSb6!!8lT2zdW`*m!JF2#^XD!QaE$#rDPL0Ov((S0@N zpwFrejjMm<3+Tji3pIXnfL>&((Uw@peYFuikL2mY(>krm7i)6-F(&M%7O5n(cqu)O zW8_K&r}BlpTwbOTIjdCG!-Ms_^byqOPvX_Qr194zy}su8Y4=h_mNgh3v?%l96Wg9+ zJ(@DpT)Q&ke9e(!nLmoxYN?;lzt$1HqH+B{cYku%xt32pJUwy97U|m;fRzhYUNqB= zJW`7ePdNC)76>+iS>sy2d;c53xGM1MZUXH#b=+RiGj0X#HiCcs>EDueMjb{10&M<1 zK7ToVdHx)2{t_!2QMd}2k{OO~CbKiZ)rFevn5=DPa4k2l<_@`(mo3bC_@ZBYQXfZv z{%9RWMNS=|NGQ+6L0Joi*tS}uXv5c0DH|fj3sL+-_N6ah06<%2g;`O(lepVOKc2t1 zKleCx_1QhHaSLgFxuYJ*_S&->JmO~#ZfBQm<^Zb*IY)gfCIf|p6vW1m&2}U$#@2iL zuZ;$=Me#-5n)S9i#=22}bk{Y=Sw>wR#()`TK9|&v@l|4>mna5`OJ+B@%K(!Uu4q%B+M) zt=R&DMUv6#iJ;E*L!2UVtsZR7K9x-|PU(elBr1-vjXSo=^}#fUP1Z@x(ynr@cGhtu zpi zfm-@0RF6M+E{}7XscfrbVyg#B8`P4IHtRB~tg*hnj<)7PTQ6zk>qNZ{>mGScFDKn2 zikr{A4B+)mv3{z#_qa;<7)8bw#yvbTNz($_#RLm{({yYMWMfS)zRn5*#7Z4FMp=11h?A~kdrI1o zT>&(M_x3*(Xf(%15BK_fy1|;9m5V5!Q|aGT&sY&em`|%owIhShB$>{`kVZOvC0tAt zhjW00Ee?qU>y2f751fxnO^1=V+-)_mIcl{jd)-f?v7^Pe;`_xDdbU{(HFJ78)^6(s zrs``5$(1h2O@;o$`N99@@6|YJsA<9)AhXrM}Ei!wAHdic@>MbXwIT>}idK#ZcL0t?Q`++75u+__su zyLGhVt)lTInfpsPs1Pfoy97C=B6%xY5=bvWtD_!VAqK=cqcG2T*1U9vo0nxWWY|MU z7UXSj|1F^-MijSrO;cn?JZ_ZJ*|}hRtdE#O8xsc#S$YCncN7KR6sO_Xz;Eqq2AD7k z4v@GwB!)Is2fKjlj02$!VGhO^bf!kRP`{-w4RwCr3h@@i>hU$S77lWuxx5bHBc7xO&NkK6P(&}Qr#<+` zPp1=P0k?ma(!!A6vW=hlgsH?wZAotjF@*{Ba`(GXX4&%XUVNSrO%6}upixZ6JCYG3Rs<2!d}f90>Vc?;O*&yM56o73AjA5Wj&{o(ZE=f5k)9V&Db zpZ)I#`^ZB`p{JIz`GhM;A7A)`v@p~cBIb;64*e>+#10(_b<)G}jbClCT>H|(dXs-* zsd{CyE!Atw>ZjYVW7Ih`qFJvnms1{U5l-3G^sWBEA$hPzdAp^ti4IcAaIQg{5|>SX zz7fBV_(q8@xJual-P^TvQLzG)w3PXn65&3T*FN z*6|#4k;TR<_H*&(w-CmUAolG%SkZWgE9P-;YMZ!Gv1~K}LFkuG(RHi{jH?6pNCS_V zs>WZv(j=~yi$++DVlQ3adRREn3G=pCQj#{ijtr+R!gF*)h0iB`?|%1J-tpv&BZG-9 z#uKy1d(vg^OqEw#Up&@p~Ieg@--Xmc1_Hrxn&B z87UmKD`#Jh8>^OVc)1Iag zJ^tok@#twe%a$W8YYSB3~{BUsnF&S&aJ z@+0R9IS&BCO<%Neeh@uhZp%3X;|Vj53xm&3?rsC_-@Uud{9W^v!6_F!w-%g#AN;1Y zSnQqcdfdy#TIb$Zn~dx#xHk3;aBJ^{VHd<(N7v}@Wkq{E&+>c_o}wDZycG<&WmzfE zq0_fPyiCX9+Qtep$*+~JlW}^uu(PWnEFRg7peF-6PJneC%zvyfe>W+oppS5 z@j@Fj5;=3EFKZ6+dFfh1d5Rg?8%9+2?OgPX4V%Az{rTgCFOE<9+M?@NqJ3=%7FYhp zGP2C8r`gH~WGB_85=0hCrH8SoT-(~Bos|e1?N}>Py~R3cv`F-dfrdS)*`rO|7kL~T zr8z5Q&=zsDD{F`>A)r^CwrHnyO(&>n1aSGWtDm{8ke81_)V57_D~F62>RIE{g`6%Y zqYZ0fSW|B6vM%peZN;)|ugFqsiEW89mD7t|9h6zL)r;JsQmwVkw`o7eHpd7);UY6o zWp<*N@K8mLDQT9_F13bst zxL=R1RlAIJnRPzKIh=EB^4{l2_w_y};%#gymr!jJz|9LYfF;^i{^f*QBB$luInTk< zCqJj;YZ}VQl(U9Rw`gD?R*>JjtAOua-|fG+4H#_M;3{G0-P?|5Yy!L9XZ$Yk^XdJY z-<;mP{m$v?1slk?>Nni{g^fhQI_{+})pT^XMPASO_F8NL;}3=Nu@S;I#YTnDHTH*WoG z(K^&j}qdyFY*8k>(th?QAabuJIUI zW%^c(ca@|wUL{W@s$1S#CF#q<`l=Z?<2%hw&b^h*42u+B=hSlaaXpcZPWS}dA=LGk zavX3PYTYivgQlUBIT=SIQG>4pGSdZa`}|jK^H*Zm__QUS*sqUKUhT#he1<~%B<>~w z7-QDlD{H(98&iabN7mq0584vB_8EstBr54sD>AXwcBv&+$U>f#cCnUnu`6qVQ?0hF zRJp=dI-*dIo@Gq6Es|-5X+(>kC7AT;U%PJ8wo0@Wu61r6<)ea?eCBBFiKUD+<+iTr z?5CX8M%rRow@juwHU9%QB_6*uFNI`>gV4J0d}(lGt(@5nH7FUXJ?O zP5EO%4L{d$DZT7+$ni*)IXj*Dao(>l3njc6V3>#(+tX({fuH?}l` zJJ|o1^Ph@dYs(QY)36Eb>jDF=>PIH-b;N@v{3Z z&wC&r9jV*9dH3+G)8{Wbe{xv)!!H@bA3WkOEqN($u@y#&xXTtE@ahgS?&A*&8+uaQ zFCh8f{gq#aW&C`D!#>~6Ku#SQ>a{Y|aqU`NQ^GyoLmbPrhiOF2Ii|0<=;f1n#5&;S zuC!(2S2u(4>pr>}9OJnf9NulhU=!Hw3Hv|Xkig%RAP8((p3eTuE;?py1x}WAmW8;? z_i*d=2D2V>ZxW6ZNpIvS9%I>aJbU|3Gtw@(#J*?x+JjwZo>!edlD~umr?IAzuF0x^ z$$Wv>F57WkVY{hDW?<*U)BV69tw1?2x}{VcU0k>E!pc8=(!9;=6`%$V*e7vGN){8; zop%pa4L+V9PQQJ8?>?6(y~5liBpues2g9WGc(2qzUYuE>3Zi%WNodijN2_% zMl5BlDQ8VNYszh1)5)ipjKEr=;6O#=229!Bwmv5trgjB|MA*o4vd z`(5g@$G(oOYg=*(hG~{KW7@}~sq~0aRLw`9_dc|Zpw?~~LEe6yc=En((wCHh{BGP! z8o{fH6)(ZsAE-GrHqUT-(r33p5x<~I@NjhjndUW{Rwiv>(5rzFEjE6!73|vBImSuW zZNLD7%^Ga#+_`VMp52vs&+hNt+h4ig0secpNrO#Zpj-%UcjoN=1n&f{@p49|t zhZ_EO%wwDsGD@s1$sGHoSg8j(#_+vy*Bo5Hc*i8~tRb*o zY+ISF)VAZ8)IwY8hcaQHoIPq$Q>QH}u}DQ&X^t}-C((k$IHW~+SgZF?j$UjR_bnpT z*5Uz-BiO>o!d@wk5x(0zF@g~u$+fgTQY>@FQXfOCjr()G#&&ag z=i13@i}X=5mk)L*DWk~OJ+9+@9adywZkAiK_y*I!zgD9gZr=>x2Fd^V{O8lZxp!C8 z#-UU;fU$*Qw@mmA)OeBcp~>32xPqM2eVB>;Uhmr-un~N68@+hj;I?}&zYmNSZdL8J z^`70e!R{8V_YV)JUw!=7r+@t6fA_Z7_{CMfD4xr=upYT>a}ms{t^r@!!xxIPNMDc< zX3u8zxS?b7_r1FTG`#|{{4B4JDft&z?)Y;_>Gs++1Z>jz($ zzsF}Z7cFaaZJT|Yvz-1ybFF|$-$#o&wudy8iN{!O`?ei(#5(b;$5_w4)a*%IDwFrV z?B{EVL>a(Ar20=$iW6OkRhcqtE5}CrHs2wdz1+O0j;$~bO51D|Ev=DUDR+rIM)vi= zimQKhy_cVL>}y$lOcBo-{_(C}AD?kVMCM0CE$i5NsxNkyTiPvrEto0)eR_Jd@%Aya zqA?$%yo`(*Twz>cFCJftj}c@0;;$Z4&0|lzz@pT>m9;It+I&bHxuf_f#{ipp9Ch2+ zXPqlXxAyyDu&ndrneWs3KUVvtjA_j{Z&v_!uSrY?9!UEYd~yHLz3eHK(!-n!$$t*X zVO)gPhHcjL%r=LDZ=UfY*=p511iY!1`G7uR=J-aR?wquT_2gKKeJ+im60DkxPyVFM>PH9V3W=!V|E&GB{HEpBv z8-f>)v?y_K1+fnCC9A2IL1byisYSje`6!Zjy$OAGozogdSBrj|5%hy(94)Ml- z+pr>+p2#&OqO9Cy%>8D%`x$dz?jPU-#np`)HS$JL?BewyTt_Wq2u-epCB(WT0uo|?9 zp`3l?r;SR`BA!xVF? z`llM@O}A$TxCC2b;KP=+wF!6%0PK?h$3NKP_kkbWu8RB?FeLbXp4<3!91reFU{L+$ z+rK$|e*WUxLd+WITnS>y0bB&~Ph-)TXw5C7EWu51 ztNs)u2%vOT)GWAS(pq0kF%GcKEgIJp!w7FvKK9Yu8OcY$nZ_GEv{BnX{x-14aITRr z5?Bmmv90tW_bqp2@EKoHakpr@(nC=wqLOopK)6~826M%g7>bl#q0Dhm^n7r|*EH74 zRAh#n5jD=+e9J}$71*A>D`Cx1VJLnx_$7?V2Rmn!WgAj%I{aOnmUA$vVZ60hDw8BT z02udFJs`9x7gj&O-SH{xfYFXite?}5Im>;rmk|fmyx727^T`3SZncwlQ0-_%USE>- zyL2RZqbsMn8PkHhY+)QBpd}7${{H^)LzWdnWz<#?Tu|`6OhKI$x5QqKDAdS1sjM3> z41L9D;Znx5B^K6>ZPw~rB`J@h(2D(*WTBPxlv}kq8NB4>>P;DLt(FYL8I{##kMY?` zKfTHEb9J&-3?y}1#ip&4FT_mgL$vnh+9^X%OL7orw1;6NcK&RHQH;!C$QAZNuhN@F zJLHo_!8^5i^;NA7N?&?~1rJLJ`ExqJ~99IzoP`lVI9x3d2^{~J4 z*IkY0W$t+Iz|ZbOO?)E{zqyNR?XVI2aP!{1d}= z7-5QiUIE!g{Dfw$!6&D2*`~qmsr}8Wy{9bQO}J?WKDb~0^^4HY2ufJ(Ht6<6H$6d~3!1_j0stal*4Zk>Q;3a!NFYYv7QtJdS{V9e*6%)m7F_ zR(Q?CxJDAqIO<-e%#bspM%F#YwWsgK^z^{|a4uuIE?N)-ogT&&vCRG8_$;lBe$^E0 z;?$0=qb;#&#QN;jL2^K-j%ZA96ANa_9nGh3Ey0qj1-mL{#9)>O$S8J63!N_?Ml-{j zwS=;staS-YaUq9O=7%NZa}r*F=0Prq|l{#r(9TS;Uz(Ty$9 zk7W}SMRkd%Bp0H(78pgu@1Ru!RIV3Fg^f7Y5{ELRHbgL%*i!Y{Dq(8uI$eX$H4vw#Cb?f{PNn!+2ywg%1|F6|`XdR*T;Vas1eHb`;nozIP43B?H+RZFehZ z$9MPT;q>PHo71n}|97tcaQf-XKe!s2u!M1ix@>SU#B<7cz>b#+@PiF4D@JToD!(;Dbd7Nj9jYkxMfEq!wmw#=;^>!qC;^0LU5S!W{b5M>6_VSPww zkj|rzF9>#>bkYUbH+$&p;*7s9Vtt*tt__+A3tN)jTCkC6=q;E;V}n5~gKn zN=W+p(-)2K-~;apuL~UIVL>qQg3CoZF7 z-h97gAIsx@o-LH7HheY%PRAiQ?URLQ)?!7i^im&+%ImCsI6EO;d)g}7Qj^2xWW?9& zY0GH@JhY+evDCD7hH5yg>xt>f-=@o2*B*^l$2M!>2z!vF66jtoEKVIIX-Mg;@xRaXjJ2TgkHe-V9R&E(U2DmPF%tj%Eg19lzW!8;OGO)e; zW0*69JKn>u=qa zzu5f6RegH4ChdH`w2W&qPuIvIt*6m71X)*BuUNuv(6Z9VZ&_ajVoOkF!B*3yVL2F8H3%(FtirZmq;Eo-2( zoquhmdW#i)tIK9RA)jixhCq!X)VSxB7WvYx$4Yy?R4C| zh!Or;IHoamL|xlE>JZPzpgymJ`X#+w+&S42A98lk6}F6P%6dBbX+++~T)RBm94R6| z*(#Uf?HI?~2JkWFVNn!VxLm{_LYsfrMID12CKO$fpfH6S9O}Whu<_wd+`(=3%Em8l z1?~Fy@0HJ|FXu#~_7x+H;nDVlPyM20du%Hsy`&P+h=n~u zP99p9WL7WjoF)0J&bF0Bq_HmShds5;w-l|d6j{@S=yqgi$KEpgY3oOKX^R$l;?$>4 zwkT&G7HEfkqVjweON5o#HubeS^=8oz?*4>fd{#TQz22+E)|^bwbNh&GUWIo)yN!Q7 zi^NVY;R$>3=<3=So%U%DO-tOm0!ru2)JH6V&naImn3&i0Ij)+Y7L4VzZRDYrfqeYa z9&>g%nT@5tJr#YKae4%0+mdGP_~zQx;()HUW>VX+QLK^QH0Gs}+XirV2C=9(x!uM? z4gTx%kM2s!htqHF_(o%T!87`6?S>+Iw)InqzmnHq?JGm@4;F7Ix!~{pV%x-Tp}5~C z#_#_=xXs}wTnX%?@|zux&Y%13*U#=ZfQskRRW5RyH|BVuO_Gr} z87*Z9k^AMDC=id1KjB**c|v&v0n^D?{Fmz3K^;w?Rc+d~fo>F&b;+@Ah z8`a^f6g)58${rcWElkE?<|Ky2eVR)E1h8`$uNLi;kISA@Wp9NvOAsWYF4bLpx%~nvS=up>4TVTVi5~^kXT} zHX4jA;()^PyHhW?@`i$@48%91hEJqW)Z`_O79trqM0 zm|7TOulfEsraXVIG#5`!*2^2>`G~g9dm&=W-rVucwX2P74bGasm#4dJ0C&$B7S-{~ zy?g$^ZJ^_)5!}g?pCdxoJ{otLxfqZWw)gPiHh6JAY0PgPt+nKe2QBrL5x;mSx!SWoFgwD`#RiE+LC-Z*OfYs6Rc*Q>)=$F0s@CVEHB zHb%g#$>uLK5~ZA_(B{Ukc*IfuxCJa9D&dSK=Mg<`Ih?!on`gYo#=Q8t8?_ninb$tp zT&?YEJ^o-6K_~WERmR|f{k{AS972|Ak8$ncGduY8gvk&gK#{YQwD&&l7!zIZl9FAW zCzH-+xI}Rg=!(%+344=|%79%X;AHNtoU%rr*3?oqnm55>A5BJWAW(OXxQ%!>)H=!9 zEJxY!v%-lC&#@^}Hjn@6RvOKAW!H(O#`(!z`TP4|^EWXs3dnmMLKc}nv)66FTt|qj z5EJ$oOkPTDdo4UTYD?ZNv7fJr4?Qs}Vk0`*6PfQrYpue5sG%1!_S7L$yJgv~tZ8TO zL)Jac%}$+FBNTq3v8MU1n~xk~tuB>}=qOG5tSNCpKF_Mg zIA3?9Smuvnl;!wrfDvWgN4xmwKi)Qg`*ZdpEbu$PkKF0aM2zLg#qQge4rQqcE!0jh zvL%A!z1!q?^6OkSMX)K1z2UQq!~Y(ze^SP#h`Zt!o5Wwvr~8M8)5o{ppFThS;I!C| z^#qPhwph?-n-8TlwqA)azHxEj*NJas{S4r?&+@y!cwr`U%(>Q@Ezw&fzB+(H%ed{8 zvkvL1lE;8XDYWHB#w@qPjBG}Rkw!#Y_=sE%>oRuEANrhgt}2`lAj3IF>ab4>+7d@O z&LNZ;jJpy*5N<7*4d6R}g|Jg?Q8?^wUmQob;h_wIQ3Rbh%&Ia5zm9%p$QjYhv5sSE z4`2_U?a>WEVu&a_h51fa=r#Ktc8+OR_q#f8nsP=MzM=|EWr+m~Ed<6&r0OoeJHDqBD4*WR!0qF91nd_m#^_v^fqMPK9!DTOZi7hm_O!g9Ir5kkHq=x zc24KA^l*C zFx#}O;Iv3tRBSlnJz{`Ql+7ns+-BU5%R+`+ysmiM!{>^_DN$#KnH828Hj*Qzoz^x+ zxNA!2oT=V14-BEBmgwU#2!W17TOHIl=vEoXPoH?N>9&gR;)kKEx0>i-?!cDX&-J^4 z-E}C}#-x+==4H}#9pHzMAIBOompHNc`~4$+SPBRmk8PKRB40a&wuI(;y^>y->)JY| zZd=z1bN$E>03~dY#4XW6N*yFxTH_$ET86EdC+-6s%JT7qtkMgSF-vF>YC~PEH^*+u zW=da=r{B8A0y&k>Wx_`wIYi2%#n`qTK`dYT$s)MPsZmj4JxjZ+NwKYx5o2ieH5!L} zFmEHd<~-2?jP`;6|g7E^DKv=uIA zsol#nZ2r1(?|$>wzf|+x%jSp!Ax2yUjDqbIfApKcPWk5U^zq$q9OARvlzn^AVpR$b zKD1nHoq%%Iib-1*!?r{tSMQ}3N0x*mIC7-8^7p;lX4i8JvM!m|T1FsJ)v=}8P=YLk z5<$*6GNau56<)H_6Z>;Kh)o|u_*OFYinZIvm~ym8;3MaUdC7Ayr+ICwlq@;_tsKDR zc*see)beqRyqS`_5}*woH--gwxzB;i3^sQy7te5(SL_kV_3Jn8c5(O$iZ2hpcy{R& zj&MQB0wgPj4a3U8DfA3;;bvcrTB zWzNY$EXN)X5D!DxH7yL{DDyIZmN}ATPb~7RIzNi9*-~dfvhecP6vly3l}8efSw?<4 zHe}%P-n#*LC`fTFT$jSN5yV}z3s8NX5+`o^{M*O3ZruWbcokYFjw9PhOEw&N_@Nj)%U0>^9P-=U&O>WjX zoye>vjl*imm8)~Olns_4GVGP^i>3S_!uMx zwUybn#l$%3h)0cLW2FvqwiyE?77I+i$ko5lwc$e+9sNA}kZrohJjBR3vBwm@mD}cj%yx1O=R{Yc)_wC?t)h}Lea7lW5C&T;1i^{^Y zZNa%MlIxpGk>DuXz;27g-TKu3=C2bzKR-A*wt^p=Ut9(Jq`PZ;Zesg?%5VkD8k-G6qG`LdTKQ0R{P67Yi7UeHCzN1Q^A!%e|X% zL@#e;xY{IU+mp6E5))d+Hn!iI35iG1%&vG6xyblZ2(r4Tx>kL)x9W^xR$^9;D3*`x zzZM_J33H7a}IgEp%Fe<3a7jB*ZYC5OCF!zUv!S^ z;q%4jss+hTg*h4MzDikD4h*73wO0)Ai?YRIOFRX~XxQVTA=B1lqu-tK86 z*WnfwL~dNi@mTlQpsjG7b}oz!-RtuWhqtM7Iz2#bUvZ5JC!fo_H1(NV8Y!wx((1E~ zZ3;Ca@>0YjxToS*J-wBpQRLU&Vx}&6h`OV)(=!h}*sl1lpD}b<4Fi|P_1^u=%kLjQ z8b6!_)<)%{eW*)gsC$-pLJn(DZr45K?dJH& zGo{ig?m6>JFFm%jNo!`f^mt>tZ2%u{m2^k+ z!}H_m-QByQUCXk=0~@%^tD_<>PM2r*TfS26xUK6ruYm{4kaHEZBOFj6b^ijlY_gxdN7L*K}Cr;2RN~ z&E#w-XE@-T-O~rD?{OY99Oid~fqcD1^S;U$o9LTBtAwX#BCfZU+~jCiA2uAIY&kai z6wllGrq2!Q;v6y$TjsuX+>8zQ9pWqItTp~6xShwoB=p1C+FWXI0I@($zj>+ZrG<6Z zhKw!KzC5o}zQc;9>yCQV*gITSpor#WHsVQvcI0d9AtxQ=_xiGEFw$sFl)?(OZ4IA4|IZ{atue$iXwrWzwSki_CN{~F#4!%?WF)H>deR70a z+ESWFL2EU(O-se3+MFbnS*CJ(UAwvL<#AIfQ(Ipzr-HKG$wXrq((CDe9OK#6D&vGYiYvMltEww6*3ew0mhs z=HhL&R-CqSe7&-BX}shu;CLR zYPKy2mT9%PZ{*_2U)tW?Negz^>cGbzegoJEp!0pVfgyU?)W8*V{_hD_0-sO!=lj#| zzx(&6w-5M6t!%8w8wB-ZTZoVT(JmKw#h(hVJCa`ih#a?m{*c-H z6|UT@iA?8L<`&Xa(;JcEnbmZ*)0kAEEoIVHUE7aSi+oEq1zWx5Io6h@`CZ#%iGOY+ z$Z!0I^A=VpYMh_s{3ST)`!BV49s8*DPd0^xN4dZWUn=))_q$?uXSW&b|J)aRp55;@in> zFmHZc+CYvvM`6^jqc<|wb`IriL&@vN)i$FTIU{RFJolAm8W&fJtqrOmHi(zs#1+37 z=RwOi?zYd|{M8W01gtFDQXlhLF_Wy-SSs8iwMWS9J9Fs^Iz3uezO&(E+P-CEo3^Y| zzapWYb{YjWDoI<4(N>CrB-N*qyk#iOTjixWuVgD(P%m{GiZ*3*Swq`7wX$lf#DjOv zQm|rqhUG@6m01SjD3iWDDkoSi9&PqnlLs|rtW{!BVOy~(&&gD4TZm8oS!qifKKR#y zUlX%5j`n=jM9b6&ToYe&T;UZ%4&!e1*#E3TfQ{j|OD_u^YeHpM%oZ}p=%VI0q^ z9$H&-Vwhvo63<$^ExwP5xm^K#%z5dK%Dzmp#&6y406*PRYc;Oz9uIh*#fJq@XtR#c zK^Hf2wyfUH9q>E9Xy5TFU^sB)*=+(pxF+f+SIhU~FB>ViiujAWo$A|rcLnf=)2H{p zJ^ka4e{vhhK*>|JywKODZLkUlytNgz4)Nf@RlvAi@h@&uXaCYZru}10Bly;B{l4?p zgUj3tLfTeB%UFiK{87W27M3xTp_fOeI7+a#dTnUCbzR^5ec9_K%;ku&jNr(v46GM& zLytc>8|kg0F&a64p~l8=*oO>fB-FH*ww|Y~z0;j9cX@EXv+fJ72)_R!?WrT(OyP=p ziLt2eRSc%`Ah=Dez)UJ@$KX` zpJoOFZE+&=rZ?#UGGONq&-P>Ha16@<(lZePviEw&8m^5v6_@W-$KuWUJ$diJ<_F+% zQBOzS>>^$6Kc&xce*5(H^u7DZ78VJ4LEt2EbvsM$J!{T7CsRM6Htd4@@nTS*b$^xWs8Sz?v+a^kFag?DJyW!BON|kOIs`<+Z>ya zVRWw^QC-_QA3ZTodCYT7TTLVK%ze^ry!6F13XQR$EP4D2!_wnz19)i$UxWU5Upe()b7~M0tb~kKhO~ zwa4(C+x*4vDu*u_FbgcU9i9SVqgrXP&l)VYO;*-59Wk~}-(XnnxOQ(`@EqIJH-E>) zYMI2Rm3*!3cs7s+k;#`-ed|}4b&+@c=haYms z6~V4NKm6oWV(A5|92m%VuzVcwFMk854rfPEIX*44CS%bMIIs2mE5N;dje{~ZWeetl&@CO zGB4A~$!#RR*4bpn#*UAy)48rA;;3fu&M>LRG*Y`_a2e`2nV)GYYPG7r( zsR?`5cTOWRd$bniw&l{cw#t^&5F6KcIjJ(Vq(^C}vuHBgnzodseew}Of7;KrQmYhY zF|l7kD?(c_PgxTq(eFd&7*bi8v#d#3+9kcLTp9A-AoqBKOx`(b6e5#;Y%|qYmh}CI zwUxG&SW9i^5TPvW!7?6?vQ4*AwrQI^5R9{TMIhECw((ezYh7irw!M#-=8VO9m@}@W zep~J5=Bbt6=AoxOp1+N;j4Eq-#x)K*cjm@La5Sc)&CtI2xorUNoB!3lW4XU`8wH;; zn*(^tau@3Q&0K6P=;lQ^EWi01srisXjpt{$VjItk^6Qs!D)Mif?%lSVa|nqP_ay8# zl~0fE>G+HLE#Y@>+(z(Qx83pRZ1uN|<*8b%wCzW6;gP3dvR;MFjc50}wQo*8Iludq z`H}AvZ|HSu^SAs`3v(D2m1qkH_E?8jeZ6u#>Zgx!J@oYE?;2|dSssz;_41NuULzN= zC*}pdu#(V6TYU4wS$@M;v=&1w@zCK6EZfQ85wz4Ick1golV7qBp1Y@Sp>*ZZ?GL-n z;MEGpFu*|n0X`n1pbCdQX1B(ja%A}EhLArH0@Zc9$y@HYk#frwfaA~-L6}C6&d(nAOCpz zAK(0T@mTOM<+9|%L`lmJV%p%z2%E~-1m=b^UdrL>V86X_y+yRsyIo-XDlj&BQQX$A z|1IFVHxH-Zefk?`bw2(0`R|?GTmKX%w}h4m8CyMGMotv_xmp+z%?B69XLn^XHpRCq z9MN_jM|r}$emcFcUiq7Q*??K$ix=ucnFsi}m)6*$_?qHuLrt;t=|i7wSK-2Di#0Uu zV;a$yjXw0&-Z@wDk{xr!m&%A+=MH+trgH@>Z*XFo@R{o^P#egZ4qf7(dc@V67f@nupf#UOX+?1vC5@oSz=wxOFb>A zkNcEMtyXLy3i^di+GL@IavL)ki4*qtsLY{8eM7E31QlxOqlZCQLyOc;>@D>hOO`TP z`;2Z_7Pg@B1VwVyC}VQM?Rc;2Um0^44j8Ykv=*$S_*ucKR<1LnUak8|_0G{#cq z*5WPso0cChqUo6Pi1J9vnmm)dVsBYrCHw8<{bSoMw$Yw$8^EJ8x-%ahVpzaEg*L29 zwr96t8$5&~1Mk-zaC>MQ12%v0+rT^t;3>r2@Y(&tmM))A9^I{_-LLSveTuWY3K)pr zfBN^Q|Kc`)6Gb_+`jCSOt%G9fdc~@MHR=sQ~Yrl#axdX_tALb1oXuB)g`MZIR)&Jd>1IoCy0W<8ZoFV zupfS9teXN&Mt5t4zy?qrbv{42+dlur<;vggR8JTTNZZ9j%oO+2Kor52)a==Jp{aFV zi}y3iB5n3nV_Rg-$*6-bjY_3ytB#8~7@6e}2CPLzr#RJF+j6@e7wmc&%f805)qPEA zdq##lDIT++XN6o#d{d*fwAg2aao@^wI?A+Wi(M5hyHNE+^E!xCTxD4^H{yKKPFpH?9l2r;%%uLyVO#+59CS zQ{Ov3;Ke?}y}KOv>}tPd;RM+7J-f|d@6&mE_E!YctNU%?vqOAw8yWz(>ibXs_VkZG z{%6OA&1YT%jDQ)N*n(fYP%gCxx&uA1raY`Q5%`s2{AO{qI$J^nDq_>;b{vdN(OzgHa+PUIEsoy`qYity=z-AHKm;Gfd3*8kkoV5} zT>n#cQ~Ed$?6=tEF?lI@r|MdjxD?!I|A{qcwYWr*pxIebsIFX_JfWT2cjQ1C$(fm!;ZQ&%U7hss9843JKb$ncMXx??Q-$% z`Q7Q;^W}E;E+_Vb`&<-O_ID3|tYnd6A;elzwn2T6Fg6(JD|T_rNn}(zt?Z%mJ$o!P z92(6QWa|g+zazNCP!8iG%_%p3<&|@)=PU8t5K?pwrLsD{=1Do?R-RL&sv~zSkJ+@Z zwkpGW7R!L1#c7{%)**-Op>0vNEjm5M*iaMqY-G@(s7za;3AJHNiqKZhUbXpF&L$^o zv98&bb!82G#`&jwR1JRIK}!mrnfQlR>6t2)6KUnrwi5MmaTin;iM-f8fjJp;CArv9 zE9Vq)*_sF|J8~QGPOqK*5ik!u+;eR5k;y7rd&TE{r_$aW_u{R`7F%RzPHx(`*IQ3L zYsuzhbbI?e@T}NBYxP*`+FaiHEpjYlWk-x@>x(i^&ukvN zj`KGlTu#vds(mQ-8^C&=SD5GFlk*Z{TsY|FAreS`a;{=;ZvEl;ESnjYD`neVcG3 z*7ofvw@Es@Z{x|1ZJl=4SW0PMC$t5u8wa|vJ0xbm^;aJ3H|KY!-#&fZB{q3o&m~jt z<)WvIHCa%TNp-2j;@MU_C0bL*8XB-_Us~+5$G(k9Wx^k_gj(`25{sow>(Ex^+9D!c zi?J8Q_q51ewwXqhZQC_vFJ%qc>-iTwiIs_U z{utw|zr00@G-ge0rV**llw=LgoKN_fp5L71Id zc7fHO&$3~FJ=vhd{XnT4vbHWyqOkGg^dL{L*et$xSEW6S>#+IAWE3we2}!THQIcsB`Z#BEhc88E|$lA;>gc_jI(`W ztt@W0@x)ebefV$TZ)596?c@FEkBzqY@MRV}I&d~Z(Rq}X=9Z5W$k`Sv+0MXu406%Q zn-TWqYzKaMT+P<68gn@WbiPcRzUuLn?)_?A=N+vt@U2E6MKsl368Oq)u>LTwv}fD zLM^prEn5&FPiQT@61QT@5h^CvQf6)CaFD@Aijr4p`W~2lSn$!Rb^7Q64#@BoBc)+2 zNRdgK%o-OZijr1Iu2Cw7yRo7FoU?2bv$yxx;B577ecREt+Lv&1d1<#a7UgMUQhaGd zJ@Pi6IYz`W-&$5~&0fb@L#2^T$0d(z>G|$KiBrngf}& zX^T7pJjc9>C2ak+d;70N zJeB&jVxRI`i+NHP2i@gq!OaISs4fOEqUoW=(>0FtoYrZchchvG?JVgYId1pa zH{cIv{Gid@=`S8X&B_IhTD?x=@Jyz~_H3I7!G;#0jyWuZF{sz>oO{@$xBn-l4PlUiT9<* zG5+cG6pm(&O~@cU`7{OX-UxDRt+Hj&FSBlq@rHX@8R%aXut3>z<%`GdeR8byZ|kkc z-#=3}+Lrch1Gptin`5xhY722}K-L@EZcnye2&|*7qqu&c=Z1Cf$>pUbo>t`+(5QJ8 zFgCy3=CAue@b1yQJoI}Q_ookUeslWi%OBlU!H>@BjXxa;ujEP@CAeCM!15`bnWhXw zvbK;vI5d9o_7}GaJnvV5>185e2UR0_T=^@TzsQa)+SiuVOWW$Ctw-b-|8m7jZ99jJ zWr*9_*mjKV>5t;c`7Grjhh0au=IB}@Mhq|aF@rh8`9(^+3T0%PWwtC%7{p$3K|bC1 z6@K0BK%Xd{aoyb%{24aXg%JopdB^|^W%q6~808taN%g-W>~!~^y==%qLYPUl$atpD z*z5=~l|z#+@w-y=Ewl6}0SDUbhqd}AhxJJr zYpaXfIgI#HWZZ{FWsFSmR$G_GEEZj2AtvWnbjnKX{CXr;YZSdc^FMWEpHtAbeMG{( z)b>c7zK^w$hjyZ&On7ZC)srhlO=}QY*^c&UJ;x?xp=1tQ-<;AzpB3Y)*Wm8u9Tku8 z;62H71fzV`voWomlP|Ki*kVPuCetv#D{qg+E>38?8-h48s+&|KrmapAXs<(U)g?!!LU$5p`4<0%9f`M^)U6X>to#MQxHaMhXH0Dk+M z)9=3dcc;Jo)Bon2YQ)--SZtqd)?u_FwL05YEaJJpZUX=G6(eG8`M&+6K^^QAe)>i1t&7K5nnu);*5&B7~oqpe53&@R<7aOQj34N zYFO=|6HaI2Z`CR<8}4vR3CH90?&`Sb;5N}-yy1a)+R$a54HqMQl{WGU)Ydh7gCgmS_0e%2#m=9CQ&dt=Mu5y}s)Bd4vDxHh=MZznA-x zU0)^J=Vr@n+tb;sAyOtQvF#cQbb@WQXvNVh-#19#_SgoajRA7@!x}h|(1Ko2Q^z{g z34*dRh6r2Jr}Zif;hJK!)>h*RrE`0EAAM}O@$@jLeaR}9-x8MckTvWPV{3e}rYOt= z|IlJP_g+<5Wd7vHGqAM~B=u@XtV&WV)!9~#OY~D3cxd%9#b_g{wkT27A^ zPc7DI-E9MSI!7-C@#sE$!sg_&+pNPfjmsM+{fw(`b4myHPpMA#>@a9!%OHy_*aKcF z;PSV5aT~cH^}isCE6H5{jF7N-;5HX{6|me2+M(R0_Q~Cv>Gb3_F&^$u?;n2Utno{i zkM4s-Tm>vo#tamZ%L^=wpdP3nZg97pWY@CRkt3ct$~SyzbmBKHLg^klUns)uso=SavG$mi1T7G}RTF zZ!9Lr)6SM69+c(`2z<^la$n_xE2=z&ZoSJ8~|DU}#ZIT>Gt^_?i@~W)LI{F~H*=&+S4rTapMOI}0 z|M&g6A4Z1Dbf#BB37S0JXbY?8DN0JJv_1;nc=3#)2C_%H~@z^;0z>U zgiFrIHAajrhf*>D`}f!BOEJ6MuipQ}e0C1Lf4BS3+pja+G9}iA$lhv}Wx1k1kP*=4 z(zBTeJJEGOdZ;pr4&DrZMrBoh&RAcW>Zy$V;yR0t9ve@(<2JmP_qV&B+wcA2%ELCx zxSp}a&-=$dS=5fJ;(7MiUbB!Ta>eLqA4e-Tq7;obm-F~qED>T;w8xDt?klAlR?IO^ zZu4;m20m17FankjnwSRLh3WT8Ce8>7!};cXuLtjX-YNASIL$R0Ma&bOY+rKu>OrnegLOry#i^SoumyuPjyU(3sS zFs?^iXl+kaqL1spN4r#JnAX?Efwd>L2UAwqj%j;Jj+%a4bd8a=Q}MPly5|(RPr>OG zU!|=^;I!-Mf+m2mLq=z>%T^=cBg%u_-VIp_dWX?BMf%k0=-n)F(=R4_(`lYP(wQH# zh79SBU>-nmIK8zAY~BUT$yWY8rIm_DLEjnCdtBbT+5PIX|7-Wpzx%(lK9mYFXls(J ze#x#FQ~(=Z<)e+46J-+~-xS8AC?$~u1<0%v5 zXcG>slx0CREeqEWyp#}~=b@$dRXKa{W85^uw0F#QNtUwqIO1E^iCk;>kBQy7AMAzp zGR}_uO?)@Fhf?%uY6JaJ-+XK!5lx%+T%HrTU@hOvvLhoN7maxF0;?Kmaeg<{DEB7H5L=EPdJMVfV%+6+RvA3jXJ3U#1@o zxnF!|a7^m;MQbjXmG{Kt4BKdB9ow*8Svp2w!&NS-4`ppW`TnQ_9h<>1kV{_Qz5Dmx z{y(!P*!=4Kn+&eA-FQsM0O45S_AOS6yaStT*D|CMnOpEE&|mu-xI&#Q@Y9+gMt zd>-$a9q&@i>(+6!Skx*TbdQr)Hf-zetx58`j~uz4YeLklWd*K}rB=M#UFwe}aw-yi zp7xKk)mY~^O276z{A@`^em0d{wu;c_Jbfx9POn0#E$w2R@|QkwD6{J>jbp|Zq1zrI z#;s!FILbzJu8kS$7DYwgF;Xaarjd$`5wi71$B0}OZ(kK2yEe`lC~140d)Fu*qL$Xm z?Tk_2Ssu??Pxrd6s=25+f2%)padZ9_?>c)sTiY|v1T2Ux-lmXk0{G^}?x-{8FF*f3cK`Of|7YMZaCPy@U8?toeq_`E-EkhPJL5Rv zfo~0eWOoDOcY)C_;KmDkHnv}`1r_6-U)<^JOTBmQZ%ZEO640#?b5uk`nYkj479VT( zaXr%Sukbs%j&byowLP{3A;FYEu8G-NXkx@IL7W-BDMLKuxx`pMJ*Vi z`grG_JU8DBnoPl0Z0P4jGF>XezD#QXHZsx%nYzaUBTkGMwnxQ7XPvYV3+qkV`@yR1 zmwENO!NA<@zeU64Y>$f0$4u#0wVP0J{PHnfRn100st0s&J#R!GX_RV6v&nEq{;I5` zaz_2c{Z-17w3pEj-q*_~9K5;zBRd=7m}*ax_7_8`u=$e9aZONmzZe-ydp?&s*qroml*t@Do=aA*b*ie^lgOc3olO?;y55q+jTYOJ z*HM$;ce``eZ0?a2)!W|vxgQ-~>F%u?fSS64%~Y||AW3ZE3y69E$i)&}3<@in=! z7kYt}q&T*2&B8`Xj*D!B=KfK*8QO@J2lmoe>a|R;P2uXky0yh$vqy&M^(o{us+MC* z8>)CJ6&zdZvGGgC{oMIteUF(t)&Y60mbSm`DRZ1pfBc#r_x-wlq#u9e*4Lg#UeE+^ zUf5MT%?RLfoi5WW12$(Ycst?*P@A{jp7JM9co8m`s$#;~MX#ITHXu$e52u>2Thxs` z4*JF(2c2@^(a=f4v??Z~%!*k2<|HP8_x5|dw=Z^|zy9;xSKs`7^0V#~Z8|Ei$z~pw zh{$b`i8bN`QFu(!k(s@~qmiH4U9xX&68HzJ6*ym1gIk`0lu!QVJ<7HD-Z*|(-$RJ( zXyu_SP9do0nlQ2Tu_jim5fiz9VvKXUG>$r*g_V}?%C-4oAAC&Kvh~IJSeE#%FBs+&1|29)0YEkAA&lat`2x z5e~IFifbpXBcB3NmfQQ+2ujOC`n_P_E#r+n;=f#2rphY43-wsn!qAh!H|^j?Ri3G) zkS2&5^*F6yli8|ERwjr~KfQaE zh3MQjGj5=)8PzhTr#8lTq)S?}k)=e}JDPLknphbLZgHxGM^=|2i?Zf6*CLa!^R36{ zHF_lWV-Y1!%_d)~En~dLt%$n4>hFfl%s;S0SoBZVwMn@U6`U8XP zkxe$W(HCRd{;{XDlzN#X>TN7M`hp}Q+Stfg?{|(ky@p!n*Ki-Itae>g$wEDj>3qF; zOfSBknd@l@$FcoBHon!5mVGWCuJo+g`_1vT>Y1}2$J>r>d*&+I#{by)(TnLCroG#Y z!j)y45x7nOuNp_}=&_k!-tx8mW-cB}jJr2$72;PL@zCP@P0C&OLz;N?p7r#y%n=WP zF-MZqBrwMe`rcmnd&AI}m%jmwUyQ>kqV8|49(2ZQZ7(GXwk?E%HlKH0r{ z|4p^8iFD$n)<4>CAk)+ZPJO5euRAsM*h8dvVbj3q0kD_|_ECiQX)LeOFCp!BuTo!p zO}ezKA2Cic#s@NAV+$Eed`*VILb>Nv+%>G~kk56Op5;7Uf8~zu@5)zl5mgqWOoJ+$+A8&|DxBj+lzv0 z;LQnZNfz49R8vR;5sS7IYUh4c70Ua#)u@W)t@^QT{m<;I;Q7NxR?dT6Kz}p5zp)3w zmrsVALvzqm@v4V=8}AQv`P`}yR_}iA4Wyb~wzwygt>8bX^po2&$UU~m6Svivqs8QL zZ|u>~dg$m2JKsXYxAuh?{BH1dIc5andRW4vwY)aICzo>cV6T`DY6MQXSsgu4d2vg& z(k0khnM>lAU~9Q_xWHY%Kfn9Pj$gP65|1KfR6Z`HcdW+>dt)O`=g(v2Xem)-D6KJ~ z*2kDP$4UcZL`kDvS;g&W#gwg(;*YJkVasJ&B6eQ(+G0-CBgVM4<~jQjvHt$39%Sr6 z8{bB?J(2Bn^~Wsuy0X6Pjy0jR;hzs_i|27M-toCrc3GvXE$yCJp0TBj9V6PY@{BpA zSQOQVadebw8KZxl4A%MWNV(^cv5G$K7_q&)MGZ?img37^9~)ot9jk9w&vs0$J|P2^ zWm_s^re52Xw>?vQr}kZDRj2Ot@%$ggxLwc$Fy4q5)a!E02#Ln4&Hw;F07*naRD5T5 z7kqCMxvyJ8X~Ud;dbg59YardI3*3N#9gB2o)33s!74P1z`acZhH&z5D0dNuU#sqvj z4wJ#CjlUTOeq1C>4~@3gCWA3Sjreo}h1~`G{N>>;;P-dmjS5m;Rp9yvni+s&3|gLu z^5mGkVxM>tn@TSjdgD&^SOEuOZwi!w+6!z z)yG-xJNW8s@U}<3M0*^hd_>t}yh>uL{D@FR+PCpn+9S^6fgv9IGS;b_K!J_isDt}z z`dL@3PIBG7`J$w@bHasuth9Uj+4(V^&E9>VHrKoA-uPUQ4PD@XZIhaK74FHxbg1( zZujrEzu(>Ar1-j=aRkmW-Z4jQyE$Wbk4S}HJl*P#==fY{T)lJH3IA!wcB3LE>OX~R z^_Udhy|wEGe|%?O7`J2ClBJ;O2t~!UDB8xaB|4AgIdezaQBLvHGL|{PFP!3-llk*1 zpgGzlXNi)q$WY^sc_{0(HInk9bw-!!exh?uk8vqRPs__=dLnu-({;(qzHY}S-m=Xz zifXqS$F2CQ~eFwk$2Rx{h3wH>V5sklS z%N63{Yla;h@r{H@;JY*l?1y^B@M2+_fE+Nm|Cc9=*gbIqBHj9HzXyDS$3YvT`WPXpt- z(4W`^NcBPE;Ujdcq*3G{#x;yye%Oh*qwE#Hs!H7|DQA;4wk50hN_&i1F88ppR=w+% z=U5h@e$GYpR6fUXDt~VuPL+Ra-f}zU{Xz$3Jwz)|+gsBl!)$k6J;xc-+9pV=9K z-KT2jSMc&(kNCT=W!jz~QPz%O*h?rMI3%-WMw4X@wK~>~;|lxVAvM03c$$0cbxT=1 zJ?{7VT`FVfNk1cEcc=Y&_`TqNc>bk_T%`|e1nS$s@tvIB@{Z>xgQ`DIwymmm9@O8g zU7d6Ig-hEN+#Hk22rR)?!rS9t1NYiyhT_lc_kQz7usU%(BXw&$O3>QE#h7ta?j37+ z;koAMR_+!ak%}oXrLHU`KI)9Yt6ND!FAli$t^-quV$?G^~6gt-& zo#T7#>Pf`P7PI8GY0sF;`&Z+EZ5-1=PT99%>B%s^b*YwlWXy-CWf3uYEHB|(f*oga z%Tk`Dc+Yfc5_*DV*&3Yd|2kGy@))mk{dtU?$#nv_Hr^Lv!yU163+^27N2(D0&Tf%?xW%1S+Hul;Z+Fn*1nikTq4@hfPsPd% z((_1C!8fv#diGUsb=>WX-vY*kxpe8@9QW2w$oh3%96tQQ9cBM5VEoRmO|jxJ(C^Ln z%($Mtu*XSbQ;rkBWl5~Q)rXcHEF39FzMFIjk9)>POOA}jhkTe^eUaiZ5sU?P{5|HP zDVNV|iux2w>>v9Zw>8N=s>FMgOQ9f8USVEZe#s0wT&leYHrWjwaf}S;yo>?A%!OVA}n0&m0f? zfzN<*6**_GG?%-VC*n@Q3H~~7-5TrZmA7N+&De|EzOwBZd;2ntJ6Bz&%X2{!!06<4 z!3gkoaUXVX@6)r6R}Bg#RdG;gjw;;dY;9WhxhWk}Qae=8OW<+PH#R&EH+BKjV!!zKzwW;J_V0IZ-~awl z#?pFKBY?lNB?h(D{e9kCWxwj96m>!b`6D*3JQ5+9NUFq&8KXO2_+CeegE*Wbpg`fPVHe z%3vGzZlV~Dd%%{XQtGJ|yd3Hn$0Yag662#x_t+9+d*m_0p;OkEv6q~V$#b;uj(TN} z#sBknU+jKoPeAzA_Hp0t-@5ZET}Plf04yo4_T+$$PlwChBmA@_sUmm zr%|OhX0NeLWpyr>Y8=yEWtc{<@gfFZvw@9mMyclf>A)eB-<8x8HP15>sZPP96l7IpH(4>nApVnTPH`i=u9ELif7 z1gS>+W~2!>=>}Z8v+nk0_xVSEw)^_~f8Krf?zbtb^^*0m08RNYro&~;5XA#LD#R4F zPGcjF`U{)gt8A~dK!0n~!EyQF$O*z%m2Vs3w|(Q{*`sx98NI`z6CnQp>7M8%I!3sq zEs;w(+PGsqs(BrcJ~|)so?e%E9EF}}i;P~3VZJR!?}sC|`hVIUVsx3gHujzy-tpGV ztuICr=W+cKxv;l#KJH)jd!OLqeolz-Ud`jV=VOejP#p9aOP$=5=~s`1jr)7qfH$;F zj_7xT#e+S|qfG{%Wpm;>tG{nKE|2qihPsCFJwv7w456wPb$nmQcHZ{+?$h)II{c>Z z^WAIi1MEbK?_$-9Rx;`{IjOYq-6`4Y&)>E5%iHRCZXa_Z-g$F0eafJBhw=(5y~Mfh zl49I4B@tcn&vDfIsOml6gZ)PE%k=l#+i%m|z`wu6Z==ugJHvUTvj4qVFRdTFbzgBl z0&CYj80Oah5!^?Fdfy&Hda{L|WU$sg`~biA`!job%*Xe*^KLw*vappFyHK zt(MPi5vy}v=FK(Oh#lKir?}K2Lb6)tQB>Y4LalSaLKeLGXLmBX&ojxU42pJyvlCN` zz_Gp^p*ZD0E4130&rwl|(JoK(MD~&^_empPjg^SD2mDiB#Jk@mWu9y2+2JgEjUOx3pcEoFu zO?tbHQ8m<@zZP>^+kD?zBU!I&p06G^W$oqc#kF&3{q(=z*5vGs>BY7CGylFr?3z4z zOnn>4F;i8#uP0`Vspl8#7%z{vJs3xCF=ml%sm%T^sd)*uRZTBPFRqp6RQ7Y!b-En+ z%+RUE=*oN65%|};?{**GJl}nk9*eBhN2QYpI*ev*Xk|r;1Z+EX>{4`AfZ&mY{hxMS2d_f&|Hoc1v zov4tz^N5nHSoG;-F=2a~CWv$9DNUTh#Jhd{#8h6kS|?>}j#{pXS0_4XHClPAL!GS3 zB?jrO7C2U~3@zjq_TH-Mx%k~z^|+2Xx7Ek*+?kb6W4iS=DE>=qu_fTKbXp*B9P-hi zy|s?q?(t$=()v3`6~V$i7kH4zEkwIlK4w(?(7318`!n{%qrDH2r;a58e2nLphLUa* zB!`R-FOqzJ`%P-k`l9Y@AWxQDiIm{v36*H3J#k%uK8ZuOFQxZ0gA?4LBf(1Xw7q%u z@Ucz#zP7(td?yX1=n>6$*K%RYYD`X(!|=%NxP%#0#V_lHxQ5i$9P$pPoX_#O-Q!&X zc8n@5xn7TPPM7jHw`-iDg|bH+B=3$vq#V2lil5xQ##dZ+ukFh(zfX4sU%(x~D)&(3 zQlUXG?*2mJqY38oHAvfh{hbZMXc9WeUsqF#;C( zz!l}l?XoIS9AXsZl3N)GkE39d=FDzWj_9LYdZ6o*gV4$(9j(W?6sLF4dy77T}Xyk3NUBzlwh3_H}C z-X4MTRCUebBe2D~*n-0=`Y@%_jgiihKg@Cak@o6a`wifCcFBmpo>(7*XSR2JhwW-& z!46oPo}jW#giX50V;{Us;BNst9236w)5LaaVkd-Y@>ls`!N&nr1I%E<1xowIZ~8r8 zBfY(Ov3v9K7rQ_F@UKpMgoOTLQU9sol^(u&T{zjrBrxpxX{|H(hg+A(YroH2WMY)Z z66ddNk7HUAYmDBpC3;&j#{gb_WWy_Lv{S|fOfAtaIrk}6*4p^H?^Kdk+@B$jfu_HH zj>|!!_G7m&^`_3F@v3_jTeip6Rr0OXm(~G%9)o_z{TeI5oL`jhvHk&JekJr#e902_NeJO^UP$}Gx-2riN^PJE)mO}gM` z`+xhrx5Q3-1$yi9iL=c1a$A6UBi3!!>FbAI zB|<)%#9r-ui6h7JC%z{EVSf5kNP6)z6z-*JI919v?}vOKb1rHnK4OW$Yu{4FGRkXl ze<=wgyL2+hnpaV`9yUmU1xu9Vl}Qk9b+(x2mmllzJo~xabG6Uq+}b}=FWietp5fcNeDE!<@f1aT z5S$BF-a>fa5ap!5w%<>GWT1k+;rqJm2vQYsTRkvt|UY6ToXm?E{Fxp$HfIa807;4XZ;r zuv3e0Qy3(~wX40oq&s=-BEBYs5r3EnHX|k_(r^CS$qJ_kFqQb8H5)h`Qtu68kB)w@ z&fM6Y&##~V+~m96H*bGal#$pATc3)^xa8x2(`i}K14$DU7X0Dj9TCEyC8I1U;J`uc z(qH44pnq77ySqmfTAl?Ji4FE{&IB<=?thzV*EP{q8xQIsf|nbCJrd5uL*y z>z~dy?XBfj1bj>TpxC8xtvdR7@cZAl#a;i1_Wg%)&?=36RNZJjr%Qa_c?_lKhea%< zooIRU9E_u_+?(;esOcSGxW{uoW+Joh;HB4VP(FQCgdXK`E=V4=OOw{pmD?b8ckurH zRSLVm{mMd^JsD2@qOP1e&w>B!2@jd41&z7Z&op|GH&9<{?-%uF1Xc&(=o>$d!+!Vj z;V1S*vQI1u7TdE}Ls>sTz;h|G4tdhVFmh3MALDa7aCueAMGs$9wOaWicW#rGbGvnH zPh3M6A}%3^#Q9r)yr*THNEkGP=9GiRzE)jk43Pt6u#AG-r~H7pwG6-$ByJyWcYpcr zr@Qy|`zQbK?02@t>|fqV4~w*J{c%YbGX_H;v-O1aKZ^~kGK2-|SX{z6j-IuEzPFTF zvL6xPyyJG_jR5QI3@MNX+uASg-q;spoiY_83XgE}OU*FD++sAMDXbS-iO~MwPr?D?MV6Hm*)t#e}wQqbK6x z$U1W=xn5_;{mxH&>8;h~F)o#HdG4B5u~WW!j}_U|_SWCS<(PWS@9l;NUwBl&H9Ib7 zU31&uPK~fNuY78OiE?Dm?PDDI{k6o))3T5Ke45`Jo^fN;*rE*EwXGcWb-6rmiUtN<=_w33RP^l<|0wv8Be-3FTLIgD5n^Wi$;Ml!V@8;`*3xaHJif)iNq8=F77!|(n2E!Tu+H;h9Dak7>&yZ_ntPT_4h&+_VD37X?9@!+z zr^*%6Y84m#IY*sIwJFYdO38I#b4}5;wvMdTR*SA>az>Z(Shu^BBV3zDICgufC%aGn zV$Z?72S2x=9@>1L;uy!qx`k}D;+%?+PaM>zG)2^qxi8ny&zv{+OB-Xx7GclVqK2L| zyrd%aYnrz|b01%Sh5ebyxfEYkg6(5!Z?cxZC$0xm*1JZZ>*F-%wpDJ+#>%(m1Rs{^ z_Xshkd1a55^lOYATTWB!mG$@$xK02cKZct#Jlo&y?(cALIC4jTcVd&HpIgX8H_=<+ zCLp=X2z7UgxDSthHUl09jb9JJ?*yY8ywHeIfy7BxO#H%gV;94AHfC5Jo|%6CV2^_S z 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

B{*J>Fu&39z5bYpS|z;Pwllo-xS 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�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 diff --git a/src/qt/res/images/overviewbackground.png b/src/qt/res/images/overviewbackground.png index 795e9b07e05e09c4c406e4ada217f4290a952210..f148b83e75c7342091c1b97c07a8f5e1b96e803e 100644 GIT binary patch literal 224876 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 z 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%0At))R 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 z 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

  • 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

    >1GpQ|qq|&8su`2e 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

    ;Y?1xxxRA<49_Z2M?nn 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 LTANU=yJ7za8axaq From b9055c9d2e153da02ad3b67a208744f5719a0516 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 13:00:48 -0400 Subject: [PATCH 0416/1888] Update splashscreens --- src/qt/res/images/splash.png | Bin 25847 -> 299496 bytes src/qt/res/images/splash_testnet.png | Bin 10138 -> 299496 bytes src/qt/splashscreen.cpp | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/res/images/splash.png b/src/qt/res/images/splash.png index 93ade42a876307aff252dafdf28e3cdf9c2ef31e..a9b5377c45e03a3cdce5d1de8648db3341ee63e9 100644 GIT binary patch literal 299496 zcmV)2K+M01P)K00001b5ch_0Itp) z=>Px#32;bRa{vGi!~g&e!~vBn4jTXfAOJ~3K~#90?7i);txIwr^s8QLpP75_cxF7F z89R>!?%j2D?p|v>{r+^il`**%f@$NG<%bGZb76PT&gMGNKaG#)7BFP16YBmY&Kyi{*b`+c$FTGKK! zfONRN`_PtK)3u$jZ5xOPRNmEw%OGt}xliGfrI8)y&t)8WKl8F~C7I)WUGh0+T?M!1wpBwsWhvNR*Q;DWlQb6O?_u$5Ntw`XI{Gp($# z(}7n=ByHZ$T-i>iyCD9MxZtgY*s ziO_&9?U!P^Si}PmsEox?_I`wf8Q5ChCiud%p(RF2lo@#$pCfbQR>n8af9&lL(YwcF zc<|2IBcaYk;=}zQqHw69a%OWrLBzC@R@d(Odq|~Dsg~oWg;blmpCf}c(9UT)ci*|W z(9lx@?ySCdeQa)_=Ni{F0A>J4`43r8+VbyQfwLnOWh)V=Xh@8dPN-mRUoL6tm~I;& zBDxa7g9*6!vaWlnc3hr!vGtVOA{vJ8PhtAyKTFg3u~Q#Q*(<5vMeqzrEHKhu9hX7d zM}4BK-j1++l?#bWgTh4L<6ao3p6iIffErfrOpk&X)W7fiiLao zeEjUW=9(2SpBr#z^gde*-j#7&)PSu7Zf&w;fU^9yt-Xvy$$+^pL*J)p+&7uIP07um zABTfVj5UVeG1)?whD)6Wts%=)I}%;PYNow;`2J+IbN>!+0l{(Jk>;50LOz04?D%xp}pdnHBt(>-74HS}j=Zd?{s(?4P6 zVOysA9QA=}!BUSX!?WzG)o6-#Fq=8TjD0t1N^J(S^NbA&S^IvaErzj%;90}{!=H04PBeOcLpu?^qB5m1ZGTBP&p_}H8FS8pZrEN;V7nANCy|J+=cItALY z0Wj5fbY!g544n%*+#Vru#$q?t*N^4NjL$Vb1=sr_ywK;7bQg3uWv}xg+Sucq2Ve&7 z1}n{RhG^n5TOfHy7sflaV6X9jUTyz|sy@~CLUb~dv1-NRt%iQjyZyWlG-BGed5$x3 z!8>i&fmizE`+T{Q>+2ZEtyei2nxSn+`I>Rad%;!|m-!p-5bri`;7>8hQU1Q{O}@~a z+8M%F5%{hVn0*;%^8~jaap|2(MvEo(a`xKJu$I9hyo+?ZQ^tMt^reP8K}|h)38W_d z*5^?@iV8dBS<6Io^+S0Zh_%ORY(LiCNN>h|8_b#ACvAaQ=vTe*(7JoPU*g5C#gro0 z{m{-IbGkQr6?T}#0HJe(ap;T@MwXHFd@uCbqS*%1UYcx1mNesBG1eUO;}P0eO3wd3 zb`E%#SdHBC34dRc^UW;uh?CH*buHEKRJ89mG?+1sixVsjt23psGYlx7{Qfl^GuW2%6CXoOnuCYDzVbj`?C$x~v9jgiR#83K# zUg#*bzPs&wY!BuTDsHSS5h~j`_lUqi4b-29hx`|*o`q#lng?L0Ol;Kc%3x=h*gA3@ z-3@i$Kl76D?Pil!^U3DtGeDOqFtIuUm3)CG=x)8_KQdX9a&65DRR9m4Vh@DZ+B|K6 zDK7!Kzpg(*8W<|IM{6^l)$;vV0Zm|yfgsXtsfTSbqe~J&;F$K?l_whdPXFGQ^WiUa zoCtFP5YPw~eO_5^;NdY)NpTegmcp%>qc>~7lt{fL#|xa4S<3gWrGX=fJ`MI1uhpL& z=)ToO`BV|D_R3uWCuJa?EHg#BgrWX+YJkn4wgUpQkC}Ca9si4^Q zr`t`?RL|zcjL?{^#8wcBEMqo0+D~?+1X8fFSOd5gFiI3%Bz|g5_+Dn^Ik-k9m3^3x z+O@-|2xv{v^B@{yU|Ry=(k3Q=HXDb$w&E!Meb!0;0Uc)j1D%; zZ?VfqLWg*4lCRWK+adzgcEE-al_w1z(~I`|LiZpyi>TiNz9w4R4gl9>l~0(67is2p z^T<-kZE^$1M_cp<_hi_Dne@^m?7p^8Oq8`JDObTMsNyM>Ec0fXxdX~hK}*F)x!E@p z4`r${&7OWsOUx*O?fpHw{I2S`V_Vg>$yrV==Ex0X-UYD7D5?1Dc&&+w8B+sb9suH4 z6BaRMt(05Ln_Pr|$S$ONRDokw8y&3*nCOICdA4olLWlM+qRWu~$Ud-qPsrHY&H^dv zh&|_oQ;7uE9-=xz0{c7>re5fU)~L18Z94BMT%Y%%9RO}jH^~F-7YOaFI(|pW5-Spx zMg=1$uF*TnEjl2$EVW~`q!)Uj+o;__P0tjmYzn{@V18N- ze@ag~pvPYr=|AE$yvcJDkodEneHcxk_B$}Y?tw6m zS$D4q9cA;3Ec1FV<)@@5D2IEV6Rm;!#14N*Qy&Z)A>;C;e*`X8h_n(!8hMl%*PaNr zEds1?JMZGUVD>_vZQA3J&*hvu*MNxuVvzWev8?ebP4{^Ou)S8m&SYJVA*spi`p(V= z>Ug==F3lD1Z>RAyuxq&6Gp9B~H^HVu#D<$m75SGVTCit!dhT;2=fb}5z5|bM`Fvlu zGH%AE!sbx`zlXQ&+zPRuca-mNyAlDHIFAI_=xbjkF^8vO4Zq)!q-*@wUg(8Jl${1M z=C$1VvNF+B@2niuQVhUFYe~igD(g!Zc*rU09;=#NPbdK1nyRZG>os(%gtAies%X%* zWrGbkFT#oyKJ52FnPL$wMQovVlWIeyrh5u*L~5RPb+V0`g#j40@0%MXdv4-!=J>%x zkES4%fn${zQP6)5#AIR>GgG5cSrhu4R@&`5QQF3v4r!Fjf;*Q~)x>YtC1H3jgN^xm zVV>C4+)^rSXk7933kA%+uMDzqDZ72OSC&~Ihv&SE^8F0qFZ6cF@)Pw!Df8m0fEl?| z<>x@LQj*BD33*MQZ4#?;Wz$%#p{pybT;eGehNWg_>gIW6Xsb|Y+O-k)uVKa-Cwvj2eYWuN1uCr@9Rp4la zqXTO^;3I2V@C*2UmdLKt(-mvBwdm-#doO>I`ZC{i8ZdR!Zs@w2Tr7i%&=?RdX4)19MDb-XGM#^E&{- zOv~+`RflzIqKi5GN-n7=9?bT|>&U!Cu#Kp;rUn$u29BcpE~y-LUacN!ihpl!NXj$` z$RP@2kgNa2?sH3tw`ogzd&BA*a0d`jOGPt&vZX<0Z+Ev>X52#Ikr}DX=gnxOV*Nip zixXlOuN8`Wvp+S94t|II`xkmXI>IA8XW$%~@(wIE1=D4(U6*E#p7RZX^5gnZV%?3h zw;mB8AsI87*W!A(@ft!+yKw(!*B%S(9_058q`~hi4N!Z&jGNh$HQF~ZXU8UD$bYGv z;T;)6rxo5rH)?f&+n=r@otja9s#w1~W~u{|sXWUwgA1ti23y|53PfEUelNHbcz{+I ze9IR`qH5LZt1M4Da4ONPvJhC9hpAvF7MFpDc$Nxa(%Nb&saw$t%q|P*^ECINeuU+f zWcF2`y@2t%K^-4nm{0x&E}OA@qMagwItamDa>qb0TY>%EeKK zs1LjWVBl=iNay;T&EKP%um66JhRXx6U7-V6#1%IK@Dfw5LEWL3F3830 zB9SMkSEqtS&Rb1+JAGI&IlBS&CQ+$p{mf$n+-f?X>&@gAa~q+mZ?bQ##I~xxh5hc; z5&vysrXBv?Z0Naea&6rz*;hg8HEqp4EB1#2OpeJ0wK6#JxqZdHFo}#h5Dokq0 zyN$B$6louu%QVG!^Q?5}HY6hIt{d#4_!kVv3*w7pe;G+jI&Zeg~$Os}mhfVwD% z(`xHpa2!nJddeo`OF0}cpQpQ~Yr~Mlx{`k|&rH})``8wdxSFTi{37#ec*>{&%{NBb zc4?Q&0%b;c%bx5=6Rs_}w&)i#_5J7?jdzo612ga2cj7FTX8yUOd~~IjduLj_jDf3p zPCG74+AhgW#R$fXvIA6U(}jBrwjN;`HpNs>Ou1r^=C{V?=I=jx_eV9d zmD3TQN9V44I+3YDDGn77JW zHX~ZZHC^g8-h7WL0p&`wbq#*ga;8Snrk!mt0=-a~0dT4>l>FVReR-Ly4b3L+C{=;N znC4}>p{7D*xd3RxX%j%Pfk*uNWOpC#wIFPSnpP4vFPudb=FPRGJ+7imSXb`})ibwf znKR&CYAFCZl{P*i@1T~g9KEc*+6-n>hLGUAo-NRF0@K!cL#k|HiMwTCnhL{tDgf)ZFUXwQxV=ux8-(uJmu~Mqv`~!Ob(F5TSK9XX z8s699OxM4A@Y5Egqcmoktou3a*|&HOzzO}L4vVp_gsT1KjQ5m=v@91UYS=2s05RrK zhPv_%wF5{Zm6X3M+=l!73_s~^)^x90yG;-1#^}4^`8qZCCUyD&pk|;Nkfgj5_eSpP zHQk?=EoWc{OG3}chV#`rU{w$XtPtV#+I2F!P#UG`N`wdUVB5L5)1+R&G<(9GR)wy^ldex9kfM1=&0qI%7SwXu%JP3g8}#zt)LKGb=<`kSY`dM2%XTLtuLvIr>lW!u z%`Lf_+o?C-RPbmJ(GfS8FkZOJ{WaPxgM*EKD7U;iUT6o5)aSiMdu{ipyF$6IdjXK$ z(J?jUiRR{+tsG-%Yff}Rdus3Q$3H}~H9wUgpXR%ytqeG}g~<3@KxyMfA1B2*LOwIz z{=S#LsF`9qw^uVx_cbYwbS2PiLD&QK0ED9|w7}ay_&S;iTyuK9v&k>?+$7@ioSyRK z=dw2}J7L9C8J7j$>l@UUVa>gx!mYMT4R|z1eb8uIuuHUnl-P_l-3BuE@KSl!YS!!$ z>{EY+*P8Kjsa;Xm46wVvo@0<`j~{huTJ-FhX%$e)b2lJ_twd!=+&ccB3%9$dV;_;k ze-0aSoB|Mb9b)eVpZD@@za*`V)YJxD+>GV;$a~6rxUBD~3QM}*zEfNkCrV%(+Q5$x zQ^itqxFC*-xYi_Fx?}}~{vQvE?(MYEar2% zU36sr;rRBgf?id0SdR6V0H+uN48m(%q}$@1TgRV=^=V8yX5xHF~}bkl2; zOArV3zaZxe4JfdY-hnzUa#gPLRTFoYNgXH%L0MCcSCUwBtUbyx$rCYR%5Lm=e+xn1 z`Z5^}=r(UuoH$e_3dZWH@!Op_!MJtjz!usenmsol$|kzio>pdoxG@i?c{9TUfK=W= zX@6sCzjcqepI?0$)?<23t+%!XVbNamZ>vpRlbu%zs&-RK48E9t&9WJxC?enE(oZr+ zo>oa>Qy$G{T0*pa?vC}m&~;=)`Dd=t(!A~^6SOK;!gucgzTtl4a9u?Vlijm61)2YM zfYO$(+PsuBU*LpBvFs|(1y*bJy}9)29YyoQ5Jhw8*XBzI{%pxiS z$=;(6@R~^8gUg9y(4j`Nk{2Yvo1KMxyYizzgSF*QWs*cx0liIli1w`j*HJsZ0<1F= z{ss+rLJNQpkicv0(S{AD{7%%1IGMlFHgD3rOJD<%J8|nf6Ph|LIZ16@09k4846N4# z17jpExR{8rZTm+7okLwjT+a2fpX)i+$8(#0^Gtebujm(gzv=#>R)40~#dwG)_<3u7 zTnfaID{BKOhB?%n8@GviW?%qQv@Gvot1t<@@{e;@e90+no&(09y^o zbq96O#R~zaGCf=%4wBOI1Ev$Ua)o(Y)Dk$-cH^8U)Jq%Iwx4R67cKaGrFOne&bQpP z)^?^wL2p*8)=NuDx+wsYVV042K4fC3Qn+idE&ys0x9R*tQigYg#G}>}B_AUuYrv=7 zH)}mC82~2(=uLN)i0^PLJp$Wyf9)ooBcQwuJ7xn|%)po_>#_=68~{17&a+xl3v|^A zGORDKVyMB`YQ4d{KBi%h1~;&nEO>P*$c81DG_xjknage6VkINLHrr+k@b2i$vC*shubcAv}&#i&K(6f@o5%crb{c?|rDp}YV3FTYo)Vn?#W%|znc+Yed{8m9J z(01EgGjUu~&ozdq1>AZ5iVhuV-{guP^_d~cL=G~~)VC_k8J=BUp`!iU_N+Ls>^W6+ zXNe=tx24v);5F?w9Ot}!)!9w1qOOx%G&VsCZt86&d{|$g#j}Ku4BB=z2wP!N(r(SO zqcp#eeq~RX%XWf~8pmKRTL5fy^k%5?_6h4d8MXuYUekOd%?4(ebHQtUC!)MBeN%85 zkr=#i_ClW_GRkIei@P6<&CC6P!x4!~sr_ZtUP7L>=bE(E(5u*@oh&p%@uoJW5y)*5 z;vzy#Sg2@Y12AH8F`9Odl!&z6M8*oRrxf;hLJGVYIqpy4|=5 zrqb*Q@0V*jV(O`HKL(-f!^GtdW74*{788MX>K$36Mrnn40dRrqBa&@`y>z}3BQpVT z-pck;2&qGy-WH3WR!s@Rqfev8zL=rk8>(}+tQWPd+%kLO_upcLt=q1lb?QS=rlu77 z#t;8FqqJV%DIRLPZNl6P|I?)`$k;4fSnxzz_FC`QiAK11>e4ZDy}QLA>~a8c*ROVw zTd<9^aGS-tD!nB}QM6=k#;ZvLr}^!S(-h1&j+B+nvHRgF_kq&-5dd~vxfqUeM5yxn z22h%n+lrQqen)D~==oB?u^+p7)MhrU_VSN@&To2kX#SehSwDx1D3E=@Is2q;soz;t zxL?;xboH^MLV7f5Rk{FPK=|DuwHwK+A-kGx7t`u$wU)JtCT(!0{P$_CDFVb-2jT$y zbl)wb0bVXlD{BQ~@C5*Ola9?F?19eOK{z?4YMC4n74S8Z&ocP748$-cH6usBo0{+8 zm**!JtqPgRS`)4gj-(JxeQTK8qNZxbT(WD)B+fQt+SOJ&4XuKs$hKtC$!obSEapxg zV@0XKP|SEPfY*_AD~hOFv*tB*-roy~V!t2V0^q8)8QRL$$sJ9)v8)$*M#}R=&pap} zxbM5OvotYu3(?wOo}%6v$x6986lDdd6|FY_AhTaK1K%MX1m7r)7&A6%*u<^xq1DDi zG=HBM1Qk%UW>fKGZPHB`?hMephjjj2_wK!CZ3MV;r>yRSYpc~`iL$b|_I51b9K24k zT(eiiKJ>0vYvqmmy|5O_-!}UZ>vOZ`awMl|2nTcN38>u%dE0{S3n|@G<88%4ClV@8 zxo@3ENfeGdM8ewBd@cBH%H%|=jdy|~#$%YUXb-ctvz4vNPbN@7)}V76y5moCYiVdQ z9FEDd6V~ch|JxvHz7;i*$}Kfky|jTk23@hBAv{sCF;IcnX5xAyjs(pBJeco+k@w6M z?|OEra?d=FtOw{=2jQ$eib`tlNFh__Eg(T)-l~5A^%pNtuDWcqRBv_(p0aIR&4NS4 zvi3PgHmh;Mv*5I1hAx#{1;VY>;9XuvFJ!3+J9A|zz1})1iHLM|y#4u+>z{i;!ylIeV6CRMZiZhZK+9FVK z+3y>9ULP?V^Jwwvks-59F$7^FK`7YCWfY5VjAcCKoUTmV;+L=|BvUaVYgtwR;`$nh zuwl#l?MB$t(w)b>!Q3O0gaCK*5htwQ;x*HtN4F_eD~3O@d8Ib~LQhU3&C|cJy{&|O z4%=F3{dFfZx_0gy-~N~f;y~>L13AF^UIoq>qAZJ4HJ7}<*hoIA2HCQMVRF*DFN2y- zbw{YQN0W2WEGXNv1_D@TM1ftE6}`ct;d|YhQYtO6xFd zmW5Xzwyaz^hX{x3+67?Smda3!sjSPy^*muoSEcP3R_ZU&eJpFkVHvKN(YTYmk9%7> zFK8O{`HFI%>O9*~S^@gVzqccEQA0Li=6AnxF1RktZ1zkHoKP1L&OBld^VE{e`Zi*j6-qr}29j1tuPm1lUo8dd}C& z^OHc#+?}M{jAsAhE zy4460r5#D!o{1~a4|#iyc(vMhE>1|{Byv%nXg3fwx-5k$i{D_dYW;a@){k9pnM<0>rmbylO`8uw6Vg^)0+o)>|8I`Kf5` zKh-mcy6qOLoL%8EAo4G9m4t_bMFdJoQ?NC$0Z?&YHDp3Y8`0tQIc2QkZCJ4}*I;E0kf zD~mapB8!GM%HBr2(g$K4VSp}ms!q(T-BBHLCYp_a!D@yQ;gC)G9t^8^N)l?#OD0?$ z&&)7PD8psqERXnq+a{PGK z3ux~VBlCe|lpAIWc*DAP^7U<@Wg+#d@{9FI9DDB*yUmj`K_3O)*1Ai|r8|U0<>ELD zxVC*-ZXi$@loI^ zWDn!CMkqBc^W0ENX35GNIOY+Zy}|o{9V>YO=S_V$Gw=eaPe~@sB8_7nKV9|LTbcHV znUPX5yyNNS(N*Vw?G{b%a5B(%_4b162Th$!&@)zU${zKrZaudQFiO}ztv=3oe)(;G z?pyk_URxLQeHN39UVr3Zus4DLh^w*;gj>kf2vPW;0O%Gh?BmI-WC1Fy7IK$HtWx zw&fNY);OX4_~1{)ygx6r$-Kt%jHJ9ZIgv!$iAl$4Jfw zCpMQeG-*0B>#S`g8oAh51@`1wn`f+z$x#O`-pJJiEkIn;iDJi0K-%2A@KMwH_8$Xb z1}K3z$2Y&I>7W7Ou&?qw|B-XU8`y_aZjx@D)#)1WZ0l!?*W)a!2vsjy@KcaGY^C61#JbS z63V6Q%*Dj&HOe_y38p(>3Ja+)y`QZCubd}eEBD3Wh`MKbhBpPKDp`0U_3wJM z-h(2uRBbB&fB*65xXb5_j5cb)SpM3$&N(@`=Tx>aoRCHW?s>LZkZ{w8MZ1g4OMdI4 zPsQeeaqvP6!dU~22B4Tq3&7f=NzDjAqlIZ4=tf}%<}g2UFw+Dj90xHjEGFnCS~3f0 z)_Bo-B-;0L&-dzKex%MCo$ZC*1JVgEeBu7{>s{l~{umPcbZu?pIz9~4y%@vToawBc z_+y=jl21=sN%2rs+kc<`ewyyyZ#FtmrtxLy&r3)4)}F1cZmS}0qxB%jKd_x(4uK>< zN>0MfL`9MRwpz@rn<6N1YqZW6gS6-UYW!(C*D(O$zL&Kl*+S&PrLuIO;Bf)}iBs_v z#MqdM2dNzAs)IzOGa7PodD}DCJsx>!p@R3})(hBoL48(8#f`!yj}8k% zAoIO7l=VXCb84JUgm{K}XLa;Ega)6FQh(2`ulGKTs5^Egd!PDiGXKxOVDE6Q1p(>^ zW^eWh1S)H#7=y5AxfhLoQ#nHxOLNoZhNCr2SWLWTry`&8b(iwidw~g5&pB?aw~sj= zh=!K6N|MN7fUG&Og3Hfhj$U=94E2beec)@g;7Zrs_q$)O%tSjQUqJXt=^4C_@5i$P ztIm}X7cHH0L?Jq+`6y3}z;|}2!Jd&6YM63Bh2J&}IMVs!Cs^dwx6cNc$afNL^ag&1rhgauP0RN!x5B2?f+sD<#%7#3hh9ax!{Qe!E-Bor z=X1TUh^qJXq56E^$&~mm((PLK3*AC0*h5?fjw)229XcPnyR?&Z3#hs@zC3ovibT5K znlw#b6)JA}@gMZPHbhE<6)RT^b)-m}}69Fwc=Tar1c#wdV>N5>(%U zO3c89K~*}3r#R2((t*UuuzA*h7a-rh#TOG$qndhW?J+HoUrYW|Hc8V3K)wFZwpYEi z-ER>iA=P-Pn6qs<%9-;X`PK)2A)LUQS!WYoB{6KbO)g)M`LW62BV14}RghTRB$ft% z9~qYnDcd+SzK?W6 zC`ur!<)e;Q0No!P54<&bWa3_E)98svUI7A+^zr+=Sj#mlnEAGDyLAzrZf;WuZz6^2 zxU>#TEno*_?5v~+WT)wZG<~nBM9c#8q6ga|*(#x)p~w5dP`?J^cF%ZUN*^CjYRt~4 zjHAsT4Wl?rF^%_Uy=5dyM3DVc-E(fIL87c|->4nV#$lCK_qEqe(IczH3q2(<;O|wx z^N_!rJQ{!s0_?rGJ;Z2p7;dJYAhB3^FBf=U@U<>fEaj7DwrMAAf}5ik1Kw z3E%`Wmo)T!px}&fBs-KgGL`3|&H4ZwM5Lzhpkbp2aW}fYN*xRhff?nKrY%&L&oU1Z z?#z$-0pN=H(!3OtbiC#ALU$tq$Zjj%yZFxr0Pl^?fldZyKMOs2-I|n{FP9AJvj7}u zL#o{v)AT-Xg(^%`{VBt=cX+XNK?|6+rrWl`N$Zw2+Ole&tG1JAe~(ruO2J!g2QzDs z5p8|5tsth{;58MzRU&lqCb1fT6f5F#UfDV>RhAi0VoDxXkSuF;LhAU zD$V|$iZC%~Nik#Z%>xavGpL6^xGcWkk%i#d_JIjlyS6X^bb0#rypYoKoauePsQ~ay zT^ebj!i4M1HlrgZSYDMDB zjHtJ%fYRpPS8bEDw*qf|UdNeaYoJ_!a3SEN&*kV)?@>L|gk2p{e=#3WI_0BAWf^6w zMLD9!B^@W{u2}cD$DZu=Dz(~ApC?jU+j)Lk1yJ!4r##-|=Hzn$-s1Y)@i2QaOW#6O z2qF?MpZkI2yAt%s(~9+FPCI+R5qMDZZ;!0D3)q*mLe%Ur(}BEN2sK!}?{j(O1Uh3Kz*b0)OiRJI9(SS_3 z8mCs$8}l>Cb$d-)?kG|Ea@!xsJ?ZzE`_b(2=sHl|1Go9}$Q&%;AEkaOZL4Kvi)_(s z^<8r9;=rqS#X3^kD`m?huKo_{70SiLoM^|6UD8h$!>-0a`{#X^y_L=9BY1l^jgyMS z;0_@0q6ObZOzx)OyVAP@yvJxZr=|cbOsM9yT5qc%3`m&{%4G{J%@>V=&f?-0YKX#+EpT}-t8_uV8Rz7%V?7q{^H4uVk@MFY(^_%B+B;J$Oh0vLtf@KHjD5Ul z+3Pllpe@Em%xYeYkZkCptv&;Toh^C*?iPcv0rfa!Mm!F zpIA8lb35S00`4ueH~(I!Cq8nVbzDlXbezao3+LM}Z;eC|)#dH4g^?}88acAkc`C(I zId`h_u$;v-fU`gGQ^8-Khil7wGD%r#QBE7#XuVa&X_=NZs)iq|e`B(Wxz&7!ZMl0CTSBFA+yXO-G6WJ_#k*f5K>Gseuk^7LvsHmAM_96U2v(tF<@JsPrI`T5fF7?o zLA2S3bNzNdTC`xn4HYJsiuPSVGj!TZ(0I|oV-W^s z08)W@*lgdg6%En_$XElr`|Z8%>0Zapm@oUnl`0mbE8x)Q=ukirYJQ=|^N^P!J0sVv zrIya0ficKb%~#T_56cno73YmZQYO{Xtl?=d{S0)E5?i~sEAM1JA1nKa0CG*M4@Kk~ zl_C4qU5hN3+4sC5nZPXfiL^8*L#-hM(tsix{M@Y}8n3Hk8vvr@O^7eOuq!I4FR{J% zvaq2Itop$KgckutO~MTwnoA+j8-^*`@K9)YVmcHZ>p-zD`@(>=5M410dk%lO*muOz zFu{vE6svTOD(C|u@G|EP8*Ci0vY8=)u$jF((K3W0hBDHcEfkO|QxdG0r#0K6=Ii2_ zs+6BSSZQ#%fy-|!XGdSM@|S1g1-8CXOM457=0w%{s*!1K#_!7vBYq8-pH#*|w=sU|tsn#|-3TOVCyay*)ltv;HMvsOfOd?z|b6ywG7!1vKK z%S)eu{{e|3nk%1c5LVh7#A9Q0?{mYq(sOJ%FtZOusq>1<6@|1OVQE}R1z({g!>!=c zGMwf@hvErl9cK1g)H-Fgz&hOTwhlZRw$G+%Z4qqt)lT|sCNUFH-OF7VS^+?NKm6YO zu6f9f-w_kE1K!2;RL8F}T|aIjIfx0DmV};&@m0->yYbNei`xPcm@n}6-P&Lgecc-v zNdse)G@Qzwu;0V3Ue0jkMNUudcpB%(V`6?2YfyeB4vav)&liWZN(p6}&!x*e7LB>M zcAXNCPT1bO=>yWavW#y7ZD=oDA)GSM>ehpu|Fk}VfNsM3ef8A>X3??MgM@sZ_kNx5 zq1z;DE!M z3_nLy$`AU}M>J|0E_bIY5_$WJW+~Ujkz+d7_o2%Rg8`-uvyvo_1v=muA6xLm%RMzyF^B z-~0Yf0b^pV-#6lVjj`tO$N5Io#M#!f!J~ZBfu7g&IWb3j@V%e5Tg!i%;2p>5?K#<1 z4OrKY1oJ;Os9gsbsKF&nI#e&`Bht>UNm%|;JRPpz=gmN2Yw|@^roT5w-Bal?O)-<{&5XWDKvVo zGwm(6H-VTT|K+`4fVTi<70dzv)*knC`qD>u^_#y6{OnHxU;8rX!&h0kJ|)m=2EO-Z zNyR)2rm`Qq<3D1{%|d*e_86b=AUw!__=>`~F5t5Z#ChoUKr#cz%zD!2cxF{|Mw2T` zpMxp@3!|W(iR@AAsoRH~tiie4yKl$!t+r+Jl`rKVJ+mg$Dy3NyV`F}^w>qeH@0s&8 z8gLA#b4FIvg(;@_wO$3R+nI~apWi>B?)doev=IuYmu;4$Uc-v`JFIkg`n&(%D-&k0femO!*3=q?~E^#Pwn zAa2Jk_b=%)wm%;z_T2#A%#NO}EukXVd_P;{qGBEv+PE;T0YxU=yq$GcsaG5@NaO9a z5>;RR5l>){Sk65gU2*d9OiRq8*3<~pBP;fpQQw8C)ddn&u=m=odyya|bmp$Xjc6g& z5fX;)*=1xxjRIqg-kJNo@sQ5nHUO8Rt(>wYHFR*Q-);SA!2GzRr7degoU#BwKru;Y zr=|?0vR`O`s1Yi;05O9#8KGQ6pdeEiR7#yWdI-WYzMRUOkiGiNS&_7T1PpKgk&6+q z;o(RB3|{^2-vG`zs42b9ouw0J;7yc2pBc1eK)sYM?`bo+PtiWG?2nr!Il(oik-*}| zZ%IjS+9>t+ZIu>ZYd)RU`5ptY3bqCl+TP^Zx86ramURRH-rnf&RSIU}+J_^wlKkwn ztmLyO_}UR`G!$1MiBy?0Rqx09+xi83ZwpM;c1%EYQ{b6t$-^<&t16&*KWe+Cbu7^= zuV{5tzegnuw9(y~+k5~NSQxw7$WiM7fPBe(8QjUCqvdibH>CfSkU_W;PTJgSU_^7< z^|%-!eDE*+I!@pIIp9qJ*973Sfl>mUHqa>nY0Fyh8-N}!Z<8xJ>i5rI=xx)j-1{Aw zTG={z#gux=;Fo9J35&p_898NYQ7>5H>WY-J6-FU@zH1s=T(&&i2i{{QXA3sf)T~#! z(N+RX#AU_KTS4006hR`A))nm=czUOWIqv$TQ}g{=K7VFdfakh0A`Me?ualakxmr!Q z3IL*Ux7BJr?t$9ociU#$B?4WT&44YTUdS+V$QojEO8D?E{S};k=4U}$0$y*Rve%on zUk}2R0Hh7+vd&_NC|h(EwY(LraAv|kLhKEAP1$-l?W(em(EFwdtJSS+BP15h_YT*; z5VVxH6~$TS#I>Cn#&incJR)D0@Ys3Vw++@U5I9 zuahwGzs}{qY{!F7@BmIIrjuYUiLi_Tzu=Cv41w{1K@f(Xp16r&R?n`Au6Kf^gF|W^f6c zC(^w%%^SnHI?Z;iL|sIkQ&suPzQ6U|$dRkq{AI^Z>$Xx35%Qid#RFaF!$1FRJp9oU?cQ_3l1fFrp3Cho zRxMXc`PJgs&U036ulCn#T5Y>BFv*q!hgHO;XP+=7>*33=+HPnKHf4K;RxAU>DX`qD z03e&&XscyziY79bwjR{`Dix6Hb%K3JNby)6JCb=3ixPo1dqYyLoHXQft%J%`kXQ=n7%df2IEg|p#c=d7j$m{x9d0@5t9;kNN`YH`M>qKby zrq0n36?2+=(Sr%9`A!_yPu%e};;ef88T2 zbBd}{(uhUtTiju!)}yz!mlSYzt)>ea0#ZW0i7aKIBJcf{Qwk~R zGXO}Z%~vs&qg=m0gl%i`P5^K=PHTeIZIs8nbWBe>@Uv*aaeMBs8NV&ZHPw9IQvIbB z09MApEGl8>_We`-->8%sp6vF%G3A|2yZgdM9bv%T4Xm9&K4;iL`LUN`kD(-m;dn?S zXANq##&Vm_P9H{0Re*yBE>hJnYfp_Mn3;1?nZpruj6Bxzn_lFaY@rSK?Y*rJfBa`a^Z)b$nD3JpxNqy*(|m7Dc**J^Hl5HHDHrv-lv$d2(^M6AMMVchfTG zk<$wmRLBvh2wN#PrHppcFXlJ7BYXzaV@WSFuJ(zU2R>J0?JwwcSvK4z&a=DwIXdFR z_~H+L3+a(7*pk`rrL5^@FqY3r(@F>E6!@pcUFqtVvAvz11N@A&1Pt&68ozx{<$q>+ zpTHLYAg1THB*Oq-K%l>n;n{m6VzzEo$;VlKqq$NsU$y7uTkB|ytDb+JqeM)D#;~0_ zg7Gi_03ZNKL_t)*TW*vt5{D9BMh{_EA2bEc5>j5Ha20K zeLDh@2{ch4MKv(ZlZGhiZH zLrnfQ%!6!8wBu&KZ^!|mQ-)uhn6Xj91}YJo zH)1t^R)?%oKuVx(%k!-;kq+BA0d%RKOMM@F_%)m#z65$x#vuVI)z5O*a0XucS^82| zR=R{j(gj>}MDl&?s8Qi3G}dVM<~o~vcLFB@d{C3w1r9G1(N>fKvKrg7kpSqnim=;$8OxnND${d_K2%rj04mE^|5D4>AjKJaL!zdtKd{@x*6Lz|jyDcaQ@P^GS zeHQGd01)kE1G$i|eCs#Bk7Zw%P_$moGI7}hCIiMvKa+dOGzfjQuH9a1us%YI+70)& zPlct)J0wQF87WdAUT8`RN>BanBU%IBY)mq7yCzZga{8+2w&iq5_qrV{pH@sgYuO^? zhK&L`k7Kb1nrC4frUSGsq^pCcCP`o#BD19&^xuzZt#8a>Rs{#!o+!tjEjY{f zt($;Vy1Ip2erIbn_4k%jm#%6}sE#ikk;yCN+P)f~Qw8x65-fApPivC5ptbQ6n zM0OE~!=LuoD6=!DA)4)y*9#oD@xHQmLkou6c-)%ETy%dveE_}yX{#Eo?*9^lC{=Bk zfJ6+W9At*{oPMb{-3UAcT<;rkl=kac-FlHZ>)*$-t8wooaU!>7o}01|IZucRax{PISqIQf;mBD0D!$9JYE#HIQ+D9G2?vW`Xes~ zfzmQ)E}p1TQT{b-m#wGM4jp)8QnUL6?02bA&M=nl3 zK<&&u%Q(iMQx+8gb$`}UFFEgn*IW{@7e2vM0 zr|~r-B2%T_B{H{26^6KNn;Kat6|J|ZhH`SXb@}VNMtWn?sg!#GVWZ+m z#Vo^!jW*=1SOV|>rVFeip__fOG)(zqwlr9RigZI?#%kMScDakA8&v$p&V>`xsL8NNzo zT{CJ4_a`a$Jh!7$O|31I-aVD{Q`uaNPt}8OzX#W-cFwUveybYs)vb%hDiD^Alw-pV zIuU}<^Kbi|o4-^}vYPV9St{1(b`MN43!v`F**k9C{^Fp%$P8~LVpMCME9k-4mUZGB z?Q0|N+LtW>_7{yFZ6bv?%`o+PA@DfObDCZe@aps`2i*XwhKqdu7qlT!Dgj4|IhqKd zEd<-7H!qFbbGv?9$!YxIJAR>ek%(pr(AyyIQxWMoQJX^_7oI(QIy&!fVv9-kR3u!W z0vGA~JE|>S?EflK$E|n4e)|!`1sh&jR zh2Lkbl$!7DglZY^zUgi1#mru)Y0X2DcQan)WdF)@^d{cwJjYsZzUmJeE|Z$_zimc~=S|IPSzA11i-5MR?(=$KVqZXTBw4I;0_C||`%_Sr?WD`^>mhv! zBo0{Hmghq%pbOE2vzIreO|1(g-qfxw1Hs`I#NEkzjmG)Z0R5r`$JDR1XC(4`qI=jG z87J@0Ds8qe3~*yX9URWRJB41*mU@X&qFdg@bJyva?a^JYi|1k8b%?5>CasoHbzquAEDc3$blixo=klfycy6X+0PaYIM#l1{{1;|G+5Lun8__v_aC2z zUO+gYrA^l-ta?NWzGRx$SXS5z%%TzZ0NYwn??ba%0N`AIG3-RON%Frt4YDw(r9I#I zK+267nO|jKk-B^T^_j~7yb+7HAx19b|G_;0kwoExJBR_CpPHhTqPd+!o z2$7paRd(Ad@DjR`?F?v|-qaQS=9yCj$j*t(N>j|ZlzrD!_IUvleBbtu8`fRGEZ4v3 zc*%Znt9zpTE&@v}3IG{mFSH%aB?=9Ksi@Lw zyz(~!wkDAPZ@WKc&oL7@_ODDdb?@NCQE8^m2CWe6Q2F8iA8A!JP*tD&r&I?q=AXOj-BX<3gth4z~TA6NZ z*m|b`l90A61`xQud(nhZK{#6;ieuKGP!V(^v%RG;0Q)ZOb>P|)2fF4O!7&mHTOs`# z8n+kC(MRlcRmXKFNIct zb*WFvRTH$fj|g$Jo49~6_1aNf4qILXi?mGr(VMso!=M=$olCyPR4l~6(1bV2yJ}_z zfaLa3`RD39$onZqqf_9w6KZS@R!D9bkjasg9EKe5GZ$8vqZBJ6Kgd!OEG9am&NLgB-~Xw zZUf4(nOv#Q-jeYo!&&~w1~ zPkTFvJe0c1s*8u+m|f!bK+Dvxyf8(n?y(I+b&j%H4OY{Z`P9aihJ=gE z?>}u`OLk>3=eXN+!nR$^eyu6fI!lS5j0zGA8AHa2oANg?gAtf7kTYRzwBS9)96cvD z_%aVX;_tqbjk6OL6@9aqnAHgjCFlmq#a?p=-g$nII%&q!J%Frr#=4`@JFOFtY4sTd z;{ng2fD3cLH^llhb9#*_7dC%~EjarIL?-CGK~peG^2D`kin=y4wqzymKvxcuxsEUe zBha3HY{54--81=>gY}yOgyOEF>sA7M*D_0OZpFQU>?$$`0qmQ+Ks}hR0S>};a&6PD zM%+Kw3k9M)Rat=^7gD*V-0MWOY;lZ9rN9h2RP&j(MCU4j?0{e!v~`0NoSBvS^m}y& z^Tk)4JKBRA?t`2E)g*b$ldf#)0;YF;WdPXpjJRs`gsKUbv66c7jLtH8?q@#hD_1AB z^G)_qWqzHI$|Vh@F3v#Lj(_aH)Ac56t+Gw9<)~dnxrH=8?EA)`t!TSI0b4Og=kLW2 zT7h^(NnSYe8tLXpZEg`j{G|+p6By0$roq|bu-K9=2bU=ojZ@c8MRxJy{Pe(B1+&iv z2op_jrH%76-(`kfGb9vgzA`7|y^?=W`H|&sdA?ig)(m(}vS6Lc5!Qtc+(6|V@U`YN z3zCJY9WwO_&}6FM+op^1pZvaz+XKjdN0D&C7p~OAydJiFkpy&I-a6j-YCJ|tS(rEp zrWKCA8Gv+7D~rvrd%(`QX_TH>1r*zdn5rZYOQ70t|GVzjhhmDZ;%I+4`d!LX6LeXO znL%&*dkf@v%6|4)8WsL7(r5k+;wp4*ona zTG}@|&!vSpztJ`jT`u5Fs9rmfPkGv;q9&%mflMabxE)X}eAbCkUMn>%F_tV` z+R&P$Z3ePK+GbXONY@q2>$uACI8yWVD(y3B@5wDgV=41N3#YKy2&o)7*>RS0MJbp(`AnV>oW!nIl8O-0vI{EaX94wSyzW6n)G0&} zAbUCmAle^Y+5;e8!NB}X4G@<=&er5Bz%2VW%$`w?Mr|u#C%)zC=*5h@ZIU2ok8^n? z?34<9L6oUwDwVIAZ8rey&svk(+RYZg3Miy1e7rR(ubhCoB|f0hcFVBPoNHd_9cZ{+ z_6|@xRx0esU%_HJI!afJ>8>tk1gY{rk_Oubmb5(vkNFJHj)m}gajx8Ncxdel=OlN} z+IexV2^kp_CD8en?+NW(dB;alhRqH-%%!aCbmOIwdU6>03HCxDl zY6rPRqYKAj%C4M3Mok%iNs~04XmkF!NRt^JwdxZjQ4mX>oa*Kqd|r?nl>{;#DKLF6ffbl}=^zKxQkr6kd9(9OP~#WJU@ zc)X{^N8no($bIVb_n+hPW?LlY7?OBE%S)BR>^sf60(^xwDlq{YBUx^Rf5lcN(&23+ zp}z8?lhb>F6A^ebH{7rt;3|nFN_h_pMLVY|$mHf_&BVrUR%2u3^tJDUh2>r(0B@g+ zUVeO_og1&)V~aEc-_|f*IlN!%u&t2y)z>3?wxmKx-JA9LYM{O9o*|Xnk{G~K^rQ;C$t(7ji-MPTTtIl5HGHXhs+hAj6j?6S9F0U$7_SgCTb4JyDNbix-z_>Se-ZtH$`SyK~^#J$2t>9~m0IXox2<8;c zSc_{-d&0ElTgS7XW^x$~m{9kyY-8-Te*3^Mrh25wZrn#lHJmnO83~u;;`$ru8?m0d zL(oFqmvy)>S=^h}R{)0Uq@jjU&NudD54Z{kcF)pM>i{$)x1U@ci+t5ho2-O6F`Kv| zO#dr`Xzo*Ps$q!snV~^~WsE$9dr#+mhAMl)de;Gu#!ePuvoAgJ!WKb6a$3L^t-7Sk z24JK9nl_aEgJopUF(9vjhkfU)0b3U4)IrT*DcnR)nzE)2JG|Gw$Gu3*SSv5#4*R7YNIW>TTOXL(-r%`pw z&|B{hcw$valHF-f_!ZWuM#HpV#!Tk`G(nF6bC{dpv2P2`ji-jlE$6 zELyzgQURl;AIznJP!<1P>kffP_P~pjBbqNXY^V`5O_2=Xf=8r>grEMcU%{8Y`NR0X z|K30C+C+9P1=FKng_F0nuE^>X5W`m6cRj+kU(^fTiR@}v7l`co+fVHk8S~BRTf;h_ z>p)Mt%+l_+0KV5xM`x)lSFiq`K|}W0VZXthfm}2{)hoDyYDnD%6q|i63pnw)VP%p{ zoBXmJNy#-o5pW`7vMmfeW2qe@Q&y_ZSea2!J#W_l&J6ej7W~A74r>MqA4xPbr$#fS z;@u~GavE`YDTmL2nlYVdu{G^hoF&R!8-S3OC#tilsRd6Vwa-wrFIa>h9xtYDc3VNq ze72f(6|CwUhmLbH0$MG{A88t$8O~#shk&$ykr+%xaIK@n{@5F;c(Cz?4HsN+!NwPS z{m=gde(7)i%h=Kh|LcGIe}K0trnO@`(t{s(w1YprSds3a)?YOBqq>?{Fi~Re(&o@ zpPq06;e><}Qn}HHG|hIp;BwlqoiCtQgpdBrSMg)t{we&>kADOI_#gZc{_ubM$Jj3G z%;tlKFXQVU{sdm7hq5#ov=xDKV}SFVq_Wr~f+=qo{PE)-;h*t8S(;ZJH)sUw-TX9s zou-Bt5PnjkHO<#&iTH8*L;T)E@nGhTGly!y&c!;y3+6J`>%Y;M9r*{c%Ux`bM-d>4F!+sRL=PAAY8Ug5)E{x-h$ z+rNP?|Kv~Miw|GKtJjQ&N5c6H;e0vad?7q+39lX#9=3#sOTxp2aK0owTuwM|gmd|R zdL(@BPd))&GtQjwicfgpGaj~c$$P?SOW3~fh{q2vxP0^mmyaIt$>~%4zd!gG|L}kL zCwTn$6KosrEXt|_|M*vb2EXyse+ziLAYA}@%*UYI=MC9ATYfj6)0yyhU;iEaoy&jK z`3v;qtsuY=)2Dp_v(CMM@E%@aRpWA9R zYUx*XZW@3fT1j4jq%h81a7DdBZzcrs$O^F!!ehp0wcJ+2EsT9n1 zqDDeb7;UQ+*qj+WX3);TDiFl9%pdL-cY+rg@)=XraK7936{K{YW8xVg8-pVUv zRLR9!U+?MvLY|f!LWS<7`F4$nMJBb( zGLX-{0}@oDWsf7R*WRi(Y2|(!!#wjzc=o_6H1Mcxiyt<6)6OSdk-#qSvJn8te%D`J zQH}{0kgZxr*aZD=Hq-$dQ%&vXu~;g z3zpSN>`l@x`ju@%%H~@8Jm(jHZn{^}2$m#HPWzTw99dX4eRl+4!{g6=3-oXNOE~@J zFM%$EH;=$~J_Sy1UgOLsoEbPX;X#DNM8Jta8x_@?KqutSCju@2o$@nEls}*HZ|Rh> z30R&>IVCz6C8~Fma&VGg{ONxU=kpiAk44New~BBore-2A6<-bgEdCEA ziW?>TJpB^>`|ZE0?>B(hXS{xM!5dE5bW8+LK|%pt zLjGGoQh!hKd&-{+2bV%r z)L5XO2~Z%e|3n);rw63%gl&4rY0gFJn%bx1n(*fvd{?Q8DV$@i9aVdW)U0Xqo~xCs zf^VH<5=t`Q8HeBL40LU4t~aqrS%X;6i&BqkPF`U(f>rFKv{qOiG?tI{QDY8K1{?LG zyddvo+P6nNYz;trt*IU-GD@{;Ti7O3zVEsO43xkLSM0ra!U3w{fI2O^=)}~tF(|q} z^3pGh-uyidQM#|ORDS^my7Sddp-vNyNZK#qC~bR=2Zku=MaU6TSowW>b;h6khkp&9 z{OiAf^Z6A{j|u$9c%YQutAeckY`-T1zV>$%@HEe;fNM!d=PWEyqWZ6B!x~k#nih6C zirLfTJ`z0TOZl;mE~})z_PUG3qLI@rzZ_Q zBPB3;3(o$93!@tQHm>D8PE9Q6S;hWY9PFSW9zXJhiYc=&LpYf!VXio;@Oj|nh zMhD#GDnO$~QljPx!|ctP(~I*}mAIx}we~k82UzZAorA6pFkeoCe(B<^Af^Ez}M3fEfyTnf=>jx6oeDN zmJUvCp8@h#%kan%kRyz3Wjs>>N4Y{Una@Rfl6S60@Qg`X3#B>k-;0Py1+n$LzRx2N zj{*R-mMqk})hP!nx`vm{iOv6IjrtJ3IRRV4VorOtHclpg><@KsI{OO^jJm(O@opuM z_V;zl02}173_N(Qzp?xg6>DJcCnyNWcj5vTvU$%IkjrK4

    R+hSN@=7><>i(d~5% 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

    hvR1Xi~z!wp#R>p}KP^rG*`x6S17rXVhgH zES1!C!IUd0M{9%kVyZ9?d0;B{rQsrlq7P&hAv2b2f53)3T%pX)z-K^Gw*P8N-Eiu@zOQGlv=l zmm+o{!R7PR$z?69v=!1?&KT_~%NeW{=05fMx6|DCd&8p$UPVj6K7THX=7H35oXspL|Ym~R>lo_UlTmnuT)GvSa zKbGdzPcVAo>1mJCn&abp*0*1vRO0mM1I1cOjF<>fB}|HVw?c2$q|*VeZfMMw-Qz#e z_YFCCzXUGkyC{OotQA=9<&H zH#FOq^tU%0K7C|3e55fg(O8`I=nQsy1!W=b50c(mPr` zoHS|NNeWb)(A^rlzTxVs18-P;_AeOrpU81Q&5_f)|H|s~ugO`{HZ96``1{XTzxs^F zKYYXV{ts+!uXyo`Ur~VL$0s%~uF<_`SOy;dzu#h}0o^L%apd&jJ(NIy^8$0V!TFBE zxBtY`$9KH`>Sw67e?`nf=o7z7mw?dBOwkL)sjoDYiosTBm(hl ztymDkmzen*=H(zHtKzWMNPvQ(7M(;&Rl-su=)_G86}dO zvyETpJC<3pykn_`8YL6+c`Yh3CF*3ODjDbO<1E&as$Q#_y_^@}jns9yb8YnlmkBgw znLt%tcAqDEt0cDZ;$Ec{s+@xr)WsNI)fmBCA{vb@nzn73r%|wCB@=6|?Ao(8a<0ir z>Qb1+eJbQw+1FK8bjIe-=|DM?RK94NWmwneiZ3fqQ^N=9XW$CVpPK&WWt6JCyaI|8LE>Et#E>y0mXt7E$LeOw>FGcmCbWuBBHGEetthZf!*Uu? z)?M&uXRJKCSscEKflv~S>F}$bRAAk%czS$K4hb5MQ!vdF?P^Q2?ie2)vA!dug*?x6 zH`kPyNhPqozvA>%O{3y~wGAZ}NEv<86CRJ^)U|F=LmBw%sLyZX<2h&I((X=aKOf1WZ``bGbnNSqwIN~?gOoxN4(*OJy|DiP7HA)+v z-u#ifFJ5pwjoiHcg5%+YjRDhiC5~CW9Pu~%b zk0cG+^=$6%MgN-(T4lz=1O4_DC1s8e-=H>ET)+4!%tsataZ0dEExtAERqJ!*Ww_qW*V7lfxrrg%UV#o^oELmIJ7hhJUOT-~#Kc!!<` zauGU77N&d#34tZda7minX$AzWf=(`#+*Q`0Xol9NB$%iz|v8HOf2M z*3quE1g&US9m8oP9}kcgOxMzGHiVQ2$D>F?Y%3-XCKBgGG?r;5D#z{1mpuOQ4;&8% zvQcQ=;#<$~=^bW?DCZeZJF<#|d7{KX2otCVV~u>6l*hNd$ZND>9`|CXfycWRRK~gu zU3VwslAO@05N0usKxLe2$T<+>D67>t3xm;mS(%-ug>yWe7Q9QBN()ND_SDK_JQo~P zEAhfjG0P!CCWNW33N7<;qHTJ{8b6p*k^^2FI=^CBCQ$hzbtyF*okDdpI-6@i<6Gug zrqzOkzgy$va92V^388xC7KwyA8)B54@y6FFGYO8D3)Z%TFbfGwX>r$58Lfq_tr2`O z6NQnR)ujMmVg@UgD^jRbSIN1C*4vBD^NjMI3!q4YYJP5=u+Exg;V8-UeYOug=iO53 zs#;roF=P!>Txg6~AgcQN#fDI(qFm(udF{|OsY$_e2ty5&picN_X^}W-iM6QWIVbqM z#xA8)2~y<*07jh?h$^{C*W{#&Zn*xAlB=AkV#>s7EMdvHAbN29gK4wWO@>U>-nC3Y z2x*WZRclXeY9pqx)?EQ(^e?aZxEqO&BmRq*G}`g;(?`6~tp5DR zOb-L@Ff*7$)2+#e2aIiq*5PtMHx4!%$`pxVMsIq;rw6(WW!0f|!?^oMS|ZLgq?;CB zJoF9ox8G5Q5oN)&YpgQ_XHfs*Km2dSsKoe(?-=5MDVf!)&rxXRX~5&~jpyOv9T-p7 zugS|o$>P#-dV1vLzxr<|L6e?7k;cg3@EzOhA7QU+j(220j6s7QeM~aDY_YrF|WscbGD>nDnJpSQZ{KnJtFDb?_PZPN; zxOwC>pJ=rs`Ie^ZIez@W=Kd9FiL}a-T1&Bp>2Q>s;?thx>507V*}nQQ*oHXlS)Lw* zGJgG%o6mm2`@jExD0#;C8$vwMH5=^9ALESS;rD+7Ig*!w{_|goBh<7fBFVYPE`rjv^oOjyVL{ro$-1G(MtAi?g12+>?XkJNv6G{oRdtO&h~p z5^dL$Pe+tdgj`6=A_w5WG9+65Nw_j6f#aZlc^N?l7J(x+p6=* z_{`YN7m3jMt6#MY(}+?|EJd>>sUqn+C@DgGD zeGW)SmuNm!30g+$Dgmn%w0cILvFAGcQu_n6I;SW>PPLH$R85jHS_plnLI$R$@SIIO zIM2sQiEPK(DispuuF)PS!c!mvRvI(qF3fFJgGr1spe3xHB-6QU|0^dTFZDf%y``$r zjF)?8>d(vxZ5?OHS1yGdGhNqK(w?L@g=J>7>KQ_YWx^OmRt8PMH68OZp^U<5U$OGY zFr2u)y(bh!8c(u#P#WL-|6ILUk7e0*o%gM7cc+goBQmqHGOOpkyd*`5h9p3uVZbm9 z!>Lp9!K3$ZC$j)7CvA z45&y<}*%#QL7; z>SJ2hGaPR5wnwXyAToyI&nzxqQMU*D@yPUS#V}aP`Ha49@pXrumBh?I(5S%@M8I5J z6Siv-gA?rWh;v&+6clGq2+`ATwp{-DU(vTUalfZ)*OZqZG5P2@(mC9Ei`SayE&jN{ z4lUl~6xYvafB2qENz~$!Zv8FNoKsz15v}9lr*D{-bJTo>bt%|Bv}=l+&)C2DhGF|Y zb+<)@)fvWnva^eH>TM77wr6qilNJ_>*==lNFv$%5|JyK%^m%I%}}>Y z7iSE?LEjJ}%rDLn^9$VD?}^zA+>sa+%0Sy532lwYb5<|E!bE}F*MvM-f%bPl(RVc> z7R;aA(Cr==nl*WOhN*J)4{tHq3_Cb<2A%8CK9ZX`I+N@U?@>Mw@`6Z2%N(6g(Mpq7 z6#Z`toQTrAJo?{{dE-c*mfEmu#j zdAMIQnUqB789ImebrN0m14KXKAfatLv`QnpqFT_mM`8#mm|SK+Le&|q#z;c>*d0QA zEYvZiC_bH;WW%v`+|{Pyme#NmDGk>4L_9|3kA=v4ix4RXHFZxPY%{4{OWll;3g_J; zVM&s@z_f3abX}sFJ^EK;#No(f&W8|(5nCC3ifkK4(E&!5bHe@^1=bE}H2?VKo_=19 zT^mA<9dAe;SyK0Q;wq=kH>rJN45*j_?@tBU14gOj4|ORgo0Df8oyL2R#(^UFM#IRq zK20#vw80~Ue)Pp^B2pWiAFWW2Sjcop8R!0q&7Bqnk1BdM2F#zXF^Z#iO0*YCzwg~y;mk3a62TwLNi$FXgYL7~qV*!3QHR*}8BA=Z{~cc55Qv~9o?8Deop z|K<&D`xd2hrk_5i*NWlY8o%Eox{j#QibMp9P$dC}J9d;$uCVnET^1>Qt+t35(dCpO z6BM6ZBR=}*UqovZm2ecRC*1$|16oF=Hy@)+i41VuzNeVZFx8ynyLXu7In%QXP>Qhr zna%xsLWJ{=ze?ni5IJn#Q_Po12|E5ySg-HVnLtL9yk>ccJ?`A z$ydC(A)6M6CI!9wF4DGJphuMzf|4xPgkT8WhT{BFz%v{lzz#$Kle6borO-+sOaMJ#dOK>-S5a}7f7cFIuN}=3yYr4IXt{W=$z%{GurJP2t{Atkr#8U7x>Vj z`hYx}W2D5l9YV%LSQ;GV#dD;B{o5aCyCZ~1S(R8(pn_xQ8!}UY@mRYDsX06Q7+Ebi zyZ9LEJ*#Jz9A3X+^Ki#(HRE_VP);hg?|xv|>~P+pjii`dF}b{A`{pf|H_ve16Qp2h zk7#Ky<%D*-=Im_A!)`-aRtZt6G-b7-Z)&n?N?GJwUfqB+>~{~upy|Cs$w)b!;dU*@ z{Vng_eveU_GM|A?;S8(!6MlaE_Y`JAmSqfXVCZY4o>S%}{jeo7CD8{C`*qqU4g=L> zLRY7;na*bHcemtOB5V0Dq&N2vP*Oll;*J>72sw?EGeYPS%UMA0QUNteV_lba+A)pX zjG57PTTWO)EtBuk+5x3gXW~OD?AmB-9}+V?q|voZi)Nx2sZlYcNH|U&(|~mYLTOG~ zVgMU#+9Up=psSH81%fyR7Qm^SR8*50ZCxWoAPu6^M+_-!Aw}vzJdJcowv#lf)k(=3 zri0hNN(Z zh?aUBZ!_AYlCI-Kff{V;5EHu7jR%V{9ZIC|_|w?@qy|1s6i$LZ2)GcEZHh>q2@smW z`mr}oP>c{i?2qM`h%~q%k)C8?A_xLLrqOf?go@+y4&%Wf?b*AbL&;Oxl)#uABNX0R ztP0?gI$n;4r?Q+d3>FvNFRnj{$*k?DvMHx^x3yhL5f*~kWKP?4Bur|23{vnyp$MaZ zT#%WJ;K4^b+KNEx#EDiSj6wDip;hYKRSL16Oeb{xfD-~`JyAu3QcPE8v~|ivFIFqG zDd_Ehkpk;Gw1+`Qj0LXF5{)V^Q-P0xs3g8_@Ol*F*%nMjtSY9Td_w3fqCXNRIlSHA zVxVv9^gCr4)nbV?IqZ+P^#k(QqLwqNr%$QZcU(^@-tYEUKTtfs!5>=s-5&9$|NZ|S zP2(sp&w2Cu55(a>v)&@HOqMsyR@ZDccXZu`YI?zJwWOHOY46{23N1tEg zfBuPKvqvr}`Y>RI7G`G*$9t9^{|QZVME5oA?YDFTRI`#8JXv-@(CLIoR2W@xJlqrN z_vDisgg+A87)WLt_S-e{vvbOu&lxtisNOUmmnh_c0R)+rf7Yo_xjbj=C-ybH%$cc3*B{W61u{mATJZk;f1%`p z$$80se_*)%5uHsaSI;p;PP4hCYt{^YpbrC8HsSdv{|qso(%nS6D0f^o!qcx7kru72dX3d!VgrjPShv z=|`@vK4M?jNR=4Nd6BW*zGLWHqD__-Q|9j|$x6xH#Ew(xJePDMpa8aAk5(o%cCIJ5hI=fU zY07fS2j=ndK%kYuMTfVRQ#zFzg;#!z+tWJjoWnS|sq&J+oep6x5zxdbrZaooNmtbb z=L60U3`3U^nWVz`hB%7joQ-ImB|XA8))z|BbzMp*8t-xRjwm&mPNXWW41L?s4e1c> zeLzXb%4rI&DGbxAOZE>Ns;d=oy&;$abFjFnNvpDD z#G%7>8+?0Yl9hDAGu&;+W=ocT_Bs1~kL*0vU;c*e|MBmWp!cg!(QmhKF`?NXQ1t;} zJwZ#%^DE5JvA?}XeEP{>#(c5F2QV@as)Ffs&hhon9P2xDF{8*Q4Avus=g{maiYe9Q zHSzu(Z3vv*e8gZq{eFi~E&GRivLRBOJ;TfwWXns~9ocVQvsg}O+W|Gb0;y=%uPJAj z1PP&Tnax)?;fXr1U$2?YmJ~OabejXs?N8_ssBWHP4>kLDUsGLvgyuYjli1`#14ejujoRXdlr4_ScLNUL@oL^C`F4(^N5v>$Y z{^h@6{h$6LO}oSI4!r!|{vE@iX7|_s7uz>K;R49Aq-*xvy!w*z{3+djgX;s!%N56F zL)>>9n*+1Socr51_;$njt1qGHsr#C$T4A>vnpm@#T+wwkU3b8kjB+}s>l>7dh^%6A zc7-er{q1{t8)=*O6j@Hwc4W!`p1R+m#>AeX8z{>u!COQ=#}CI8GGPZyrl`9OMrJIR z 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%0DDwQ>F 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

    {gXbS4wU)a*uKozVPqe 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Šz{XZ!%1-*cctK=?EhZ%JzS=sBjau;O;?vr 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 literal 25847 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 JWP=2HQsMhZUstq5k3y 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 Ukk7bx4lJO!udb_Bs$v=RZxzPCT>t<8 diff --git a/src/qt/res/images/splash_testnet.png b/src/qt/res/images/splash_testnet.png index eff1692de3e3f62d8beca8dd050951411bab0ef0..a9b5377c45e03a3cdce5d1de8648db3341ee63e9 100644 GIT binary patch literal 299496 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

    R+hSN@=7><>i(d~5% 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

    hvR1Xi~z!wp#R>p}KP^rG*`x6S17rXVhgH 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 z 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%0DDwQ>F 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

    {gXbS4wU)a*uKozVPqe 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Šz{XZ!%1-*cctK=?EhZ%JzS=sBjau;O;?vr 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 literal 10138 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 s5R-g*%ZfgetSplashImage(); QPainter pixPaint(&pixmap); - pixPaint.setPen(QColor(100, 100, 100)); + pixPaint.setPen(QColor(200, 200, 200)); // check font size and drawing with pixPaint.setFont(QFont(font, 28 * fontFactor)); From ea1c978969c5dc60a6321996b88b7fd9813a63ec Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 13:08:44 -0400 Subject: [PATCH 0417/1888] Update sidebar for Dark theme --- src/qt/res/css/Dark.css | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 9ff09c7c31..0cf888908d 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -107,8 +107,16 @@ QDialog .QTabWidget QTabBar::tab:selected, QDialog .QTabWidget QTabBar::tab:hove background: qlineargradient( x1: 0 y1: 0, x2: 1 y2: 1, - stop: 0 #5e0057, - stop: 1 #1f192a + stop: 0.1 #24474b, + stop: 0.2 #1d424d, + stop: 0.3 #1c3d4d, + stop: 0.4 #1f374c, + stop: 0.5 #263049, + stop: 0.6 #292c45, + stop: 0.7 #2b2840, + stop: 0.8 #2c243b, + stop: 0.9 #292237, + stop: 1 #262133 ); padding: 3px; } From be59aca317728f4219672d1a1c19000ff38caac0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 14:07:23 -0400 Subject: [PATCH 0418/1888] Update icons --- src/qt/res/icons/bitcoin.icns | Bin 81731 -> 373780 bytes src/qt/res/icons/bitcoin.ico | Bin 34032 -> 21090 bytes src/qt/res/icons/bitcoin.png | Bin 868 -> 29623 bytes src/qt/res/icons/bitcoin_testnet.ico | Bin 34062 -> 21090 bytes src/qt/res/icons/bitcoin_testnet.png | Bin 13012 -> 29623 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/res/icons/bitcoin.icns b/src/qt/res/icons/bitcoin.icns index 0c78a138fda792a857eceb4e1fe7230e989bada6..b6276dddfb445619649235fd16f8b7a9201600f6 100644 GIT binary patch literal 373780 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 WYU|BKyYVeOiy;j#CpF6XUi~kB-bEh( literal 81731 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 NWYzTcu*mD;{{T53&FugH diff --git a/src/qt/res/icons/bitcoin.ico b/src/qt/res/icons/bitcoin.ico index aefa66f7c90ab2f774719dc44f497173107e85bc..74152d23918dd1dcf904e8f6dffd96c135c273ad 100644 GIT binary patch literal 21090 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 literal 34032 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 diff --git a/src/qt/res/icons/bitcoin.png b/src/qt/res/icons/bitcoin.png index 80e82ad637df0fa85a899a238da9c3f11014af74..bbc22527267c3b0b47b45d9e92dde0ede1cda72a 100644 GIT binary patch literal 29623 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
    pg=_2 z=4^ezq^4T&7w?D%YUHFsFkoa#<@Rp}1JoWk1CXq@%+@m{FrQ3Hj0piomaieAxCB9y zd5{yDRuA}08xzZn^9-MiEe}Y;7T1i?X#a8kSKoz0cMVEy-bKfF0Y@Q;jaS||M`}cX zC=OJEd@zctC(|)-E9)U_co~=x!t|-vXr2$;Q)hlWxx_XxWa|J^*K?Q|?Hca?qv-k6 zsQxLf=L%l~;O*$_qKdY%_}jVd2X%ft7^Q;F_dJSj+xT%LvSl0ZF|sIF^exwp`YUs8 zrhNqGk6wlvk-KS#zC=5X)2^~~2Sm)udLatKYaTbxNINR|EH1q z64b0Ji*Gx%QkrK)yg1SmNQ4CCSEYy;MHn%0xY{XDi+Eh&1Mg!t6;l_{y@v?cC!^i0 z#HM|h;rE6Num<3w(uZR}h#$8s#L249Z?V?DxA@JS?i3 zw<)}yj=CBDOOfDPT(dq7$#n=ZGgq^Z8yuGkxMe8U_Ezz%DyOwYBC%eVSBJST`$|%bpI){?@5Th@*5LNAyK1$BbUjv@nCe`oUyMGb}kk zrZZ2a^!}^(|L&lENoQu3?VDYwk=DA7`n7YXL=_FU!>GtVu0lp2Gwo%luaUHERQHT> zE+0%(z!fx?=Df&%-p!VpPyK|v-!5?*d5N!L)40R>y1HjLeBm*IHe0~_F@Sj@G7E;pvHi@L z(D`LlJ{dDxj@r+3F*dTKfWs{jz}MCMDB<;k!;BUc-;=7(ZC~Ev%P~{sK+Ep9DIXlvCfh46 z(l}B0_qC9_#)}W>i7ajjM56`H2Rv(A*L>oXUq6?*+-6P;^O~;z?$dWXXw!EI`NI_R z!J*~o{ong<)~(s?;Lw!4hapa&;F!Hj+zQUDoCO!mn)M%C;PBY)k_Qon_TP@8=S{Gaz0?x}wPj&mB*U<1Z|Dg4u zRl70;6}Fmted}Mq-F;p|ETvQM)Ca+Xx=c@0imt3!{`i6_$I)j3SMHbXOnWg!mT@7s zyx3y*j+EtGhD;KU?FL3n7Yvz{85r2yEPN8)d~b6osCK)Nax16!w_EY-&-VnDE%y1V zv8jjYq2=aTxf`X7c<20T71y8Hly`i|rc~Fg1;Vk z>$_I4#Qwi9NqLK1_5wGJExb-b$~<<}8m3Kk*P~p$3a;JTUn0|Z&+69v`Nt>RZ#uZn zQl4|RnO4H4ovj}pZ#l^=n$0_Dk&-E=V^YZmmnfTqpIV}B`wAKA+;;Hl4UoM0=v|R0 z)5%M3pIqU%v_X#9?ykdwO@Cro4VwZB{_qzbZntIi+i^?QaIyP@Zu3a~^|=$@7ykV8 z+T`=|_4o5D)>tQb^=)Xq%x5PcWb?hh!KL_-+{)d>?B~4xPrG-{_SSE^Z7#=6|EE`` zFq{)kV{UQX%Tk)D@y$&_(dF=kfd0@sPkE%3Zv>U!?6TkrTI?w5`tr}4$wp_TS23_m z?O5wj)yuzkzN>vS$1jyE7s){58E>PsHfdbEv_5x7udrm%l=UuUcOxEm@;$9-+P#x$ irB$m@^~oJs|9SJL2eL;gOT_?l4}+(xpUXO@geCy&MsD%| diff --git a/src/qt/res/icons/bitcoin_testnet.ico b/src/qt/res/icons/bitcoin_testnet.ico index 47903634224734c79021cff8c799a33fc52dfe37..74152d23918dd1dcf904e8f6dffd96c135c273ad 100644 GIT binary patch literal 21090 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 literal 34062 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
      JI}bEsE)Z`q{Uky|sH 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
      pg=_2 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 Date: Thu, 24 Sep 2020 14:54:33 -0400 Subject: [PATCH 0419/1888] Restore time check --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3f4688df4f..8afd92789c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2927,9 +2927,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!CheckPoABlockRewardAmount(block, pindex)) { return state.DoS(100, error("ConnectBlock(): This PoA block reward does not match the value it should.")); } - //if (block.GetBlockTime() >= GetAdjustedTime()) { - //return state.DoS(100, error("ConnectBlock(): A PoA block should not be in the future.")); - //} + if (block.GetBlockTime() >= GetAdjustedTime() + 2 * 60 * 60) { + return state.DoS(100, error("ConnectBlock(): A PoA block should not be in the future.")); + } } // verify that the view's current state corresponds to the previous block From 648cebf92f174f8a1947f08ddb907f1ae7304636 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 15:08:06 -0400 Subject: [PATCH 0420/1888] Add EnsureWalletIsUnlocked(); to generatepoa/getpoablocktemplate We need this here as CreateNewPoABlockWithKey requires unlocked wallet to GenerateAddress --- src/rpc/mining.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index f8e576cdf2..067292728d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -222,6 +222,8 @@ UniValue generatepoa(const UniValue& params, bool fHelp) if (pwalletMain == NULL) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + // We need this here as CreateNewPoABlockWithKey requires unlocked wallet to GenerateAddress + EnsureWalletIsUnlocked(); int period = 60;//default value if (params.size() > 1) { @@ -703,6 +705,10 @@ UniValue getpoablocktemplate(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getpoablocktemplate", "") + HelpExampleRpc("getpoablocktemplate", "")); + + // We need this here as CreateNewPoABlockWithKey requires unlocked wallet to GenerateAddress + EnsureWalletIsUnlocked(); + LOCK(cs_main); { From 099b95bc49a0e39227f98911fb2d3c5021f6b735 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 15:43:10 -0400 Subject: [PATCH 0421/1888] Bump version to v1.0.8.0 --- configure.ac | 4 ++-- version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 72971a5040..40566740c9 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 7) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_REVISION, 8) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index 97244d8e52..91bccd652f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.7.1 \ No newline at end of file +1.0.8.0 \ No newline at end of file From 8a10b05623b73a072bb5397ab921a90ec9b6f281 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Jul 2020 16:44:16 -0400 Subject: [PATCH 0422/1888] If wallet is locked, return false on generateKeyImage --- src/wallet/wallet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 02abf59954..ddd735d1ec 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6753,6 +6753,9 @@ bool CWallet::findCorrespondingPrivateKey(const CTxOut& txout, CKey& key) const bool CWallet::generateKeyImage(const CScript& scriptPubKey, CKeyImage& img) const { + if (IsLocked()) { + return false; + } std::set keyIDs; GetKeys(keyIDs); CKey key; From 45dc3bb1a97c452594f1afc4728f73f94d085b59 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 16:49:03 -0400 Subject: [PATCH 0423/1888] Update colors --- src/qt/res/css/Dark.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 0cf888908d..61935bc473 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -30,7 +30,7 @@ QDialog { background: qlineargradient( x1: 0 y1: 0, x2: 1 y2: 1, - stop: 0 #5e0057, + stop: 0 #1e1824, stop: 1 #1f192a ); } @@ -271,7 +271,7 @@ QComboBox::indicator { QPushButton { height: 25px; border-radius: 10px; - background-color: #470143; + background-color: #1e1824; font-size: 20px; font-weight: 400; padding: 5px 5px; From 93d0c4072073a52ec86c340f35e4830fdd380ef9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 17 Jul 2020 13:26:30 -0400 Subject: [PATCH 0424/1888] gui: fix ban from qt console Rather than doing a circle and re-resolving the node's IP, just use the one from nodestats directly. This requires syncing the addr field from CNode. (slightly modified version of https://github.com/bitcoin/bitcoin/pull/8885/commits/cb78c60534e5be205f9190cb0cde700f9e9fa38d as we do not have conman) --- src/net.cpp | 1 + src/net.h | 1 + src/qt/rpcconsole.cpp | 18 +++++++++++------- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 922c68175b..3b6d1725db 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -635,6 +635,7 @@ void CNode::AddWhitelistedRange(const CSubNet &subnet) { void CNode::copyStats(CNodeStats &stats) { stats.nodeid = this->GetId(); X(nServices); + X(addr); X(nLastSend); X(nLastRecv); X(nTimeConnected); diff --git a/src/net.h b/src/net.h index 983781c421..c58584ecf3 100644 --- a/src/net.h +++ b/src/net.h @@ -179,6 +179,7 @@ class CNodeStats double dPingTime; double dPingWait; std::string addrLocal; + CAddress addr; }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 06b0d1760b..691b104cc0 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1003,15 +1003,19 @@ void RPCConsole::banSelectedNode(int bantime) { if (!clientModel) return; + + if(cachedNodeid == -1) + return; + // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); + int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeid); + if(detailNodeRow < 0) + return; + // Find possible nodes, ban it and clear the selected node - if (FindNode(strNode.toStdString())) { - std::string nStr = strNode.toStdString(); - std::string addr; - int port = 0; - SplitHostPort(nStr, port, addr); - CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime); + const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); + if(stats) { + CNode::Ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime); clearSelectedNode(); clientModel->getBanTableModel()->refresh(); } From 4eebc33dc7bc6fc17006507b5d20baf681678b86 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 20:47:02 -0400 Subject: [PATCH 0425/1888] Update nsis images --- share/pixmaps/bitcoin-bc.ico | Bin 34032 -> 21090 bytes share/pixmaps/bitcoin.ico | Bin 34032 -> 21090 bytes share/pixmaps/bitcoin128.png | Bin 6007 -> 11950 bytes share/pixmaps/bitcoin128.xpm | 499 +++++++++++++--------- share/pixmaps/bitcoin16.png | Bin 1033 -> 848 bytes share/pixmaps/bitcoin16.xpm | 224 +++++++--- share/pixmaps/bitcoin256.png | Bin 14940 -> 29623 bytes share/pixmaps/bitcoin256.xpm | 793 ++++++++++++++++++++--------------- share/pixmaps/bitcoin32.png | Bin 1497 -> 1872 bytes share/pixmaps/bitcoin32.xpm | 351 ++++++---------- share/pixmaps/bitcoin64.png | Bin 2807 -> 4320 bytes share/pixmaps/bitcoin64.xpm | 321 ++++++++------ 12 files changed, 1273 insertions(+), 915 deletions(-) diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico index aefa66f7c90ab2f774719dc44f497173107e85bc..74152d23918dd1dcf904e8f6dffd96c135c273ad 100644 GIT binary patch literal 21090 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 literal 34032 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 diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico index aefa66f7c90ab2f774719dc44f497173107e85bc..74152d23918dd1dcf904e8f6dffd96c135c273ad 100644 GIT binary patch literal 21090 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 literal 34032 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 diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png index 2850ff96f42af60dee16162e5f9d881683a9de4b..3f7072e912afb88084d3088b8c6614b1f865f3aa 100644 GIT binary patch literal 11950 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 KRIgLDkNzJMcRxx1 diff --git a/share/pixmaps/bitcoin128.xpm b/share/pixmaps/bitcoin128.xpm index dba114838b..f67da62e17 100644 --- a/share/pixmaps/bitcoin128.xpm +++ b/share/pixmaps/bitcoin128.xpm @@ -1,203 +1,304 @@ /* XPM */ -static char *_9ff7ff8992c4aabd34f81e1c0734771[] = { +static char *result[] = { /* columns rows colors chars-per-pixel */ -"128 128 69 1 ", -" c #50074B", -". c #540C4F", -"X c #560F50", -"o c #571051", -"O c #5A1555", -"+ c #5C1857", -"@ c #5F1C5A", -"# c #601E5B", -"$ c #63215E", -"% c #662661", -"& c #672863", -"* c #6A2B65", -"= c #6C2F68", -"- c #6E326A", -"; c #71366D", -": c #74396F", -"> c #763C71", -", c #783F73", -"< c #7A4276", -"1 c #7D4679", -"2 c #7F497B", -"3 c #824D7E", -"4 c #834F80", -"5 c #865382", -"6 c #885785", -"7 c #8A5986", -"8 c #8D5D8A", -"9 c #91638E", -"0 c #946790", -"q c #966A93", -"w c #996E96", -"e c #9A7097", -"r c #9D749A", -"t c #A17A9E", -"y c #A47EA1", -"u c #A682A4", -"i c #A984A6", -"p c #AA87A8", -"a c #AE8BAB", -"s c #B08FAE", -"d c #B190AE", -"f c #B494B2", -"g c #B799B5", -"h c #B99BB7", -"j c #BB9EB9", -"k c #BEA2BB", -"l c #C0A6BE", -"z c #C1A8BF", -"x c #C4ABC2", -"c c #C7B0C5", -"v c #C8B1C7", -"b c #CCB6CA", -"n c #CDB8CC", -"m c #D6C4D4", -"M c #D8C7D6", -"N c #DBCCDA", -"B c #DFD1DE", -"V c #E2D6E1", -"C c #E5DAE4", -"Z c #E8DEE7", -"A c #E8DFE8", -"S c #EDE5EC", -"D c #EFE9EF", -"F c #F4EEF3", -"G c #F6F2F6", -"H c #F8F5F7", -"J c #F8F5F8", -"K c #FFFFFF", -"L c None", +"128 128 170 2 ", +" c #3F2567", +". c #3F2668", +"X c #3C2B69", +"o c #2F3F6D", +"O c #36356B", +"+ c #38316A", +"@ c #323B6C", +"# c #3E396F", +"$ c #3D3B70", +"% c #441D66", +"& c #451E68", +"* c #491C6A", +"= c #412267", +"- c #412468", +"; c #432D6C", +": c #41356E", +"> c #433E73", +", c #4C3B74", +"< c #4E3572", +"1 c #573F7A", +"2 c #1F5772", +"3 c #1D5B74", +"4 c #2C436E", +"5 c #254C6E", +"6 c #29486F", +"7 c #32416F", +"8 c #22516F", +"9 c #2D4770", +"0 c #264D71", +"q c #284A70", +"w c #354472", +"e c #394272", +"r c #344C74", +"t c #3C4B76", +"y c #225472", +"u c #2B5174", +"i c #205973", +"p c #2E5D7A", +"a c #395078", +"s c #345D7B", +"d c #395E7E", +"f c #1A6175", +"g c #32667F", +"h c #32687F", +"j c #444276", +"k c #4C4378", +"l c #4D4B7C", +"z c #56437B", +"x c #524D7E", +"c c #43517B", +"v c #4B537E", +"b c #52507F", +"n c #3A6681", +"m c #356E82", +"M c #3F6984", +"N c #3F7489", +"B c #377185", +"V c #5B4C80", +"C c #485780", +"Z c #4F5882", +"A c #465F82", +"S c #545582", +"D c #5A5483", +"F c #525A84", +"G c #5A5F88", +"H c #685488", +"J c #625B89", +"K c #6D5C8D", +"L c #456384", +"P c #4E6787", +"I c #446B86", +"U c #556489", +"Y c #5E678D", +"T c #427188", +"R c #4D738D", +"E c #5E6D90", +"W c #527B92", +"Q c #5D7994", +"! c #66668E", +"~ c #6D6B93", +"^ c #646E92", +"/ c #706190", +"( c #736C95", +") c #786694", +"_ c #677C98", +"` c #727097", +"' c #7A759B", +"] c #767E9E", +"[ c #7F7B9F", +"{ c #7F7CA0", +"} c #82769F", +"| c #807A9F", +" . c #837CA1", +".. c #8A7CA3", +"X. c #5A899A", +"o. c #64849B", +"O. c #74809F", +"+. c #6C8EA1", +"@. c #7C85A3", +"#. c #7789A3", +"$. c #7B8BA5", +"%. c #6C91A3", +"&. c #799DAC", +"*. c #7399A8", +"=. c #8483A4", +"-. c #828EA9", +";. c #8C8BAA", +":. c #9285A9", +">. c #948CAD", +",. c #988AAE", +"<. c #8291AA", +"1. c #809DAE", +"2. c #8A95AE", +"3. c #9B8EB0", +"4. c #8F97B0", +"5. c #9694B1", +"6. c #9B95B3", +"7. c #9B9AB5", +"8. c #9F9DB8", +"9. c #A297B6", +"0. c #A199B7", +"q. c #A89FBB", +"w. c #A79BB9", +"e. c #8BA7B6", +"r. c #92A3B6", +"t. c #9FA7BC", +"y. c #9EAABD", +"u. c #9BB1BF", +"i. c #A3A1BB", +"p. c #A9A2BD", +"a. c #A1AEBF", +"s. c #9EB1C0", +"d. c #A0AFC0", +"f. c #ACABC2", +"g. c #B0A5C0", +"h. c #A0B0C0", +"j. c #ACB4C5", +"k. c #AEBAC9", +"l. c #B5B2C7", +"z. c #B9B9CC", +"x. c #B9B7CB", +"c. c #B4C2CE", +"v. c #BCC3D1", +"b. c #BBC9D3", +"n. c #C2C2D2", +"m. c #CBC6D7", +"M. c #C9C8D7", +"N. c #CCCCD9", +"B. c #C5CCD8", +"V. c #D2CFDD", +"C. c #C2D3DA", +"Z. c #CDD1DC", +"A. c #D3D3DF", +"S. c #D6D6E1", +"D. c #D9D5E2", +"F. c #D5D9E2", +"G. c #DDDBE5", +"H. c #DFDFE8", +"J. c #E2DFE9", +"K. c #D7E2E6", +"L. c #E3E5EB", +"P. c #EAE9EF", +"I. c #E4EAEE", +"U. c #E7ECF0", +"Y. c #EBECF1", +"T. c #EFF2F4", +"R. c #F3F3F6", +"E. c #F5F6F8", +"W. c #FFFFFF", +"Q. c None", /* pixels */ -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL52>>*$;-%*;;13LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL2<&#++O+++@+@@+O+O++@&;5LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL2*@++@@@@@@@@@#@@@@@@@@@@+O+&2LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL5&+O+@@@@@@@@@@@@@@@@@@@@@@@@@@@OO%2LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL<@O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O@;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL;OO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@OO>LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL<+O@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#OO>LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL9@O@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@#@@@@@@@@@@#O+5LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL;o@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@O*LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLw@O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@++8LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1O+@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@O>LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL;O@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@#@@@@@@@@@@@@@@@@O*LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL$O@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@#@@@@@@@@@@#O@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL%+@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+$LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL++@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@+OLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLL$+@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@+@LLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLL$O@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@#@@@@@@@@@@@@+@LLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLL;O@@@@@@@@@@@@@@#@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O&LLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLL5o@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++O+++O+@@#@@@@@@@@@@#@@@@@@@@@@@@@@OLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+-GKKKKKKG-+@@@@@@@@@@@@@@@#@@@@@@@@@@+##@@oLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLL1O@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@O-GKKKKKKG-+@@@@@@@@@@@@@@@@@@@@@@@#@@#@@@@O-LLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLO@@@@@#@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@+-GKKKKKKG-O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@OpLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLL<<<<#@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@O8LLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLL,O@@@@@@@@@@@@@@@@@@+o+LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL$%%%@2KKKKKK1O@@OOOOOO+@@@@@#@@@@@@@@@$LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL*+@@@@@@@@@@@@OnKKKKKKKKZ3.OO@@@@@@@#+##@@@@#+O-GKKKKKKG=o@+@o1KKKKKK1o#OgmmmmmtO@@@@@@@@@@@@@@*LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL%@@@@@@@@@@@@O;JKKKKKKKD;X@@@@@@@@#@##++@@#@+++=GKKKKKKG-+@@@O1KKKKKK1O+ONKKKKKjX@@@@@@@@@@@@@@%LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL$@@@@@@@#@@@@oeKKKKKKKKwX@@@@@@@@@@@+###@@@@##+;GKKKKKKG-+@@@o2KKKKKK1O@OmKKKKKhX@@@@@@@@@@@@@@%LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL*+@@@@@#@@@@@XzKKKKKKKC@+@@@@@@@@@@@@@@@@@@@@@+-GKKKKKKF%.XXo.:mmmmmm:O@OmKKKKKhX#@@@@@@@@@@@@@&LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL*@@@@@@@@@@@@@BKKKKKKKsX#@@@@@@@@@@@@@@@@@@@@@O-GKKKKKKKcxxxxk=oOOOOOO+@XmKKKKKhX@@@@@@@@@@@@@@$LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL-+@@@@@@@@@@O*DKKKKKKK5o@@@@@@@@@@@#@@@@@@@@@@+-GKKKKKKKKKKKKK,o@@@@$%%%$MKKKKKkX@@@@@@@#@@@@@@*LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL:O@@@@@@@@@@OLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLL5O@@@@@@@@@@o8KKKKKKKN+@@@@@@@@@@@@@@@@@@@@@@@O-GKKKKKKKKKKKKJ>O@@#XkKKKKKmO@@@@#@@@@@@@@@@@#@O3LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLO@@@@@@@@@@o9KKKKKKKmO@@@@@@@@@@@@@@@@@@@@@@@+-GKKKKKKKKKKKKK>O@@@okKKKKKmO@@@@@@@@@@@@@@@@@@O8LLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLL@@@@@@@@@@#XqKKKKKKKMo@@@@#@@@@@@#@@@@@@@@@@@+-GKKKKKKKKKKKKJ>O@@@XkKKKKKmO@@@@@@@@@@@@@@@@@@+LLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLL%@@@@@@@@@@o0KKKKKKKmO@#@@@@@@@@@@@@@#@@@@@@@+-GKKKKKKKKKKKKJ>O@@@XxKKKKKNO@@@@@@@@@@@@@@@@@@#LLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLL>O@@@@@@@@@O8KKKKKKKNO@@@@@@@@@@@@@@@@@@@@@@@O-GKKKKKKKKKKKKK>O@@@O5tttrt9+@+XXXXO@@@@@@@@@@O-LLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLL5O@@@@@@@@@o5KKKKKKKC$@@@@@@@@@@@@@@@@@@@@@@@O;JKKKKKKKJJKJJG>O@@@#OXXXXXO@OJKKKKKKG3;>>>:$@@@@@#@#@##@#XqKKKKmo@@@@@@@@@OrLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLL$+@@@@@@@@O-GKKKKKKK3O@@@@@@#@@@@@@@@@@@@@@@O3KKKKKKKD$oOOOO@@@@@@@@#@@@@@o9KKKKbO@@@@@@@@@@LLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLL3O@@@@@@@@@#VKKKKKKKyX@@@@@@@@@@@@@@@@@@@@@@XqKKKKKKKZ$@@@@@@@@@+O+++@@@@@o9KKKKbo@@@@@@@@O>LLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLao@@@@@@@@@ovKKKKKKKNO+#@@@@@@@@@@@#@@@@@@@@XkKKKKKKKM+#@@@@@@@@*****#@@@@oqKKKKmO@@@@@@@@orLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLL$@@@@@@@@@XyKKKKKKKK6X#@@@@@@@@@@@@@@@@@@@+%SKKKKKKKxX@@@@@@@@@mFFFF3O@@@O>pppp9O@@@@@@@@@LLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLL5O@@@@@@@@O,JKKKKKKKC%O@@@@@@@@@@@@@@@@@@@ pKKKKKKKKiO#@@@@@@@@BKKKK5o@@@@+.XXXO@@@@@@@@O*@@@@@@@@++O+O@#@@+$NFdX@@@@@@@@XtLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLL:O@@@@@@@#@+xKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB@OOO@@@@#@@@@@@@@#@@@@@@**%@@@@@@@@O=LLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLO@@@@@@@@@+@jKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKC-O@@@@@@@@@@@@@@@@@@@@@@@O+@@@@@@@@@OLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLL6X@@@@@@@@@OOeDKKKKKKKKKKKKKKKKKKKKKKKKKKKKm=O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O1LLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLL%+@@@@@@@@@@X-fDKKKKKKKKKKKKKKKKKKKKKKKKAt@O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@LLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLO@@@@@@@@@@@OX*qxVGKKKKKKKKKKKKKKKKHCc9%X+@@@@@@@@@@@#@@@@@@@@#@@@@@@@@@@@@@@XiLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLL8o@@@@@@@@@@#@+oo#-1566666666666652;$oo+@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@o3LLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLL>O@@@@@@@@@@@@@@@OOoOXoooooXOXOXOOO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O*LLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLL#O@@@@@@@@@@@@@@@@@@@@@###@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+@LLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLO@@@@@@@@@@@@@@@#@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@OLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLO@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@XrLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLaO+@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XyLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLuO@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@OyLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLiO+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+@6LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL$O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@O@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL-o@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O*LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL3O+@@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@#@#@@@@@@@@@@@@@@@@@+O1LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLq$O#@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O#9LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL5LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", -"LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL" +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% = % = % = = % = = = % = = = - Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * * = % * % % % % % % % % % = = = % = = = = = = = - - Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % * % % % % % % % % = % % = % = = = % = % = = = = = = - . - - - . . Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % * * % % % * = % % % = = % = % = = = = = = = = - = - - - - X - . . . . Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * % % % % % % % % % = % % % = = % = % % = = = % = = = = = = = = - . . . . X Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % * % % % * % % % % % % % = % % % % % = = % = % = = = = = = = - X . . X . X . X Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * % % % % % % % % % % % % % % % % = % % = % = = % = = = = = = - = - - = - X - . . . . . X X X X . X X Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % * % % % % % % % % % % % % % % = = % = = % = = = = = = = = = = - - = - X - X . . X X . X X X X X X : Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % % % % % % % % = % % = = % = = % = = = = = = = = - - = X - - - X X X X X X X X X X X X X Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % * % % % % % * % % % % % % = % % = % % = % = % = = = = = = = = = = = - - - ; H ,.l.V.L.z - X X X X X X X X X X X + X + X + Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % * % % % % % % % % % % % % % % = % % % = % % = = = % = = = = = = = X = = - 1 w.Y.W.W.W.W.W.b X X X X X X X X + X + X + X X + X + Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % % % % % % % % = % % = = % = = % = % = = = = = = = = = ; < p.E.W.W.W.W.W.W.W.z X X X X X X X X X X X X X + X + X X + X + # Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % * * % % % % % % % % % % % % % = % = % = % = = = % = = = = = = = = - ) P.W.W.W.W.W.W.W.W.W.V ; . X X X X X X X X X X + X + X + + + X + O + Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% * % % % % % % % % % % % % % % % % % % = = % % = % = = = = = = = = = - - 3.W.W.W.W.W.W.W.W.W.W.W.z X X X X X X X X X X X + X + + X + + + + + + + + + Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * * * % % % % % % % % % % % % = = % = % = % = % = % = = = = = = = - - 9.W.W.W.W.W.W.W.W.W.W.W.W.V . X X X X + X X + X X X + X + + + X + + + + O + O # Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % * % % % % % % % % % % % % % % % % % = % = % = = = = = = = = = = = - :.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X X X + X X X X X + + X + + + + + + + O + O + O + O O Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % * % % % % % % % % % % % = % % % = % = % = % = = = = = = = = - - - - - K E.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X X X X X + + X + + X + X + + + + + + + + + O + O + O O Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % % % % % % = % % % = % % = = = % = = = = = = = - = - - ; J.W.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X + X X X X O + X + X + + + + + + + + O O O + O + O O O @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * % % % % % * % % % % % % % % = % % = = = % = = % = = = = = = = = - X ,.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X X X X + X X X X X + + + X + + + O O O + O O O O O O O O # Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * % % % * * % % % % % % % % = % % % = = % % = % = = = = = = = - = - ; - ; P.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X X + + X O + X O + + + + O + + + O + + O O + O O O O O O O @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % % % % % % % % % % = % = = = % = = = = = = - - ..W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.D X O X X X X X + X O + + + + + O + O + O O O O O O O @ @ O O @ O @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* * % % % % % % % % % % % % % % = % = = = % = = = = % = = = = - = - X X m.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X + + + + O X X + + + + + + + O + O O O + O O O @ O O O @ @ @ @ @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % % % % % % % % % % = = % = = % = = = = = = = = - . : E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.x + X X + + + + + O + + + O + O + + O O O O O O O O O O O O @ @ O O @ @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % % % % % % % % % = % = = % = = = = = = . . . X ; - K W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b X + + + X + + + + + O + + + O O O O O O O O O O @ O @ @ O @ O @ @ @ @ @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % % % % % % % % % % = = = = = = = = - = = - - - - X - . . . ..W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.V X X X + + + + + + O + O + O O O O O O O O O O @ O @ @ @ O O @ @ @ @ @ @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % % % % % % % % % % = = % = = = = = = = = - X X - X X X 0.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b + + + + + + + + O + O + + O O O O O O O O O @ O O O @ + @ @ @ @ O @ @ @ @ Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% * % % % % % % % % % % % % % % = % % = = = = % = = - = = - - X X X . p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.D X + + + + + + O + + O + O O O O O @ O O O @ O O @ @ @ @ @ @ @ @ @ @ @ @ @ o Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.* % % % % % % % % % % = % % % % % = % % = = = = = = - = = = - X X - X X X X . X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b O X + + + + O + O O O O O O O O O O @ O @ O @ @ O @ O @ @ @ O @ @ @ o @ o @ 7 Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % = % % = % = % % = % % = = = - = = = = = X X - X - X . X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.D + O + + O + O O O O O O O O O O O O O @ O @ @ @ O @ @ @ @ @ @ @ @ @ o @ o o o Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % % % % = = = % = % = = = = = = = X = X - - X X X X X . X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.D + O + O + + O + O O O O O @ O O @ O O O @ O O @ @ @ @ @ @ @ @ @ o o @ o o o o o Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.= % % % % % % % = % % % = % = % = = = % = = = = - = = = - = = - - X X X X X X X X . p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.> X X + + O O O O O O O O O O @ O O O @ @ @ @ @ O @ @ @ @ @ @ o @ o @ o o o o o o w Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.% % % % % % % % % % = = % = % = = % = = = = = = = = X X = X X - X X X X X X X X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.A.O O O O O + O O + O O O O O O O @ @ @ O @ O @ @ @ @ @ @ o @ @ o o @ o o o o o o 9 o Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.& % % % % % % % % % = = % = = = = % = = = = = = = - - X X - X X X X X X . X X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.5.O + + O O O O O O O O O O @ O O @ O @ @ @ @ @ @ @ @ @ @ @ o o @ o o o o o o 9 o o 4 4 Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.% % % % % = = & % = = % % = % = = = = = - = = - = X - X - X X X X X X X X X X X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S + O O O O O O O O O O @ @ O O @ O @ @ O @ @ @ O @ @ o @ o o @ o o o o o o o o 4 o o 4 Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.% % = % % = % % = = % % = = % = = = = = = = - - - - - X X X X X - X X X X X X X X X . X X + p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.x.O + O O O O O O @ O O @ O O O @ @ O O @ @ @ @ @ @ @ @ @ o @ o o o o o o o o o o o 4 4 4 9 Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.% % % % = % % = % % = = = = = = = = = = - = X X X X X X X X X X X X X O p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.T.l O O O O O O O O O @ O @ O @ @ O @ @ @ @ @ @ @ @ o @ o o @ o o o o o o o 9 o o 9 4 4 o 4 9 Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.% % % % % % % % = % % = = % = = = = = = = = - X X - X - X - X X X X X X X X X X X X X + X p.W.W.W.W.W.W.W.W.W.W.W.W.W.R.~ + x l O O O O O O O O @ O @ O @ @ @ @ @ @ @ @ o @ @ o o @ o o o o o o o o o o 4 o 4 4 4 o 9 9 Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.* = = % = = = = % = = = = = = = = = - - X - X X X X X X X X X X X X X + X + X + p.W.W.W.W.W.W.W.W.W.W.W.W.V.D O O n.S O O O O O @ @ O @ O @ @ O @ @ @ @ @ @ @ @ @ o @ @ o o o o o o o 4 4 o 9 4 o 4 4 4 4 9 9 Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.= % % % % = % % = = = = = = = = - = - = - . X X X X X X X X X X X X X + + X X + + X O D | | | [ [ [ [ [ { { ' S O O O 5.W.S O O O @ @ O O @ @ O O @ @ @ @ @ @ @ o @ @ o @ o o o o o o o 9 o o o o 9 o 4 4 4 4 4 9 o 9 Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.* = % = = % = = % = = = = = = = = = = - - X X - X X X X X X X X X X X X X + + X X + X + + + X O X O X O + O O O O $ 0.W.W.S @ O O O O @ @ O @ @ @ @ @ @ @ @ @ @ @ o o o o o o o o o o o 9 o 4 4 4 4 4 4 4 4 4 q 6 6 9 Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.% = % % % = % = = % = = = = = = - = - - - X X X X X X X X X X . : : : : : : : + : : + : # + # # # # # # $ $ # $ S ;.L.W.W.W.S @ O @ O O @ @ O @ e @ e e e e w e e e w o @ 4 @ 4 7 o o 4 4 o 4 o 4 o 6 6 4 9 6 6 o 6 o o q Q.Q.Q.Q.", +"Q.Q.Q.Q.% % = = = % = % = = = = = - = = - . - X X X X X X X . X z } q.m.J.R.W.W.W.W.E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.W.W.W.W.W.W.W.W.W.W.S O O O @ @ @ e f.E.W.W.W.W.W.W.W.E.W.W.W.E.j.t @ @ 4 4 o 4 o 4 4 4 4 6 4 o 4 6 o 6 6 6 q 6 6 Q.Q.Q.Q.", +"Q.Q.Q.Q.= = = % = = = = = = = = = = = = X X - X X X X X X V 9.J.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ @ @ @ O n.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.N.4 o o o o 4 o o 4 4 4 o 4 6 o o 6 4 6 6 6 9 6 Q.Q.Q.Q.", +"Q.Q.Q.& = % % % = = = = = = = = = - = X - - X - X X X ; ) m.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S O @ @ O @ G W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E 4 o 9 4 4 4 4 4 4 4 4 4 6 o 6 6 6 9 6 6 6 6 q Q.Q.Q.", +"Q.Q.Q.= % = = & = = = = = = = - X - X X X X K A.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ O @ @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.4 4 o 4 4 4 4 4 4 q q 4 4 q 6 4 6 6 q 9 q q q Q.Q.Q.", +"Q.Q.Q.= = & = = = = = = = = - - . - X X X X < l.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S O O @ @ @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.o 4 4 4 4 4 4 4 4 q 4 q 4 4 6 6 6 6 q q q q q Q.Q.Q.", +"Q.Q.= = = = = = = = = = = = - . - . - X X X - X ; / P.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ @ @ @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.<.4 4 4 4 4 4 4 q 4 4 4 q q q 9 6 9 9 q q q q q 0 Q.Q.", +"Q.Q.= % = = = = = = = = - . . . . . X X X X X :.E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F @ @ @ @ @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.4 4 4 4 4 4 4 4 4 q q 4 q 4 6 6 6 q q q q q q 0 Q.Q.", +"Q.Q.= = = = = = - = = - X - X - X X X . + p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F @ @ @ o @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.4 4 6 o 6 6 6 9 9 q 4 6 6 6 6 q q q q q q q 5 0 Q.Q.", +"Q.Q.= = = = = = = = - X X X X X . p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ @ @ @ #.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.4 4 6 6 o o 4 6 4 q q q 6 q q q q q q q 0 q 0 q Q.Q.", +"Q.= = - = = = - = - - - X - X X X . . 6.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ o @ o @ ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.-.4 q o 4 9 6 6 6 6 6 6 q 4 q q q q q q 0 q 0 0 0 0 Q.", +"Q.= = = = . - . - - X X X X X X X . . .W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F @ @ @ @ 4 ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.<.4 9 6 q 6 4 6 6 6 6 6 q q q q q 0 q 5 q 0 q 0 0 0 Q.", +"Q.= = = . = . = . - - - X - X X X X X . V R.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F o o o o @ O.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.<.q 4 6 o q 4 6 6 6 6 q q q q q 0 5 q 0 0 0 0 0 0 0 Q.", +"Q.= = = - . - . . X X X - X X - X : D.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F o @ @ o 4 ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.$.4 q 6 6 4 q 4 9 6 6 q q q q 5 q 0 q 0 0 0 0 0 0 0 Q.", +"Q.- = - . . . - X X - X X X X X X X X >.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F @ 4 o o o O.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.$.6 6 6 q q 5 q q q 6 q q q q q q 0 0 0 0 0 0 0 0 u Q.", +"Q. - . . . X X X X - X X X , R.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F o @ o @ 4 ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.#.o 6 6 q 4 q q q 0 q q q q 0 0 0 0 0 0 0 0 0 y u 0 Q.", +"- - X X X X X X X X X X X X X p.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z 4 7 o o 4 ] W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.L 4 6 4 q q q q q q q 6 q 0 0 0 0 0 0 0 0 0 0 y 0 0 y ", +" - - X X - X X X X X X X X , E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F @ 4 4 o o #.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.r.9 6 6 q q q q 6 q 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 y 0 y ", +". . . X X X X . . X X X X X X X 6.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.L.S.B.n.n.n.n.z.n.z.n.n.n.z.v.n.v.n.n.v.v.n.v.v.v.n.v.v.v.v.n.v.v.v 4 o 4 o 4 E v.v.v.v.v.v.v.v.v.v.v.v.v.b.k._ 6 6 6 q q q q q 0 0 6 0 0 0 0 0 0 0 0 y 0 0 0 y 0 y y y ", +". . - . - X - X X X X . X X X X X X X + X J.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.R.n.5.` x $ O O O O O O O @ @ O O @ @ @ @ O @ @ @ @ @ @ @ @ o @ @ o @ 4 o o 4 o o 4 o o 4 o 4 4 4 4 4 9 4 4 q 9 q 4 q 4 6 6 6 q q q q 0 q q 0 6 0 0 6 0 0 0 0 0 0 0 0 y y 0 y 0 y 0 ", +" . . . X X X - X X X X X X X X X + X X H W.W.W.W.W.W.W.W.W.W.W.W.W.R.l.~ # O O O O O O O O O O O @ O @ O O @ @ @ O @ @ @ o @ @ @ @ o @ o o o o o o o o 4 o 4 4 o 4 4 4 4 4 4 4 9 4 4 q 4 q 6 6 6 6 6 q q q q q q q q 0 0 0 0 0 0 0 0 0 y 0 0 0 0 y 0 0 0 y y ", +". . . . - X X X X X . . X X X X X X + 8.W.W.W.W.W.W.W.W.W.W.W.L.>.> O + O O O O O O O O O @ O @ O O O @ @ O O @ @ @ @ @ 7 @ @ o o o o o o o o @ 9 o 4 7 4 o 4 o 4 4 4 4 q 4 q 4 4 q 4 6 4 6 6 6 q q q q q q q 0 0 0 q 0 0 0 0 0 0 0 0 0 0 y y y 0 y y y y y ", +". . . . X X X X X X X X X X X X X A.W.W.W.W.W.W.W.W.W.R.>.# + O + O x ;.~ O O O O O O O @ O @ @ @ O @ @ @ @ @ @ @ @ @ @ @ o @ o o o o o o 9 o 4 4 o 4 o 4 4 4 4 4 4 4 q q 4 4 q 4 6 6 4 6 q q q q q q q 0 q q 0 0 0 0 0 0 0 0 0 0 y y 0 y 0 0 y y y 0 y ", +". . X . X X X X X X X X X X X X X + + : E.W.W.W.W.W.W.W.W.M.l O O O > ;.S.W.G.# O O O @ O @ O @ O O @ @ @ @ @ @ @ @ @ @ @ 7 @ o o @ o o o o o o o 4 @ 4 4 4 4 4 4 4 q 4 4 4 q 4 4 q 4 6 6 6 q q q q q q 6 0 q q 0 0 0 0 0 0 y 0 0 0 y 0 y 0 y 0 y y y 0 y y y ", +"X X X X X X X X X + X X + X X + X D W.W.W.W.W.W.W.W.5.O O + > 8.R.W.W.W.! O O O O @ O O @ @ O @ @ o @ @ @ @ @ o o @ @ o o @ o o o 4 @ 4 4 4 7 o 4 o 4 4 4 4 4 4 4 q 4 q 4 4 q 4 6 6 6 q q q q q q 0 q q 0 0 0 0 0 0 0 y 0 0 0 0 y 0 y 0 0 y y y 0 y y y y ", +" X X X X X X X X X X X X X X + + X + ' W.W.W.W.W.W.E.' O X O =.U.W.W.W.W.D.O @ O O @ O O @ O @ @ O O @ @ @ @ o @ @ @ o o @ @ o o o 4 @ 4 4 @ o 4 4 4 4 4 4 4 4 6 4 6 q 4 6 6 6 6 6 6 6 q q q q q q 5 q 0 0 0 0 0 0 0 0 0 0 0 0 y y 0 y 0 y y y y y y y y y y ", +"X X X X X X X X X X X X X + + X X + + X >.W.W.W.W.W.E.` O + k M.W.W.W.W.W.W.7.@ O O @ O @ O O @ @ @ @ @ @ @ @ @ @ @ o o o o o o o o o c t.Z.F.F.F.F.F.F.F.F.S.F.F.F.F.y.4 q 4 6 q 4 6 6 9 q 0 6 q 6 0 0 0 0 6 0 0 0 0 0 y y 0 0 0 0 0 y 0 y y y 0 y y y y y y i ", +" X X . X X X X X X + X X X + X + + X i.W.W.W.W.W. .O X G P.W.W.W.W.W.W.W.~ O O @ O O @ @ @ @ @ O @ @ @ @ o @ @ o @ o @ o o o o o C U.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.6 6 6 4 4 q q 0 6 0 6 6 q 0 0 6 6 0 0 0 0 0 0 0 0 0 0 y y y y 0 y y 0 y y y y y i y y y ", +"X X X X X X + + X + X X + X X + X + + f.W.W.W.W.0.+ O ~ E.W.W.W.W.W.W.W.W.D @ @ O @ O @ @ @ @ @ @ @ @ @ @ @ @ o @ o o o o o 6 o o z.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.4 6 6 4 0 q q q q q 0 0 0 0 0 0 0 0 0 0 0 0 y y 0 y 0 0 y 0 0 y y y 0 y y y y y y y y 2 ", +"X X X . X X X X X X X + + X + + + + X O f.W.W.W.A.O O ( E.W.W.W.W.W.W.W.W.W.S O O @ @ @ @ @ @ O @ @ @ @ @ @ @ o o o o o o o o o 9 w R.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.6 6 6 q 6 6 0 6 0 6 6 0 0 0 0 0 0 0 0 0 0 y 0 0 0 0 y y y y y y y y y y y y 2 y y 2 i i ", +"X X X X X X X + + X + X X + + + + X O + f.W.W.E.D + D R.W.W.W.W.W.W.W.W.W.W.S @ O @ @ O @ @ @ @ @ @ o @ @ o o @ o o o o o o o o o r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.6 0 q q 0 0 6 0 6 6 0 6 0 0 0 0 0 0 0 0 0 0 y 0 y y 0 y 0 y 0 y y y y y y y i y y i y 2 ", +"X X X X X + X X X + X + + X + + O O + + f.W.W.i.O j L.W.W.W.W.W.W.W.W.W.W.E.Z O @ @ @ @ @ @ @ @ o @ @ o o @ o o o o o o o o 9 o o r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.q q 6 0 6 6 0 6 0 0 0 0 0 0 0 0 0 0 y 0 0 y 0 0 y 0 y 0 y y y y y y y y 2 y y 2 y 2 y i ", +"Q.X X X X X O X + X + + X + + + X O O X f.W.T.j O l.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ @ @ @ @ @ @ @ @ o @ o o o o o o o o o 9 o o 6 7 r E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.4 q q q 0 6 6 0 0 0 0 0 0 0 0 0 0 y 0 0 y 0 y y 0 y y y y y y y y y y y y y i 2 y i i Q.", +"Q.X + X + X O X X + + + + + + + X O O X f.W.i.O ~ W.W.W.W.W.W.W.W.W.W.W.W.W.S @ @ @ @ @ @ @ @ @ o @ o o @ o o o o o 4 o 9 o o o 4 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.q q q q 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 y 0 y y 0 y y y y y y y y y y 2 i i 2 y 2 2 2 i Q.", +"Q.X X X X X X X X + + + + + + + O X O O f.W.S O A.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ @ @ @ @ @ @ o o @ o o @ o o o o o 4 4 o o 6 o 6 4 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.0 q q 0 0 0 0 0 0 0 0 0 0 0 0 0 0 y 0 y y 0 y 0 0 y y y y y y y y 2 2 y y i i 2 i i 2 Q.", +"Q.X O X X O X O + + + + + + + O O O O O f.M.O ~ W.W.W.W.W.W.W.W.W.W.W.W.W.W.b @ @ @ @ @ @ @ @ o @ @ o o o o o 4 o 4 o 4 4 o 9 o 4 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.q 0 0 6 q 0 0 0 0 0 0 0 y 0 0 y y 0 y 0 0 y y y y y y y y y 2 y i y y y 2 2 2 y 2 i 3 Q.", +"Q.X X X O X O X + + + + + + + + + O O O f.=.@ M.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ @ @ @ @ o o o o o o o o o o o 9 o 4 4 o 4 4 4 4 4 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.q 0 0 0 0 0 0 0 0 0 y y 0 y 0 y 0 y 0 2 y y 0 y y y y y y y y 2 y y 2 i i i i 2 2 2 2 Q.", +"Q.+ O O X O X O + + + + O + O O O O + O f.k j W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ @ @ 4 @ o o o o o o o o 9 o o o 4 o 4 4 4 4 4 4 4 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.0 q 0 0 0 0 0 0 0 0 0 0 y 0 y 0 0 y y 0 y y y y y y y 2 y 2 y y 2 i 2 i i 2 2 2 2 n 3 Q.", +"Q.Q.X X X O O O + + + + + O O + O O O O ;.O =.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ @ o @ o o o o o o o o 9 9 o o 9 4 4 4 4 4 4 4 9 9 r W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.q 0 0 0 0 0 0 0 y 0 0 0 0 y 0 y y y y y y y y y y y y y y i 2 2 2 2 i 2 2 2 i 2 i 3 Q.Q.", +"Q.Q.O X O X O X + O + O + O O + O O @ @ ! O x.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z @ o @ o o o o o o o o o o o o 9 o 4 4 4 4 4 4 q 4 6 r E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.v.0 0 0 0 y 0 0 0 0 0 y y y 0 2 0 y 0 y y y y y y 2 y 2 y y 2 y i y i i 2 2 2 i 3 2 3 Q.Q.", +"Q.Q.+ + + O X + O + O + O O + O O O O O j @ L.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z o @ o o o o @ 4 o o o 4 4 4 o 4 4 4 4 4 4 4 q 4 4 6 r E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.0 0 0 0 0 0 0 0 y y y 0 y 0 y y y y 2 5 8 2 8 2 2 y 8 2 n 2 2 2 2 2 2 2 2 2 2 3 3 3 Q.Q.", +"Q.Q.O + O X O O + O + O O O O O O O @ O @ # E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.F 7 o o @ 4 4 o o 4 4 o 4 o 4 4 4 4 4 4 4 4 4 0 4 q 6 6 B.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.0 0 0 0 y 0 y 0 y 0 0 y y y 0 y y 2 5 2 n 8 2 2 y 2 2 2 2 2 2 2 2 3 m 2 2 2 3 3 2 3 Q.Q.", +"Q.Q.Q.+ O O O + O + O O O O O O @ O @ O O l W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.^ @ o o o @ o o 4 @ o 4 o 4 4 4 4 4 4 6 4 4 4 4 6 6 4 6 P E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.0 0 y 0 y 0 0 y 0 0 y y y 0 0 y y y 2 2 8 8 2 8 2 2 2 2 2 2 2 2 2 2 3 2 2 2 3 3 3 Q.Q.Q.", +"Q.Q.Q.O X O + O O O O O O @ O O O O O O @ G W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.4.@ o o o 4 9 o 4 9 4 4 4 4 4 4 4 4 q 4 4 6 4 0 4 4 6 6 6 L c.U.T.T.T.T.T.T.T.T.T.T.T.T.T.k.0 0 y 0 0 0 y 0 y y y 0 y 2 y y y y 8 8 2 8 8 8 n 2 2 2 2 2 2 2 2 3 2 2 3 3 3 3 3 Q.Q.Q.", +"Q.Q.Q.O + O O O O O O O O O O O @ O @ @ O Y W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.N.4 o o o 6 o o o 9 4 4 4 4 4 4 4 q 4 4 6 4 0 4 4 0 4 q q 6 q q q q q 0 q 0 0 0 0 0 y 0 0 0 y 0 0 y 0 y y y y y 0 y y y y y y y 2 8 2 8 2 2 2 2 2 8 2 2 2 2 3 2 2 3 3 i 3 3 3 Q.Q.Q.", +"Q.Q.Q.Q.+ O O O O O O O O O O @ O O O @ @ G W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.U o o o o o 9 9 o o 4 4 4 q 4 9 4 q 6 4 6 6 6 4 q q q q 0 q q q q 0 q 0 6 0 0 0 y 0 0 0 0 0 y y 0 y 0 0 y 0 y y y y y y y y 2 y n 2 2 2 2 2 2 2 m m 2 3 2 2 3 3 2 3 3 3 3 Q.Q.Q.Q.", +"Q.Q.Q.Q.O O O O O O O O O O @ @ O @ @ @ O v W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.B.6 o o o o 4 o 6 4 4 4 q 4 4 4 6 4 6 4 6 6 4 6 q q q q q q 6 0 0 0 0 0 0 0 0 0 0 0 0 0 y 0 0 0 y 0 y 0 y y y 0 2 y y y y y y y y 2 2 2 2 2 3 2 3 2 2 2 2 3 3 3 3 3 3 3 3 Q.Q.Q.Q.", +"Q.Q.Q.Q.O O O O @ O O O @ O @ O @ O @ @ @ @ E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.2.o 9 o 6 o 6 o 4 4 9 4 4 q q 4 q 4 0 4 6 0 0 6 q q q q 0 0 0 q 0 0 0 0 0 0 0 0 0 y y 0 y y 0 y y y y y y y y y y y y 2 2 y 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.O O O O O O @ O O @ @ O @ @ O @ @ L.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.$.9 4 4 4 4 4 4 4 q q 4 q 4 6 4 6 6 4 q q q q q 6 q 0 0 5 q 0 0 0 0 0 0 y 0 0 y y 0 y y y y y y 0 y y 0 2 y 2 2 y 2 y 2 2 2 y 2 2 2 2 2 2 3 2 3 3 3 i 3 3 3 3 3 3 3 Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.@ O O O @ @ O @ @ @ O @ @ @ @ @ @ z.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.y.9 4 4 9 4 q 4 4 4 4 4 6 6 6 6 q q q q q 0 0 0 0 q q 0 0 0 0 0 0 u 0 5 0 y 0 0 5 y 0 y 0 y y y y y y 2 2 y y 2 y 2 2 y 2 n 3 2 m 2 2 2 2 3 3 i 3 3 3 3 3 3 3 3 f Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.O @ O O @ @ @ O O @ @ @ @ @ @ o -.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.L.<.a 4 4 4 q 6 4 q 4 q 6 6 0 q q q q q q 6 0 6 0 0 0 0 0 0 0 y 0 u y y 0 0 y y y 2 y y y 2 2 y y 2 2 2 2 2 n 2 n 2 2 2 2 2 2 3 2 2 2 3 2 i 3 3 3 3 3 3 3 3 3 Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.O @ @ @ O @ @ @ @ @ @ @ @ @ @ @ c W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.Z.k.a.a.a.a.a.a.a.a.d.d.d.d.d.d.d.d.s.h.h.h.h.s.h.s.s.s.s.s.h.s 0 y y 0 y R y.u.s.y.s.s.s.s.u.s.y.s.e.e.1.B 2 2 2 2 2 3 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 f Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.O O @ @ O @ @ @ O @ @ @ o @ @ @ N.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.I y 0 y u y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.Q m n 8 2 2 2 3 3 2 3 3 3 3 3 3 3 3 f f 3 Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.@ o O @ o O @ @ o o @ @ 7 4 @ 4 @.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.p 0 y y y y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.U.m 2 2 3 2 3 3 3 3 3 3 3 3 m 3 3 3 3 3 f Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.O @ o O @ @ @ @ @ @ @ 4 @ @ @ 7 L.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.L.y y y 0 y y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.X.2 2 2 3 3 3 3 3 3 3 3 3 2 3 f 3 f i Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.o @ O @ @ @ @ o @ o @ @ @ 4 4 7 @.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.y 0 y 2 y 0 +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.%.2 2 3 2 3 3 3 3 3 3 3 3 3 f 3 3 f f Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.@ @ @ @ @ @ o o @ @ o o o o o o S.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.y y y y y y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 3 3 3 3 3 3 3 3 3 f 3 3 f 3 Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.o @ @ @ o @ @ @ 4 @ 4 o o o 9 o U W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.E.M y y y y y y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 3 3 3 3 3 3 3 f 3 3 f f 3 f Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.@ @ @ @ o 4 @ @ o o o o o 4 o o <.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.0 0 y y y y y %.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.i 3 3 3 3 3 3 3 f f 3 3 f 3 3 f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.o o o o @ 4 4 @ 4 9 @ 4 @ 9 o 9 j.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W y 2 y y y 2 y +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 f 3 3 3 3 3 3 f f 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.o o @ o o @ 4 @ 4 4 @ 4 4 4 4 4 4 v.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.c.y y y 2 y y y i +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 3 3 3 3 3 f 3 3 f 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.o o o o 4 o 4 4 4 4 4 @ 4 4 4 4 9 z.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.T.n y y y y i 3 y 2 %.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 f f 3 3 f 3 f 3 f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.o o o @ @ 4 @ 4 4 4 4 4 4 4 4 4 9 y.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.o.y 2 2 y y y 2 y y %.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 3 3 f 3 f f f 3 f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.o o 4 4 4 4 o 4 4 4 4 4 9 4 9 4 q #.E.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.y y y y y i 2 2 2 3 +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 f 3 3 3 f 3 3 f f 3 Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 o 4 4 4 4 4 4 4 4 4 q 4 4 4 q 4 L Z.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.2 y y y 3 y y 2 y 2 3 +.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 3 f 3 f 3 f f 3 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 4 o 4 4 4 4 4 4 4 4 q q 4 4 0 4 6 $.U.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.T.o.y y y 2 y 3 y i i y 3 3 %.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.&.3 f 3 f 3 f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 4 4 4 4 q 4 4 6 4 4 4 6 4 6 q 6 0 r <.I.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.g y 2 y 2 y y y y i 2 3 2 3 W W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.X.3 f f 3 f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 4 4 4 4 4 4 4 6 6 0 6 6 6 4 q q q 0 q o.k.R.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.b.W y 2 y y i y 3 i 3 i i 2 y 3 y i F.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.K.f f 3 3 f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 q 4 4 q 4 6 4 0 4 6 6 0 q q q q q q 0 0 u Q r.b.K.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.W.I.b.&.n y y y y y 3 y y 3 y y 2 3 2 y 3 3 2 h b.W.W.W.W.W.W.W.W.W.W.W.W.W.C.B 3 3 f f f 3 f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 4 6 q 4 0 6 4 4 6 6 q q q q 0 q q 0 q q 0 0 0 0 0 u d I I I I I I I I I I I I I M p y y y y y y y y y y 3 y y 3 3 3 y i 3 2 2 3 3 3 m N N N N N N N B B N N m f f f f f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.4 6 4 0 4 6 4 6 q q q q q q q q 0 q q 0 0 0 0 0 0 0 0 0 0 0 y 0 y y 0 y y y y y y y y y y i y 3 y 3 3 y y 3 3 3 2 3 y 3 3 3 3 i 3 3 3 3 3 3 3 3 3 3 3 f 3 f 3 3 3 3 f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.6 4 4 6 6 4 q q q 0 q q q 0 q 5 0 0 0 0 0 0 0 0 y 0 y 0 y u 8 u 8 2 0 y y y y y y 2 y y y y i y y y 3 y 3 y y 3 y 3 3 3 y 3 i 3 3 3 3 3 3 3 f 3 3 f 3 f 3 f f f f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.6 6 6 6 q q q q q 0 6 0 0 6 0 0 0 0 0 0 y 0 0 0 y 0 0 0 0 y y y y y y y y y y y y y y y i y y 3 y 3 2 3 2 3 i 3 3 y 3 3 3 3 3 3 3 3 f 3 f 3 3 f 3 3 f 3 f f f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.6 6 6 q q q q 6 0 0 0 6 0 0 0 0 0 0 0 y 0 0 y 0 y y y y 0 y u y y y y y y y 3 y y i i y 3 3 y 3 y 3 y 3 y 3 2 3 3 3 3 3 3 3 3 3 3 3 3 f 3 3 f f f f f 3 f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.q q q q q 0 q 0 0 0 0 0 0 0 0 0 y 0 0 y 0 y 0 y y y y y y y y y y y 2 y y y 3 3 y 2 y y 3 3 y i i 3 3 3 3 3 3 3 3 3 3 3 3 3 3 f 3 3 f 3 f f f 3 f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.5 q 0 q 5 0 0 0 0 0 0 0 y 0 0 0 0 y 0 y 0 y y 0 y 0 y y y y y y y y y 3 2 y y 3 y 3 2 3 y 3 3 2 3 2 2 i 3 3 3 f 3 3 3 3 3 3 3 3 f 3 f f 3 f m f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.5 q 0 q 0 0 0 0 0 0 0 0 0 y 0 0 y 0 y 0 y y y y y y y y y i 2 y i y 3 y i i y 2 3 y 3 3 2 2 2 3 3 3 3 3 3 3 3 f 3 3 3 3 3 f 3 3 f f 3 f 3 f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.5 0 0 0 0 0 0 0 y 0 y 0 y y y 0 y y y y y y y y y 3 y y y y 2 y 3 3 y 3 3 3 y y 3 y 3 3 3 i 3 3 3 3 3 3 3 3 3 f 3 f f 3 f 3 f f f f f f f 3 Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.5 0 y 0 0 y y 0 y 0 y y 0 0 y y 0 y y y y y y y y y i y 2 2 2 y y 3 y y 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 f 3 3 f f 3 f f f f f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.5 0 0 0 0 y 0 8 y 0 y y y y y y y y y y y y 3 y 2 y 3 y i y 3 y 3 3 y 3 3 3 3 i i 3 3 3 3 3 3 3 f 3 3 3 f 3 3 f f 3 3 f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.0 u y 0 y u y y 0 y y y y y y y y y 2 y i 2 2 y 3 y 3 2 2 3 3 2 3 2 3 3 3 3 3 3 3 f 3 3 f 3 3 f 3 f 3 f f 3 f 3 f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.0 y 0 y y y y y y y y y y 2 2 y y 2 i i i y y 3 3 2 i 3 2 3 2 3 3 3 3 3 3 3 3 3 3 3 f 3 3 f f 3 3 f f f f f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.y y 0 y y y y y y 2 y y 2 y y i i 2 y 3 3 y y y 3 y 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 f f 3 f 3 f f f 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.0 y y y y y y y 2 y y 2 2 2 2 y 3 y 3 3 3 3 3 3 3 y 3 3 3 3 3 3 3 3 3 3 f 3 f 3 3 f 3 f f 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.y i y y y y y i i 2 i 2 2 2 2 3 y 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 f 3 f f 3 f f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.2 i 2 2 i i i 2 2 2 3 2 2 3 3 3 2 3 3 3 3 3 3 3 3 f f 3 f f f 3 3 f 3 f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.2 2 2 i 2 3 3 2 3 3 3 y 3 3 3 3 3 3 3 f f 3 3 f 3 3 f f Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.", +"Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.2 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q." }; diff --git a/share/pixmaps/bitcoin16.png b/share/pixmaps/bitcoin16.png index e9078c3acecf643fa8776536541c9e7ff2d5d77a..131dc66f7eddb8fea08c2fbd4e79d8fe356282de 100644 GIT binary patch delta 836 zcmV-K1H1f*2+#(Q8Gi-<001BJ|6u?C00DDSM?wIu&K&6g000DMK}|sb0I`n?{9y$E z000SaNLh0L01m?d01m?e$8V@)0008zNkloMF~;}kr@WkUto-{0)MT*M$OTDrDo=PoC-e* zjK*e~d)wz;Gi}4>oV(B7Yp=b|xdQ&P<3?AG3{=Vt2gy?F5K*fN_aQRvZg5fagYg-_RAQ$SOWmUc2+5oTPX}qgJg49Y~ z%6Ty*@kAUuV}Hk4R}qp-@d#@urn>7lLzAuGs$m^K7I2F?9#uNHCMoD;2`{eQUI(5f_{#$_6!<0Jt7fg86k zq40!FDcWf4Jwsx09Fh`aVKyhI3>2m)*3c$}7uyPU_gDVt<4-$0 zVxuAJ*!q<*nzC z|MIH;RpaC1uB^0@kD7mbhG}GTS5RefV~d7*o|ulUsGhmJw#wt<>ani2T2f;}H&#+Z zaZ*BaR77`CKyp?@cUnq&cxsfrwaKxrwo64-Y+i}FvdB$ESbsb-Ojk#EY+i~@M_M&4 zL0wIJH7-InE<;*MdatduO-5NZE<{{Qd~98axv|Hv}}x22r6cx#hfOnkw+%{((qXIg`NZqKze=sOLnU$YnT7PgvHeFOib22JGk&T&MS7$OS zKsqr=LO4}II!-(_NjNY?H!nkmhK7fShlq%XiHV7dii(Sii;Rqnjg5_tj*gFykC2d% zk&%&-l9H2?la!Q{m6es2mX?>7mzbECnVFfInwp!No1C1Sot>SYo}QndpP-Cf>sHv%`s;a81tE;T6tgWrBuCA`HudlGMu(7eRva+(X zv$M3cw6(Rhwzjsnx3{>sxVgExy1Kf%ySu!+yuH1>zP`S{zrVo1z`?=6!otGC!^6bH z#KpzM#>U3S$H&OX$jQmc%F4>i%gfBn%+1Zs&VSC%&(F`$(9qG*(bCe=)6>(`)YR40 z)z;S5*VotB*x1?G+1lFL+uPgR+}z#W-QM2b-{0Th;Naom;o{=ruz* z=jZ3>=;-O`>FVn0>+9?6?CkCB?e6aG@9*#M@bK~R@$&NW^Yioc^z`-h_4fAm_xJbs z_<#8M`T6?#`uqF){QUg={r&#_{{R2~+8{(p00001bW%=J06^y0W&i*Hw@E}nR2b83 z$T4cfFc1Y$O*8F^G{2C+XOP^eOtpo|>BR1)@D+kx{K~gX*kTE}K`?|EB9j9+uY68K zeqK`wFSR~)5plAvkt9K~wDwPI^GuR)B6qo%iR%GiSw;iM5LTDSREEJcC6FAB!5DS& z{`uo_$tS?OP;0-O&q-^2I+0iBbABh_Kf5lCR diff --git a/share/pixmaps/bitcoin16.xpm b/share/pixmaps/bitcoin16.xpm index c031e6c08f..0a89a94107 100644 --- a/share/pixmaps/bitcoin16.xpm +++ b/share/pixmaps/bitcoin16.xpm @@ -1,56 +1,176 @@ /* XPM */ -static char *_c12b5849e0c45b784f94f3ca12ab2cd[] = { +static char *result[] = { /* columns rows colors chars-per-pixel */ -"16 16 34 1 ", -" c #352C41", -". c #3A3149", -"X c #433756", -"o c #44365D", -"O c #514072", -"+ c #564477", -"@ c #5C4B7C", -"# c #60507F", -"$ c #645484", -"% c #6C5D88", -"& c #71638B", -"* c #796B93", -"= c #7D7095", -"- c #867A9E", -"; c #8C80A4", -": c #968BAB", -"> c #9A8FAF", -", c #A69CB8", -"< c #A89EB9", -"1 c #AEA5BF", -"2 c #B1A8C1", -"3 c #B4ADC2", -"4 c #B9B1C7", -"5 c #BDB5C9", -"6 c #CDC7D7", -"7 c #D7D7D7", -"8 c #DADADA", -"9 c gray87", -"0 c #E2E2E2", -"q c #EBE6F0", -"w c #F3F3F3", -"e c #F6F6F6", -"r c #F8F8F8", -"t c gray100", +"16 16 154 2 ", +" c #3F2567", +". c #3F2668", +"X c #3E2768", +"o c #3B2B69", +"O c #3D2868", +"+ c #3D2968", +"@ c #3E2868", +"# c #3C2A69", +"$ c #3A2D69", +"% c #392E6A", +"& c #2F3E6D", +"* c #2F3F6D", +"= c #37326A", +"- c #37336B", +"; c #35356B", +": c #36346B", +"> c #34366B", +", c #34376C", +"< c #38306A", +"1 c #38316A", +"2 c #33386C", +"3 c #33396C", +"4 c #313B6C", +"5 c #323B6C", +"6 c #303C6D", +"7 c #313C6D", +"8 c #303D6D", +"9 c #303E6D", +"0 c #461B65", +"q c #431F66", +"w c #451C66", +"e c #441D66", +"r c #451D66", +"t c #441E66", +"y c #422066", +"u c #432066", +"i c #422166", +"p c #422067", +"a c #422167", +"s c #412267", +"d c #412367", +"f c #402467", +"g c #402567", +"h c #422468", +"j c #432D6C", +"k c #1F5873", +"l c #1F5973", +"z c #1E5A73", +"x c #1D5B74", +"c c #1E5A74", +"v c #1B5E74", +"b c #1B5F74", +"n c #1B5F75", +"m c #1C5C74", +"M c #1D5C74", +"N c #1C5D74", +"B c #2E406E", +"V c #2D426E", +"C c #2C436E", +"Z c #2F426F", +"A c #2B446E", +"S c #2A466F", +"D c #2A476F", +"F c #29486F", +"G c #274B70", +"H c #264C70", +"J c #264D70", +"K c #264D71", +"L c #254E71", +"P c #254F71", +"I c #284970", +"U c #284A70", +"Y c #235172", +"T c #225372", +"R c #245071", +"E c #215472", +"W c #215572", +"Q c #225472", +"! c #205672", +"~ c #205673", +"^ c #205773", +"/ c #1A6075", +"( c #454E7B", +") c #536589", +"_ c #566F8E", +"` c #567791", +"' c #63618C", +"] c #606E91", +"[ c #696B92", +"{ c #706491", +"} c #657D98", +"| c #777D9D", +" . c #757E9E", +".. c #787B9D", +"X. c #85759F", +"o. c #67879D", +"O. c #6E849E", +"+. c #648D9F", +"@. c #71849F", +"#. c #72849F", +"$. c #6F8CA2", +"%. c #6C90A3", +"&. c #6F90A3", +"*. c #7293A5", +"=. c #779FAC", +"-. c #8181A3", +";. c #8382A4", +":. c #8C86A8", +">. c #888CA9", +",. c #938CAD", +"<. c #8A9EB2", +"1. c #939FB5", +"2. c #979FB6", +"3. c #A096B5", +"4. c #A197B6", +"5. c #A699B8", +"6. c #91A4B6", +"7. c #9BA4B9", +"8. c #99B1BE", +"9. c #A0A6BC", +"0. c #ABA2BE", +"q. c #A3AFC1", +"w. c #A3B1C1", +"e. c #A2B2C1", +"r. c #A0B5C2", +"t. c #A5B5C4", +"y. c #ADBFCB", +"u. c #B7B4C9", +"i. c #B4B6C9", +"p. c #B9B4C9", +"a. c #BDB7CC", +"s. c #B6BACB", +"d. c #BCBBCD", +"f. c #BFBECF", +"g. c #AEC5CD", +"h. c #B1C1CC", +"j. c #BAC3D0", +"k. c #B6CAD2", +"l. c #C5CBD7", +"z. c #C6CCD8", +"x. c #C9C9D8", +"c. c #CBD1DB", +"v. c #CFD2DD", +"b. c #D5D4E0", +"n. c #DBD7E3", +"m. c #E2E4EB", +"M. c #E7E5EC", +"N. c #E7E6ED", +"B. c #E6E7ED", +"V. c #F8F8FA", +"C. c #FBFBFC", +"Z. c #FCFDFD", +"A. c white", +"S. c None", /* pixels */ -"tttr3%%O@;;9tttt", -"tww@ooooXooo2trt", -"tww@ooooXooo2ttt", -"r##oooo@:ooo.66t", -"5XXXX..*6XXooOOw", -"%oo%2446q%%Xooo4", -"%oo%2446q%%Xooo4", -"o@@q:--19,,=&XX-", -"O;;5. %q;;<&oo>", -"-==7oXX-0++%*oo7", -"-==8oXX-0++%*oo7", -"qXX6866q:oo#o==q", -"r22X@$$+XooX+qqt", -"tqq5OXXoooo*qtrt", -"tqq5OXXoooo*qrtt", -"trte922;>66wrttt" +"S.S.S.S.S.w t u s g X S.S.S.S.S.", +"S.S.S.0 r q i h 5.3.# $ < S.S.S.", +"S.S.w e q s f X.A.p.% 1 : , S.S.", +"S.r t y d X 0.A.u.= ; 2 5 9 S.", +"S.q a f . O o ,.b.;.> 3 7 * V S.", +"p s g j 4.n.M.N.N.i.>.B.7.C S F ", +"f . @ a.A.A.A.A.A.s.9.A.j.D U J ", +"X + { C.d.-...| .] ) #._ G L R ", +"# $ :.f.x.2 4 & 2.l.@.I H P Y E ", +"% 1 ' V.v.6 * V c.A.<.K R T W ^ ", +"- ; [ A.m.Z C S O.6.` Y Q ~ l z ", +"S.3 ( Z.A.z.q.w.e.$.o.r.%.z M S.", +"S.8 B 1.A.A.A.A.A.&.8.A.k.N v S.", +"S.S.A D } t.h.y.*.^ +.g.=.n S.S.", +"S.S.S.G L R T W k c m v / S.S.S.", +"S.S.S.S.S.T ! l x N b S.S.S.S.S." }; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png index ed360021cf5892028b5b26eeba9ec8ac48ae6ae9..bbc22527267c3b0b47b45d9e92dde0ede1cda72a 100644 GIT binary patch literal 29623 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
      pg=_2 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 diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm index 5af3c77167..4c70033cce 100644 --- a/share/pixmaps/bitcoin256.xpm +++ b/share/pixmaps/bitcoin256.xpm @@ -1,338 +1,463 @@ /* XPM */ -static char *_96e75000d6d46fcfb31ccb360837221[] = { +static char *result[] = { /* columns rows colors chars-per-pixel */ -"256 256 76 1 ", -" c #4C0146", -". c #50064B", -"X c #530C4E", -"o c #550E50", -"O c #571051", -"+ c #5A1555", -"@ c #5C1857", -"# c #5F1C5A", -"$ c #601D5B", -"% c #63215E", -"& c #662661", -"* c #682762", -"= c #672863", -"- c #6A2B65", -"; c #6C2E68", -": c #6D3169", -"> c #71356D", -", c #74396F", -"< c #763C71", -"1 c #783F73", -"2 c #7A4276", -"3 c #7D4678", -"4 c #7E487B", -"5 c #814C7D", -"6 c #83507F", -"7 c #844F80", -"8 c #845281", -"9 c #885684", -"0 c #8A5986", -"q c #8D5D89", -"w c #8F608B", -"e c #91638D", -"r c #936690", -"t c #966992", -"y c #996E95", -"u c #9A7097", -"i c #9D749A", -"p c #9F789D", -"a c #A1799E", -"s c #A47DA1", -"d c #A681A4", -"f c #A883A5", -"g c #AA87A8", -"h c #AD8AAA", -"j c #B08FAE", -"k c #B190AF", -"l c #B596B3", -"z c #B798B4", -"x c #B99BB6", -"c c #BB9EB8", -"v c #BEA3BC", -"b c #C0A6BE", -"n c #C4ACC3", -"m c #C7B1C6", -"M c #C9B2C7", -"N c #CBB4C9", -"B c #CEBACD", -"V c #D0BDCF", -"C c #D1BED0", -"Z c #D4C3D3", -"A c #D8C9D7", -"S c #DACBD9", -"D c #DED1DE", -"F c #E0D2DE", -"G c #E2D6E2", -"H c #E5DBE5", -"J c #E8DDE6", -"K c #ECE4EC", -"L c #EFE8EF", -"P c #F0EAEF", -"I c #F3EDF2", -"U c #F6F2F6", -"Y c #F8F5F7", -"T c #F9F6F8", -"R c #FFFFFF", -"E c None", +"256 256 201 2 ", +" c #3F2567", +". c #3F2668", +"X c #3C2B69", +"o c #372F68", +"O c #2F3F6D", +"+ c #36356B", +"@ c #38316A", +"# c #323B6C", +"$ c #393A6E", +"% c #3C3C70", +"& c #3D3670", +"* c #441D66", +"= c #461D69", +"- c #491C6B", +"; c #4C1D70", +": c #412267", +"> c #422369", +", c #422B6C", +"< c #48206D", +"1 c #43316D", +"2 c #4A316F", +"3 c #4B3672", +"4 c #443E74", +"5 c #493C74", +"6 c #463671", +"7 c #503874", +"8 c #1E546D", +"9 c #1C596F", +"0 c #1F5771", +"q c #1D5B74", +"w c #264669", +"e c #2C436E", +"r c #244C6C", +"t c #29486F", +"y c #274467", +"u c #31426F", +"i c #21526E", +"p c #2D4770", +"a c #264D71", +"s c #284A70", +"d c #354371", +"f c #344C74", +"g c #3D4A77", +"h c #3D4E78", +"j c #3A4573", +"k c #225472", +"l c #205873", +"z c #2B5B78", +"x c #3E557B", +"c c #345C7B", +"v c #3E5B7E", +"b c #1A6175", +"n c #196473", +"m c #2A657B", +"M c #33627D", +"N c #38627F", +"B c #454175", +"V c #484276", +"C c #404977", +"Z c #4A4679", +"A c #4D4A7B", +"S c #454A79", +"D c #53457B", +"F c #524C7E", +"G c #5B467E", +"H c #41547C", +"J c #3A6681", +"K c #396983", +"L c #3D7688", +"P c #584C80", +"I c #445E81", +"U c #4D5D84", +"Y c #555281", +"T c #5A5684", +"R c #5A5986", +"E c #565E87", +"W c #614D83", +"Q c #635386", +"! c #6C5B8C", +"~ c #68578A", +"^ c #426282", +"/ c #476987", +"( c #5A638A", +") c #576B8C", +"_ c #4D758D", +"` c #49788D", +"' c #557B93", +"] c #5B7D95", +"[ c #5A7592", +"{ c #64618C", +"} c #68638E", +"| c #6C6B93", +" . c #636F92", +".. c #736593", +"X. c #786695", +"o. c #746C96", +"O. c #7A6D98", +"+. c #786895", +"@. c #637394", +"#. c #6E7397", +"$. c #6D7698", +"%. c #6D7C9B", +"&. c #717197", +"*. c #75759A", +"=. c #797299", +"-. c #727A9B", +";. c #7B7C9E", +":. c #7E7FA1", +">. c #82759E", +",. c #847DA2", +"<. c #8A7CA4", +"1. c #5B8799", +"2. c #65859C", +"3. c #6B839D", +"4. c #618D9E", +"5. c #75809F", +"6. c #6B8FA2", +"7. c #7487A1", +"8. c #7E85A3", +"9. c #738AA2", +"0. c #7C8BA5", +"q. c #7795A8", +"w. c #7895A8", +"e. c #6F95A5", +"r. c #7FA4B1", +"t. c #8184A4", +"y. c #8A8BA9", +"u. c #8788A8", +"i. c #928CAD", +"p. c #9485AA", +"a. c #8A94AE", +"s. c #859BAF", +"d. c #9192AF", +"f. c #8D9BB1", +"g. c #9594B1", +"h. c #9D92B2", +"j. c #949BB4", +"k. c #9B9AB5", +"l. c #988EB0", +"z. c #A69CBA", +"x. c #A29AB7", +"c. c #8AA6B5", +"v. c #93A2B6", +"b. c #9BA5BA", +"n. c #95AABA", +"m. c #9DABBD", +"M. c #A5A4BC", +"N. c #AAA4BE", +"B. c #A4ABBF", +"V. c #9FB7C3", +"C. c #ADA6C0", +"Z. c #A6AEC1", +"A. c #AEADC3", +"S. c #B2ACC4", +"D. c #B1A7C2", +"F. c #ABB4C5", +"G. c #A5B9C6", +"H. c #A8B4C5", +"J. c #B3B1C7", +"K. c #BAB4CA", +"L. c #B3BBCB", +"P. c #BBBCCD", +"I. c #B6B6CA", +"U. c #C2BACF", +"Y. c #C0BED0", +"T. c #B3C3CE", +"R. c #BBC0CF", +"E. c #B7C7D1", +"W. c #BBC1D0", +"Q. c #B6C8D1", +"!. c #BCCBD4", +"~. c #AAC0CA", +"^. c #C6C5D4", +"/. c #C9C5D5", +"(. c #C9C8D7", +"). c #CCCBDA", +"_. c #C5CED9", +"`. c #CFD6DF", +"'. c #C6D6DC", +"]. c #D3D3DF", +"[. c #CEDCE1", +"{. c #D5D6E1", +"}. c #DAD7E2", +"|. c #D6DCE4", +" X c #D9DCE4", +".X c #E1DDE7", +"XX c #E2DFE9", +"oX c #D5E0E5", +"OX c #DBE0E7", +"+X c #DFE5EA", +"@X c #E3E4EB", +"#X c #E4E9ED", +"$X c #EAE9EF", +"%X c #ECEDF2", +"&X c #EDF1F3", +"*X c #F2F2F6", +"=X c #F6F6F8", +"-X c #F8F7FA", +";X c #F6F8F9", +":X c #FFFFFF", +">X c None", /* pixels */ -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE039;=>=&$#@###@##%&:-%42,uEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEr82>%&+++O@@+######@#####@+##++#+$&=25eEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE81:%++++@####$########################@@O+O#;>2wEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE4>&$+++##########################$##############++++%:55EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEr5*#@+###################################################++#%:qEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEr2&@O##$#######################$################################@O#>rEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE3;+O##$################################$###########################$#+O%>rEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9>#++#####################################################################@++=1EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5%@+@##########################################################################@@#1yEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5$O################################################################################@+O;pEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEr<+o#$##################################################$##############################$$+o:qEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEu>#+#$#####################################################################################$$+O;qEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5@+#############################################################$###############################++=9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9#O#################################################################################################@@,EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEq;o#$###################$##############################$#######################$########################O@8EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE>O@#######################################$##############################################################$#O&9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE0#O#################################################################################$#########################++>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEf:O@########################$##$#####################$###########$################################################+#9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEq#+####################################$########$#############################################$######################O,EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEO####################$##############################$###############$##################ofRRRRRRRRRRRRRRRRK-+######################$#############################################@olEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEaX######$#######################################################################$#######$ofRRRRRRRRRRRRRRRRK=O$#######################$######################$####################$O>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE%@######################################################################################$XfRRRRRRRRRRRRRRRRK=@$#############################$#######################################oyEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9o$#############################################$##########$############################$$ofRRRRRRRRRRRRRRRRK-+###############$###############################################$######+=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE#@###################$######################################################$########$###$XfRRRRRRRRRRRRRRRRK=+#######$###############################################################OeEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEqo########################################################################################$ofRRRRRRRRRRRRRRRRK-+##############################$########################################+%EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE#@########################################################################################$XfRRRRRRRRRRRRRRRRK-+#####################################$###############$##################oqEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEwX############################$########$####$#############$################################$XfRRRRRRRRRRRRRRRRK-+$#######################################################################+&EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE$@###################################################################$#####################$XfRRRRRRRRRRRRRRRRK=+$###########$#####$######################$##########$####################XiEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEeX$##########################################################$###########$#############$####$ofRRRRRRRRRRRRRRRRK=@$######$####################$#############$#############################$+=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEE*+$#############$#####$#####################################################################$odRRRRRRRRRRRRRRRRK=+###########################################################$#############$OyEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEtO$###########$#######################$######################################################$ofRRRRRRRRRRRRRRRRK=+##########################################################################+>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEE>+###########################################################################################$ofRRRRRRRRRRRRRRRRK;+###########################################################################OgEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEf+############################$####################################################$##########$XfRRRRRRRRRRRRRRRRK=+$#################################$########################################+5EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEE5+############################################$########$######################################$XfRRRRRRRRRRRRRRRRK=+$#########################$#####################$####################$#####@$EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEE&+####$############################$################$#####################$##################$$ofRRRRRRRRRRRRRRRRK-+##############$#######$#####################################################OwEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEr+#############################################################$##############################$$XfRRRRRRRRRRRRRRRRK=@#$######################################################$##################$O>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEE3X$#########################$##############$###################################################$XfRRRRRRRRRRRRRRRRK=+$##############################################################$##########$#@@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEE@@$############################################################################################$XfRRRRRRRRRRRRRRRRK=+$##$#########$########################$######################################X9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEErX$####$#######################################################################$################$XfRRRRRRRRRRRRRRRRK-+$############################################$###############################+;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEE2O################################$##############################################################$ofRRRRRRRRRRRRRRRRK-@####################################################$##########################@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEE%###################$##############################$################$#############################ofRRRRRRRRRRRRRRRRK=+###############################################################################+rEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEf+#########################################$#######################################################ofRRRRRRRRRRRRRRRRK=@$#$#######################################$####################################+2EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEq+#########################$#############################$$#########@####@#@######@####@######@####XfRRRRRRRRRRRRRRRRK=O##@@##@#@@#################$##$#################################################=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEE<+###################################################@+OOOOOOO++++++++@+++@+++@+++++++@+++@++++++++.sRRRRRRRRRRRRRRRRK&+@##@$###@##########################################$############################+jEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEE&+##############################################$#OXo@&>8rshzvnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnDRRRRRRRRRRRRRRRRRSASAASASSAADb#@###################################################################OrEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEu@##############################################+XX&5sbSPRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRH$@###################################################################+2EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEErO##################################$#########@X#9cDYRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF$+############################################$######################+:EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEE3O##########################################@X=iSYRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF$@#####$#####################$#######################$###############+$EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEE;+#######################################$@X%pJRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#@####################################################################+aEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEE%+######################################$+oqARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF$@#################################$#######$##########################+5EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEE+############$####$##############$#####$X&vTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#@##################$#################################################O5EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE9+######################################X2SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#@###############################################################$####+>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE9O###$###############################$@XqLRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#+###############################$####################################@%EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE>+##################################$@XyTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#+####################################################################@$EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE;+#############################$#####XuTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF$@####################################################################$+EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE%@$###################$##########$##XwTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF#@#$######$###########################################################$+qEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE#@###############################$$X3PRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRD#+@+@++@@+@+@++#########$########################$#####################+1EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE#######$##########$##############%+%DRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRF$@@@@@+@@+@@+@@########################$#######$######################$O8EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEq+###############################$#XcRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRFO8NNNMNNNNNNNMN3+$####################################################$@:EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEpo############################$###X9TRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRFXuRRRRRRRRRRRRRwo$#######$############################################$@=EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE4+###############################+$ARRRRRRRRRRRRRRRRRRRRRRRRRRRTYIPPPPLPLLLLPPPPPPPPPPKPLLLLLLLLPPPLLPLYRRRRRRRRRRRRRRRRRRRRRRRRRRRRRHXtRRRRRRRRRRRRRqO$###################################################$#+;EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE=################################XyRRRRRRRRRRRRRRRRRRRRRRRRPSvs92>;:::;;::::::::::;::::::::::::::::;::&jRRRRRRRRRRRRRRRRYnvvvbbbvbbbnhXuRRRRRRRRRRRRRqO$########$$###########################################@&EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE<@$#############################@%DRRRRRRRRRRRRRRRRRRRRRRSf3#XXoO++++++++++@O+O@+++++++++++++++O+++++@.sRRRRRRRRRRRRRRRRK$.XOXoXXXOXoOXuTRRRRRRRRRRRRqO$######$$$$$$$$$$$$$$##################################%EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE5O$##################$##########orRRRRRRRRRRRRRRRRRRRRRHr%XX+#$$$##########$$$#$##############$$######ofRRRRRRRRRRRRRRRRK=+####@$@#@##.uRRRRRRRRRRRRRqO$#$####XXXXoXXXXoXoXO##########$#######################@EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE<+##############################+ARRRRRRRRRRRRRRRRRRRRv=XO#$##########################################odRRRRRRRRRRRRRRRRK=+#####$$$###XuRRRRRRRRRRRRRqO$#####%fcxxxxxxxxxxci#@################################@jEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE,@$########$###$##############$O4TRRRRRRRRRRRRRRRRRRTao+####################$########################$ofRRRRRRRRRRRRRRRRK=+###########XuRRRRRRRRRRRRRqo$####@%KRRRRRRRRRRRRA#+###############################@#dEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE;@#############################XzRRRRRRRRRRRRRRRRRRTaX#$###########################################$#$ofRRRRRRRRRRRRRRRRK=+###########.iRRRRRRRRRRRRRqO$#####%GRRRRRRRRRRRRC@@#################################rEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE=###############$#############+%GRRRRRRRRRRRRRRRRRRxX+#######################################$#######$odRRRRRRRRRRRRRRRRK=@$#########$.iTRRRRRRRRRRRRq+$####@&GRRRRRRRRRRRRC@+#####$##########################@qEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE=@##$########################$X8YRRRRRRRRRRRRRRRRRD$O##############################$##################ofRRRRRRRRRRRRRRRRK=+$#########$.iRRRRRRRRRRRRRqo$####@$GRRRRRRRRRRRRC@@################################@wEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE=#############################XgRRRRRRRRRRRRRRRRRRqX#####################################$###########$ofRRRRRRRRRRRRRRRRK-+##########$XuRRRRRRRRRRRRRqO$#####$GRRRRRRRRRRRRV@@#################################qEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE:+###########################@+BRRRRRRRRRRRRRRRRRZ+##################################################$XfRRRRRRRRRRRRRRRRK=+###########XpRRRRRRRRRRRRRqO$#####&GRRRRRRRRRRRRC@@###########$#####################tEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE<+$######################$###O:HRRRRRRRRRRRRRRRRRwo$#################################################$ofRRRRRRRRRRRRRRRRK=+###########XrKKKKKKKKKKKKK9+#####@$GRRRRRRRRRRRRC@+################################@fEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE<+#$#########################X6TRRRRRRRRRRRRRRRRH&+##################################################$XfRRRRRRRRRRRRRRRRK&X+o++o++o+o+@%;;;;;;;;;;;;;%######@&GRRRRRRRRRRRRC@+#################################sEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE5O$###################$######ouRRRRRRRRRRRRRRRRRxO#############$################$####$##############$$ofRRRRRRRRRRRRRRRRTmnnnnnnnnnnnz:O++@++++++@+++########%HRRRRRRRRRRRRC@@#################################EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEE1+$###############$##########OlRRRRRRRRRRRRRRRRRrX####$#######################################$######$XdRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPO###################################################$ofRRRRRRRRRRRRRRRRRRRRRRRRRRRRRK>>>>>>::,HRRRRRRRRRRRRZ@+###################$##########$@;EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEyO$#########################+;KRRRRRRRRRRRRRRRRnO+####################$##############################$XfRRRRRRRRRRRRRRRRRRRRRRRRRRRRRK,O$#########XtIUPIIPIIPIRRRYIIIIIIIIIB@@############$##################@;EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE###########################+O$#########XyRRRRRRRRRRRRRw oXoooooXO################################$o9EEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE###########################O9RRRRRRRRRRRRRRRRT9X$########################$########################$$$XfRRRRRRRRRRRRRRRRRRRRRRRRRRRRRKO$#########XuRRRRRRRRRRRRRyO$#########################################+EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEE<+$#########$##############OsRRRRRRRRRRRRRRRRK>O$#######$#####################$####################$$XfRRRRRRRRRRRRRRRRRRRRRRRRRRRRRKO####################################################$ofRRRRRRRRRRRRRRRRRRRRRRRRRRRRRK>O####$#####X9NNMMMMMMMMMMB6+####$$$$$$$$$$$########$################+>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEs########################$oyRRRRRRRRRRRRRRRRP2o########################################$###########$odRRRRRRRRRRRRRRRRRRRRRRRRRRRRRK>>>>>>>>>*@#######################+eEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEE>+#######################O9RRRRRRRRRRRRRRRRTrX################################################$###$olRRRRRRRRRRRRRRRRRRTRRRRRRTRRRK>O$#############################XeIIIIIIIIIIsO$######################@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEE9+#######################O3TRRRRRRRRRRRRRRRRaX########################$#########$#################$XlRRRRRRRRRRRRRRRRLtrtrrrrrtrtte=@##############################XrRRRRRRRRRRho$#####################+;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEs+#######################+>IRRRRRRRRRRRRRRRRzX@###################################################$obRRRRRRRRRRRRRRRRHO.XXXXXoXXXXX#$############################$$OrRRRRRRRRRRho$###########$#########+3EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEE&#############$#########@=GRRRRRRRRRRRRRRRRB+@################$###################################OBRRRRRRRRRRRRRRRRF%##$$#$$$#$################################$$XrRRRRRRRRRRgo$#####################OaEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEE5O$#####################@$CRRRRRRRRRRRRRRRRG;O###$#################################################SRRRRRRRRRRRRRRRRS@@###########################################XrRRRRRRRRRRgo$######################EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEyO$#####$###############@+vRRRRRRRRRRRRRRRRY4o####################################$##############+&KRRRRRRRRRRRRRRRRV+############################################orRRRRRRRRRRgo$#####$##############+:EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEE$@######################ofRRRRRRRRRRRRRRRRRaO##################################################$X3URRRRRRRRRRRRRRRRnO########################$###################XrRRRRRRRRRRgo$####################orEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEE3O$###############$#####oeRRRRRRRRRRRRRRRRRB@@#####################$###$#######################$XuRRRRRRRRRRRRRRRRRlX#####################$######################XrRRRRRRRRRRgo$###############$####@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEsX$#####################O1PRRRRRRRRRRRRRRRRT1O$#################################################obRRRRRRRRRRRRRRRRRsX%####$##############@OOOOOO+OO++############XrRRRRRRRRRRgo$#########$#########O>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEE$+############$########+&SRRRRRRRRRRRRRRRRRjX$########################################$#######O&GRRRRRRRRRRRRRRRRRwO####################&9qq99999993############XyRRRRRRRRRRjo$###################oyEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEE2o$####################@XvRRRRRRRRRRRRRRRRRK;+$#$#############################################XeTRRRRRRRRRRRRRRRRR4+###################X5TRRRRRRRRRZ+###########O8ZCCCCCZCCZrO$##################@@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEa+@#####################XyRRRRRRRRRRRRRRRRRRzX###########$#####################$#############++NRRRRRRRRRRRRRRRRRK;+#######$##########$o3IRRRRRRRRRC+##############@@##@@#@######################+>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEE%+####################%o>LRRRRRRRRRRRRRRRRRY9X##############################################X9RRRRRRRRRRRRRRRRRRZ++###################o4IRRRRRRRRRC+#############+++++@++++####################$OpEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEE9+######################OCRRRRRRRRRRRRRRRRRRG:X############################################O&SRRRRRRRRRRRRRRRRRRjXO++#################o4URRRRRRRRRC+###############$##########################$@%EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEv+######################XiRRRRRRRRRRRRRRRRRRRA:.@########################################$O+nRRRRRRRRRRRRRRRRRRRSvbbv;@###############o4IRRRRRRRRRC+###########################################O6EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEE>+$###$################@;LRRRRRRRRRRRRRRRRRRRG7X+#######################################o#nRRRRRRRRRRRRRRRRRRRRRRRRR2+###############X5IRRRRRRRRRC+####$###################$####$#############@EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEsX$$####################oxRRRRRRRRRRRRRRRRRRRRUj%X+##################################@Oo3ZRRRRRRRRRRRRRRRRRRRRRRRRRR1+###############o4IRRRRRRRRRC+#######################################$#$+>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEE;+#########$###########O3TRRRRRRRRRRRRRRRRRRRRRHs>@oOO++@@##@#####@#########@@#++OXX#4cYRRRRRRRRRRRRRRRRRRRRRRRRRRT1O###############o3URRRRRRRRRC+################$#########################XgEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEaX$####################@+bRRRRRRRRRRRRRRRRRRRRRRRPnp5>%#+OXXXXXXXXXXXXXXXXoXoO+#&>9fZTRRRRRRRRRRRRRRRRRRRRRRRRRRRRR2+###############o4IRRRRRRRRRC+###########+XXX.O#################$#####$+=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE%+#####################X3IRRRRRRRRRRRRRRRRRRRRRRRRRTHABbvxllzllzlzllzllllllcvnBSKRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRT2+###############X5RRRRRRRRRRA+##########@4faddw#@######################oaEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEqO######################XzRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR<+###############+>lcxxxxxxxva@##########ojRRRRZ@+#########$###########O=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE%+####$###############$o;HRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR2+#################O+O+++++OO+###########ohRRRRC@@#####################ouEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE8O$#####################owTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRHGGGGGGD,@##########$#############@##########$###OhRRRRV@+###################$+=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE%#######################olRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRB%&&&&*=&$########################################ojRRRRA#+###################$OaEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEtO$#####################@#BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRL<.+O++OO+#########################################+pFDDGc#@###################@=EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE&+######################o&ARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRpX##################################################$$%#%######################XsEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEao#######################o;ARRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRv+@#############$#####################################@@######################$X2468888868688888888688888858854<:&+XXX+$$##################################$########################$#######################+aEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE@@############$######################@@OOXoXXXOooooXoXXOXXXXXooXoXoooooOOOO@##$####################################################$###############################$X9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEuX#################################################################################################################################################################O>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9X########################################################################$######################################$######################$#######################$+#EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE>o$#################################################################$###########################################################################################+jEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE=+################################################################################################################################################$###########OrEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEO@##########################################################################################$###############################################################XqEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEh+#$############################################################################$#####################$####################################################X3EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEErX@$$$##############################################################$####################################################################################OO+$##################$################$###################$##########################################@O%qEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEw=O###########################################$#####################################################++3EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE6%+@############################################################################################@+,hEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE2$O##########$##############################################$################$###########$%@++:eEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5%O@####################################################################################O@>8EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9=++########################################$#######################################O@3iEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9:@+#####$####$#########################$#########################$#########$$@++%5EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEr<%++@#$##################################################################+O#:qEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE5>$++#$###########################################################$$+O+;4wEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE6:#O+####$####################################################@O+&3yEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE9;%@O@@##############$#################################@++#=3aEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE94;%+@@@@#####################################@#@++$=<9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEe3;=$+++@+####$#$$#$#$#######$###$###++O++#&:24EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEw33=&$@@@O@@+O@@@####@@+++#OO@@#==230rEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEfE*1<;==$##%=;>3>=69>uEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", -"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X< < : = * * < : : * : : * : : < : : : < > : > > >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; * < * * : * * * * * : * * : : * * * : * * : : * : : * : > : : : : : : > > , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; * - * * * : * * * : * * * : : * * * : : * : * * : * * * * : * * : * : : : : : : > > : > > > > , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; - - - * - * * * * * * * * * * * : * * * : : * * * : * : : * : : : : * : > : : : < : : : : : : : : > : > > , > >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * ; - * * * * * * * * * * * * : * * * * * * * * : * * : * : * : * : * * : : : : : * : : : : : : : : : : : : : : . : . : : X , , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; * * * - - * * * * * * * * * * * * * * * * : * * : * * * : * : * : * : * : : : : : : : : : : : : : : : : : : : : : . : : : : , , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * - - * * * - * * * * * * * * * : * * * * : * * : * : * : * : * : : * * : : * : * : * : : : : : : : > : : : : : > . : : . : : : X . . . . . X , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; ; * * * * - - * * * * * * * * * * - * * * * * * : * * * * : * * * * : * : * : : : : * : : : : : : : : : : : : : : > : : : . . : . : . . > . . . . . X . , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; - * * * * * * * * * * - * * * * * * * * * * * * * * * : * : * * * : * * : : * : * : : : : : : : : : : : : : : : : : : : : : : . : . . : : : . . . . . . . . . . X . . X . , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; - - - * * * * * * * * * * * * * * * * * : * * * : * * : * : * * * : * * : : : * : * : * * : * : * : : : : : : : : : : : : : : . : . : : . . . . . . . . . . . . . . . . . . . X X X 1 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * * : * * * : : * : * : * : : : * : : : : : : : * : : : : : : : > : : : . : : : . . . : . . . . : . . . . . . . X . . . . . X . X X . 1 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; ; * * - * * * * * * * * * * * * * * * * * * * * * * * * * * : * * * : * : * : * : * : * : : * : = : : : : : : : : , : > : : : : : : : . : . : . . . . . : . . . . . . X . . . . . . . . X . . . X X . X 1 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; - * * * * * * * * * * * * * * * - * * * * * * * = * : * * * * * : : : * : : * : * : * * : * : * : : : : : : : : : : : : : : > > : : . : X . : X . . . : . . . . : . . . . . . X . X . X . . X . o . X . X X X X >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; ; - - * * * * * * * * * * * * * * * * * * * * * * : * * * * : : : * * * * : * * : * : * : : : : : * : * : : : : : : : : : : : : : : : : : : . : . . : X . . . : X . . . . . X X . . X . X . . X . . X X X . X X X X >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * * * * - * * * * * * * * * * * * * * * * * * * * * : * * * * * * : * * : * * : * : * * * : * : : : : : : : * : : : : : : : : : : : : : . : : . : X . . : X X . . . > X X . . X . . X . X X . X X . X . X X X X X X & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; ; - * * * * * * * * * * - * * * * * * * * * * * * * * * * * * * : * * * : * * : * : * * * : * : : : : * * : : : : : : : : : > : : : : : . : X . . : : X . . . . . . . . . X . . . X X X > X X . X X X X X X X X X X X X 6 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - - * * * * - * * * * * * * * * * * * = * * * * * * * * * * * * * : * * * : * * : * : * : * : * * : : : : * : : > : : : : : : : : : : : : : : : . : . : . : : , . : . . . : . . X . . . X . . . X . . . o . X X X X X X X X X X X X X X X @ X X X X & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * - - * * - * * * * * * * * * * * * * * * * * * * * * : * * * : * * : * : * * : * * : : : * : * : : : * : : : : : : : : : : : : : : : : : . . : . : . : : : : : . . : X . . . . . X . . X . . X . . . . X . > X X X X X X X X X X X X X X X X @ , X & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * - * * * * * * * * * : * * * : * * * * * * : * * : : * * : : : : * : : : : : : : : : : : : : , : . . : . . : . , : , 7 ~ >.h.N.^.^.Q . . . . X . X X . X . X X X . X . X X X X X X X X X X X X X X X @ @ X X @ X @ >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : : * : : * : : * : * : * * : * : * : : * : : : : . : > : : : : . : : : . > 3 +.N.].*X:X:X:X:X:X:X+.: . X . . . X . . . X X . . X . o X X . X X X X X X X X @ X X X X @ X X @ X X X & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * - * * * * * * * * * * * * * * * * * * - * * * * * * * * * * * * * * : : : * : * * : * : * : * * * : * * : : : : : : : : . : : : : : : : : +.U.=X:X:X:X:X:X:X:X:X:X:XO.. X X : X . . X X X . X X X X X X X X X X X X X X @ X X X @ @ X X @ X o X X @ X @ @ & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : * * : : * * * * * * * : * : * * * * > : * = > * : : * : : : : : : : : : : : X : : . . 1 p..X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. . . X . X X X . X . X . X X X X X X X X X X X X X X X X X X X @ X X X @ @ X @ X X @ @ >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; - - * * * * - * * * * * * * * * * * * * * * * * * * * * * * * * * : * * : * * * * : : : : * : * : * * : * * > : : : : : : : : : : : : * , X : : : : 2 p.%X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. . . X . X . X . X . X X . X X X X X X X X X X X X X X @ @ X X @ X @ X @ X @ @ @ @ @ @ @ & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * - * - * * * * * * * * * * * * * * * * * * * * * * * * * : * * * * * : * * : * * : * : * : * : : * : * : : * = : : : : : . : : : . . : X : : X..X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. X X . X . X . X X X X . X X X X X X X X X @ X X X @ X X X X @ X @ X @ X X @ X @ @ @ X @ @ & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * - * * * * * * * * * * * * - * * * * * * * * * * * * * * * * * * * : * * * : : * : * * : : : : : : * : : : : = : : : : > : : : : , 7 N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. X . X . . X X X X X X X X X X X X X X @ X X X X @ X X @ X @ X X @ X X @ @ X @ @ @ @ @ @ @ @ @ >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : : * * * * : : * * : * : : * : * * : : : : * : : : : * : : : : : . : . : : : : ! @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X . X . X X X X . . X X X X @ X o X X X X X @ X X X @ X X X @ @ @ X @ o @ @ @ @ X @ @ @ @ X @ @ @ & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * - - * * * * - * * * * * * * * * * * * * = * * * * * * * * * * * * * * : * * * * * * : : * : : : : : : * : * : : : : : : * > : : : : : . 2 >.*X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. X . X X X . . X X X X X X X X X X @ X X X X X @ @ X @ X @ X @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * - - - * * * * * * * * * * * * * = * * * * * * * : * * : * * * * * : : * * : * : : * : * * * * : : * : : : : : : : : : > * : : : : . : . : : h.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. X X . X X X X X X X X X X X X X X X X X X @ @ X X @ X @ X @ X o o X @ X X @ X @ @ @ @ @ @ @ @ @ @ + & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- ; - - - * * * * * * * * * * * * * * * * * * * * * * * * : * * * * * * : * * * : * : : * * * * : : : : * : : : : : : : : : : : : : : : : > : x.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X . X X X X X X X X X X X X X X @ @ X X X @ @ X @ X X X @ o X @ X @ @ @ X @ @ @ @ @ + @ @ @ @ + @ @ % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * ; - - - * * * * * * * * * * * * * * * * * : = * * * * * * * * * * * * * : * * * : * : : * : * * * : : : : : : : : : : : > : > : > : : > : z.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.. . X X X . X X X X X X X X @ X X X @ X X X @ X X X @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + o o @ @ + + & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; - * * * * * * * * * * * * * * - * * = = * * * * * * : * = * * * * : * : : * * * * : * : * * * : : : : : : : * : : * : : : : : : : > h.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X . X X X X X X X X X X X X X @ X X X X + X + X @ X @ @ @ @ X @ X @ @ @ X @ @ @ @ @ @ @ @ @ @ + + + + @ @ + + & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; * * * * * * * * * * * * * * * * * * = * * * * * * * * * * * * : * * * * * * : : * : * : * : : * * : : : : : : : : : : : : : : > : : : : : : > +.=X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X X X X X @ X X @ X X @ X o X X X X X @ X @ X @ @ @ @ X @ @ @ @ @ @ @ @ @ @ @ @ + + @ @ @ + @ + + + + @ + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; - * * * * * * * * * * * * * * * - * * * * * * * * * * * * * : * : * * * : * * * * : * * : : * > : : : : : : : : : : : * * . : . : : > : W $X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X X X X X @ X X X X X X @ X X o @ @ X @ X @ @ @ @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ X + @ + + @ + + $ + + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; - - * * * * * * * * * * * * * - * * * * * * * * * * : * * * : * * : * : * * * * * * * : * * : : : : : : : : : : : : : : : . : . : . : > , ^.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X X X X X X X X @ X o o X X @ o X X @ X @ X @ @ @ @ @ @ X @ o @ @ + @ @ o @ + @ @ + @ + + + + @ + + + @ + + + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * - - * * * * * * * * * * * * * * * * * * : * * * * * * * * : * * * * : * : : * * * * * : * > * : * : : : : : : : : : : : : : , X . : : : . : l.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X X X X X X X @ X @ @ X X @ X @ X X @ @ X @ @ @ X @ @ @ @ @ + @ @ o @ @ + + @ + @ + @ + + @ + + + + + + + + + # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; - * * * - - * * * * * * * * * * * * * * * * * * * * * * * : * * * * * : : * * * * * : * * * * : : : : : : : : : : : : : : : : : : : : : : : . . : . . X : G =X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X o X X X X X @ @ X X X X X o @ X @ X @ @ X @ o @ @ @ @ @ @ @ @ @ @ @ @ X + @ @ + @ + + + + + @ + + @ + + + + + + + + + % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * * * : * * : * * * * * * > : * : : : : : : : : : : : : : : : , : : : . . : . , D.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X @ @ X X @ X X X @ X @ @ X @ X @ @ @ @ X @ @ @ @ @ X @ @ @ @ @ @ @ + + @ + @ + @ X + + @ + + + + + + + + + + + # + + % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; - - * * * * * * * * * * * * * * * * * * * * * * * * * * : * * * * * * : * * : : * : * * * * : : : : : : : : : : : : : : : : : X : : : : : . . X > ~ :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X X X X @ X @ X @ @ @ X X X @ X @ @ X @ @ @ @ @ o @ @ @ @ @ @ o + + o + o + @ + + + + + + @ + + + + + + + + + + + # + % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * - - * * * * * * * * * * * * * - * * * * * * * * * * * * * * * : * : * : * : : * : * : : * * * : : : : : : : : : : : : : * : : . . . > > K.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X X @ @ X X o X @ X X @ @ @ X @ @ @ @ @ o @ @ @ @ @ @ @ @ @ @ @ + o @ + X + + + + @ + + + + + + # + + + + + + + + + + + # % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * - * * * * * - * * * * * * * * * * * * * * * * * * * : * : * * * : * : * : : * : * * * * * : : : : : : : : : : : : : * . . . : > X , P -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ X @ X X X X @ X @ X @ @ X X @ @ @ @ X @ X @ o @ @ @ @ @ @ @ @ + @ + + + @ + + @ + @ + + + @ + + + + + + # + + + # + # O + # + % >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * - * * * * * * * * * * * * * * * * * * * * * * * * * * * : * * * : * * : * : * * * : * : * : * : : : : : : : : : : : : . : . : . : : . : X . . . . : . . . : N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X X X o X X X X X X @ @ X X @ X + X + X @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + + + @ + + + + + + + + + + + + + + + + + # + + # + + # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : * * : * * : * * * * * * * : : : : : : < : : > : : : : : : . : . : : X : . . . . . X : X . 3 $X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ @ X X X @ @ @ @ X @ @ X @ @ X + X X @ o @ @ @ @ @ @ @ @ @ + @ @ @ + @ + @ @ + + + @ + + + + + + + + + @ # # + + # # + # + # + + # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : * * : : * * * : : : : * : : : : : : : : : : : : : . : . : . : . : : : . X : : . . . . . : X +.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XO.X X X X @ @ X @ X X @ @ X + @ X + @ X + @ @ @ @ @ @ o @ @ + @ @ @ @ + + + @ + + @ + + + + + + + + + + + + + + + + + + + # # + # + # # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * - * * * * * * * * * * * * * * * * * : * * * * : * * : : : * : * : : : : : : : : : : : : : : : : . : . : : : . : . : . . : : , X . . . : . . X : J.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ X o X @ X @ X @ @ X @ X X @ + X X + + X @ + @ @ @ + @ + @ + @ @ + + + + + + + + @ + + + + + + + # + # + # @ # + # # + + + # + # # + # + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : : : * : * : * : : : : * : : : : : : : : : : : : : : : : : . : . : . . : . X : . . : . : . . . . , @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ X @ X @ @ X @ @ @ @ @ + X + X + + X + @ @ o @ @ + @ @ + @ + @ + + @ + + + + + + + + + + + + + @ # @ # + + + # + + # # + # + + # o # + # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : * * : * : : : : * * : : > : : : : : : : : : : : : : : : . . . . : . . : X : : X . X . . X , G :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.X X @ X @ X @ @ @ X + @ @ X + X @ + X X + @ + @ @ @ @ + @ @ + + @ @ + + + + + + + + + + + + + # + + @ # + # + # + # + # + # + # # + # # # # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * : * : * * * : : : : : : : : : : : : : : : : : : : > : : X . . : X X : : X : X . . X . . , X >.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ X @ X @ @ @ @ + X X + @ + + @ + + + X @ @ + @ + @ @ + @ @ @ + @ + + + + + + + + + + + # + + + + + # + + # # + # # # + # # + # # # # # + # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * * * * * 2 * * * * * * * * * * * * * : * : * * * : : : : * : : * : : : : : : : : : : : : : . . : : X : : X : . . X . . : X : , J.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.o X @ X @ X @ @ X X @ @ X + X X + X X + + @ @ o + @ + + + + + + + + + + + + + + + + + + + + + + + O + + + # + + # + + # # + # # # + # # # # # # d >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * * * * * * : * * : * : * : * : : * : : : : : * : * : : : : * : : : : : : : : : : : : . : . : : . . . . : : : X X : X . . X X . . . (.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X X + @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + + @ + @ + @ + @ + + + + + + + + + + + + + # + + + # + + # + # + # + # + # + # # # # # # # # # # # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * : * * * : * * * * * : * : * * * : : * * * * : : * : * : : : : : : : : : : : : : : : : : . : : : X . . : X X : X : . . . . . . . X . @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.o @ X @ @ X @ @ X @ X @ @ @ @ @ @ @ @ @ + @ o @ + @ + + + @ + + + @ + + + + + + + + # + + + # # + + # # + # + + # # # # # # + + # + # # # # # + # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- - * * * * * * * * * * * * * * * * : * * * * * * * * * * * * * : * * * : : : * : : : : : * : : : : : : : : : : , : : : : : , X : : . X : : X : . . . X : X X . . X . X . . . . 1 *X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ @ @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ + @ + @ + + + + + + + + + + + + + + + + # + + + # + + # + # + # + # + + # + + # # # # # # # # # # # # O >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * * * * * * * : * : : : : * : : : * * : : * : : * : : : : : : : > : : : : : : X X : : . . , : , : . . : X : X : : . X : . X . X X X 7 :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ X @ @ @ @ @ @ @ @ @ @ @ @ + @ @ @ @ + @ + @ + + + + @ + + + + + + + + + + + # + + # + # + + # + + + # # + # # # # # # # # # # # # # # # # # O # O d >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * : * * * * * * * * * * * * * : : : * * * * * * : : : : : : : : * : : : : : : : : : : : : : : . . . . : X : : X . . . . X : X : X . X . X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ X @ @ @ @ @ @ @ @ @ @ @ + @ @ @ + @ + @ + + @ + + + + + + + + + + + + + # + # # + # + # + + # # # + # # # + + + # + # # # # # # # # # # O O O # # O >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * : : * * * * * * * * : * * * : : * < : : : : : : : : : : : : : : : : : . : . : . . : X . . . . X . . X X X . . . X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.X @ @ @ @ @ @ o @ @ @ @ @ @ @ + @ @ @ + @ + @ + + + + + + + + + + # + + # + + + + # + + # + # + # # + + # # + # # # # # # + # # # # # O O # # # # # # O # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * * * : * 2 * * * * : * * * * * * * : : : : : : : : : : : : > : : : : : , : : : X X : : : X : X . . X . . . . X . . X . X . X X 7 :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + + + @ + @ + + + + + + + + + + # + + + + + + # # + + # + # + # + # + # + # # # + # # # # # # # # # # # # # O O # # O O # # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * - * * * * * * * * : * * * : : * * * * * * * * : * : * * : : : : : : : : : : : : : : : > > : : : : X : : . . : X : X X : . X , X : . X . X . X . . X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.X @ @ @ @ o @ @ + @ @ + @ @ @ + @ + @ + @ + + @ + + + + + + + + + + + + + # + + + # + + + + # + # + # # # + # # # # # # # # # # # # # # # # # # O O # O O u u >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * * : * * * * * * * * * : * * : * * : : * : * * : * : * : * : * : : : : : : : : : : : : : : : : : : : . . : . . : X : X : X X . X . . X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ o @ @ @ + @ @ @ @ + + @ @ + + + @ + + + + + @ + + + + + + + + + + # + + + + # # + # + # + + # # # $ + # # # # # # # # # # # # # # # # # O # # # O O O O # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * * * * * * * * * * * * * * * * * * * * : * : * * * * * * * : * : : * : : : : : : : : : : : : : : : : : : X : : X : . X : X : X X , . . X . X X X X X X , X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ @ @ @ @ @ @ + + @ @ o + + + @ + + + + + + + + + + + + # + + # + + + # # $ # + + # + # # # # # + # + O # & # + # # # # # # O # # O # # # O # O d O O # O O u >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; * * * * * * * * * * * * * * * * * * * : * * * * * : : : * * : : * * : * * * : : : : : : : : : : : : : , : : : , . . : . X : X . . X X X X . . . X X . X . X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=.@ @ + @ o @ @ @ + + @ + @ @ + @ + + + + + + + + + + + + + # + + + + # # + + + + # # + # + + # + + + O O + # # # # # # # # # O # O O # # O O # O # O O O O O O e d >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * * * * * * * * * * * * * : : : * * : * : : * : : : : * * : 2 : : : : : : : : : : : : : : : : . : X . : X : X X : X X X . X X X X X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xo.@ @ @ @ + + + @ o @ @ + + + @ + + + + + + + + + + + + # + + + + # + # + + + # # + # # + # # # # # O + O O # # # # # # # # # # O O d # O # # O O O O # O O O O O # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * * * * * * * * : * * * * * * * : * : * * : * * : * : : * : : * : : : : : : : * : : : : : : : : : : : : : : : , . . . . : : : X : X X X X X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XR @ @ @ @ @ o @ @ + @ + + @ + + + + + + + + + + + + # + # + + + # + + # + # # # + # + # # # # # + # + O + O # # # # O # O # # # # # # # O O # O O # # O O O O O O e u >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X7 * * * * * * * * * * * * * * * * * * * * * : * : : * : * * * : : : : * : : : : : : : : : : , : : : : : : : : , . . . . . X X X X X X X X X X X X X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X@X% @ @ @ + @ @ + + @ + @ + + @ + + + + + + + + + + + + + + + + # + # + + # + # + + # # # + # + + O O O + O + # # # # # # O # O # # # O # # O O p # O O O O O O # e # e >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * * * * * * * * : * : * * : * : * * : * : * : : : : * : * : : : : * : : : : : : : : : : : . : X : : . X . X . X : X X X X X X X . X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X^.@ @ + + @ @ + @ + + + + + + + + + + + + + + + + + + # # + + # # + + # # + # # + # # # + # + O # # + + # # # O # O # # # O # # O O O # p O O O O O O O O O O O e O O e # >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * * * * * * * * : * : * : : * : : * : * : * : * : * * : : : : : : : : : : : : : : : : X . : . , : X , . X . . . X X , . . X X X X X X X . X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xy.@ @ @ @ @ + @ + @ + + @ + + + + + + + + + + + + # + + + + # + + # + # + # + + # # + # + # O + # O + O O + O # # # # # O # # O # O # # # # O # O O O O O O O # O p O e e u >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * : * * * * * * : * * : * * * : * * * * * : : : : : : : : : : : : : : . : : : : : . : : : : X : . . . . . : . . : , . . . . . . X X : X X X X X X X X X X X X X X X X X X P :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XY + X + o + + @ + + + + + + + + + + + + + + # + + + + + + + # # + # + # + + # # + # # + O + # + O # # # # # # # # # O # # # O # # O O O O # O O O O O O O O O O O e O e O e >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X= = * * * * * * * * * * : = : * * : * : * : * : * * : * : * : * : : < : : : : : : : : : : : . : . : : . : : . . . : X : X : . X : . . . X . X X X X X X X X X X X X X X X X X X X X X X @ X Z :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X).+ + + + @ + + + + + @ @ + + + + + + + + + + + # + + + + # # + + # + # + # # + # # + # O + O # # # # # # # # O O # O # # O O O O O O # # O O O O O O O O O O p O O O e O e e p >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * * * * * * : * * * * : * : * : * * * : : : * : : : * : : : : : : : : : : : . : : . : : , : . X : . . . : X : X . . X X : . . . . X X X X X , X X X X X X X X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xi.@ + @ @ + @ @ + + @ # # @ + + + + + + # + + + + + @ # + # # + # + # + # # # # # + # # # # O + # # # # # # # O O # # O O O O # O O # O O O O O O O O O # e O d O e O e e e e e >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X= * * * * * = : * * : * : * * * : * : * : * : * * * * * : * : : : : : : : : : : : : : : : X : : . : : . X . . : : : . . . : : X . . X : X . X X . X X X X X X X X X X X X X X X @ X X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*XA + + + X + # @ @ + @ # @ + + + + # # # + + + # + O # + # # + # + # + # # + + # # # # # # + O # # # # # # O # # # # O # O # # O O d O O O O O O O O O p e # e e e O e e # e e # I >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * : * * * * * : : : * : * : * * : * * : * : : : : : : : : : : * : : : : : : . . : : : : . : X . . . : X . . X : X X : X X X X . X . X X X . X X X X X X X X X @ X X X F :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XB.@ + @ @ @ + + + + + + + + + + + + + # + + + O + + + + # # + # + O # + # # # + # + # # + O # + O # # # # # # O + # O # O # O # O O # O O O O O O e # e e e # e e O e O O e e e e O >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X- * * : * * * = * : : : * * * * : * : * : : * : : : * : : * : : : : : : : : > : : : : : : X : X : : . . . X . . . . . X : X X . X X . X X X X X X X X X X X X X X @ X X X X X X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*XA + @ + + + + + + + + + + + + # + + + + + + # + + + O + # # + + # + # + # + # # # # # # O O + # # # O # # O # O O # # O # O O O O O O O O O O O O # e # # O e e # O e e e O e O e p O >X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * * * * * * * : * * : * : * : : * : : : * * : : : : : : : > : : : : : X : : : : . : X X : X . . X : . . X X X : X X X X X X X X X X X X . X X X X X X X X X X X X @ X @ X X X A :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xi.+ X + + + + + + + + + + + + + @ # + + # + + + + # + # # # + # + # + # # # # # # # # # # + O O # O # O # O O + O O d # O O O O O O O O O O O O p p e e e e O d e e O e O e e e e e O s >X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X< * * * * * : * : : * * : * * : * : * : * : : * : : * * * : : : : : * : : : : : : : : : : . : , : : X : . . . . . X . X : : X X . X X X . X X X X X X X X X X X X X X X X X X X o X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X/.& + + + + + + @ + + + + + + + + + @ # + + # + O + + # + # + # + # # # # + # # # + # # # # # + O # # # # # O O O # O O O # O # O O O O O O O O O O O # e # O e e e # e e e e e O e e p O p >X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X* * * * * * : * : * * * : : * : * : * * : : * : : : : : : : : : : : : : : : : : : . : : . . : X : . : X : X : X . X X X X X X X X X X X X X X X X X X X X X @ X X @ X o @ @ X o X X A :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X XA @ + + B Y + + + + + + + @ + + + + # + + # # + + # + + # + # # # + # # # # + # # # # # # # # # # # # O # # O # O # O O O O O O O O O O O s O O O O O e e e # O e e e O e O e e e e e p p p >X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X* * : * * * * * * * : : : * : * * : * : : * : : : * * : : : : : : : : : : : : : : . : . : : . : : . : , : . . . : X . X X . : X : X X X X X X X X X , X X X X X X X X X X X X X X X X X X X o @ F :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X}.F + + + + d.*.+ $ + + + + # # @ + + + + # + + + + # + + # + # # + # + # + # # # # # # # # # # # O # O d # # O # O # O O O O O O O O O O O O O O e O e e e # e e e e O e e e e e e e e e O O p p >X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X* * * * * : * : : * : * * : * : * : : : : : < : : : : : : : : : : : : : : : : : : . : . : . . . : X . . . : . . . . . . X X X X X X . X X X X X o X X X X X X X X X @ X X X @ @ X @ X @ @ @ X D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XS.Z + + + + F &X*.+ @ + + + + # + # # + # + + # # + + + + O + # + + # + # # # # # + # # # # # # # O # # # # # # O O O O O O O O O O O O O O O O O O O O e O # e e e e O e O e e e e e e e e e e p p >X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X; * * : * * : * : * : * * : * : * * : * : * : : * : : : : : : : : : : : : : : : . : . : : . : . . . X , : . : X . . X : X . X X X X . X X X X X X X , X X X X X X X X X X X @ X X X X X X @ X X X F :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X).*.+ + + + @ 4 ^.:X*.+ + + + # + + + + + + + # + # + # + O O + # # # # # # # # # # # # # # # # # O # # # d O # # O # O # O O # O O O O O O O O O O O O O s O e e e # e e e O e e e e e e e e e e e p s p >X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X* : * * : * : * : * : * : * : : * : * : : : : : : : : : : : : : : : : : : > : . : . . . : : . . . : X . X . . : X X : X . X X . X X X X X X X X X X X X X X X X X X X X o X o X @ @ @ X X @ X @ 5 /.(.^.(.(.(.^.^.(.(.^.^.^.(.(.(.^.(./././.Y.A.y.Y + @ + + + + + g.:X:X*.+ @ + + + + @ # + # # + + # + # + # + # # + O # + # # # # # # # # # # # # # # # # O # O O # O O O O O # O O O O O O O O O O O O p O e O O e e # e e e e e O e e e e e e s e e e s p >X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X< * : * * : : * * * : * * * * : : : * * : : : : : : : : : : : : : : : : : : : X : . : . . . : . . . X . . . . X X : , X X X X X X X . X . X . X X X , X X X X X @ X X @ X @ X X @ X X X o @ o @ X @ @ + X X X @ X X o @ @ @ @ + @ o @ @ @ + @ + @ @ + @ + + + + + + + u.:X:X:X*.+ # # + + + # + + + + # # + # + # # # + # # + # # # + # # # # # # O # O # # O # O # O O # O O # O O O O O O O O O O O O s O p O O e O e e e e e e e e e e e e e e e e e e s e e e p p >X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X- * * * * * * : : * * : * * : * : * : * : : : : : : : : : : : : : : : > : : . : . . . . . . . : X . . . . . . . X X . X X X X X . X X . . X . X X X X X X X @ X X @ X o X @ X @ X @ X @ X X @ @ X + X + @ @ @ @ @ @ @ @ @ o @ @ @ @ @ + @ + @ + + @ @ + + + + + $ i.:X:X:X:X*.# + + + # + # + # # + + # # + # # # + # + # # + O + # # # # # # # # # # O # O O # O # # O O O O O O O O O O O O O p O O O O O O p O e e O e e e e e e e e e e e e e e e e e e e s p s >X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X< : * : : * : * * : * * * * : : : : : : : : : : , : : : : : : : : : > . . . . . . : . X . . . . . X . X . : X X X X X X X X X X X X X X X X X X X X X X X X X , o X X o X @ X o X @ @ X @ + X @ X @ @ @ o @ @ @ @ @ @ @ o + + o @ + @ + @ + + + + + @ + Y K.:X:X:X:X:X*.+ + + + + + # # + + # + # # # + + # # # + O + O + O # # + # # O # O # # u # # O O # O O O # O O O O O O O O O e O p O O p O p O O e O e e # e e e e e e e e e e e s e s e s e s e p p >X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X* * * * : * : * * : * : * : * : : : : * : : : : : : : : : : : : : . : : : . . . : . . X : X X . : X , X X . . X X . X X X X . X X X X X X X X X X X X X X X X X X X @ X o X X @ X @ @ X @ X X @ @ @ @ @ X @ @ @ @ @ @ @ + o @ @ @ @ @ + + @ + @ + + + Z k.$X:X:X:X:X:X:X*.+ # + + # + + + # # + # # + # # + # + # # # # # # # # # # # # # # # # # # O # # O # O O O O O O O O O O O e O O O p O p O O e O e O e e e e e O s O s s O e e e e s e s e e e s e e s t >X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X: * : * * : * : * : : : : : : * : * : : : : : : : : : : : : : : . : . . : . . . : : : . X X X X : . . X . . . . X X X X X . X X X X . . @ 1 1 6 5 5 4 5 5 4 5 5 4 5 5 B 5 4 B 5 4 V 4 4 B V 5 4 4 B B B B 4 B B B B B B B B C B B B B B C A { y.K.*X:X:X:X:X:X:X:X:X*.+ + # # + # # # + + # + # + # # # + j C C C C C C C C C C C C C h C g h C j I C C d d O O O O O O # e # p O O O O O O O O e O e e O e O e O e e O s O O s e s e s e e e e s e e s t t e >X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X: = * * : * * : : * : : : * * : : * : * : : : : : : : : : : : . : : : . . : . . . . . X X : X . . X X . . X X . X X X X o X 1 5 ~ ,.x.P.].@X&X;X:X:X-X-X:X:X-X:X-X:X-X-X:X-X:X:X-X:X:X-X:X:X-X-X:X-X:X-X:X-X:X:X-X-X:X-X-X:X-X-X:X:X-X:X-X-X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# + + + + # + # + + # # + # # S g. X*X:X:X:X-X-X:X-X-X:X-X:X-X:X-X-X:X:X-X-X-X:X-X:X+Xd.g O O O O e O e O p O p p O e p O e e e O e e e e e e O e O s s O e e e e e s s e e e s e t t t s >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X: * : : * : : * * : : * : * : : : : : : * : : : : : : : , . : . . . . . : . , . . X X X X X X X X . X X X X X 1 G >.N..X*X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.+ # + # # + + # # # + # # # R X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X:X:X:X:X:X:X+X .O O O # e O O O O O O p O O p O e e e e e e e e e s O s O O s e s e e s e e s s s e s e s e t >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X* : * : : * * : : : * : : * : : : : : * * : : : : : : X : . . . . . X . . , X X X X , X X X X . X . X X X X ~ h..X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.+ # + + + # # + # # + # # E %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X( e e e # # e O e O e O e O e O e e e e e e e e t e e O s O O e e s e p e e e s e e t t t t t >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X: : * : * * * * * : : * : : : : : : : : : : : : : : : , : : : . , . . . : . . . . : X X X X X X X . . X G h..X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.+ + # # # # + # # # # # # (.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X@Xu O O e e O p O e O O e e e e e e e e e e e e e e e s e s s t e s e s e t t e s s e t t t t s >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X* * : * : : : : * : * : : : : : : : * : : : : : : : : : : : : , : . . . . . . . X . . . . X X X X . X X : 1 ../.-X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.+ + # + + # # + + + # # | :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X%.O e O O e O O e e O e O e O e e e e e O e e e e s e s e e s e e s t t t e s s e t t t t t s >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X: : * : * * : : : : : : * : : : : : : : : : : : : : : : : . . : . . . . . . . . X X X X X . X . 6 >.].:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # + # # # # # # k.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XF.O O p e O O e O e e e e e t O e e t e s e s s e e e s e s e e s e e t t t e s s s t t t s s >X>X>X>X>X>X>X", +">X>X>X>X>X>X< : : * * * : * : : : : : > : : : : > : : : : : : : . : X : : X : . : : X . . . . . X X X X X X 1 >..X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.# # # # + # + # # # # # P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X{.O e O e e e O e e e e p e e e e e e e e e O s s O s s s O e t t t t t p t t t t s s s s s s s >X>X>X>X>X>X", +">X>X>X>X>X>X: * * : * : : : * : : : * : : : : : : : : > : : : . . . : X X : . : X . . . . . X , X X X X X X ~ ).:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.+ + + # # # # # # # # # P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e O e e O e e O e e e O e e e e e e e s e s O O s s O s s t e t e e t t t t t t p s s s s s s >X>X>X>X>X>X", +">X>X>X>X>X>X* : * * * * : : : : : : : : : : : : : . . : : . . X : : X : . X . . X X . . . X X X X X X 3 N.*X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # + # # # # + # # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X XO e O e e O e e e e e e e e e e e e e e e s O s s O s O s t t t t t t t t t t p s p s s s s s >X>X>X>X>X>X", +">X>X>X>X>X: : : * * : : > : : : : : : : : : : : : : : . : . , X . : : X : : X : : X . . . . . X X X X X ..@X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.+ # + # # # + # # # # # W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e O e O e e e e e e e t e e e t t e t e O s s O s s O s t t e p t t t t t s s p s s s s s s s >X>X>X>X>X", +">X>X>X>X>X: : * = = * : : * : : > : : > : : : . : : . . : : . . : . : . . . X X . X . X X X X , X , 3 N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.+ + # # # # # # # # # # P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe O e e e e e e e e e e e e e t e e t e s s e e s s s s O p t t t t t t t s s s t s s s s s s s >X>X>X>X>X", +">X>X>X>X>X: : : * : * : : > : : : : : : : : : : : > . : . . . : X X . . . . X . X . X X : . . X X X , G ].:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # # # # + # # O W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe e e e e e e e e e e e e e t e t t e e s e t t e O s s s t t t t t t t s p s t s s a s s s s s >X>X>X>X>X", +">X>X>X>X> * : * = * : : : : : : : : : : : : : : : . : . : . X : . . . . : . . . X , X X X X X : X O.$X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # # # # # # # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe e e e e e e e t e e e e t t e e e s e e s O t t s e s O t t t t t t s t s s s s s s s s s s a s >X>X>X>X", +">X>X>X>X: : : : * = : : : : > : : : : > . . . . . . : . . : . X X X . . X X X X X , X 1 l.*X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.# # # # # # # # # # # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e O e e e e e e t e t e e t e t e e s s s e s e s s s t t t t s s t s t s s s s s s s s a s a >X>X>X>X", +">X>X>X>X = > * : : : : : : : : : : : : : , . : . X . . . . . : : X . . X . . X . . . X . X . , X X X 2 M.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # # # # # O O # W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e e e e e e e e s e s e s s e e s e t t e e t t t t t t t s s s s s s s s s s s s a s s a a a >X>X>X>X", +">X>X>X>X* > * : : : > : : : : : : : : : : . . . : : . . . . X . . . . . . . X . X . . X . X X X X 2 N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*.# # # # # O # O # # # O W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e e e e e e s e e e e s e e s s e t s t t t t t t t t t t s s O s s s s s s s s s s a s a s a >X>X>X>X", +">X>X>X> * : : : : : : > : : : : : : : . . . : : . : . . . . . . . . . X X X . . X . X X . : 1 N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # # # # O # # O W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e e t e s e e e s e e e e e e e t t e t t e t t t t s t a t s a s s s s s s s s a s s a s s s a >X>X>X", +">X>X>X> : : : : : > : : : : , : : : . . X X . . . . . . X X . . X : X X X . X X . X o K.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # # O # # # O O # P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.t e e e e e e e s e e s e e s s e t t t t e s s s t t s s t s t r s a s s s a s a s a s r r s a a a >X>X>X", +">X>X>X> : : : : : : : : : : : : . : . : . : : . . . . . . . X X , X X . X . . , X X C.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # O # # # # # # O # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe e e e e s e s e s e s s s t t e t e t t t t s s t s s s s s s a s a s s s s s a s a a a s a s a s >X>X>X", +">X>X>X: : : > : : : : : : : . : . X , . : . . : X . X X . . X X X X X . X X . X l.-X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O # # O # # O O O O O u P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e p e e t e e s e e t e e e t t s s e t t t s e s s s s s s s s s s s s s s a s a s a s a a s s a k >X>X>X", +">X>X>X : : : : : : : > : X : . : : . : . : X . . . . . . : X X X X X X X . X . X X >.*X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.u # # # # # O O # # O e R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe e t p e s e e s s e t s s e e t t t t t t t s s O s s s s s s s s s a s s a s a a a s s a a a a a >X>X>X", +">X>X> > : : : : : : : . . . : , : X : X X . : X . . . X . X X X X X . X X Q *X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# # # # e O O # O O # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xt e t e p e s e e e t e e t t t t t t t s s s s s s s s s s s s s s a s s a s s s s a a a a a a a a a >X>X", +">X>X: : : : : > : : . : . . : . . . . . : , X X X X X X X X X 6 ).:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# O O O # # # e e # # # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xt e p t e e s e t t s t e p t t t t t e s s s s O s s s a s s s a a s s s s a s a a s a s a a a a a a >X>X", +">X>X> : : , : : : : : : . . . . . : . . : : X X X X X , X X X X X X X X X X . . C.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# O # # O e # # # # e e R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e t t e t s e t s t e t s t t t t t t s s s s s s s s s s s s s a s r a a a s a a s s a a a a a a a a >X>X", +">X>X: : : : : : : : . : X : . . . . . : . X . . X X X o X X X X X X X X =.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# O O O O e # # O e # e R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e t t e s e e e t e s t t t t s s s s s s s s s s s s s s s a s a s a a s s a k s a a s a a a a a >X>X", +">X>X: : : : > . . : : . : . . : X . . . . , X X X X , X X X X X X D %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O # # O # # O O O # e # R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.t p t e p s e s t s s e s t t s s s s e s s s a s s s a s a a a s s a a a s a a a a a a a k s a k k a >X>X", +">X> : : . > > : > X : : X . : : X X X : X X X X X X X o X X X X o , X J.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O O O O O O O O O # e O R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.p t s s e t t t e s t t t t t s s s t s s s s a s s s s s s a a s a a a s k a s k k s a a a a k a a a >X>X", +">X, : : : X X : . X . . X : . . X X X X X X X . X X X X ! -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O O O # O O O O O O # e W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.e e e t t t e s t t t t t s t s s p r a s s s s s s s s s a s a s a s s a r s a s s s a k k a s a a k k >X", +">X> : : > > . . . . . : . : . . . . : X X : X X X X X X X X X X X X X X 1 ).:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O O O O O O O O O e # O R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X[.t t t e s e s t t t t s s t s s s s s s s a s s s a t a s s s a s a r a a a s a k a k s k s k s k s k z >X", +">X : : . . . . . : X . . X . . X : X X X X X X X X X X X X X X X , =.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.# O O O O O O O O u e e R.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XL.s e t t s e s t t t s t s s s s s s s s s s s s a a a a s a a r s a a a a a k s s s k a s k s k s k a a >X", +">X: : . : . : . : . . . . : . : X . . . . X . . X . . . X . X X X X X X X X X X X X X , @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.e # e # e O p O O O O O P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xa.t t t t t t t t p s s s t s s s s s s s s r a s s s a a s a s a a a a a a a a a a a a k k a a a k a k a >X", +">X . : . : . . : X . . . . . : . . . . . . . X . . X . X X X X X X X X X X X X X X X X u.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O e # e # O O O O O s p P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&Xv e t t t t t t s s p s t s s s s s s s s a s a s s a s a a a a a a s a a a a a a k a a a a k a a a k a k >X", +">X. : : . . . X : . . . : . X X . . . . . . X . X . . X X X X X X X o X X X X X @ .X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.O # e # e O e O O O s O E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xf.t t t t t t t s s s s s s s a s s s s a s a s s s k s a a s a a a a a a a k a a a a a k a a a a a k s k a >X", +">X: . . . . : : . . . . X X : : X . X . X . . . X X X X X X X X X X X X X , X X X X X <.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.e e # e O O O e e O O O P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-Xv.t t t t t t s s s s s s s s s s s s s s a s s k s a s s r a a a a a a a a a a k a a k a a k k a k k a k a k >X", +". : : . : . . . : . : X . . . : X X : X . . X . . X . . , X X X X X X X X X X X X X (.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-.e # u O O O e O O O p p P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.3.s t t t t t s s s s s s s s s s s s s a s a s a s a s k s a a a a a a a a a k a a a a a a k a a k a a a k a k a ", +"X . . . . . . . . . X . X . . X X . X . X X . X X . X . X . X . X X X X , X X o X ~ :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X$X].^.J.M.k.d.y.u.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.8.t.t.t.8.t.t.t.8.t.8.t.t.8.t.t.8.t.8.t.8.8.t.8.t.0.8.0.0.8.8.0.8.0.8.0.8.8.8.8.0.U O e O O e O O O e O O O [ 0.0.0.8.0.0.0.0.0.0.0.0.0.9.0.0.0.0.0.0.0.9.0.0.0.0.0.0.5./ f t t t t t s s p s s s s s a s s s s s s s s a s a s s s r a a a a s a a a a a a a a k k a a a a k a a k k a k k k ", +": . : . . . . . . . . . X X : X X X . X X . X X X X X X X X X X X X @ X X X z.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X@XY.k.*.R Z % + + o + + + + # o + + # + + @ + + # # + + # + # # + + # # # # # # # # # # # # # # # # # O O O # # # # # # # O # # # O O # e # e # e O O O e e O O p O O p O e e e e e e e e e e t e t e e e t e t e s t e e t e s t t e t t t t t t t s s s s s s s s s s s s s a a s s a s a s a s s a a a a s a a k z a a a a a a a a a a k a i k k a a k a k ", +"X . X : . . . : . . X . . . X . , X X X X X X X . X X X X X X X X X X X X X X X X X 1 @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X{.C.*.A @ + + + + + @ + + + + + + + + + + + + # + + # + # + + # + # + # # # # + + # # + # # # # # # O # O # # # # # # O O # O O O O O # e e # e # e # # e e O O O O e e O e p e O O e e e e e e e e e e e e e e e p p e p e t s e t s t t t t t t t t t p s p s p s s s s a s s s a s s a a r s a a r s a a a a a a k a s a s a k a k a k a k k k a k a k k a k k a k ", +"X . . . . . . X . . X X . X X X X X X X X X . X X X X X X X X X X X X X X ..:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=X).t.A @ + + @ + + + + + + + + + + + + + + + # + + # + # + + # + + # + # # # + + # # # # + # # # # # # # # # O # # O # O # O # O # O O O O O O O O O O O O O e e O e O O O p O e e e e O e e e e e e e e e e e e e t e e e t e t e t e s t e t t e t t t t e s s t s t s s s s s s s a s s a a s s k s a s a k s s s k s a a a a a a a k a a a a a k k a k a k a k k a k a k ", +"> : . . . . . . . . . . X . X X X . X X X X X X X X X X X X X X X X @ X X @ @ N.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X}.y.A @ @ X + + @ + + + @ + + + + + + + + + # + + + + + + # + + # + # + # # # + # # # # + # # # # # # # # O # # # # # # # O # O # # O O O O # O O O O O O O O p O e # e O O p O O e e O e e e e e e e e e e e s e e p e p e t e t s e s e e t s e e t t t t t s s s t s s s s s s s s a s s a s s a s s s a a a a s k k s s k s k a a a k a a k a k a k a a k a k a k a k k k k k ", +"X : : X . . . . . . X . X X X X X . X X X X X . X X X X X X X X @ X X X X o 1 @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;XP.{ @ + @ @ @ @ + + + + @ + + + + + + + + + + + + + + + + + # # + + + + # # + # + # + # + # # + # # # # # # # # # # O O # O O # O # O O O O O O O O O O p O O O O O e O e # u p O p O e O e O e e e e O e e e e e e e t e e e p t t e e s s e s t t t t t t t t s s s t s t s s s s s s s s a s r s a s k s a a a a a s s k s k s a k a k a a a a k a a k k k k a k a a k k a a k k z ", +"> X : X . X . . . X . . X X X X X X X . X . . X X X X X X , X X o X X X o X @ X Q :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*XM.F @ @ + @ + @ + + + + + + + + + + + + + # + + + + + # + # + + # + # + # # + # # # + # # # # # # # # # # # # # # O # # # # O O # O # O O O # O O O O O O O O O e O O O e e O e e O O p O e O e e e e e O e e e s e e e s e p p t e e t t t e t t t e t t t t t t s s s s s s s s s a s s s a s s a a s a s s s s a a a a k s s k a s k s a k a k k a a k k a a k a k a k k k k k k k k a ", +"X X . . X . . X X . X X X X X X X X X X X X X X o X o @ X X X , o X X p.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=XA.F + @ + + @ + @ @ + + + + 4 | A + + + + + + + + # @ # @ + # + # + # + # # + # + + # # + + # + # # # # # # # # # # # # # # # # O O d # p O # O O O O O O O O O O p O O O O O O e O e p e e O e e e e e e e e t e e e e e s e e s e s t e t t t e t t t t e s t t s s t s s s t a s s s s s s s k t s a s a a s s s k a a a a k a k a a k s k a k a a a a k a a k a k k a k a k k k k k k k k ", +" X X X > X X . . X . X X X X X X X X X . X X X X X X X X X X X X , o X @ X o ^.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X].} @ o + + o @ + @ + @ $ Y u.(.&XI.& + + + + + + + + @ # + # + # # + + # # + # + # # # # # # # # # # + # # # # O # # # y # # # O O O O # # # O O O O O O O O O O O O O O p O O e p O e e O O e e O e e e e e e e e e e s e s e e e e t e e t t t s e t t t t s s t s s s t t s s s s s s s a s a s s r s s a s s k r s s a a a a s a s s k s k a a a k a k k a a k a k a k a k k k a k a k a k k ", +" X > X X > . X . X X . X X X X X X X X X X X X X X X X X X o X o X @ X @ @ $X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*Xi.4 @ @ @ @ @ + + @ + Z u.].-X:X:X%XZ + + + # + + + + + + + # # + + + # # + # + # # + + # + # # # # # # # # # # # # # # # # # # u # O # # # O O O # O O O O O O O O O O O s O e O O O e e O e O e e e e e e e e e e e e e e e e e s s e e s t t e t e s t t t t s e s e s s t a t t s a s a s a a s s a a a k r s a s k k s a a a a a a a k s k s k a k k a a i k k a k a k k k k k a k k k a k k k ", +"X X > X X X X . X . . X X . X X X X X X X X X X X X X o X o o X @ X X o X o o D :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X].Y @ @ @ + + @ + @ @ { I.=X:X:X:X:X:X,.+ + + + + + + # # + # # + + # + # + + # + # # + # # # # # + # # # # # # # # # # # # # # e # O O O O # O O O O O O O O O O O s O O O O O e O e e e O e O e e e e e e e e e s e e s e e s e s e e e s e t t e t t t t t t t t s s s s s s t t a a s t s s s a s a a a s s s s s k s s s k a k a a a k k s k s k s k a a k a k a k i a k k k a k a k k k k k k k k ", +". . . X . X . X . X . X . . X X X X . X X X X X X X X X @ X X @ X X @ X X X X X X o.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-XB.$ @ @ @ @ @ @ + $ } {.:X:X:X:X:X:X:X`.+ + + + # + # + + + + + # # + + + + + + # # + + # # # # # # # # # # # # # e # # # # # # # O # # O # O # O O O O O O O O # e O O O p p O O e O e O e e e e e e e O e e e e t e p e t t e t s p e t e t t e s s t t t t t t t s s s s s s s s s s s s s s a s s a r a a s a a a a a a a a a a a a a a a k a a a k a k a k a k k k a k k k a a k k a k k k k a k k k ", +"X . X . . . X . X . X X X X X . X X X X X X X X X X @ X X X X X @ o X X + X + + X i.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*Xt.o @ @ + @ @ @ $ } (.:X:X:X:X:X:X:X:X:X| + + + + + + + + # + # + # + + # # # # # # # # # + # # + # # # # # # # # # # # # # e # # e # O O O O # O O O O O O O # p O O O O O O O p O O e e e e O e e e e e e e e e e e e e e e e t e e s e t t t t t t e t t t t t t t s s s s s s s s s s a s a s s a a a s a a a a a a a a a a a a a a a k a k a a k a a k a a a k k a a 0 k a k k k k k k k k k k k k k k ", +". X X . X X . X . X . . X X X X X X X X X X X @ X X X X X @ @ X X X X @ X X X X @ A.:X:X:X:X:X:X:X:X:X:X:X:X:X:X%X} @ + @ + @ + + Y P.:X:X:X:X:X:X:X:X:X:X].+ + + # + + + + # + # # # + # + + # # # # + + # # # # + # # # # # # # # e # # # e # # # # # # # O # O O O O O O O O O p O O p p O p O e O O O e e e e e e O e e e e e e e p p p e p e e e t e e t t e e s e t t t t t t t s s t s s s s s s s a s s s s s a a s a s a a a a a a a a a a a a a k a a a a k a k a k a a k k a a a k a k a k a k k k k k k k k k k k k ", +"X . . . X . X . . X X X X X X X X X X X X X X X X @ X @ X X X X X @ @ X X + X + @ (.:X:X:X:X:X:X:X:X:X:X:X:X:X@XR @ @ + @ @ + 4 k.&X:X:X:X:X:X:X:X:X:X:X:Xy.+ + + + # + + # + + # + + + # # # # # + # + # # # # # # # # # # # # e # # # # # # # # e e # # e O O O O O O O O O O O O e e O O O O p O e e e e O e e e e e e e e e p e t e t e t e t t e t s e t t s t t t t t t t s t s t t s s s s s s s s s a a a r a a a a a a a a a a a a a a a r r J a a k k k a a k a k a k k k a k k k k k k k k k k k k k k k k k k k k k ", +". . X . X . X X X X . X X X X X X X X X X X X X X X X @ X o X @ @ @ X @ X + X X @ .X:X:X:X:X:X:X:X:X:X:X:X:X@XR @ @ + @ @ @ R (.:X:X:X:X:X:X:X:X:X:X:X:X:XY # @ + + + # # + & # + # + # # # + + # # + # # # # # + # # # # # # e # # # # # # # # # # e # # O O O O O O O O O O O g @.j.Z.F.F.F.F.H.H.F.Z.F.F.F.F.F.F.F.F.F.F.F.F.H.F.F.H.H.H.H.) t p e e t t t e t t t t t e t s s s t s t a s s a t s s s s s s a s a a r a a a a a a a a a a a a a a k a a a a a k k a a a k a k a k a k k k k k a k k k k k k k k k k k k k J ", +"X X . X . X . X X X X X X X X X X X X X X X @ X X @ X X @ X @ X @ X @ X + X X + 6 &X:X:X:X:X:X:X:X:X:X:X:X@XF @ @ @ @ + @ :.&X:X:X:X:X:X:X:X:X:X:X:X:X:X.X$ @ # + # + + + + # + # + + # + # # # + # # # # # + # # # # # # # # # # # e # e # e # e # # # O O O O O O O O p O p :. X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t e t t t t s e t t t t t s s s s s s s s s s s s s s s a s s a a a s s s a a a a a a a a a a a a a a a a k a k k a a k k k a k a k k k a k a k k k a k k k k k k k k k k k k 0 ", +"X X X X . X X X X . X X X X X X X X X X X @ X X X X @ X X @ @ X X X X @ @ @ @ X V -X:X:X:X:X:X:X:X:X:X:X*X{ + @ @ @ + 4 A.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XK.# + + + # # + + # # # + # # + + # # # # + # # # # # # # # # # # e # # # # # # e # # # O O e # e O O O O O O p O p Z.-X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.e t t t t t t t t t e s s e s s s s s s a t s s a t a s s s a a t a a a s a a a a a a a a k a k k a k k a k a a a k k a k k k k a k k k k k a k k k k k k k k k k k k k k k 0 k ", +". . X . . X X X X X X X X X X X X X @ X X X @ X @ o X @ X @ X @ @ o @ @ X @ @ X Y :X:X:X:X:X:X:X:X:X:X-X*.+ o @ + + B ^.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xi.# + + + + + # + # + + # + # # # # + + # # # # # # # # # # # # # # # # # # # e # # e # # e # e O O O O O O O O O j.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t t e t e s t t t t s s s s s s s s s a s s t a s a s a a a a s a a a a a a a a a a a a a a a a a a a a k a a k a i a k a a k a k k a k a k k k k k k k k k k k k k 0 k k 0 k 0 ", +"X X X X X X X X X X X X X X X X X X X X @ X o X X @ X @ X @ @ X + X X + X @ X + P :X:X:X:X:X:X:X:X:X:Xd.@ @ + @ @ A }.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:.+ + # # + + # + # + # # + # # # + # # # # # # # # # # # # e # # # # # e # # # e e # # O # O O O O O O O O O O ) *X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.p t t t t t t t t s s e s s s s s s s s a t a a s a s s s a a s a a a a a a a a a a a a a k a k a a a a a k a k k a k k a k k 8 8 k a k a k k k k k k k k k k k k 0 0 k k k k J ", +"X X X . X . X X X X X X X X X @ X @ X @ X @ @ X X @ @ X X @ X o X @ + X @ @ + X T :X:X:X:X:X:X:X:X:XS.$ @ + @ + Y @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.+ # + + # # + # + + # # + # + # # # # # # # # # # # # # # # # # # e # # e # e # # # e O O O O O O O O O p p O Z.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.e t t t t t t t s s s s s s s s s s s s t a t s a s s a a a s a a a a a a a a a a a a k a a a a k a k k k a k a a k k a k k a J r k k k k k k k k k k k k k k k k 0 k k 0 k 0 0 ", +"X X X X X X X X X X X X X @ X X X X X X X o X @ @ X @ X @ @ @ @ + X + @ @ @ @ X T :X:X:X:X:X:X:X:X@XV @ @ @ + Y @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.+ # + # + # # # + # # # # + # # # # + # # # # # # # # # # # # e e # # # # # # # # e # O O O O e e O e O O O O @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t t t t t t s t s s s s s s s s s s a s a t t a s a s a a a a a a a a a a a a a a k k a a a k a a k k a a k a k a k a k k a k k k k k k k k k k k k 0 k k J k 0 0 k 0 0 k k 0 0 ", +"X . X X X . X X X X @ X X X X X X @ @ X X X @ X X @ X @ X @ X @ X + X @ @ X + + T :X:X:X:X:X:X:X;X| @ @ @ $ F OX:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.# + # + # # + # # # + + # # # # # # # + # # # # # O # # # e # # # # e # e e # e e # e O O O O O O O O p O p h *X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t t t t t s t s e s s s s a s s a s s a t a a a s a a s a a a a a a a a a a a k a a a a k a a k a a a k a k k a k a k k k k a k k k a k k k k k k k i 8 8 r k 0 k 0 k k 0 0 k 0 ", +">X. X X X X X X X X @ X X X X X X @ o X @ @ X @ @ X @ @ @ X @ @ @ X X @ @ + @ @ T :X:X:X:X:X:X:XA.+ @ $ + 4 ).:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X| + + # # + # # + + # # # # # # # # # # # # # O # # # # # # # # # # O O # O # # e # e # O O O e e O O e O O O h ;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t t t s t s t s s s s a s s s s t a s a s a a a a s s a a a a a a k a a a a a a a a k a k a a k a k a k k a k k k a k a k k a k k k k k k k k k k k k k 8 8 i k k k k 0 k k 0 >X", +">XX X X X X X X X X X X X X @ o o X X @ @ X @ X @ X @ X @ @ @ @ @ @ + @ + X @ @ T :X:X:X:X:X:X@XV + @ @ + P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # + # # + + # # + # + # # # # # # # # # # # # # O O e # # e # # O O O O e O # e # e O O e O O O e O p O O I ;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.t t s s s t s t s s s s s s s s s r a s s r s a s k a a a a a a a a a a a k a k a k a k a a k a k i k a a k k a k k k k k k k k a k k k k k k 0 k 0 k 0 J 0 k k 0 k k 0 J 0 J >X", +">XX X X X X X X @ X X @ @ X @ X X @ @ X @ X X @ @ @ X @ X @ @ @ @ @ @ @ @ @ @ @ T :X:X:X:X:X:X,.+ + + + g.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X$.# + # + # # # + # # # # # # # # # # # # O # # O # O O e # e # e # O # O # e O e # e # e O e O O e e O O O e h :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.s s s s s s s s s s s s s s s a a s a a s a a s a a a a a a k a a a a a a k a k a a k k a k a k a a a k k a a k k k k a k k k k k k k k k J r i k k k 0 0 a 0 0 0 0 J 0 0 0 J >X", +">XX X X X o o X X X X X X @ X X @ X X @ X @ X @ X @ @ @ @ @ @ @ @ @ + X + + X + T :X:X:X:X:X).% + @ + | :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=X&.+ # # + # + # # # # # # # # # # # # # # # O # # # O # # # # # e # O O O e # e # e # e O e O O e O O e O e e I -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.s e s s t s a s s s s s a a s a s a a s a s a a a a a a a a a a a a k a a a a a a k a i a a k k i k a k k k k k a k k k a k k k k k k k k k 8 0 k 0 k k 0 0 0 8 J 0 0 0 0 0 0 >X", +">X. @ X X X X X X @ X X o @ X o @ X @ @ @ X @ X @ X @ @ @ @ @ o @ @ @ @ @ @ @ o T :X:X:X:X:X&.@ + + B @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# # + # # # # # + # # # # # # # # e # # # # # # e # # # # O # O O O # O O O O e O O e O e O e O e O O O e O H -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.p s p s s s s s s a a s a s s a a a a s s a a a a a a k s k a a a k a a a a s k a k a k a k k a k k a k k a a k a k k k k k k k k k k k k k k 0 0 J i i 0 0 0 k J k k 0 0 k J >X", +">X& X X X X @ X X X @ X X X + X X @ X @ @ @ @ X @ @ @ @ @ @ @ @ @ @ @ + @ + + @ T :X:X:X:X^.+ # + + B.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.+ # # + # + # # # # # # # # # # # # # # e # # # e # e # e O O O O O e O O O O O O O O e O O O e O e e e e e H :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s s s s s s a s s s s s s s a s s s a a a a a a a a a s a a a a a a a k a k k s a a a k k a a k a k J k k k k k k k k k k k k k k k k k 0 k 0 k k k 0 0 k k k k k 0 k 0 0 k J >X", +">X@ @ . X @ X X + @ X @ @ X X X @ X @ @ X X @ @ X @ @ @ @ @ @ + @ @ @ @ o + @ @ T :X:X:X:X=.+ + @ { -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# + # # # # # # # # # # # # # # # # # # # e # # # # # # # e O O O O O O O O O e O O e O e e O e e e O e e e x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s s s s s s s s s a s a a a a a a a a a a a a s a s a a a a k a a k a a a k a k a a a k k a k k a k a k k k k k k k k k k k k k k k k 0 k 0 k 0 k 0 0 0 k k k k k 0 k 0 0 0 0 >X", +">X@ . @ X X @ X X X @ X X @ X @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ o @ @ @ + @ + @ + T :X:X:X}.$ + + % ].:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.+ # # # # # # + # # # # O # # # e # # e # e # # O e O e O # O O O O O # # J O O e e O e O e e O e e e e e e x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a s s s s s a a s r s a a s s a s a a a a a a k a k a k a a k a a a k k k a k a 0 k k a a k a k k k k k a k a k k k k k k k k k k k 0 k 0 k k k k k k 0 0 J k 0 0 0 k J q 0 J >X", +">X>XX X @ X X @ @ X X X @ X X + @ X o @ @ @ @ @ @ @ @ @ @ @ @ @ + @ @ + @ @ + @ T :X:X:Xi.+ + + *.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# # # # # # # # # # # # # e # # # # # # # e # # e O O e # # e O O O # O O O O s O O s O e O e e O e e e e e h -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s s s s s a s s s s a a a a s a a a a a a a a a a a a a a a k a a a k a k a k a a a s k k a k k k k a k k k k k k k k k 0 k k k k k k J 0 k 0 k 0 k k k J 0 0 0 0 0 0 J 0 0 >X>X", +">X>X@ X @ X X + X @ X @ X + + X @ X @ @ @ @ @ @ @ @ @ @ + @ @ @ + o @ @ + + + @ T :X:X=XA + @ & X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # # # # # # # # # # # O # # # # e # # e # # O # # O O e # # O e # e O p p O O O O O O e e e e e e O O e e x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s s a s s s s r a a a s s a a a a a a a a a a a a a k a k a a a a k k a a k a k k k k a k k a k k a k k k k k k k k k k k k k 0 0 k 0 k k J 0 k J k k k 0 k k k 0 0 0 0 0 q >X>X", +">X>X@ X X X @ X @ X X @ X + X + @ @ @ @ X @ @ @ @ @ @ @ o @ + + + @ o + @ @ + + T :X:XA.+ + # *.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&.# # # # # # e # # # e # # # # e e # # # # e e O # e O O O # e e # e e O O O O O O O O e e e O e e e e e e e x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s r s s a s a a s a a s a a a a a a a a a k a a a k a k a a k a k a k a k a k a a k k k k k k k k k k k k k k k k k k k k k k a 0 k k 0 k k 0 k 0 k k 0 0 k k 0 0 J q 0 0 l >X>X", +">X>XX @ @ X X X X @ @ @ @ X @ X @ X @ @ @ @ @ @ @ @ @ @ + @ @ o @ + + + + + @ + T :X:X=.+ + $ {.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# # # # # # # # # # # # # e # # # # e e # # # O O O O O e e e # e # e O O p O O s s O e O e e e e e e e e e H :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s a s s s a a s a a r a a a a a a a a a a a a a a a a k a k a k a k a k a k k a k k k k k a k k k k k k k k k k k k 0 k 0 k 0 0 k k 0 0 k k 0 k 0 0 0 0 0 0 J 0 0 0 k q l q >X>X", +">X>X@ @ X @ X @ @ @ @ @ @ X @ @ @ @ @ o + @ @ @ @ @ @ + @ @ + @ @ + + @ + @ + + T :X$X% + + #.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# # # # # e # # # # # e # # O # # O O # # e # e # e # O O # e # # e e O s O O O O O O s O O O O O s O e e e x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a s a s a a a s a a a a a a a a a a k a a a a k a a k a a a 0 a k 0 a 0 a k k k k k a k k k a k k k k k k l k k k k k 0 k 0 k 0 k 0 0 k k k 0 k 0 0 0 0 k q l k 0 q J 8 8 8 >X>X", +">X>X>XX @ X @ @ X @ X @ @ @ @ @ @ @ X o @ @ @ @ @ + @ @ + + @ @ # @ + + + + + + T :XI.@ + + A.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# # # # # # # # # # e # # # e # # O O e e # e # e # e # e e # e e # e O e O s O s s O O O s s s s O s e e e x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s s a s s s a a a a a a a a a a a a a a a k a k k a a k a k k a a a k a k a a k k k k k k k k k k k k k k k k k 0 k 0 k 0 k a 0 k k 0 k 0 J 0 J J 0 0 0 q k q q q 0 9 9 J 8 >X>X", +">X>X>X@ X @ @ X @ @ X @ @ @ X @ @ @ @ @ @ o + @ o + + @ @ + + + @ + + @ + + + + R :X-.# + % %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # # # # # # e # e # # # # # e # O O # e e # e # e # e e # e e e e e e O e e O O s O s O s O O s s O t t e x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s a a a a a s a r a a a a a a k a a a a a a a a s k a k a a a k a 0 a 0 k k k k a k a k k k k k k k k k k k k 0 k k k 0 0 k 0 k 0 k k 0 0 0 0 k 0 0 0 J k q l 0 0 0 q 8 q >X>X>X", +">X>X>X@ X @ @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ @ @ + @ @ + + + + + + @ + + R -XZ + + ;.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # # # # # e # # # # # e # O O e O O e # # # e e # e # e e e # e # e e e O O s O O s s O O O s O O s e e t x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s a s a s a a a s a a a a a a a a k a k k a k a k a k a k a k a a a k a k a k k k k k k k k k k k k k k k k k k k k J k k k 0 0 J k k 0 k k 0 k 0 0 0 k 0 0 0 q 0 q 0 J l >X>X>X", +">X>X>X+ @ @ @ @ X @ @ @ @ @ @ @ @ @ @ @ @ @ @ + @ + @ + + @ + @ + @ + + + + + + R }.+ + # S.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.# O # # # e # # # # e # # e # # e # O # e # e e # e e e e e # e # e e e O e e O s s O O s O O O p s O t e t x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a s a a a a a a a a a a a a a a k a a a k a a k s k k s a k 0 a k k a k k a k k k k k k k k k k k k 0 k k k k 0 k 0 k 0 0 k k 0 0 0 i i 0 0 0 0 0 J q k q k q q l l q >X>X>X", +">X>X>X@ X @ X @ @ @ @ @ @ @ @ @ @ @ @ + + + @ @ o + @ + @ + + + + + + + + + + + R A.# + % @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.O # # # # # # e # O # e # O e e # e O e # # e # e e # e # e e e e e e e O e e O O O s s O O s s O O s e t e x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a s a a a a a a a a a a a k a a a k a a k k a a k a k k k k k k k 0 k a k k k k a k k k k k k k k k k k 0 k k q k k 0 k k J k k J k k k 0 J 0 0 0 q 9 8 q k l q l k q q q >X>X>X", +">X>X>X>XX @ @ X @ @ @ @ @ @ @ @ @ @ + @ @ o + @ + + + @ @ + + @ + + + + + + + + R t.+ + R :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# O # # e O # # # e # O O O O # e # # # e e # # e e e # e e e e e e e e e O e s O s O O s s s O s s O e t t x -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.s a a a k a a k a a a a a a a a a a k a a k a k a k k a a a k a k a k k a k a k k k k k k k k k k k k k k k k k k J k 0 0 J 0 0 0 0 0 0 0 0 8 0 8 8 9 J k q l l l q q l >X>X>X>X", +">X>X>X>X@ @ @ @ @ @ @ @ @ @ @ @ + o @ @ + + @ + @ @ + + + + + + + + + + + + + # R { # + y.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # O # # # e # e # # O O O O # e e e e # e e e e # # e e # e e e # e e O s e O s O O s O s O s O s s t e t x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a a a a a a a a k a a l a a a k a a k a k a k a a k k k k k k k k k k k k k k k k k k k k k k 0 0 k k 0 0 k 0 k k k 0 k k k 0 k 0 i J 0 8 8 J J 8 8 q l q l q q q l >X>X>X>X", +">X>X>X>X@ + X + @ @ @ @ @ @ @ + @ + X + @ + @ @ & @ + + + @ + + + + + + + # # + A A # # Z.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#.O O O # O O # # O O O O O e # e # e e O O e O e O e O e O e e e e e e e O e e t e e e s s O s O s s O e e t x :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a a a a k a a a k k a a a a k a k a k a k k k a k k k k k k a k k k k k k k k k k k k k k k k 0 k 0 k 0 k k 0 k 0 k 0 0 0 k 0 0 0 0 J 0 0 J i 0 J i 8 J 8 J 8 8 0 q >X>X>X>X", +">X>X>X>X+ X @ @ @ @ + o @ + o + + o + + + @ + + + + + @ + + + + # + + + + + + + $ $ + + ].:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.# # O O # O O O O O O O O # e # e e # O O O e e O O O e e O e e O e e e e e e e e e t O s s O O s s O t t p s &X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a a a a a a a a a a k a a k a k a k a a k a a k a a a k k k k k k a k k k k k a 0 k k k 0 0 0 k 0 k k k 0 k k k 0 k k J 0 k i 8 0 0 0 0 0 0 0 0 0 0 8 J 8 0 8 J q q >X>X>X>X", +">X>X>X>X>X@ @ @ @ @ @ o o + o @ + @ + X + + @ + + + + + + + + + + + # + + + # + # + # $ %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X$.O O O O # # O O O u # O e # # O O O e O p O e O e O e O O e e e e e e e t e e e e e t e e t e s s s s t t t t P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a k a a a a k k a a a a a k a k a a k k k k k k k k k k k k a k k k k k k k k k k k k 0 k J k k 0 k k k J 0 k 0 k J k 0 0 0 0 0 J J 0 0 0 k 0 8 J J 8 8 8 8 J 8 8 J >X>X>X>X>X", +">X>X>X>X>X@ @ @ @ @ @ + + @ + @ @ + + + @ + + + @ + + + + + + + + + + + + + + # + + # Z :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X8.O O # O O O O O O O e e # e e e e # e e O e O e e e e e p e e e e e e e e e e e t e e s e e t s O O s e t t e [ :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X6.a a a a a a a a a a k a k a a k a k a k a k a a a k k k a k k k k k k k k k k k k k k 0 k 0 k k k 0 k k 0 0 0 0 0 k 0 0 k J k k 0 i 8 0 0 0 J 0 i 0 0 0 8 J 8 8 J 8 8 >X>X>X>X>X", +">X>X>X>X>X+ + X @ @ @ @ + @ @ + + @ + + + + + + + + + + + # + + + + + + + + + # # + # R :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xa.# # O O O O e # O e # O O O O O p O e e O e e e O e O e e e e e e e e e e e e t t e e t e t e e t t s p t t e p T.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.k a a a k k a a k a a k a k a k k a k a k a k k k k a k k k k k k k k k k k k k k k 0 k 0 k 0 k k J 0 0 k 0 0 J 0 0 0 0 k J i 0 i 0 0 i J 0 J 8 0 J 8 J 8 8 J 8 q l q >X>X>X>X>X", +">X>X>X>X>X>XX + + + + @ @ @ + + + + + + + @ @ + + + + + + + + + + + # + # # + + + # + #.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XB.# e O O O # e e O # e p O O p e # p O O e e O e e e e e e e e e e e s e e s e e e e t e t e t t s e e t t t t s s |.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a a a a a k a a k a k a k a k k k a k k a k k k k k k k a k k k k k k k k 0 0 0 k 0 k 0 k k k k k k k k k k 0 k k J 0 0 0 0 8 J J 8 8 8 8 8 0 8 8 8 8 J 0 8 J q >X>X>X>X>X>X", +">X>X>X>X>X>X+ + @ o + @ + @ + @ + X + + + + + + + + + + + + + # # + # + + # # + # + # 8.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X Xe e # O O O # # e e O O O O O O p O O O e e e e e e e e e e e e e t e e s e s e e s e O t e t t t s t t t t t e t s B.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X9.a a a k a a a k a k a k a k k k a k k k k k k k k k k a k k k k k k k k k 0 k 0 k k k 0 k 0 k k k k k 0 0 0 0 0 k k 0 k 0 0 0 0 0 0 J 0 8 0 J 8 0 8 J J 0 8 J J q q >X>X>X>X>X>X", +">X>X>X>X>X>X+ + + @ @ @ + + @ + + + + + + + + + + + + # + + + + + + + # + + + # + # + u.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xj # e O O O e e # # e p O p O O O O p e e O e O e e e e e e e e e e e e e e e s s e t t t t t t e e t t t t t s s s s I m._.OX@X+X+X+X+X@X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X3.k a a a k a k a a k a a k a a a k a a k a k a k k k k k k k k k k k k k k k 0 k 0 0 k k 0 k k 0 J k 0 0 0 J k 0 0 J 0 0 0 0 0 J 0 0 8 8 8 J 8 8 J 8 8 0 J 8 8 8 q q >X>X>X>X>X>X", +">X>X>X>X>X>X>X@ + + @ + + + + + + + + + + + + + + + + + + # # + + + # + + # # + # + O y.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X7.# # O O s O O O O O O O e O O e O e e e e e e e e e e e e e p t t e e e s e e s e t e e s t s e s t t t t t p s s s s s s s s r s s s s a s a s t a a s a a a a a a a a a k a a a s a a a a k a k a a k a k a k k k k a k a a k k k a k k k k k k k k k k k k 0 k k k k 0 k k k k k 0 0 k 0 0 k k k 0 0 0 k J 8 0 J 8 0 J 8 8 8 J J q q q q q q q q q >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X@ + @ + @ + + + @ @ + + + + + + + + # # + + + + # # + + # + # + # # # # y.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XP.# e O O O O e O e e e O O e e e e e O e p O O e e e e e e e e e e e s e s e e t t t s t t e e t s t t t s s s s s s s s s s s a s s a s s a a a a a a a a a a a a a a a a a a a k k a k a k a k k a k k k a k a a k k k k k k k k a k k k k k k k k k k k J 0 k k k k J k 0 J 0 0 0 0 J k 0 J k 0 0 0 0 0 J 0 0 0 0 8 0 0 0 J 8 8 8 0 q 0 q q q q q q >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X# @ + + + @ @ # + + + + + + # # + + + # + # + # + + # # + # # + + + # + t.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XH O O O e O O e e O O O e e e O O e e e e e e e e e e s e s e e e t s e e s e s t t e s t t t t s e t t s t s s s s s s s s a s s a a s a s s s a s a a a a a a a a a a a a k a a a a a k a a k a k k a k a k k k k k a k k k k k k k k k k k k k k k k k 0 k 0 k 0 0 k k k k 0 0 k 0 k 0 0 0 0 0 0 0 J 0 0 8 8 8 8 0 8 J 8 8 8 J 8 0 0 q q q q q q q >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X+ @ + + # @ @ + + + + + + + # + + + + + + + # + + # + + # + # # + # # :.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XL.e O O O O e O O e e e e O e e e e e e e e e e t e e e e e s e t e e e s e s e t e s e t t t t s s t s t s t s s s s s s a s a s s s s a a a a a a a a a a a a a a k a a a k a k a k a a k k a k a a k a k a k a k k k a k k k k k k k k k k k k k k k 0 k 0 k 0 k 0 0 k 0 k 0 J k 0 0 0 0 0 k 0 J 0 0 0 0 J 0 0 J J 8 J 8 J 8 8 J q J q q q q q q >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X+ + @ # @ @ + + + + + + + + + + + + + + + # + # + # # # # + + # # + # #.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XU s O p O O e O O e O O e e O e e O s O e e e e e e e e s e t e t s e e s e s s t t t t t t t s t s s s s s s s s s a r a s s a a s a a a a a a a a a a a a a a a a k a a s k a a k a a k a k k a a k k a k k k k k a k k k k k k k k k k k k k k k 0 k k 0 k 0 0 0 0 k 0 k k J 0 i 0 0 0 0 i 0 0 0 0 0 0 0 J 8 0 8 8 0 J 8 0 8 8 q q q q q q q q >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X# + + + @ # + + + + + # + # # + + O + O # + + + + # + # # # # # # # # ( :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X].O O O O e O e e e e e e e p e e O s e e e e s e s e e e t e t e e s s e e t e t t t t t s s t s t s s s s s a s s s s s a s a s a s s a a a a a s a a a a k a k a a a k k a a k a k a a k a a k k a k k a k a k k k k k k k k k k k 0 k k k k k 0 k 0 0 0 k k k k J k 0 0 0 0 0 i J J i 0 8 J 0 0 0 8 J 0 8 8 J 8 J 8 8 8 J J 8 q q q q q b q m >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X+ + @ + + + + + + + + + + + O + O + + + + + O # + + # + # + # # # # C :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xa.O p O e e O e O e e e e e O e s O s O s e s e s e s e t t t e s e s s s t t t t t t s s t s s s s s s s s s s s a a s a s r a a a a a a a a a a a k a a a k a a k a a a k k a k a a k k a k k k k k k k k k a k k k k k k k k k 0 k k k k J k k 0 0 0 k k k J k k k 0 J k k k 0 0 i J J 8 8 8 J 0 J 0 0 8 0 8 8 8 J J 8 J 8 8 q q q q q q q >X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X+ $ @ # @ + + + + # + + + + + + + + O + O + + + # # # + # # # # # # + %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X%.p O O e e e e e e O t e e e O s O s O s e e e e s e e e t t e s e s t t t t t t s s t s t s s s s s s s a a s s s s a a a s s a a a a a a a a a a a a a a a a a a k a k a k r k k k a k a k k a k k a k k k k k k k k k l k k k 0 k 0 k k k k k k J k k k 0 0 0 k 0 0 0 0 0 0 0 0 0 0 i J 0 i 0 i 0 0 J J 8 J 8 8 0 J 8 8 J q q q q q q q >X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X# + + + + + + # + + + # + + + # + + # # + # # # + # + # # # # # # # # |.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*X@.p e e u e e e e e e e e e e p e t e e e t e t e s e t t p e t t t t t t t s t s s s s s s s s t s s s s a r s s s s s s k s s s k s s k s a a k k a a k a a k a k a k a k a k k a k k a k k k k k k k k k k k k k k k k k 0 k k 0 8 k J 8 i 0 k 0 k J 0 0 0 0 0 0 0 0 0 J 0 k 0 0 8 8 0 8 0 0 q 0 q 0 q q q q q q q q q q q q q q q q m >X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X+ + + + + # + + + # + # # + + # # # + # # + # + # # # # # + # # + # J.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*X@.e e e e e e e e e e e e e p e e e t t e t e s e t e t t t t t t t t t t s s s s s s s s s s a s a a a s a s s k s k a a s k s k s k s k a a a a k a a a s k a k k a k a k a a k a k k k k a a k k k k k l k k k k k k k k 0 k k 8 8 8 8 0 0 k k 0 k k 0 0 0 k J 0 0 0 0 0 0 i J J 0 J 8 q q q q q q q q q q q q q q q q q q q q q q >X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X+ + # + + + @ # # @ + + + # # # + + # & # # # # # # + # # # # # # # u.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xa.e e e e e e e e e e t e t p e t e t t e e e t t t t t t t t t t s t t t s s s s s s s s s s a t a t a s a a s s s s a s k s s a a a k a a k a a a k k k a k a a k k r k k a k k a k k k a l k k k k k k k k k k k l 0 0 k k k k J 8 0 k k J 0 J k k 0 0 0 0 0 0 J 0 0 J 0 0 0 8 8 8 J q q 0 q 0 J q q q q q q q q q q q q q q q b >X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X# + + + + + @ # # # + # + + # # # + # # + # + # # # # # # # # # # ( :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X_.H t e e e e e t e t p e e t e t t e s t t t t t t t t t t t s s t a s t s s s s s a s s a a a s a a a a s a k r a a k s s k a k a s k a a a a k a a a k a k k a k k a k k k k k k a k k k k k k k k k k k k l k k k k 0 k J 0 k 0 J 0 0 0 0 0 k 0 0 0 i J i 0 k 0 0 8 0 i J J 0 8 8 q 0 q q 0 q q q q q q q q q q b q q q q b >X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X+ + + + # + # + + # + + + # + + # # + # # # # + # # # # # # # # # % %X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-Xb.f t e p e e t e t t e e e t t t s e t e t t t t t t s s t t a t s s s s s s s s a a s s a a a s r s a a a a a a a s a a a a a k a a k a a k a k k k k a k k k k a k k k k k k k 0 a a 0 k k k k 0 k 0 0 k k k 0 0 0 0 0 0 J 0 0 0 J 0 0 0 0 0 k i 0 0 8 8 J 8 J 0 0 J 8 8 J J 8 q q q J q q q q q q q q q q q q q q q q b >X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X+ # # + # # # + + # # + # # # # # # # # # # # # # # # # # O O # O W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XZ.@.p t e e t p s p t t e t t t t e w t t t s t s s s t a t t s s s s s r a s s s s r a t a a a s a a a a a a a k a a a k a a a a a k a a k a a s k k s k k s k a k a k k a k k 0 0 a k k k k 0 0 k k k 0 k 0 k k 0 0 0 0 q 0 0 k k 0 k 0 0 J 8 J 0 J 8 0 8 0 J 0 0 8 8 8 0 8 q 0 9 9 q q q q q q q q q q q q q b q q >X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X# + + # + # + # # + # # + # # + # # # + # # # # # # # O # # # O O :.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X%XW.a.%./ I H I H I I I I I I I I I I I I I I I I I I I I I I I J I I ^ ^ J I I J I I I J J ^ ^ ^ J ^ ^ ^ ^ ^ ^ J ^ J ^ ^ I J k a k a a k k k k a k a k N J J J J J J J J J J J J J J K K J J J J J J J J J J J K J 0 J 0 k k 0 k k 0 0 0 0 0 0 0 0 0 8 8 8 J 8 8 J J 8 8 9 8 9 J q q q q q q q q q q n q b b q q >X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X# + + # + # + # # # + + # # # + # # # # # # # # # # O # O # O O g ;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X6.k a k k a k s a k k k k E.-X:X:X-X:X:X:X:X:X:X:X:X:X-X:X:X:X:X;X:X:X:X:X:X#X&X;X-X&XOXV.0 0 0 0 0 J 0 0 0 i 8 J 0 8 J J 0 0 0 8 J 8 8 0 J J J 9 9 q q q q q q q q q q q q q q q >X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X# + # # + + + + # # # # # # # # # # # # O # # # # # # # # # O # # ^.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X2.a k a k k k s k k k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&X` J k q k q k q 8 0 J 0 J 8 8 8 J 8 8 8 9 8 8 J 8 9 9 J 8 8 9 J q b q q q b q q b q b >X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X+ # + # # # # # + + # # # # # # + # # # # # # # # # e # O # O e $.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X' k a k k a k k k k a k a W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X#XK q q q 0 q l 8 J 8 8 0 8 J 8 8 8 J J J J 9 9 8 J 8 J 9 J 9 8 q q q q q q b q q q >X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X# + # # # # # + # # # # # # # # # # # # # # # # # # # # # O O # d $X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X/ k a k k a k k a k k k k E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X#Xq q k q l l 8 0 8 J J J 8 8 8 J 8 8 8 8 J 8 9 9 9 9 J 9 J 8 q q q b b b q q q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# # + + # # # # # + # # # # # # # # # # O # p # O # O O # # e # b.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=Xc k k a k k k a k k k k k E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X-X:X6.q q q k q 8 J 8 8 8 8 8 J J 8 J 9 8 J 9 8 J 8 J 8 8 8 J 9 q b q q q q q b q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# # # # + # # # + # # # # # # # # O # # # # O O # O O # p u O O g :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XOXk a k k k k a k k k k k k E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XL.l l l q q 8 J 8 8 8 J J 8 8 8 8 J 8 9 J J 9 J q q 9 9 J 8 b q q q b q q q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X+ # # # # + # # # # # # # # # # # # # O O O # O O # # # # # O O v.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XQ.k a k k a k k k k k k k l W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X[.q q 0 q 0 8 8 8 J 8 8 8 J 8 J 9 8 J 9 8 9 9 q q q J 8 J 9 q q b q q q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# # # # # # # # # # O # # O # O # O O # O O # # O # e # O e e # g -X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xn.k k a k a k k k k k k k k W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q k q q l 8 J 8 J J 8 8 8 J 8 J 8 9 9 q q q q q q 9 J 8 9 q b q q b q m q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# + # # # # # # # # # # # # # # O # O O # e # O O O O # e # e # a.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X] k k k k k k k k a k k k k E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q q q 0 q 8 J 8 8 J 8 J 9 8 8 J 9 J q q q q q q q 9 9 9 J q b q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO # # # # + O # # # O # # # # O # O # O p # # O O O O O O e # e e XX;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXJ k k k k k k k k k k k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q q q l q 9 9 J J 8 9 J 8 9 9 J 8 q q q q q b q q b b q q q b q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO + # # O # O # # # # O # O O O O # O # O O O O O O O O # # e O .:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XG.a k k k k k k k l k k k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q l q l q 8 J 8 9 8 J 9 8 J 8 J 9 q b q q b q b q q q b q q b b q q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# # # # # # # # O O # O # # # p O O # O O O O O O O O e e O O O P.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xq.J k a k k k k k k k k k l k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq l q q q q q q q 9 9 J J 8 J 8 9 q q q b q q q q b b q b b q b q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO O # O # # # # O # O # O O O # # O O O O O O O e e O O e O O O I @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&XJ a k k k k k k k k k k k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q l q q q q q J 8 8 9 9 9 8 J q q q q q b q b b q b q q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X# O # O O # O O # O O # # O # O O O # O O O e O e O O e O O O s ) ;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XG.k k k k k k k k k k k l k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q q q q q q q q J 8 q q J 9 q q b q q q 9 b 9 q q b q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe # # # # O # O O # O O O O O O O p O O O O O O O O e O O O O O p j.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X_ k k 0 a k k k k k k l i k q 0 Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq l q q q q q q q b q q q J 9 q q q q 9 b q q b b 9 J b q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO # # O O # # O O O O O O O O O O O p O O O O O e e O s O s s O p L.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XG.k k k k k k k k k 0 k k k k k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q q q q q q q q q q q q q 8 8 9 9 q b q b q b b q q 9 b b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO # # O O O O # O # O O O O O O O O e O e e O O O O O O O O p O f {.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X&X/ k k k k k k k k k k k l k l k k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X|.q q q q q q q b q q q b q 9 J J 9 q q q b b b q b q b b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xy # O # # O # O # e O O O O O p O O O O p O O e e e e O e O e e p p +X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XG.k k k k k 0 k k k 0 k l k k q k l Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q q q q b q q q q 0 b 0 b q q b b q q b q b q b q K >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO # # e # e O O O O p p # O O O O p O O O O e O e e e e e e e e e f +X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X%XK k k k k 0 a k k 0 k 0 k k l k l k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q q q q q q b q q b q b b q b q b 9 b q b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe # O O O O O O O O O O O O O O O O p O O e O e O e e e O e O e e x @X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:Xw.k k k 0 k k 0 k 0 k 0 k l k k l l q E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q b 0 b b b q q b q b q b b q b b q q b b q b q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe O O O O # e p O O O O p O O p O s O e e e e e e e e e e e p e e h `.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X!.z k k k k k k k 0 k 0 k l k l 0 l 0 k Q.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q q q b q q q b q b q b b 0 b q q b q b b q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe # O O O O O O O O O p O O s O O O e e e e O e e e e e e e t p e p f W.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XOXK k k k k k J k 0 0 k k 0 k k q k k l l E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q b q b q q q q b b q b b q b q b b b q b b b J >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe O O O O O O O O p O O O O O J e e e O e e e e e e e t e e e e p e t b.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*X1.k k k k l k k 0 k k 0 0 J 0 0 k 0 0 l 0 E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq b q q b q q 0 q b 0 b q b q b q b q b q b q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO O p O O O O p O p s O O O e e e e e e e e e e e e e e e p e t e t p 3.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X=X6.k k k k k k 0 k 0 k k k k k 0 k q k l k 0 E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q b q q q b q 0 b q 0 b 0 b b b b b b q b J b 9 b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XO O e O p O O O O O O s O O e O e e O w e e e e e e t e t e t p e e e I X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;Xs.k k l i k k q k k k 0 0 k k 0 0 J k l l q l E.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q b q b b b q b b b b b b 0 b q b b b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e O e e O e O e e e O e e e e e e e e e e e t s e e e e e e e s e e s t b.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*Xw.k k k J k 0 0 k 0 k k k 0 0 k k 0 0 0 0 0 0 J ~.*X;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q b q b q q b q b q b 9 q b q b b b b b b b b m >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e O O O e e O e O e e e e O e e e O e e e t e e e s e s s e e s t t t t ) |.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*Xe.l k k k k 0 k k k k 0 0 J k J k 0 0 0 0 J 0 0 8 V.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXq q q q q q b q b q b b b b q J n b b q b b n n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e e e O e e e e e e e e e e e O s e t e e e t t e s e e e t t e s p t t t v.-X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X+X' k k 0 k k 0 k k 0 k 0 0 0 k k k k k 0 0 0 0 8 0 J ~.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XoXb b b q b b q b q b q q b b b b q b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe O e e e O e e e e O e s e e s e e e e t e t e t e s s s t t e t t t t t t v Z.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XQ.K k k k k k 0 k 0 0 0 k k 0 k k 0 0 0 0 0 0 q 0 8 J J V.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X[.q q q b q q b q b q b q b q b b b q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e e e e e e e e e t e e e e e t e e t t p t e e e e t e s t t t t t t p s s ^ H.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X%Xw.l 0 0 k k k k k 0 k 0 k k k k k k 0 0 0 0 J 8 0 0 0 0 J r.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XT.q q b q q q b q b n q b b b q b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe O e e e e e e e e e e e s e t e e t t e e t s t s t s e t t t t t t s s p s s v n.;X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XQ./ l k k k 0 k k k 0 0 k k J k k J 0 0 k 0 J k 9 9 8 8 8 J J ` :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;Xr.b q q b b b q b b q b b q b b b q b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e e e e e e e e e e t e e e t e e e e t t t t t t t t t t p t t s s t s s s s s s w.].:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X!._ k k l k k l l k 0 k k k k 0 0 0 0 0 0 J k 0 0 0 J J 8 J i 8 0 J +X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X&XK q b b q b q b b q b q b q b q b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe e e e t e e e t e s e s t e p t t t t e s e e t t t t t s s s t s s s s s s s s s s ^ c.{.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*XG._ z k k k 0 k k 0 k k 0 J k k 0 0 0 k k 0 k k J 0 0 0 8 8 8 8 0 J 0 0 1.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;Xe.n b b q b b b q b q b b b b q b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw e e e t e s e e e e e e e t t t t t t s t t t t t e t s p s s p s s s s s s a s s s a s a v w.F.$X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X&XE.4.J k k k k q k q k k k l k 0 k k 0 0 k 0 k 0 0 0 0 q k q k q k l q q l 0 q q e.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X;X:X:X:X:X:X:X:X*Xc.b q b q b q q b b q b b b q n b b b b K >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw e e e e e e s e s s e s e t e e t e e t t t t t s s s s s s s s s s s s s s s a a s s a a s a k c 2.v.L.[.%X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X*X#X!.n.1.J k k k k k 0 0 k k k k k l k q 0 k k 0 J k 0 J 0 q 0 J k q 0 q q l q k k 0 q l q q ` !.:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X;X:X:X:X:X:X;X'.1.n b b q b q b b q b b b q b J n b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw e t e s e p e s e t t e s t s t t t t t t t s s s s s s s a s a r s a s s a s s a a r a s a s a a a a a a c ^ ' ] 2.2.2.2.2.2.2.2.3.2.2.2.2.2.2.%.6.2.2.2.2.3.2.2.2.1.' / M k k l k k k k k 0 0 k k 0 k k k k l 0 l k J 0 k 0 k 0 k 0 J 0 0 q 0 0 l k q l q q q q q q 0 q q K 1.4.4.4.4.4.6.1.6.1.4.1.4.6.1.1.4.' 1.4.4.4.4.1.L b b b q q b b b q b b b q b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw e e e e p s e s e t t e t s e t t t t t s s e s s s s s s s s s s s a s r a a s a a s a a a a a a a a a a a a a a a k a a k a k k k a k a a a 0 a k k k k k k k k k k k 0 k k k k k k k k 0 k J 0 k l q k l k l l k 0 0 0 0 k 0 0 0 0 q 0 k 0 l q l q 0 q 0 q q q l q q l l q q q q q q q q b b q b q q b q b b b b q b q b q q q q b q b q b b b b q b b b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw p s p p e t t t t t e s t t t t t s t s s s t s s s s t s s s a s s s a a s a s s a a a a a a a a a a a a a a a a a a k r k k s a k k k r k k k k k k a k k k k k k k k k k k k k 0 k 0 k k 0 k k k k k 0 q k l 0 k J 0 0 8 8 8 0 q 0 0 q l l k l q 0 q q l q k q q q q q q q q q q q q q q b q q q q q q q b b q b q b q b q b b q b q b b q b q b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xs p p t s e t e s e t t t t t s t s s s s s s s s s a a s s s a a a r a s a a a a a a a a a a a a a k k a k a a k k a k a r k a k a k a k k a a k k k k k k a k k k k k k k k 0 k 0 k k 0 k 0 k k q q k 0 k l 0 0 0 0 0 8 J 8 0 q 0 q l q q q q 0 q q q l q q l l q q q q q q q q q q q q q q q b q b b q q q b q b q b q b q q n b q q b b q b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xt t t t t e t t s t t t s s t s s s s s s s s a s a a s r s s a s a s a a a a a a a a a k a a k k a a a a k k a a k a k k a k k a a k k a k k k k a k k k k k k k k k k k k 0 k k 0 k k 0 0 0 0 0 k q k q k 0 0 8 J J 8 8 J 9 8 q 0 q k q q q l k q q q l q q q q q q q q q b q q q q q q q q b q q b q q b q b q b q q q b b b b b b b b b b b b b b q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xt e t s e t t t t e s s s s t s s s s s s s s s s s a a s a a s a a a a a a a a k a a a a a a a a a k k a a k k a k a a k a k k k k k k k k k k k k k k k k k k k k k k 0 k k 0 k 0 0 0 J 0 k k q k l k q 0 0 i 0 0 i 8 J 9 J 0 q q k q l q q q q l q q q q q q q q q q q q q q q q b q b q q q b q q b q b q b q b b b b q b q b b q b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xt t t t t t t s s s s s s s a s s s a s s a a a r s s s a s a k a a a a a a a a k a k a a a k a a k k a a k a k k a a k a k a k k k k k k k k k k k k k k k k k k k k 0 k 0 8 8 0 8 8 i k J 0 0 0 0 0 k 0 0 J 0 0 J 8 0 J 8 8 0 J J 8 8 0 q q 0 q q q q q q q q q q b q q q q q b q q b b q q b b b q b 9 b b b q b b b b b b q b b b n b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw t t t t s s p s p s s s s s s s s s s a s s s a r a a a s r a s a a a a a a a a a a a k a k a a a k k a k a a k k a k k k k k a k k k k k k k k k k k k 0 k 0 k k k k k J 0 0 J 0 0 k k k 0 k k 0 0 0 0 0 0 0 8 0 0 0 8 8 J 8 8 8 J q q q q q q q q q q q q q q q q q q q q q b q q q q b q 9 b q q b b b b b b q b q q b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr t t p s p s s s s s s s s s r s a a s s a a s a s a a s a a k a a k k s a a a k a a a k a k a k a a k a k k k k k k k a k k a k k k k k k k k k k 0 k k 0 k k k 0 J k 0 k i J 0 0 0 0 0 0 J k 0 J 0 0 k 0 J 8 8 J J 0 J 0 8 8 8 J q q q q q q 0 q b q q q q q q q q b q b q q q b q b b b 9 9 b 9 b b J b b q b q b b b b b q b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw s s s s s s a s s s s s s a s a s a a s s a a a a a a a a a k a f a k a k k a a k a a k a k a k k a k a k k k a a k k k k k k k k k k k k k k 0 k 0 0 k 0 k 0 0 0 0 0 0 0 k 0 0 0 0 0 i 0 0 0 0 0 0 i J 0 0 8 0 8 0 8 8 J J 8 8 q q q q q q J q 0 q q q q b q q b q q q b q b q q q 9 b J b b b b b q b b b b b b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr s s s s s s s s s a s a a s a s a a a a a a a a a a a a a a k a k a a k a a k a k a k a k a a k a k k k a k k a k k k k k k k k k k k k 0 k 0 0 k k k 0 k J k k 0 k 0 0 0 0 0 0 0 J 0 0 8 8 0 J J 8 0 0 8 8 8 J J 8 8 8 0 J q q q q q q q q b q q q J 9 q q q b b q q q b b b q b b q b q 9 9 q J b b q b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xt s s s s s a s a s s s s a s a s a a a a a a a a a a a a k a a a a a a a k a a a k a k a k k k k k k a k k k k k k k k k k k k k k k 0 0 k k k k k 0 k k k k 0 0 k 0 0 k k 0 i 0 0 0 0 0 J 0 i 0 0 J 0 J 8 8 8 8 8 8 J 8 8 q q q q q q q q q q q q q q q 9 q q q q b q b q q b q b b q b b q b b b b b b b J b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr s s s s s s a s r a a s a s a a a a a a a a a a k a k a a a a k a a k a a k a k k a a k k a k a k k k k k k k k k k k k k k k 0 0 k 0 k k k J 0 k k k k J 0 0 0 0 0 J 0 0 J 8 J J i 8 0 0 0 0 0 8 J 8 8 J 8 8 J 8 J J 8 q q q q q q q q q q q q q q q b b b q b q 9 q b b q q 9 b q b b b b 9 q b b b b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr s a s a s s a s a a s a a a a a a a a a k a a a a a a k a a k k a k k a k l a k k k k k k k k a k k k k k k k k k k k k k k k 0 k k 0 k k 0 0 0 J k k 0 J k k 0 0 0 0 0 i 0 0 0 8 J J i J 8 0 0 8 J J 8 8 J 8 8 J 8 q q q q q q q q q b 9 b q b b b 9 b q b q b b b q q b b b J b b b q b b b b b b b b q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr a s a s a s s s k a a a a a a a a a a a a s k k a a k a a k a a a k k a k k a k a k a a k k k k k k k k k k k k k J k 0 k 0 0 k k 0 0 k J 0 k 0 0 k 0 k k J i 0 0 0 0 0 0 0 0 J 0 8 J J 8 J 8 8 8 8 8 8 J 8 8 8 J q q q q q q q b q b b q q q q q 9 9 q q b q b b b b b b b b b b q b b b b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xw a r a a a r a s a a a a s k a a k s k k k a a a a k a k a k k k k a a k k k k k k k k k k k k k k k k k k 0 k 0 k 0 k k k 0 k 0 0 k k k 0 k 0 k 0 0 0 J 0 0 0 0 J i 8 J 8 8 8 8 8 8 8 8 8 8 J J 8 J J 8 8 J 9 8 q q q q q q q b q q q q b b q b J b q b q b q b q J q 9 b b b b b b b b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr a s s a a a a a s k s a a a a a k s s k k a k a k a k a a k a k k k k a k a k k k k k k k k k k k k k 0 k k 0 k 0 a k k k J k k k k 0 k J k J k 0 0 8 i 0 i 0 8 0 0 0 J 8 8 J 8 8 J 8 J J 8 J J 8 8 J 9 J 8 q q q q b q q q b q q b q b b q 9 b b b q q b b b b b q q J b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr a a a a a s k s s k a a k s k s k a a a k a k a k a k k a k k a k k k a k a k k k k k k k a 0 k k 0 k 0 k k 0 0 0 k k 0 0 0 0 J k 0 k 0 0 0 0 0 0 J 0 0 8 0 J 0 0 8 8 J J 8 8 8 J 8 8 8 8 8 8 8 J 8 8 J 9 q q b q q b b q q q q q b q q b q b b q b b q b q q b b b b b b b b q J b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr a a k s s k a k s k s k a k a k s k a a k a k a k a k k a k a k k k k k k k k k k k k k k 0 k k 0 k k k k 0 0 0 k k J 0 0 k 0 0 i 0 0 0 k 0 0 0 0 0 J 0 J 8 0 J 8 8 8 J 8 8 J 8 9 J J 8 J J 9 9 9 J 8 q q b q q b b q b q b q b q b q q b q b q b b q J b q b b b b q b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr s k s s k s k s k a a s k k s a k a k k k k a k k k k k a k k k k k k k k k k k k k 0 k 0 0 k 0 0 J k k k 0 k 0 0 0 J k 0 0 8 J i 0 0 i J i J 0 0 0 8 8 J J 8 J 0 8 J 8 8 J 9 8 9 9 9 8 8 J 8 J 9 q q q b q q q q q b q b q b q b q b 9 b q b q 9 b b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xk s k k s k a k s s k k k r k a k k k a a k k k k k k k k k k a k k k k k k k k k 0 k J k k k 0 0 0 k k k k k k k 0 k 0 0 0 0 J 8 0 0 0 0 0 i 0 8 0 0 0 8 8 8 8 0 8 J J 8 J 8 J 9 J 8 9 J 8 J 8 9 n q q q b q q b b q b q b q q q b b b b b q J b b 9 q b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xi s k s k s k k s k r k a k k k a k k k a k a a k k k k k k k k k k k k k k k k 0 k k k k k k k 0 0 0 J 0 0 0 0 0 0 i J 0 0 0 J 0 0 0 0 J 0 J J 8 J 8 8 J J 8 8 8 J 8 9 9 8 8 J 9 8 J 9 9 8 J q q b q b q q b q b q b q b b b q b q J b b b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr k a a k a k a k a k k a k k k a k k k k k k k k k k k k k k k k k k 0 k 0 k k 0 0 k k J k 0 0 0 0 0 0 0 k 0 k J 0 0 0 0 0 0 0 J q 0 0 q 0 q q q q q q q J J 8 9 9 J 8 8 9 J 9 J 8 q q b q b q q q b b q b q b q q b b b b b b b b q b b q b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr a k k a k r k a a k k k k k a k a k k k k k k k k l k k k k 0 k k 0 k k 0 0 k k k 0 J k k k J k 0 J 0 0 0 0 0 8 J i 0 b 0 0 0 q q 0 q q l 0 q q q q 8 8 8 J 8 J 9 J 9 8 8 J q q q q q b q b q b q b q b q b b b q b q q b q b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xk s k k a k k k k a k k k k k k a a k k k k k k k k k k k k 0 k k k 0 0 k k k k 0 0 0 0 0 0 k 0 k 0 J 0 0 J 8 8 J q q 0 q q q 0 q l q q q q q q q 8 8 9 J 9 9 9 J q 9 9 9 q q b q q q b q b q b q b q b b b q b q b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xr k k a k a a k k a k k k k k k k k k k k k k k k k J 0 k 0 k J k k k k k 0 0 0 0 0 i 0 0 0 0 0 0 0 0 0 0 8 0 0 q q q 0 q q q q q q q q q q q J J 9 8 J 9 9 q J 9 J 9 b b q q q b q b q b q b q b q b b q b b q b b q b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xi k k k k a k k a k k k k k k k k k k k k k k k 0 k 0 k k 0 k k k J 0 0 0 8 8 i 8 q 0 q 0 0 k 0 0 0 J 8 8 q 0 q q q q 0 q l q q q q q q q 8 9 J 8 9 J q q q b b q q q q b q b q b b q q b b b b b q b q b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xi i k k k k k k k k k k k l k k 0 l k 0 k 0 k k k 0 0 k 0 k 0 0 k k k J 8 0 J 0 0 q q J 0 8 J 0 8 J 8 q q 0 q q 0 q q q q q q q q q q 8 J 9 8 9 8 q 9 q q q q q b b q b q b q q b b q q b q b q b b b b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xi 0 k k k k k k k k k k k k k l k k k k 0 k 0 k J k J 0 0 0 0 J 0 8 8 J 9 0 0 0 q i J i 0 0 8 0 8 9 8 q q 0 J q q q 0 q q q q q q 9 9 J J J J 9 9 q b q b q 9 q b q b q q b b b b b b b b b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xa k k k k k k k 0 k 0 k k 0 0 k k J 0 k k k 0 0 J k 0 k k 0 J 8 8 9 8 J 0 0 0 0 0 0 0 J 0 J 9 J q 0 q q q q q q q q q q q b J 8 8 9 8 9 9 J q q q b q b b b b q b b b q q b b q q b b n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xk l k k l k 0 k l k k k 0 0 J k 0 k l k k k k J k 0 0 J 0 0 0 q q 0 J J 8 8 8 8 8 8 J J 8 8 J 8 8 8 J q q q q q q q q q q q q q q q q b b q b b 9 q q b q b b b b b b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xk l k k k k l k 0 0 0 0 q k q l 0 0 0 0 0 0 J 0 k q 0 q 0 0 q 0 8 8 J J J J 8 8 J 9 8 J 9 J 9 8 b q q q q q q q q q b b b b q b b b b q b b q b q b b q b q q b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xq 0 l l l 0 k k 0 k q l l 0 0 0 0 0 0 0 0 0 l 0 0 q 0 q q 8 J 8 8 8 8 J 8 8 8 9 9 J 9 J 8 q q q b q q q q b q q q q q b q 9 b q b b q b b q b b b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X8 k 0 0 0 k 0 k l l k J k 0 k 0 0 0 q k q 0 0 q 0 q 8 8 8 J 8 J 8 8 9 J J 8 8 8 J 9 q q q q q b b q b q b q q b q b q q b q q b b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X0 0 l l l 0 q k q l J 0 0 0 0 q k 0 8 8 8 J 8 J 8 8 8 9 J J 8 J J 9 9 9 J 8 q q q q q b q b q q q b b q b q q b q q b q >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X0 0 q l q 0 0 i J q q q q J J 8 9 J 8 8 J J 9 8 9 9 9 8 q J 8 J 9 q q q q q q q q q b b q q b q b b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X9 J 0 0 q q 9 J 8 8 J 8 8 J 8 J J 8 J 9 J 8 q q J 9 8 9 q q q q b q b q 9 b n 9 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X9 8 9 9 8 9 8 8 9 9 8 8 J 9 9 9 8 8 J 9 n b 9 b >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X" }; diff --git a/share/pixmaps/bitcoin32.png b/share/pixmaps/bitcoin32.png index 90d532882e4095b58a19027562128caf23fd118d..417cb3e62943e2c0caa5c5dd8e17b208a282b8f3 100644 GIT binary patch delta 1858 zcmV-I2fg^&3(yXbBYyw^b5ch_0Itp)=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi z!vFvd!vV){sAK>D2IWaaK~z{rjaPe2R%IA}-t&D3dAp6%KDyzg`QJ@0d#_dVw@8XzS*Xl)?AY^_yObsB(me|<=jdU=n=$S zA4+dTta7;Zo`0<#($it($AK(R7;s<>BS5DmO`@rZ6X}P8r|D|N4d_)O8udWGi`i}K zi!bGLh`@b_hw4Yk5oyu7?mmVfu>!~hH4>0(e*Sjan6r#to;gAItxe0NlC$L^F=1y^ zM5793(^Ah}+;vSDdJ*4)4<(IU9tZHh;23M}#AH4PbAJHvqBU=t;G7hgViTPE#JWi@ zPIxgrPMMknwM9u0%c6DW`3;VtKHx?`BRJMx&h+jqoWe0KSprI_{7yQ+)r#H$~7e$9X>?_6}wc9V1CSG z623t-R3I?OpRQcFL1kq%^!?E@G$_E28t=53Hh-qSlFfBS8swm+>hs6htWjxBgO_xF=}mQ+6OeHQhQFi;XZlcG1t#`VQe^U3U$=ax5P*MmitsshtyO`z>N z)08_=Z?BvFtE#8ljV(eJ&!5|hQSBH*-hZJ#=w|&L+O&3oEHkJJJ&?WkXKHM@CqTV= zfZMdN88K;Y2%2!<*qJLP>_M71}Y=)&Jusn>%OY&r8C$kAICItb>5 z`s=tX^~}SjkKqY0k${om;o}>`xbv$Y>EpDy)Nrer)@J7U1Tx-+!66Qso0LFyKYyF3 zNN0Bs9Vsj}!NiW0Y$c&|8hLOESQ{1x8;jh)jx(OOr;xU6UrY{10Cs;3>ry9!Si#q=&Zr4;TbvHTZZs;_0mw{5fLi{>BLJUb z3GpkPjF`NNxe<1ozVaH5w`mJi(SJbUKov1;zE*6;X_^Y+H~tn#~Bht6URnTU1PKO5D7u&JDm=UK|&UD zaHqSM+z1{qER;e}MJG5Qa1h-?g+yW^A)W|~G&)#&AiIF)L{nZ`g;yi{7Y2525RBj_ zj&34Hpg&g+nC7p`p_&HV8Grek)rzDKwtYjz6;%>g?4Ej=jmFjP&#vS-(LW`*m3Uq` z;@M%PwY`IO?JX3}1Etpc9aL6RCwJM0!d$@uT$Wx`B8P)>ooVi|>Fc4WFdF5+Pk+*$ z!@rZRiwpOOly#_(I(d)qUG^abs+d)1Hf_C9SqWS|liPvar^4v2GJmA6zbm4ppY5hg z<<*Z&qzyY?x92DwIeAWice&l<#+B_&?cL}Bo)=?x(QB!-`Cpj-2>sF>o0t)YFAVu* z%&Wn(2Zs&`p=Tn8;)BGl8j0v$XBU-K;}~M+R<{$yMvbI!SBQ|ipew1YCcMG`PRaH8 zS(g-)Aei*0=jW`BCV!?KLnZKI!h`b1VgN|l0({6EqcK;>R$!i5zb~ubk4gV~6m+NR z{9RW}+1F^K$zX1QVx9k-GFE_h$c~16vfCd;+O0*vPQ0~KPzC&+8!AwPwNi|yJk0Y;!~QP^@Ow`5KVAPw*UYD07*qoM6N<$f;`ZSod5s; delta 1480 zcmV;(1vmQ84%rKkBYy>;NklQ@>UVn2M8e{0g7mn3YsD&BCjC9MFe^1hC`$Uh@c`YD+nqs?*u%Za}mds z^%MJ}X7bLQ`DVG_ch2wre&?KfU;x1WO=C|1{O164Yr0u?M}IeeDl<;8l9VELI=z(T z@5^HcgZIyfv6?ZahtPVY!t(OTT6I#;ckzdB=!EYdqGHp76vDM&odzgN|$ zSZ`PFkYBXX0mwYX%CeL!=lg7@EY-KWEg5GGc6uU^POt&lL|bq`lfG>OcH>1r zdoEL!-i)*jkAFF~`{=mxoHI`jpr@mUmFJ#e34XiWoZpjaY~Qrv!DN#pk2C^fGiC{R z&2X#B+>&O}+R!?B06m>OtpCq`w#z3jl$_bWB_1&t0U|a=+Lw&Crv1Lcq!ZS6?f^d! znIM3!TU~5$V2~Z(t8ld)i>D^4wFF1~!PnRmyk;&R@qZnX1>fndF0Go~*VD%|*EPZb zG;Oz7jk0-(y@4?)&yYPf&id}&b0y{BVUI?lLA`mn}q=sB^OSY=}QJ2CfGhiIR%j3HJdS( z$bdfw(0^2;0*6Ud4PvcQ_!@g$IeX%_R|Em<@{J1>qx1U%i*+q|iP0$?4ei0vz#i;T zp7jgm9Dw?Q3YNX=z{^q_V+0~CGR0I7z`D-^3Mm*bDLg6VLHx>{@JG?_(1d}AZZ+A3 zCTMNA#sOf(K=Y-m5GC0J<}aGUgY1#nj$H!VTz_IB1Od2x;B=Wgm^h@fB0d*}*WlnF z4BYOAf&Kw}4)EvwEA`tH2(t(Q*C~!*{kl01igMm#03}No1b`IZpy2dz=;9#m7#j)f z^xgqJvpm4(BM)ABo<=UPNfgHSn=f7k*Y_PEYg-2Y?LT)Vq-;uteQWmcz#ITF>Ho=! zdVfIxPKMGp0zfB7i#oy`9{)iB<}a9XXXJ=Xq+<^9`F?N*yNsqy1F4aRVY_P#Y<1cU zUoQ%RjvF0Np(y8NILv_m+!d9A06dIbYpI=zbuHlJ!2%9oZ$LZ;^iUa^1OPUzdlC>! z&X|m}6!AGcICVssz8wd!eu4auAOO5{j(?vhxi%|U_y4g~F6W%Gt5511Z(SAx9?FhdFWO-M4JS-!Lg!puYXeqDJj z4@}8R`g=}y1(B{fTqvu7A$P7IfU<0*A-3Tz5i&qp((1z`OjxxOR)5a+ z9N&pPG+D||zh<7_x%0~E=LG?% z&Ns3+kL^1MHPM{6=h)v$jVLD@UQ~_;gA>7Xh8s^#pIPpB6))#ifx`=@UyO_%+npnA zzjjl&6=U`?b#0U03S-Yk`j8w@BY!$qa26V?8vq9kZVi=J@U*``xYb6mdd-Yei~|dQ zpI^^dN%neTeh);5zfp8t*F4+a(*79NaeEiT2E!^8zb?dN>nGiLD@Hab`6vh(zv-}7 zkZEhb)Jw2$sMNJ;1Go~A zrukxYBN-ZvQ7xC7S!PW7JnVo~G@NLgj2@hj2yoy+c`i1v$s}oSXYZ2%XsEivhth(? ze4VY1(Sh#MTV`%vq8r+muucLm)FZbU3DbfdSh@>aN_)|ZJE!}2w$9hl9i?w ij~>9&|BU{30R94{CTKq!Fjap50000 c #581252", -", c #581253", -"< c #581353", -"1 c #591353", -"2 c #591354", -"3 c #591454", -"4 c #5A1454", -"5 c #5A1554", -"6 c #5A1455", -"7 c #5A1555", -"8 c #5A1655", -"9 c #5B1656", -"0 c #5B1756", -"q c #5C1756", -"w c #5C1757", -"e c #5C1857", -"r c #5D1957", -"t c #5D1958", -"y c #5D1A58", -"u c #5D1A59", -"i c #5E1A58", -"p c #5E1A59", -"a c #5E1B59", -"s c #5F1B59", -"d c #5E1B5A", -"f c #5F1B5A", -"g c #5E1C59", -"h c #5F1C5A", -"j c #5F1D5A", -"k c #5F1D5B", -"l c #601D5B", -"z c #601E5B", -"x c #611E5C", -"c c #611F5C", -"v c #621F5D", -"b c #62205D", -"n c #62215D", -"m c #63225E", -"M c #64225E", -"N c #64235F", -"B c #652560", -"V c #662561", -"C c #662661", -"Z c #672762", -"A c #672863", -"S c #692A64", -"D c #692B65", -"F c #6A2B65", -"G c #6B2C65", -"H c #6A2C66", -"J c #6B2D66", -"K c #6B2E67", -"L c #6C2E67", -"P c #6C2E68", -"I c #6C2F68", -"U c #6D2F68", -"Y c #6E3169", -"T c #6E316A", -"R c #6E326A", -"E c #6F336A", -"W c #6F336B", -"Q c #70336B", -"! c #71356C", -"~ c #71366D", -"^ c #73396F", -"/ c #74396F", -"( c #753A70", -") c #753B70", -"_ c #753B71", -"` c #773D72", -"' c #773E73", -"] c #773F73", -"[ c #783E73", -"{ c #783F74", -"} c #794174", -"| c #794175", -" . c #7A4276", -".. c #7A4376", -"X. c #7B4377", -"o. c #7A4476", -"O. c #7B4477", -"+. c #7B4577", -"@. c #7C4577", -"#. c #7D4779", -"$. c #804A7C", -"%. c #804B7C", -"&. c #814C7D", -"*. c #824D7D", -"=. c #834F7F", -"-. c #845080", -";. c #845180", -":. c #865483", -">. c #875684", -",. c #885785", -"<. c #8A5886", -"1. c #8A5986", -"2. c #8B5A87", -"3. c #8C5C88", -"4. c #8E5F8B", -"5. c #90628D", -"6. c #92658F", -"7. c #93668F", -"8. c #966A93", -"9. c #986D95", -"0. c #996E96", -"q. c #996F96", -"w. c #9B7198", -"e. c #9C7298", -"r. c #9E769B", -"t. c #A0789D", -"y. c #A47EA1", -"u. c #A57FA2", -"i. c #A884A6", -"p. c #AA87A8", -"a. c #AC8AA9", -"s. c #AC89AA", -"d. c #AD8BAB", -"f. c #AE8CAB", -"g. c #B292AF", -"h. c #B99BB6", -"j. c #B99BB7", -"k. c #BA9DB8", -"l. c #BB9EB9", -"z. c #BB9FB9", -"x. c #C0A5BE", -"c. c #C5ADC3", -"v. c #CAB3C7", -"b. c #CAB3C8", -"n. c #CEB9CC", -"m. c #D1BED0", -"M. c #D3C1D2", -"N. c #D5C4D4", -"B. c #D9C9D8", -"V. c #DBCCDA", -"C. c #DDCEDC", -"Z. c #E1D4E0", -"A. c #E2D6E1", -"S. c #E3D8E3", -"D. c #E4D8E3", -"F. c #E4D9E3", -"G. c #E5D9E3", -"H. c #E5D9E4", -"J. c #E5DBE5", -"K. c #E6DBE5", -"L. c #E7DCE6", -"P. c #E7DDE6", -"I. c #EAE1E9", -"U. c #F1EBF1", -"Y. c #F2EDF2", -"T. c #F6F2F5", -"R. c #F6F3F6", -"E. c #F7F4F7", -"W. c #F8F4F7", -"Q. c #FBF9FB", -"!. c #FCFAFB", -"~. c #FCFAFC", -"^. c #FCFBFC", -"/. c #FDFCFD", -"(. c #FDFDFD", -"). c #FEFEFE", -"_. c gray100", -"`. c None", +"32 32 105 2 ", +" c #3F2567", +". c #3E2668", +"X c #3B2B69", +"o c #2F3F6D", +"O c #35356B", +"+ c #38306A", +"@ c #323B6C", +"# c #39386D", +"$ c #3E3B70", +"% c #441D66", +"& c #412267", +"* c #412568", +"= c #442A6B", +"- c #4A3F76", +"; c #513F78", +": c #1F5773", +"> c #1D5B74", +", c #2C436E", +"< c #264D6F", +"1 c #29486F", +"2 c #264D71", +"3 c #284970", +"4 c #334672", +"5 c #3C4B77", +"6 c #225472", +"7 c #2D5676", +"8 c #295A77", +"9 c #3C5C7E", +"0 c #1B6075", +"q c #2C617B", +"w c #34637D", +"e c #424D79", +"r c #55437B", +"t c #57497E", +"y c #396881", +"u c #495C82", +"i c #655387", +"p c #6A5B8B", +"a c #466384", +"s c #406A85", +"d c #57658A", +"f c #487A8E", +"g c #5E7191", +"h c #567B93", +"j c #5C7B95", +"k c #60608A", +"l c #6B6690", +"z c #6F6C95", +"x c #756794", +"c c #736B95", +"v c #786D97", +"b c #7D6B98", +"n c #6D7397", +"m c #617895", +"M c #77769B", +"N c #807DA0", +"B c #598497", +"V c #568798", +"C c #5E8B9C", +"Z c #63839A", +"A c #6C809C", +"S c #618F9E", +"D c #7586A1", +"F c #7E85A3", +"G c #6D95A4", +"H c #7A99AA", +"J c #8C8AAA", +"K c #8391AA", +"L c #8B94AE", +"P c #939CB4", +"I c #9B9BB6", +"U c #A599B8", +"Y c #97A2B7", +"T c #97A4B8", +"R c #9DA4BA", +"E c #A1A3BB", +"W c #A8A0BC", +"Q c #A4AABF", +"! c #A9A8BF", +"~ c #ADABC1", +"^ c #B8AFC7", +"/ c #BBB7CB", +"( c #B5BBCB", +") c #BCBECE", +"_ c #C5BDD1", +"` c #BAC1CF", +"' c #C1C1D1", +"] c #C9C4D6", +"[ c #C6CAD7", +"{ c #CDCDDA", +"} c #D1CFDC", +"| c #CCD4DD", +" . c #D7D6E1", +".. c #D8D7E2", +"X. c #E0DFE8", +"o. c #E2E2EA", +"O. c #E8E6ED", +"+. c #ECEEF2", +"@. c #F0EFF4", +"#. c #EEF1F4", +"$. c #F3F3F6", +"%. c #F6F6F8", +"&. c #F7F8F9", +"*. c #FFFFFF", +"=. c None", /* pixels */ -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.^ Z b n S { `.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.#.c 8 r r f f f 8 8 Z 2.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.n < f h h h h f h h h q , P `.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.0.; r h h h h h f 8 8 h h f h 8 f `.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.8 f f h h h h f n Y L h h h h h 8 n `.`.`.`.`.`.`.", -"`.`.`.`.`.`.N 8 f f h h h h < } E.C.c r h h h h > ' `.`.`.`.`.`.", -"`.`.`.`.`.3.$ h h h h h h h > +._.H.c r h h h h h $ `.`.`.`.`.`.", -"`.`.`.`.`.h f h h h h r r f > ._.H.h r h h h h h 8 Q `.`.`.`.`.", -"`.`.`.`.0.; h h f ; 8 h c c q +._.G.n h f h h h h h 8 `.`.`.`.`.", -"`.`.`.`. .8 f r 8 q.M.S.H.H.G.I._.Q.P.2. f h h h h 2 6.`.`.`.`.", -"`.`.`.`.Z f f 8 j._._._.^._.Q.^._._._.s.;.Z $ 2 h h q .`.`.`.`.", -"`.`.`.`.c f > *._.E.0.Y Y W F >._.P.Z g._.( p.t.8 h 8 ( `.`.`.`.", -"`.`.`.`.c f $ s._.l.. 8 q 8 + ' _.U.s.7.5.*.Y.n.2 f 8 ( `.`.`.`.", -"`.`.`.`.S f > x._.r.$ f h h 8 .^._._.0.n _.j.; 8 h 8 +.`.`.`.`.", -"`.`.`.`.#.8 $ x._.r.$ f h h 8 ._.Q.S.3.f y.%.*. .8 8 `.`.`.`.`.", -"`.`.`.`.`.> $ f._.l. 8 q 8 o -._.V.r f ( F ; B.i.$ f `.`.`.`.`.", -"`.`.`.`.`.N ; %._.T.e.! W ! .N._.T.' o v.c.2 ^ n 2 { `.`.`.`.`.", -"`.`.`.`.`.8.$ > l._._._._._._._.^.y.F 8 Y P Z 2.r ; `.`.`.`.`.`.", -"`.`.`.`.`.`.Q ; q w.m.S.S.S.Z.b.>.+ r c r r f e $ ,.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.f 8 > < f k h f ; ; f h h f h f ; Y `.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.h 8 f f f f f f h h h h h h 2 S `.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.Y 2 w f f f f h h h f 8 8 +.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.S 8 8 8 f r 8 8 f Y `.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.%.' S I ' `.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", -"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`." +"=.=.=.=.=.=.=.=.=.=.=.=.% % % % & & & * =.=.=.=.=.=.=.=.=.=.=.=.", +"=.=.=.=.=.=.=.=.=.% % % % % & & & & * X X =.=.=.=.=.=.=.=.=.", +"=.=.=.=.=.=.=.% % % % % & % & & * b ^ i X X X X X =.=.=.=.=.=.=.", +"=.=.=.=.=.=.% % % % % % & & & = _ *.*.x X X + X + O =.=.=.=.=.=.", +"=.=.=.=.=.% % % % % & & & U *.*.*.x X X + + + O O =.=.=.=.=.", +"=.=.=.=.% % % % % & & & = $.*.*.*.c X O X O O O O @ =.=.=.=.", +"=.=.=.% % % % % & & & * . . r *.*.*.*.c O + O O O @ @ @ @ =.=.=.", +"=.=.% % % % % & & . X t *.*.*.*.l O O O O # @ @ @ @ , =.=.", +"=.=.% & % & & & . . X . X t *.*.*.#.# O O O @ @ @ o o o , =.=.", +"=.% % & & & & . . . X . X - ! ~ ! M p O O @ @ @ o o o , , , =.", +"=.% & & & . . X p U ] { } { { { } %.n @ ( { | [ u o , , 1 1 =.", +"=.& & & . . ; ] *.*.*.*.*.*.*.*.*.*.n e *.*.*.*.D , , , , 3 =.", +"& * * X r O.*.*.*.*.*.*.*.*.*.*.*.n 5 *.*.*.*.D , , 3 3 3 2 ", +"& * . X } *.*.*.*.*.*.*.*.*.*.*.*.n 5 *.*.*.*.D 3 3 3 2 2 2 ", +" X X X v *.*.*.&...' ) ) ) ) ) ) ` d 5 ` ` ` ( 9 3 3 < 2 6 2 ", +" X . X X / *.@.J z # # # @ @ @ o o o , , , , , < 3 3 2 2 2 6 6 ", +"X X X + + o.X.c .) O @ @ @ @ @ 5 L L L K , 1 3 3 2 2 2 6 2 6 6 ", +"X X X X + O.M %.*.E @ @ @ @ , o P *.*.*.#.3 3 2 2 2 2 2 6 6 6 6 ", +"X X + + + I o.*.*.E @ @ @ , @ , Y *.*.*.+.3 2 2 2 2 6 6 6 6 : 6 ", +"+ + + + + L *.*.*.R @ @ o , , , T *.*.*.#.2 2 2 6 6 6 6 6 6 > > ", +"=.+ O O O I *.*.*.Q o o , , , 1 A &.&.*.+.2 2 6 6 6 6 6 > > > =.", +"=.O O O @ E *.*.*.o.4 , , , 1 1 3 3 2 2 2 6 6 6 6 6 > 6 6 > > =.", +"=.O @ @ @ F *.*.*.*.[ g u a a a a a a 7 6 a y s y 6 > > > > > =.", +"=.=.@ @ @ 5 %.*.*.*.*.*.*.*.*.*.*.*.*.h w *.*.*.*.V 6 > > > =.=.", +"=.=.@ , @ @ L *.*.*.*.*.*.*.*.*.*.*.#.7 w *.*.*.*.G > > 0 0 =.=.", +"=.=.=.@ , , , T *.*.*.*.*.*.*.*.*.*.H : w *.*.*.*.G > > 0 =.=.=.", +"=.=.=.=., , , 1 j | *.*.*.*.*.*.#.H : : q *.*.*.*.S > 0 =.=.=.=.", +"=.=.=.=.=., 1 3 3 3 9 j Z Z Z h 8 6 : : > f C C V 0 0 =.=.=.=.=.", +"=.=.=.=.=.=.3 3 2 2 2 2 6 6 6 6 > : > 6 > > > > > 0 =.=.=.=.=.=.", +"=.=.=.=.=.=.=.< 2 2 6 6 6 6 6 6 > : > > > > 0 0 0 =.=.=.=.=.=.=.", +"=.=.=.=.=.=.=.=.=.6 6 6 6 : : > > > > > 0 0 0 =.=.=.=.=.=.=.=.=.", +"=.=.=.=.=.=.=.=.=.=.=.=.6 > > > > > > 0 =.=.=.=.=.=.=.=.=.=.=.=." }; diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png index 1d3ad055774fdc01e2ea8402998ce0ced8766d35..0af3d823b64e2633238040b7d68f3f27c5dcb253 100644 GIT binary patch literal 4320 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 c #6C2F68", -", c #6F326A", -"< c #71356D", -"1 c #73396F", -"2 c #763D72", -"3 c #783F74", -"4 c #7A4276", -"5 c #7C4578", -"6 c #7E497A", -"7 c #824D7E", -"8 c #83507F", -"9 c #855382", -"0 c #885684", -"q c #8B5987", -"w c #8D5D89", -"e c #8F608C", -"r c #90628D", -"t c #966A93", -"y c #9A6F96", -"u c #9D749A", -"i c #A1799E", -"p c #A47DA1", -"a c #AA86A7", -"s c #AB87A8", -"d c #AD8BAB", -"f c #B191AF", -"g c #B596B3", -"h c #B79AB5", -"j c #B99BB7", -"k c #BB9FBA", -"l c #BEA3BC", -"z c #C1A7BF", -"x c #C1A8BF", -"c c #C4ABC2", -"v c #CBB4C9", -"b c #CEBACD", -"n c #D5C3D3", -"m c #D8C9D7", -"M c #DBCCDA", -"N c #DDD0DD", -"B c #E1D3E0", -"V c #E6DBE5", -"C c #E8DEE7", -"Z c #EBE3EB", -"A c #EFE9EF", -"S c #EFEAF0", -"D c #F1ECF1", -"F c #F6F2F5", -"G c #F8F4F7", -"H c #F8F5F8", -"J c #FFFFFF", -"K c None", +"64 64 137 2 ", +" c #3F2567", +". c #3F2668", +"X c #3C2B69", +"o c #2F3F6D", +"O c #35356B", +"+ c #38316A", +"@ c #323B6C", +"# c #393B6F", +"$ c #441D66", +"% c #461D68", +"& c #412267", +"* c #412468", +"= c #422C6B", +"- c #42306D", +"; c #4C3773", +": c #423C72", +"> c #543D77", +", c #573F79", +"< c #1F5773", +"1 c #1D5B74", +"2 c #2C436E", +"3 c #264C6F", +"4 c #29486F", +"5 c #32426F", +"6 c #264D71", +"7 c #284A70", +"8 c #314671", +"9 c #3B4272", +"0 c #304972", +"q c #394C76", +"w c #225372", +"e c #205873", +"r c #2E5A78", +"t c #35587A", +"y c #1A6175", +"u c #226378", +"i c #2C627B", +"p c #444576", +"a c #404A77", +"s c #444C79", +"d c #4D4B7C", +"f c #45567E", +"g c #3F6B85", +"h c #5F4C82", +"j c #4B5D83", +"k c #565281", +"l c #5C5684", +"z c #545C84", +"x c #5C5D88", +"c c #6B5C8C", +"v c #406984", +"b c #486B87", +"n c #486F89", +"m c #526086", +"M c #59668B", +"N c #467289", +"B c #4D758D", +"V c #4B7B8F", +"C c #5A718F", +"Z c #64618C", +"A c #70618F", +"S c #616E91", +"D c #6D6C94", +"F c #726693", +"G c #716893", +"H c #697496", +"J c #657A97", +"K c #637D98", +"L c #747198", +"P c #797D9E", +"I c #7E7EA0", +"U c #83739D", +"Y c #897FA4", +"T c #5E8398", +"R c #64819A", +"E c #6D839D", +"W c #77819F", +"Q c #7485A0", +"! c #6E93A4", +"~ c #7B95A9", +"^ c #8382A4", +"/ c #8B83A7", +"( c #8089A6", +") c #8A89A8", +"_ c #9081A7", +"` c #938DAD", +"' c #819DAE", +"] c #9090AD", +"[ c #8A9FB2", +"{ c #9493B0", +"} c #9B93B3", +"| c #939EB5", +" . c #9D9AB6", +".. c #9D9DB8", +"X. c #A29DB9", +"o. c #84A8B4", +"O. c #9AA0B7", +"+. c #98A2B8", +"@. c #94B3BD", +"#. c #9BB0BE", +"$. c #A4A3BC", +"%. c #ADA5BF", +"&. c #9DB4C1", +"*. c #9FBAC4", +"=. c #ACA7C0", +"-. c #A7AEC1", +";. c #AAABC1", +":. c #B1AFC5", +">. c #A2B5C3", +",. c #ABB5C6", +"<. c #B4B4C8", +"1. c #BEBBCE", +"2. c #BDC6D2", +"3. c #BBCED5", +"4. c #C3C5D4", +"5. c #C0C8D4", +"6. c #C6CFD9", +"7. c #CDCCDA", +"8. c #D2CDDC", +"9. c #C3D0D8", +"0. c #CAD1DB", +"q. c #D6D4E0", +"w. c #D6DCE3", +"e. c #DBDDE5", +"r. c #E1DFE8", +"t. c #DCE1E7", +"y. c #DBE2E8", +"u. c #E5E4EC", +"i. c #E8E5ED", +"p. c #E7EBEF", +"a. c #EBECF0", +"s. c #EFF1F4", +"d. c #F2F2F5", +"f. c #F5F6F8", +"g. c #F7F8F9", +"h. c #FFFFFF", +"j. c None", /* pixels */ -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKK6<:***=<7KKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKK6=@@@%%%#&#@@-7KKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKK4++%%%%%%&&&%%&#+%7KKKKKKKKKKKKKKK", -"KKKKKKKKKKKKw%+%%%%%%%%%%&%%%%%#O*rKKKKKKKKKKKKK", -"KKKKKKKKKKK4+@&%%%&%%%%%%&%%%%%&&@+5KKKKKKKKKKKK", -"KKKKKKKKKK-+%%%%%%%%%%%%&#&%%%%%%&%o2KKKKKKKKKKK", -"KKKKKKKKK,O%%%%%%%%%%%%%#%#&%%%%%%%%O3KKKKKKKKKK", -"KKKKKKKK7o%%&%%%%&%%%&%&***&%&%%%%%&%O9KKKKKKKKK", -"KKKKKKKyo%&%%%%%%%%&%%@aADf%@%%%%%%%%%+iKKKKKKKK", -"KKKKKKK#@%%%%%&%%%%%%##hJJc&#%%&%&%%%&@*KKKKKKKK", -"KKKKKK7o&%%%%%%%%&%%&##gJJz##%%%%%%%%%%@0KKKKKKK", -"KKKKKK+%%%%%&%%%%%%%%#@gJJx%@%%%%%%%%%&@&KKKKKKK", -"KKKKK9O&%%%%%%&&&%%%%$$gJJz%@&&%%%%%%%%%+wKKKKKK", -"KKKKK*#%&%%%&&@++++++oXfJJlOX#%%%%%&%%&%+1KKKKKK", -"KKKKK+%&%%%&+o&>11<11<#%%&%%KKKKK", -"KKKK2#%%odJJm#%#%%%%%@$gJJJJJ4otJJe +#&%%%&KKKKK", -"KKKK9+%%XdJJm#%&%%%%%%$gJJJJJ6O6ll6#-*%%&&*KKKKK", -"KKKKK@%%XpJJC*$%%%%&%#@jJJnee:##@#osZp+%@-6KKKKK", -"KKKKK-@&XeFJH5o%%%%%%+%vJJfoO#=2,$XgJs+%+2KKKKKK", -"KKKKK0+&+,CJJc$+@+@+@+9HJJc*#+8JM=+:4:%%@wKKKKKK", -"KKKKKK@%%OlJJJny0000wsZJJJJe+@6Cv*@7=@%@=KKKKKKK", -"KKKKKK9X*+,BJJJJJJJJJJJJJbi<#%*>;#%j7@%+0KKKKKKK", -"KKKKKKK%+&O4nJJJJJJJJJJJb>.#%%#+@%%*&%@*KKKKKKKK", -"KKKKKKKiX%&O=uznNMMMMmci*O&&%%%&%%%#%%+sKKKKKKKK", -"KKKKKKKK7X%%+O#-::::::&O+&#&%%%%%%%%&o9KKKKKKKKK", -"KKKKKKKKK2O&&%++++++++@%&&%&%%%%%%%&O4KKKKKKKKKK", -"KKKKKKKKKK1+%%&&%&%*&%%%%%%%%%%%%%%+2KKKKKKKKKKK", -"KKKKKKKKKKK4#$&&%%%%%%%%%&%%%&%%%#@2KKKKKKKKKKKK", -"KKKKKKKKKKKKq*+#%%%&%%&%%%%%%%%##*tKKKKKKKKKKKKK", -"KKKKKKKKKKKKKK4*@@#%%%%%%%%%#@@=2KKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKK6>*&%%%%%%%&*<7KKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKK<&%&%%%&%*2KKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK", -"KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK" +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.% % $ & $ $ & & & & & & j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.% $ % % % $ $ $ & $ & & & & & & * * . . j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.% $ % $ $ $ $ & $ & & & $ & & & * & * . . . . . j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.% % $ % $ $ $ $ $ $ & & & & & & & & & . . . . . . . X . X X j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.$ $ $ $ $ $ $ $ $ & & $ & & & & & * & d U c * . X . X X X X + j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.% $ $ $ $ $ $ $ $ $ & $ $ & & & & & & * _ u.h.h.%.. X X X X X X X X + + j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.$ % $ $ $ $ $ $ & $ & $ & & & & & & & d 8.h.h.h.h.%.. X X X X X + X + X + + j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.% $ $ $ $ $ $ $ $ $ $ & $ & & & & & & & > i.h.h.h.h.h.%.X X X X X X + + X + + O + + j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.$ $ $ $ $ $ $ $ $ $ $ & & & * & & & 8.h.h.h.h.h.h.%.X X X + X + + + + + + + O + O j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.% $ $ $ $ $ $ $ & & & $ & & & & & & . U h.h.h.h.h.h.h.%.X X + X + X + + + + O O O O O @ j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.% % $ $ $ $ $ $ $ $ & & & & & & & & . 8.h.h.h.h.h.h.h.%.X X + O X + + + O O O O O O @ @ @ j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.$ % % % $ $ $ $ $ & $ & & & & & & . . . ; h.h.h.h.h.h.h.h.%.X + X + O + + O O O O O O O @ O @ @ j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.$ $ $ $ $ $ $ $ $ & & & & & & . . . . . c h.h.h.h.h.h.h.h.=.+ + + + + + O O O O O O @ @ @ O @ @ j.j.j.j.j.j.j.", +"j.j.j.j.j.j.% % $ $ $ & $ $ $ $ & & & & . & . . . . . . G h.h.h.h.h.h.h.h.%.+ O + + O O O O O O @ @ O O @ @ @ @ @ j.j.j.j.j.j.", +"j.j.j.j.j.& $ $ $ $ $ $ $ $ $ & & & & & . . . . X . X . G h.h.h.h.h.h.h.h.=.+ + O + O O O O @ @ O @ O @ @ 5 @ o @ 2 j.j.j.j.j.", +"j.j.j.j.j.$ $ $ & $ & $ & & & & & & & . . . . . . . X . G h.h.h.h.h.h.h.h.` O O + O O O O O O O @ @ @ o @ o @ @ 2 5 j.j.j.j.j.", +"j.j.j.j.$ $ $ $ $ & $ & & & & & & . . . . X . X X X X G h.h.h.h.h.h.h.h.k O O O O O O O O @ @ @ @ @ @ @ 2 @ 2 o 2 2 j.j.j.j.", +"j.j.j.% & % $ & $ & & & & & * * . . . X X X X X X G h.h.h.h.h.h.h.1.O O O O O O O @ @ @ @ @ @ @ o @ @ 2 @ 2 o 2 5 j.j.j.", +"j.j.j.$ $ $ & & & & & & & * . . X X X X X X X G h.h.h.h.h.h.4.p D O O @ O @ @ @ @ @ @ @ @ 2 o o @ 2 2 2 2 2 2 j.j.j.", +"j.j.j.$ $ & $ & & & & & & . X X X X X X X X X + : l l l l l d O .=.O O O @ O @ @ @ @ @ 2 @ @ o o 2 2 2 2 2 2 2 j.j.j.", +"j.j.$ $ & & & & & * * . . . . . - c ^ } .X.} . . . . . . . .$.e.h.=.O @ @ z ...O.O.O.O.( 8 @ 2 @ 2 2 2 2 2 2 2 4 j.j.", +"j.j.& & & & & & * * . . . . X X A 1.f.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.@ @ 9 a.h.h.h.h.h.h.h.| o 2 2 2 2 2 2 7 2 7 4 j.j.", +"j.& & & & & & & * * . . . . . d 8.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.=.O @ z h.h.h.h.h.h.h.h.5.2 2 2 2 2 2 7 4 4 4 7 7 j.", +"j.& & & & & & & . . . . X . / g.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.@ @ z h.h.h.h.h.h.h.h.5.2 2 2 2 2 2 7 4 4 7 7 7 j.", +"j.& & & * * . . . X = X.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.;.@ @ z h.h.h.h.h.h.h.h.5.2 2 2 2 4 7 4 7 7 7 7 6 j.", +"j.& & * * . . . X * ` h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.@ o m h.h.h.h.h.h.h.h.5.2 7 2 4 4 4 7 7 3 7 6 6 j.", +"& & & . . . . X X X c g.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.@ @ z h.h.h.h.h.h.h.h.2.7 2 7 4 7 7 7 6 7 7 6 6 6 ", +"& * * * . . . . X X - r.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.o 2 z h.h.h.h.h.h.h.h.2.4 2 7 7 7 7 7 7 6 6 6 6 w ", +". . . . . . . X X X . / h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.-.o 2 m h.h.h.h.h.h.h.h.~ 2 7 7 7 7 4 6 6 6 6 6 w 6 ", +" . . . X . . X . X X r.h.h.h.h.h.h.h.d.4.X.) P P P P P P P P P P P W I W W M 2 2 q Q Q Q Q Q Q Q C 4 7 7 4 6 3 6 6 6 6 6 w 6 w ", +". . . X X X X X X X d h.h.h.h.h.g.<.Z + O O O O O O @ O @ @ @ @ o o @ 2 o o 2 o 2 2 2 2 2 2 4 4 4 4 7 7 7 6 7 6 6 6 6 6 6 w w w ", +". . X . X . X X X + { h.h.h.h.4.d + L ;.p O O O O @ @ @ @ @ @ @ o o o o o o 2 2 2 2 2 2 2 7 2 4 7 7 4 6 7 6 6 6 6 w w 6 w 6 w w ", +"X . X X X X X X + X <.h.h.h.` O P u.h...O O O @ @ @ @ @ @ @ o @ o o o 2 o 2 2 2 2 2 2 4 4 4 4 7 7 4 6 4 6 6 6 6 6 w 6 w w 6 w w ", +". X X X X X + X X X 7.h.h.) : 1.h.h.h.x @ O @ O @ @ @ @ @ 2 @ @ o H e.a.a.a.p.a.p.0.2 4 4 7 7 7 7 6 6 6 6 6 6 w w 6 w 6 w w w w ", +"X X X X X + X + O + q.h.%.p q.h.h.h.h.p @ O @ @ @ @ @ o @ 2 @ 2 o a.h.h.h.h.h.h.h.y.2 3 7 7 7 6 6 7 6 6 6 w 6 w 6 w w w w w w e ", +"X X X X + X + X + + q.u.: 7.h.h.h.h.h.p @ @ @ @ @ @ @ @ 2 @ 2 @ 8 h.h.h.h.h.h.h.h.y.7 7 7 7 6 7 6 6 6 w 6 6 w 6 w w w w w w e e ", +"X X + X X O + O + + q.^ { h.h.h.h.h.h.p @ @ @ @ @ @ @ 2 o o 2 2 8 h.h.h.h.h.h.h.h.t.7 7 3 6 7 6 6 6 6 w 6 w w w w w w w w < e e ", +"+ X X + X O O X O + 5.d f.h.h.h.h.h.h.a @ @ @ o @ 2 @ 2 2 2 2 2 2 h.h.h.h.h.h.h.h.t.7 7 7 6 6 6 6 w 6 w 3 w w w w w w e < < < < ", +"j.X + + O X O + O O / ] h.h.h.h.h.h.h.a @ @ 2 @ o o 2 o 2 2 2 2 0 h.h.h.h.h.h.h.h.t.6 6 6 6 6 w 6 6 w w w w w w e w w e < < < j.", +"j.+ + + X O + + O O z 7.h.h.h.h.h.h.h.a 2 @ @ @ 2 @ 2 2 2 2 2 2 7 h.h.h.h.h.h.h.h.t.6 6 6 6 6 6 w w w 6 w w w w e < e e 1 < < j.", +"j.+ X O O O + O O @ @ g.h.h.h.h.h.h.h.a @ o o 2 2 o 2 2 2 2 2 2 7 s.h.h.h.h.h.h.h.y.6 6 6 6 w w 6 w w w w w w e w < e < < < 1 j.", +"j.O O + O O O O O O p h.h.h.h.h.h.h.h.z 2 5 o o 2 2 2 2 2 2 7 2 2 W p.g.g.g.g.g.g.w.6 6 w 6 6 w w w w < w w e e e < e 1 1 1 1 j.", +"j.j.O O O O O O O @ s h.h.h.h.h.h.h.h.| o 2 2 2 2 2 2 2 2 4 4 4 2 7 3 7 7 6 6 6 6 6 w 6 6 w w w w w w w < < e < < < 1 < e 1 j.j.", +"j.j.O O O O O @ O @ 9 h.h.h.h.h.h.h.h.d.f o 2 2 2 7 2 4 7 2 4 7 7 7 3 6 6 6 6 6 w w 6 w w w w w w w w e e e < e 1 < 1 1 1 1 j.j.", +"j.j.j.O O O @ @ @ @ @ p.h.h.h.h.h.h.h.h.e.j 2 2 2 2 2 2 4 2 7 7 7 6 6 6 6 6 6 w 6 w w w 6 w w w < < < w e < < 1 e 1 1 1 1 j.j.j.", +"j.j.j.O @ @ O @ @ @ @ <.h.h.h.h.h.h.h.h.h.g.,.Q J J K K K K K K K K K K K T b 6 6 r T T T T T T T N < < e e 1 < 1 1 1 e y j.j.j.", +"j.j.j.@ O @ @ @ @ @ @ H h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.#.w w n h.h.h.h.h.h.h.h.! < 1 1 e 1 1 1 1 y y j.j.j.", +"j.j.j.j.@ @ @ @ @ @ 2 @ w.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.~ w w n h.h.h.h.h.h.h.h.3.< e 1 1 1 1 y 1 1 j.j.j.j.", +"j.j.j.j.j.@ @ o o o @ 2 S h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.g w w N h.h.h.h.h.h.h.h.3.1 1 1 1 1 1 y 1 j.j.j.j.j.", +"j.j.j.j.j.@ o @ o o 2 @ 2 ..h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.9.w w w N h.h.h.h.h.h.h.h.3.1 1 1 1 y y 1 y j.j.j.j.j.", +"j.j.j.j.j.j.o @ o o 2 2 2 2 ,.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.g.B w w w N h.h.h.h.h.h.h.h.3.1 1 1 1 y 1 y j.j.j.j.j.j.", +"j.j.j.j.j.j.j.2 2 o 2 2 2 2 2 [ h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.' w < w < N h.h.h.h.h.h.h.h.3.1 1 1 y 1 y j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.2 2 2 2 2 2 2 2 7 C w.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.~ w e < w e N h.h.h.h.h.h.h.h.3.1 y y y y y j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.2 2 2 2 2 2 2 7 4 7 E 0.h.h.h.h.h.h.h.h.h.h.h.h.h.9.V w w e e e < i f.h.h.h.h.h.h.h.@.1 1 y y y j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.2 2 7 4 2 7 7 7 7 7 7 t K [ &.>.>.>.>.>.>.#.~ g w w w < e 1 < < < V &.*.*.*.*.*.o.u y y 1 y j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.4 2 4 7 7 7 7 7 6 6 6 6 6 6 w 6 w w w w w w e w e e < < < < 1 1 1 1 1 1 1 y 1 y 1 y y y j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.4 4 7 7 7 6 6 6 6 6 w 6 w 3 w w w w w w w w < e e < 1 < 1 1 1 1 1 1 1 y 1 1 y y y y j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.7 7 6 6 6 6 6 6 6 6 w w e w w w w e e e < e e < < 1 1 1 1 1 1 1 y 1 y y y y j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.3 6 6 6 w 6 w w 6 w w w w w e w e e < < 1 1 e 1 1 1 1 1 y 1 y 1 y 1 y y j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.6 6 6 6 w 6 w w w w w w w w e e < < < 1 1 1 1 1 y 1 1 1 y y y y j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.6 w w w w w w w e e w e e < e < 1 1 1 1 1 1 y 1 y 1 y 1 y y j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.w w w w w < < w < < 1 1 1 < 1 1 1 1 1 y 1 y y y j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.w e w < < < e < < 1 1 1 1 1 y 1 1 y y y j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.", +"j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.w 1 e 1 1 1 1 1 1 1 y 1 j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j.j." }; From a69443bd531872d5e52ce8c9888053cee0a48552 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 24 Sep 2020 22:40:18 -0400 Subject: [PATCH 0426/1888] Missed icons for nsis/resize --- share/pixmaps/favicon.ico | Bin 1150 -> 21090 bytes share/pixmaps/nsis-header.bmp | Bin 14676 -> 166398 bytes share/pixmaps/nsis-header.png | Bin 2730 -> 14081 bytes share/pixmaps/nsis-wizard.bmp | Bin 132552 -> 51014 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/share/pixmaps/favicon.ico b/share/pixmaps/favicon.ico index c9a1fc95920d4c0d3617d2c0920481210f91b58b..74152d23918dd1dcf904e8f6dffd96c135c273ad 100644 GIT binary patch literal 21090 zcmX6^cRbbq_kX*tO?E0|@0BRYxK?H|Qj%3vO0vhbu011rWL+V$6WO!Kc6}(9>^&~7 zYhAAE`n~)9+&|pw;lAFl_jx_f^PKZM=M4a4;OpNH8NdtNHwA#p;QJWk2RaP2*J#1F z40^g+;9vj!4;esB3I4Kj|MKeJCl~hzW@M-WpDX|{rPR|>H-rD(X`_OtzC6B-AO%<< z&diBZ#u|Tzituy(H#b!T1)~zd>r<~er zhJeAoLZ(bjc}f`WM%PE>AY6@dQ2(b^pnt9v*kt{oHdRl2=IelnzKNt(Gd4*jZAC62 zQG+Yr)ogAse|6=jt(i6c*nWK=nKEB|S$mf%xZI#xoSgER-k!Dwd}&u%hz;)ZgMS~h zN}4riA)^*s8lWkvUlVn%2eg;9w zmUs>z-BAY+p|c3}F&#af8@%+7%r0wv(FE_Y36KuUQIlQKVXAq*V+Z{tUy3~IT5xoJ zY`u4x9Cv>9DYZIMgGcs+b%3?EBbG_Ec+z}M!zzg5^r(S0P%Cv?vuIXFV1M|z!;(=3 zu_+~Ko?elS3>vcZX+{mVIK$g-S;RSc5Bf<6rosJ?3+gEQYNqKsqZMO$;q_qJj_bcxBl4t-SsNE`@&jZ&%D#a~)t(}JM5XY(UOg(;n$DK6 z#5Qun7~31%OGY6z)O~;5-KC0^P;e!58V)(6<#Xr})?a_v!2_^AS11 z_kPkZ8a~%1eoUNCszNHTq8s!{vM)H91+NQRcXDXa=ZVZ{5Sq0iGz zJol@(EXy^pg5g+x=Z?t6Hrlbv>0>Y(v#s(kGRNtvHY-whtu|(39MRn|%1SD2^3UwQa>vG%T~{ z6y~VT!*-_oN%rLN*0HRR>Nke&b4E5luS@KHUe6ZIx_wLrQPOCn;%P6R+09gTVUkFC1;+Q}LPq@M+tqctVW@6}Z9x9KS*0KAdM<%+|I6U(b zV}d}tR28bn|B^@GdumpD?M$fLkIz3XlJ*0qWc6ci=&dKQjMDn*Jw1u^g!VLr%`o0I zf8{{z%;r66zWIf}5~1oAK#p78w{yXr6&-avdl1l4N6dKL>fnM_U@&*8^X7=%PJ@W2#>tFC zpLh%%d01}{>XU;YIEED-&F~d|=1}~%<0vt1u*BV-%OZkFz{8tq#8XJBFa zQ`S7ycf{LI-8$N;XerTyN4Jw72g$rSLRs>+Kco!IaBOw3MK?ry#_DdK4!u5|+lD`~ zf9`z|T5*ShZS64RMj@y8K!a;{qoD8^iSyZ`zFgzo@?zvcf63QwO9DS1N%3v>`cm5z zBOzy(P~4qxB_U3CvuWtc>3c=JYtOxoCQhgH9KV#c)5Pvm-U%K0<4E6lHTtLAI&lS~ zzmYGK+ITU0Z?53s;~3E5w_6aGPlp8OQx@m@dFAp`_z=#~P>-KQhi_ERE)ibol1#Lc zu`$Vc191;$a#IQz;t!pITRl~Zdi(M#QnML{O3Rq(HFD=Ec^?>|&d{j@QTdgei~bk? z_E*}E)a&0x_fxCsRb0#9sJJ&=#@+ZGZ+_CrEwkj2&>m9VUdMBB(t|K4xZ|?%j6Q9 zs=NaqE+z2C@;>$B6L?H=^!}#Z_;kOsHAkLX%kQ>^n=GC;$@1~7Y92=lOmNQ5r&#ok z#g@Rl_TO{Xlx9^9tc8f`I}A;k>0#poUq%w?G!TB$(TgMQ`R0_3AUlHJKEmH;0?eC9 zqPSl5*cED5egX9+DTTs8xp*$B{R0A@OiPqN>RHZ_OGp6f@|VLunmT>EzN@NRHwnCq zZhk@<|Y z3bFFH&Gt4AnlB{_^cb7|8m4?={hj!IbfJM=H{0lL@Z7!6bKOU6!aVzKxV&3SDRQcB zjxvh8mS+`U@yMY4TO)NK`~IqOi6?ryf|kkVmwN0iE|BC&Zejg?jD^kEtoc&7#_q1h z#GjiNmiaR}22amz8c7!M#tisKQw=C#*A@1K=cqOdqde||FOEsZHgo66Yt(x#d$1$>s zme$`orF>OE-K$mDVw}xoxAR}EWC5Eo3LiuAR2*}FuLY|O@gQ18QFl(0;$Ea_XU_X5 zGL!Gw8vpWyS~cCATdofA>lg+D1HS`FT0N%0so`^mcOx8CpN`b_C!{OwjlxuQ{4Wat zj{JanZpD?uDSZ;#!)})D{>X6__Lf>X&(Kup)s+l-jSq>OOwC2&fi3-t9gL9bmGN|2 z-KQiUhaCdQF*;O%Ka9oZ>W`U~eTnjaTPkRS>8$3(PwgubVcz^>EGyVoMQ_5}6B(zP zR&*09*Qqz_oNT``=w>srxBD%TEM)|24Tfaa7na&KR|yeG?g6gr@8P?>$Wi87>cC9@ zkrc1uhXCQe4@D(qf)tE(c!@4@9TK2Yv1n z=wTe#DK!Lzsy7zv3O`Z4TlR}4`2Dg? zQbA?Vy`+W{d+E9C*=hg7q&bGIv%RQshySkLqj+W;VJoC zE)gIj6D7$HSmaO-Rfz|*fKa+N2q@IkL68jN4j%5KaSG=Z z-IndeedPy|9N1x!`-tSeFMb%c&_l;zEdcQGPxSiBxt+V|ratGtmrQhWFLO71pm%{9 z^YBVcFO0~c-Tn1Rulz#?#Xz8E93Z*q(%9N5K9#ij$z4Aq z2;ObU~}8>>jYQdcIL+2URnG z@|vxr-yRE@za5o`jK}4r z)bEYfb~sH*!3n>wdea1FgORU+Slq3Uj0~9(g-qWZ^b69a;1x3Wc$3mG(15%Xr0{!R z0VRV=uN0H#JaNO#Z8z+VzU1m4t-jqD$l?W@uVD?RkK(%(?v(|IifJ|p7q&VeVvVWZ zP!J5#h~#mACsakLy4&)TnEZP}Bi!ZK5`MEE|NA9=c=)=5k(zLT5z+3~Vf2mP3SGjHVy%O*5^&pDj3>yqf6Q;4a{qlnGr zHgKW&S$|JX)O(}$h$?Aqz!PuxtrTd~Yt4}7L>uMl22hq#GBMxDO0BGlHcVId-T{it zhj0zl{T4homBlm7{RRVmi`}ykkoo7&6+YOHDKI(R@JDZ~PjDR_FCqZ?OxjMX7`&6y zsZ>&s8FY-DM`X3^ASt86=a{2xls745*R zdyjtNVc!gZ8QD35thIa;7=3BA39}R2w{@W%EryfTO-x8LWtVk4&q1y=}{Yla3Fbq{fY9EE(~YP*=?K0 z+fvge8?*gj!s!|~{yF<&7k_{w9wW&f+{A?Kf3-?rO?*HiI<0;Ry367<{*o2mtl1W=cHQp;38LC zP6ECn3Fa)m&)PkPy5Ex&uKfMR?T0iWh~dPitG^m((@x5$acRa|vF!!%_Yu$p6sg5NqUN3FU95!`_R-&2fvwQ z%vv@_6LQWBHaQWkq`~(AMJ-KmlJqoxz?6c&KL<5m4AyNqfcwE zb|@W@D^YY>BbR;hF-B^|c6X%BKQBss30oPE)~)m|^i^v&mtZ64g2w&$5;p^8rrz&P zhZS~_~8{>5zVtXO`aM3$5KZxdk76JNf)c5+%;N z9+-vCNJ2dXUCOdmAw?Z|Ykz#!|4kP^KVWGg0>o&OHA0u$-lV_=p;NIB-83Fq+^=W( zvDD+_eEtXe6s6&UQ;Gte?DZg`(9=Y{)@eg?^F0o zoe+JJU-6Oc+C_QI1oAz8`#RQ88!?{iU%?hE%@3H^IgdJ&W3m%rcc+6Vl~?O$j=vwU z4ECGkN8Zy3(cr0hzJ)DkyG)3F;EKyzrV5n8m@IE`C;+UoaCwF+ z3PL1NcQz3_IdkG z+-CAokI@ROfZ$5dt#&PcL#rCfB?&8Hu<_?-tY)Y0LYz=fMfcO*(gtX8fa%w*Dwk%r zjCYW|O_8V?$qtSbd%^ANhl&G7a>a{;6!0c=VoVeV=wwgD4PS>slee1r-jveuFo`d2 zf{-sdGLK5O?-T*g=`LDV(Oqvco3*r^r5az84#?gH7(R;p=F z`-jPLtDuEk{QS1MST&V6)N+l3ppOO7xqgXIk%Z*Gl}fFq;tze+du(fOS2yV!rs@Oo z*XvWm7+5SAk50>4QZOy+y=iaxYDOrm)jn0{sOc*Kd~eQ;z(hL5dY<-l+(HU6?cmV(2iC%PL&7)dJ)TR4w8=Ez z=oMuM+1n*C$|`7v>D91+@$NGSy7sM}N!p#z$(sz_=sRw_nL8F#;oEg|uZQr=xy#_* zLC;D;zJs`)RT{-Nf$84x$dMt_M;%_XJb~SL-S)`D7cm}vwnNx3{=9UxhOeDE-!k6g zt>iXpwTLEU)b>#T7isH`bfrx~%5N#<`qAWvtn|A)zZH9TaY z`3dxskp$bxKu`BM$^&;@$toxmkZ-gBt|MMEf@vm*MMIJ@9g{dphrO(uSy8_cmyJ}q zbIf|E&S!LQ#&#JL4iO3O@srDhVgrRu+N#SObe$Qth%g2(kcth!Yo|*E6?yG*CRPW? zG@I=(TNgx5I#PL)F)SKs=Aj%#7y4JiS2#dgYQp77tr*#d09K8zWIlH=#!AhKr?N#xH*(7!IK`yjx4YmS7V2kX;dd{Aq&9Mr2_p z21-VxbE=qwxB1c4mQNNWrogyS#dB!E-|mJhE{85u2c2KZP;e4n$%t!K7CIl9Mt05R zo!!VI-33o|;7CA(B?u}m*c%-9-)dF_lWF6EBMAy8WGK8;D^*U1)C!FpEVz85i z9aM6rkHYuH+(wYug+F1f2tdZBHM*@0|2(G&xFa{`aiNZ+SV~BOwRQ$a^Z&`)5Z?*i z&}ZnDY51uGp@7_4IS~APZV-KjT(m;wf_&g97eTbKo_ZRv`Z@4~l5c^tn)^n;hlK>W z9-d1#$lFWu0>~R&{8=osUAneC8I}n#!VeMpq~9+n=7Q#3a6cm655=o3LxUM`d7PkA zHU0uBklzR7r$bpm%Lm#9W>0v5N945PYZyMA3hREoaY6um{k1b zM(1bqSQ|D6v)67wVj+b5;A&p$;G4ook-I;@V~)p5rr6#+{Wbeq$!X?0P7&d^h8h@M zsIo>af0SGQHA~Y+t=1Y2GWsIn^l~&z13`JOOd#pyR%V~+EiLrOQdfR*zG0%KEpgF6 zVQB71NhSu4VwdW$o_L2^%98dwE*Y`y@Dw1etp?sv4nX|)oWBMEvng*dMEARB#rSC& zXF=>TP@_HZ$$^LDN1(nViO5ELk= z46ZwfNmsKB;J>6j>V!E5u-hiU{Yk-quy z8Oe8pGKSB&=RW2Qw3LsZ@(?qmE4J1nR&(c3RGOm76U!UHM?!CFYV1^`6$;!{Za>vX zW9HPZi7W7PlsEqUq>F`oYuLoU@SdcQR>=#Or#0+p`$``@NZ6nY>FbK_?gMYTN`Y<` zvdmIUFLP*bGE7GE%g=8@Z{75kf8m~}UcW_u`}r^}=F9CKee!{86ZU>?9NNsx`Tt5u zrPKG?vTQbGRU#Syv)on6%O^fb($9ti_-ywZ%a_`$IGRbGl!5e%VpC!F;s!Z{-h8d` z`}+{ae>b`**IN69f?++icerek#;CFzs#-;!yk@urXt4@rq>8!fiJxq4DsgQ7Wc*1khL zq6xTI=!LHb$~@ovc68;9G(__1p@rvp0ghV6MCJN;elE`=xnV`M=g(l909zd$wa9Kz zrbi%McgZCqYNLK5n)#Zm8l{vQHZDur7O@_8t$|B|h^t$c?sIRWFiv|IP_M zh}gS%F~fr(3hB2XLQE{&(O|_Q2n)0O^L&Z4SVtcHv@CabJgCz1q{N#M?PJrb!{JiQ z+8|^2r?BkEJ76Qvd~d;@XSvj+!{Iu7aUctrF@mbymD=wWHgJ2189q7X(6K&7Ayy_E zCX44{lC+>!TLg-6-u4h8WoqefK8o=G@vppUI{6(MqD| z#9C$%c5!?)?^aB6<2Mt)Y53?N!}__x95EY%y`{Xz{OZy1^B46$zT@)VRiSu2q0c{; zsW2PJn`=$_(Th@VMFhYUL-_UjIC5K4msRuwwoX3xKjktzmm%Ts*yYlcd5^ff7~qhV zOgHr}7xo@2KBLShUiJRUKtatbbR?B*jyKu%wL?RYM1{6e7TL3kZn)D&*R5VLW~t%c z56JF6wf*Z;`pcgl7k0Ns@==r}6(WM_nCAx)acwPA*?=sX5AqD7sUknog6}eaa)8}i zp>z2!f~zV4FU%LTp|vkZEn$wQSTEJU|r=WOBW z>}b1?J@`5JXPY8_+6-`le-Tl&4v{(c=6OrvJ|?Z&WkM!32PpTj+OpDOaKn z6Y4JZ;bSCZW9m}d;j?{wbYemAkvH*xlV@R+Y5n99Gr-BSYS?GIB;h~za=7CsiJa%T z{+kT1B_-Lp+Mc7{PiBGq6{f64fXSe+A|;$@1@~7?G_g$PvpSE;I(nUPq1vZoB+Kim zhbfR;bQ{)-Oe}qt3kb53MfbhD*Xkg5swt}9k7jrDa+M9_6?IA8kTItEv5+^o4_#WH zC1go+TEoH`5f6&!(OG726?Sw1~s`R)urGzInBqTV4u9XF3ObNiJ>sGQa@>m=6|q^N8d5 zpRC{;ZwEEQyZrhNST*xH>hhQZ;nKbShpjS>jWqM~c)s2T4m6#e=T{7&of8fCrP?Rr zK*iO=QmK@V-?Rh2e|}2a@*AU3gSSyIGesV&ABPI^Ly~hn6z2wMQx^PY1BYr)tQ0MP z9Gkh&PTy5;l3@s@eSM-}Vnx@pZqnImM^eiw7A$*ho&#{59CwFlpv+`BWeQ`>+osTG^w9yI{{2by3hv}aFK z1kk8DmpyjW+lS&UGHt^&-@6%YCD?muGX$)n5gcoiONe5Jgz z_xjAw@8^=t!Jxc230D-sPz0;s@^)4fs5=)Eg|e6+(YqVueKeRzt00;c%06+L&8V4k z_XmCtjUI=yVVid>xUSzt)g%}~62)tM@itbMI4SZue@?+RYNPXM1>`lm{$vd-h%qH3uvj*61Y^mYCh~hZuA5ao!ElA2b}2#9X??! z1%i4&Mt~T9_LYBHl+96Z1u9@#6pCGCa1^ZEENtZG0*@HSRB;qiEYZ^q# z+uhzi`H#bva61nRaezY7C-Ch`wY+-TnyYK2uxO?#b0(*#P~s}w zvz~J|D??2{*rH<<#QEbYm(WiA;RJO9`BU}7NL~%NI3#zs**~G4G^jtZSi-}-mifz$ zY&4rTn4ty#L=1Rj59zFjqb~1LT{F2yYSbRTs%y(Ia$rHxM3(&S|G#)BYg;v=1vptX z_rD^0_U0c3K@n36s6S(W0DD!C#I8GY~pNIu$KAl%0oC2GuE{A#ydI(@!t2y0*mB)~-81H}tqn+}m@ z+X=A6s;Hp%vg~)Yfwf>v!ly{0P3|j|9l(3_>&%fDZd@SxEXC+~0qs2E0LxWAV+c&d zQwIy}TRv&tEW5Puqvt)G5LMfV?d1FIHO`((c0uI3WbE;=64Ct z-YomY4LrWTMJVR;k7q+D$u$V=vm{ z-cliAa(9%zR(X?O<~X+VF1|c&nwps-`V*`)fA#8J>Ha8yP_`3exzER~SwJRRteZvM z933{-twbhfAAKz%&ezffGWKGKHGnlyHIiE3W(DuV+eyTx39ur7f8hH0jmDjx`j$?W zBHNW@2Z|rE&}{yB2rXNEOZx$GxqTgHeu!?8>>h<0J=~na6b*{3H*A5p%qT1cX zHapIb{fU?}o@Id++n$hiDp%j1uO$0+e*D&=5bkDi?`29vh2Ig=Jn4pC6&8vMjty2! z7Ut)hV%wK3isPGOyInC|f24}Al-d5e8KcTMLP(FsZq52X2eovHzq$bz*QCh#0jg3U zV4z+dDYRa)6O^zd%|+-x#S?-KhQ)}>JeL-v6jVYC<1J+q8vR)K;1E84emyqcWFP)JbP`|pDc?(Gu4kFg!iWqD zp&M`&E{yxNo^*_sl!0qiE?`ppbjQ4o{LU~agC)bHG~zy6Sf4C*w7cHH870b{8_2ZA z>u;j2mKen`%jw?cJHN9pG8saYbUS~d)7U<1iAeKzS`@P{!DQ2Pz7YpBoxB5MQ*SWq zXSwvq!S3uVa`Q(3hw3EwwJm2*aF{q-;J7Rg@^@SAJUA{h)EmHfBwQH8Zb zE8NTVrv9cO$T4+uLrx^U7R7XNhD9wMpmuv+X%N{owoDonex#nb-TaxK zz^n2o;?^UKaV3G`K#vL`=W!0I`X4wCn~qjWUec9QR(l5WjtWnP+svODz0RsXep*1=B0;Ukk1E2~Ix~|u zHy7g(rh3+-s<4rra{@)Mc|C>JH?=FCJ{0Ibg|*PZ2zwpg0v9!f^GhS#sAuZ+*I5gP zqhU*gxM|k0lH}#iF(FRZvtgs9=^&B_EBQ4{E$YJ!-yn_F6&9|;;ShNBBn8eUV)hL|{yv%pHG~&_-U@j*!)I~$Z!yz@LP|JAcjf#C zutlMyPtUD7NPKY$B0*z9cQ&#yIGfEG*FcYbPAG3UcbKZj5@!;Z^bf?2N-g3vYVHcL zPqW(2&8Fccng^VlD8B4}h+oJKA^@nI8dcALgJH%S5(e*SiYq~Z&Mi!}o`F!ogsi`a z6aeU~gXqIE7ww2WJE#%qze*%-=h+i#kBNpA!r}A0I5T#~M?Q;l4Wtk2BMgRO!cTW* zhXh)!T0!Zk!ZVPw5B30RY~dd6|)Jqa`0~;d(#>C z#VNUUC&Jry{2bp<|9@9!K=t?z+D8t}(__jHgwJqTvty?;NEJ|__S4>u;b> zU6g;sGntBNtLh}Ws7>A(avB9UdpjA_NjUff%#`Kdp&4t9S{1J1#7z6D*9KOBJ8x zku#egI(Z0kBzzZ~CE`LEedsOzL6`pDmsSSN(mP;N>JS_}i8kWR|AM}xuAO;OCjox$ zb72cE`+*=5VLB!E#*AR+*DSN@4FzFuPUTF^;Nxq(dmBkE4!<7->~%S0iu|_MDDWKl z<^Owg`QX-M%O;=lNdjtb#z<4z_u$(_deldA?^*u2@|;(L*af(Y>AnoNdfTzQ3M624 zOC70*i`NyNpKe^yCaz72We2@(R}FxC&TTMyeYTljtvmTsdG~Bwa!xd0F`_{>Cegp@ z5<&DdCH4@0A>d!k6?ylY^gks{0T!pOK>-SYymPf%1cP3hPLN+tQW?Tj4RmAK>@l(L z;Dp1g*@)L0_#>bB-W;qU&(^1v>dL24L0OBEU3CaIG~G}Hw};f6+$BOm|LOVhMPS$J z*=4ZBY1_p>*#5IGlgkSrP08+Ti2s}IyF&g2h<-dj(3++6h=CE=tAvH8`{vE(5G69+ zb%jx>)(kSP#b;lC<&1HY0QoPbJz7#xn!}}cS>!m8<66{tuI25xhy%!A0*J$?~DLrZp3zgzUti zKe5?+qn~7Ujy3gK=mYU8Lu~;bJ3DQ<`|`;Dr^dh^58YSz{qBV{rq02TDOmCF*amuf9$Op_Kg@o(%^YkQ z4X}xV?F$y%TZauo_(|cD;%SOf=Hw%%H>dI4MlrWKFO$LdaWK25$#yg4EvrK0Cm9`+ zL2viI0D}7KGt>UeQ|?w{&Fn^#o1Z28snr;ngFD?Iodpf}NiM9RI)X$Ejc-0O1OC!X zMde<_8m@uvJijWb8XAoc;bmX~DthoGloTK?l0#80kM6HPG@$;R_I)LeO6X_0F zbiFiy-MwHs@MzYqUMV*BdUMNXia6AHpF+)n4N!>1JNf!2e1{l+S)mLB#YmlKm(H8B zvR$H?ZrL%m5+$sVzQm=)?{)w97pkyxCp$=T4$*NP1PDr!5N8N`0_^*3vB-@t%GZq-lfNxkJo1*2^BTM^f z1D4!+*U@pnAt)X+xhjfeEB&jBK=3MvfQuXxZoRDz&1b_Af9v+Mj>Li4^+hJIeMJN~ z6qjyJ9)xo%oSTXH$TplcYXEBlt2v8J+dBYw`VXpHVzp;k$xM#|M5&Vj=HPeWmy7w^ zH`%S1KHwmG4Pi(-)wT(Vxv%~*GUf?q$LE7$u+(Mfvk%rISAUs;W4Wex8&<2cgikH5 zU=8(1FQJ28(*fc~K=@%Ii_m7BK2dkQxqZ`vm=0a2w?y(gAi~bZQJf0fuc9~aljU=I zuaB+fXp?>MrXm9ehDw)IFx@Ee%5#dN}5Or3yAJZo`&HBLVNcLV-s0RtK<1f9@-JIrwUi zf0lvVTz2=7&VOH&hFr!dnSt(KF``w%kgxL=Ai}y8cIOJoRZZ3}DeFLkldDTGHf!jO z%h&zH)=B3)caNgnbN-DY{QrWq$26UlT0m@C4hH2pihia|lqH*#c~aSy1@Q8lKvh5P z9Q2tin3&TOgr^(dvH^Z!jI%!;KK_fE={Bfdek_iy+r0I>g-(r!IhbuTXZnXdQ*bs| zZ-VVwDzrim?QCI)->`DW1Af3a^ip4JqK11Myt6c{{iGEAj*}u-J4mK=&*8rC4y-K< z789U)Fl71Q;*&f_a8sSX%za&Gewa066x4?1MgMt=5}L;&Xr=l$!-@2t5c8x^Pe70V z6;mdgK$YMMkNZbVcGA2VFp{I#Td`O$!ebO(_|2UGf$NdYpiyIE4sNRVmjRoQ?3NUr zptzq6IvH~iRFf!dEwl;gG%6ye9!b^IsL13GXCi*Br3y@shKU2=dv^croUCTdFMNBM z{jud_GcbTWjInWL{Q?vX z{QsH>E!1Ee#ISJHr7oDgxdHmFS%T(SUFbul=dNA6ij=zEO@BdhHIiozj`GIJT6Gyh z^S^%KU<^F`jDhCQhXP;k%++ck3@{BE2Qh%>wg+){*$ z#y((EH!IjETY1v2^x*@(Sn#56BKHI;HX&&d#hw;+#R$7-kiPg3)w=0U7JWaZ$q+<# z^A6MgdTN79m&*f0?=`ZGYwZ7aT!Z24H|n%3_177#YH^%74XUHl-2wWSY;d~(Oba~3BZ3aQ2R0=9Dm;i+sys%Km)JWR`ghC%Z`yQ5e7NY_& zE?!z{vuIT1YbTR9wB55jB!fQt{`wkI&R>LuY0ir8?Z);^l1g)&reNF8P1Hp;y0Rs& zr_b}_G?)!EwTo%c*ok|d{FZR3)dalbXh28~hZ3Q!!siF1o98bP1$t0m@t$r%lDbB# z)=nS%-;9EF$35&4cB>7&YWbEYXpJFq4-~?t^byOuZHfFsYZX@SgC_Al6aRyE!zwzV zmzEzG_WO>ysZV-^fiNY`U2==GS5xLA&^Um(d{g@-LCTLE-^}SF2fI>L5r{=Zi$&Z8 zRf=N4_K5hFE-mQIjOs31)dL-6-z}<)^M+kv2yg!X?C2h-A3!N_Bm$Qrz~>xQprS3$ z#=vRt@UOo|Bv_V(s+Gj&YWt6dy|E@_lS@AwfH*I(QS#)wyMXqq0c%d|)PF}(J9Bh= zNamMMos6-aw#xfT#R4ao4%MF>fhVWiuCLv>N2MPX- zNhVN8UEH@0Y63ge-!J^3Ea&Wyr0Y)7f)@q}LcPISF?ajBaCwjRvn%HcAYYveF;T(4 z{Fa&&WQC1ZFN4FZR>; zuz8Fjo@i|@Kkztb!*Kd+8n))TqhZu9p1QOjFy61;=<4H&uY%J9MNA{4XrY7^p|41>dOmeK|y`K+ZLwCOkPfRvwsB`c*s3Px;2Q;Z+R&4GO4Y) ztr0~2Vz88TmmYzL^nP4nJ-1Z6HQxTi&Z z=?(}`eMIda%bL=gl4V?-s3-gNSvBn!i;~CA1a|F2>CW7xHYRX3;rO2oAL4C4!#c6s zPqhHjU*}8{-?hrf0$r(YA%ok3cR^`?=pP%aXBoc_^2KVtu;f-k(58jq?ch~Eq?T2j z@p+tJP)rPZani6DX(|>${bP^ z-yxrPr>gjy0YM9cl@AZ_ymduyg|Es-698cr-ijn0va9g*Yvwk<(Iru#u%p|LD zdF)GaPd>vmXF9qayg2r>tZ!iU#a@Sv#yy}O*?ywd9ISE-1{MB}O+w|BeJ}Mt0Aha% z-FJMKFf7)J|8L&@9_CeC5!!iO{6-G7#vM>$z~zx!A=O!zN&ZAO6*}mcGqsHzwRh=? zmLgL_RHm68D7qe3kz)39`(1YkPtc+i8-6~1>L~1rg;umqGlcR7 z^Gbrwje8;NY}c6NX+JMUaMMvs)`up`LNg0~Lk3beP-?fXuP!e-Xhpn)nw6H!?$h<5 ziH^5u@0%2Ax6{D2C9g8JZ}Ona{zJ2D$zRUDcb%DH;+KDV-@JV2Bf@j{T^D}jLYoGo zw*r%pKKvokLEax zYjNsM6Fc30r`}fLa$z$!w}w95Seh{TZ7N!+b}Le7&Dc^qK2q%+B%b|sWnmUCVih2m z8&wy`7ihV2<-^zgcX55 zw|E6VnZvue4@CX>-p+p~7YjKsfAqGH*h)uDgkS!{=@i z)-2&H?te}O-eUR8cTIk3ZC@e#Vm1{pQ3Bap%Eq>U68v)Y2fOuSDvKRL;qH7zkS*`- z@xuG)GtLae-?sEL^``~21>=J58prQxMqC5wBpNp=TiZAh{Z`|{X`Ea^h-*KJzjtKv z0x1lqUx3yHJF;ij_wRaL%dVdZQ!Qe3JGm}we?$NN<8XVzxctWHoch(s(1UaFp0yczT+(f3ZZ2w%jMdaTjhSw9wWiL;KWZN)IY}!KI z5{Lv#RVW{6|w&Odd2Y7b@33|x`#WMsyl(?x$Z*tW%x{r;{e*9%g z&L*Kan*T&mf$rJ6b9wo=oouWoBF*n7Xn1KMD#~4`P^R-X(yObC`Mo@S!ws2E<-9O0mA?t18T$tF}8kv)8ZWfD0x;k^jdE z$iWh91bDkUl;eW816$Yr(j!MdWR^x2^wc#K);4ub#GL9dQIGHQz$B ziSgQv`=OgIHh!x6N--tRlBp}cLu)zc+Ipp9vgdnv)Daz?J@F?lyNkRNzd4G|QEATF zT`a?OGV6yf&$594@JZbfFu7%#pCmMRw{2B#wfr)gqYJSn?~IM@PgFN6j^m=}{*g(4 zO4HleZZ|ONzc}TddUPR^cQ-K7o`-I0(frs>E!SC_!~5$)fO6EKiOwph;t1Boil+_y z+uYUineNF$Rq){)-rUZMQt6KzABARbgSPqw<^v_h5ny}@xkaZX{inbMcZ+_mzqK5e z0`~kRfst#6@tPhS1n)y91Aouy*3LY2YKvORCy&UQ-Z5p((sU_u=l%EbTi~(#`R4B2 z`@TodOiS~!sTvz?{6MIFtMLDY_N*}k=D^Bn>~`?nV6NN-rzVFcVu^4@Og+zo`0|{* zJqt-oOPQpS{pe0Tcsb*q!+_D0$EZRs_>h9%?)G0Y;!h-OA#;NtZ(Fm=VZRFtd)rLR z*qqe_xV8ywMYFJ;l*9BS0l><-2$)EBA&IYvy54*9r*v2D4(X9lSODiw z+~PdlRod6z(U+l7j&zI|if5k%`sZ)yBdY&IPQad{*L*{)>yB*cDy03`sQWj=^Jk9l znM{3C$XO+%gO7cbH%UCby?hpQk!t@rC06z1VNv_lQ_p?a`$5H0KpCY?=DL^f!gb0} zdBI8ABHe>fyg9#hzHpg6<5PH_lUVp#^tXcA6`g;JU3Lp!?XUUfCASMZk?nmz#nG1k za;MFxF#oX}MxyC_QW&_%vI4fJ_7lF7W_3=+<|OYP;jK!k8pNob zfd7BP&TQUMgmnko=XrLR@QI*eJnrlk3)$qL2HBIvCup8`=hOb)R9=iW5B>&GZ(oNt zR3y$kpdMydH@1o5y{U7&>$Ife?=-_8G@oKM8-`bHrwUT;ZBuwwU7)a8HRHVF=fHx~8*A~ji(MN5 zYu0)n)}R_|%X5})U(L-A+ZoaM_5J*KvaMH}jQYAF$X^Zq`EB4;wDPjB zT2|K9}TpOMzd(Q5zKf`s~p@rnHQKH6<{=4umfBT3V5ZZX= zr)|H#P2`{1#$Ca3HxhtZwERZ$dv|m{=cntxmapgofvOMYWQFEQAVesJ!2HgDh&=f| zM-2L=B)^r7yR;ifZ|KKc?t32p`!#pR;AGSOrW@~O&ipfp_iSCa%~}CiX~&kIz>|`{ zy?Y;D*%#m|?FC;+56s!}DqaDZ8Eb)b01%unN+BZf@oeM0nYg~Sb=x6DN(SYfTk)ai z-oWGEp5_>D@{rGqZ@rH~#a3qHt~~~QlP%s9kR!meZ?R|n+nawsgn{k-V;#V3U4Ml9 zUTxhU^JKj#qyvDfiNb4r<+t$IiSI6H^3#hw*53Ct^N5OMQ52wuAuE{XCjY9?3(HOV_6Bwx}TAyk~6^`LKtu0IYX z>Tw7nLJ(G_!5aB3c<--Y#ZSLH>UL|%XEo?Ma~2Cree14tAp{{QVx`jvi z^M~>L1$Nx)F!-xyaq&v6U0i>J{HJ}yJ-1}EtvHmU$ zYUpyB>zgj#^j)UKM9BvH;8WLM@%G8r$1q*L6+N4DGk1Lx@_V*)oh9VgBtEfqo?ll# zP+XEFC~5`&!Zz?MZk!*IFI^KZR1Dc8-kXiN7+zA1=r3LkO|klyhS^Sptp>fF#U zc0cfIa`x9*cKvCz{3GNa^6uz4{G;(;K|2wFcJL}$`LmD$>9+8E z#d*6A`if^yegqyzxW1*OoBS1e9DML;Jn4dt>ogIbtxx_21+6`^Zuv*Z zf1Z$koBzPT&v?pS;3<26D^gSdD11s*T~0*cw(xxAdB+a=)RxIV1@VpKA4NIo3dm<* zsge7Vm9W`$vPDZ zM`CFBJpTC85YyIwMgIODeEeVh4I%vPPrQO1H{Fj}(oKdopOBtE@;I*}!pmFov_{#nd@Eano^xw&0|GminCnt#5ymsJU*nHdl=)1a`Y5iyA`eWq3P0-VK zxi3ThUXJ+VI)S1N@F(ysUVTMKq3rhX0_AyU4Emzauo)YsnEZafP4m5 zYB8#=8&jLsV7_QGR%>p>75#T&>$?BN&W-n?Xw!Y;v3U%g=GbD6`>kWE0d1S_#g*hN zU){3-EfwJM_vfeytte-fOT=%Rkw=ZLeio3~cVj!k+EeeDi(Sdg}wz zLJP%hQ)AVw_hZrEZ5Y_m&kX%$?fPTnzn!n|xx!b`0~B1Dl}G6^A_AQT5h!WCBDhd` zTbQW`*dgAtm+M<3e}xg6@u<{bAO-oo0P=l)L?Db1SVDyXd~;Mz1h0~ixXKEu%|OY% zL}T%?4nI3T$3I)wx3+ta-pK1szQ>b@!D35jv<{EuQ((myEE0bvu0KM4FXH?>LVh24 zH~7eVz;6xb{+30cWEuDu6A>uxV2%Ss1h$10Du-C%`qs!_VTJsa;}K{?l@(NLFu)RO zCc?i)Ykk%BG*@u3+4Wtyd(TefAM)z#+Q#edx!gxV$=?lr104CM>;$L)_!YN1 z1sBQI5D_@*ltG^zU4H`cok9NT65pAwKgpnPR^)fq<(#&}d*jJ})~lmy4ZpYNXAJoX z1cTii!EG(S5fNBi+Au$;NU8}fRGywz%kN0nFSnoT2Tq6hH7<7jdN*=?J73Oev+Enk zf0{VIhS%3M-$&8Kke{m=i9kCDirWBcGUo*qOPWKA6i3~`^@CjC`u@}0z31w9kG-xx z!$F@BtzAb6`J038?VabN>;i9j7f0mT6tAQOd`nhCS@t~;P%N$>BJeRA2Yrrc`R(rd zEQ?Q81xGug2d^E)Q)tvL&=iPzQX7Da;f`}q51eAzULW<@4 zoEq=3&GorKAG=(iqOEJ6mqef9*+kC!Iz4!6^c->RSw2Jnt}U;E;9@!Wm2?CI70aLF zT%TowzQ*aa{Q6n9{H$<&1NooxlIjD=Y z?FcDRo#Wy?&h?!d?~M)n&Uv=$cX%mu*LsQc;88(Z{~pfy9UBu85eO`i&@O;}eOX|M zR1#96JaQ=v`nY(H1@Yb(`Hy&Z>Lp%X+RI4m59Dj`?&X}{X~i#X2VQ9_loUM({v~2z zP^scwhsAppT)fA{d#1xa{kxtbozOFBEqE$);3?yX@1nUtGb}D$4x|GBL1~8|uvES~ zxKuSfCkB07yvM#lUrX1pXPbVvr$i?pUxTMk1D;APM?{y-18i^E zN~N0MGUX9&(8tAlc6EK)@^|PpiIslGnY_3IR4G>bM1%6ovTu~;R z=T|N+3oKXc;z%}s6dJVaXXS<(+TXt=Y!`_Bf-SA%ES zN(iWsgHL(uHGbtXO<;xUlS?(;<8$$znd|F6A+E1kBvoItn4I+&DLL1ld$WP^1|k4T z@GWnLxT-C{ujmZ*uaMszSgAV2#e0`%yw{>XwYW`pw}(g*>bqnRJj5DU+@go;b#jg{ zbG2wEaBXQN2r9&IbxHYreuY@*U#WO8ph|s?8}wZw@m@>UInwUG=+U7SUfV66Pd?$g z9tqr_;M)C5qOLEmBgcXkA_h(1M~(%a6-^5SmC{E4D&^k5D)o6T-kY=W-g!d&y&mn_ z#_Q$E1;qVWHcazU{4?&eoPK4lnA_N!g z7Vp(^@t%|8y$gi+?|ZaqjKU`B@Ip4Qh9K)}XZ}3~9 zI^b8U8R7P6fSDp!scf+eu1ayeXGRz?J%0|ZOR4`BI{`93w`a9*uk&97DM z5!7i;a;|Tmc+YdS{^a5oa<*^Ps&8mlh5wJNbw2aN9wGb{%GGdCvL8U(~7$xTdrHGV1gmEo$QOQuzPXb;R*Gr{~I@ zj|r7^@Q(+P9u0s90FW*KibQ_|k0q^FdDlr|e3mL&eCt)ac=hVHcnzAv{08mN9E|sd z2;mQVHtXIZgx^J6zGYF1D(3n&=~XFZj{*?_;`B4{lpzb-q*vw({{UXidgAgbxV}vWS9i9-wH@5_o~ui+ zuB}-L*Vn9o>uT!3qmBr|QVEc50Q{Hr!_O*(^E{TeU+q;d3G!}`=X*COJAIa^w)rem zKjGV`*-LQ9w^4hH;0(dA6XU&M? literal 1150 zcmb_cTS!z<6y2j%kcN^an)%FpYZ8@_feD3BP#>B$Ix~0Pj$>-37G2U$G6AK(hQT8Pyc1HGG5M@V8WkNcl{u^j3#sgMxeIcu43Rmjtp)Ae z*YueCn+Le_`hB(}afH!t+hcz*EE1+-Pp*44-Tn zt%dD8Kl71qWz;gX<;t{bc|||d`iLBVfJ#nWb4BegQ%o+u9i8E7Wj&wYoh9Rr)WFM2 z%RJC#=ewny+*Q-V`f#(*;s^Ra3au$8{^Azo_oD}Pbid>g`zYJ=ja;X;aUV2Tc=w6L zTtbVMyf!vQ=ZgGa$WMW{#LS}q4&@#V7bTVQ^9O@G<{0PKgJV29Imb(jOWal4!_bUH zjPL^WzQW5mctP-qprHhxSLE{miNVe4U_CcmTlvk<6dR)~n|xFS>KyQUhbh)d!h7`O zi@jl|&tlE=RdGG$AF;n;_#@Yq&jX}CsHaQwR?^jzWirxtDG4=G(bxPs2Rs*^z$3ZdG4sW{tj9Ww@lsfZl~$BN()@7{))zah5{v+P7avTo}HxDmZ1 z(_xy diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp index 65fb860b20f1b940d191c6c2a57c8864997d43bf..f9dac28812b86254bd8c552d450af0d531fdc4d4 100644 GIT binary patch literal 166398 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 literal 14676 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 diff --git a/share/pixmaps/nsis-header.png b/share/pixmaps/nsis-header.png index 93cd83b171685badfd1fa7e0b36f5185161e23f3..d8968b4800d2ffbf197f40f808daa674511f6c3c 100644 GIT binary patch literal 14081 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 XH;t>0b4-7Jq^7K(E?+Kd9{m3Rh(Bn~ literal 2730 zcmV;b3RU%qP)~8s}=Zu$G@;9BO7xqZ(;Jw;}PFG4r6{l z5)=PEPF#BvYcjKOXzM|gmzCpo{cX*<_X>zNuG~O=&Q81&F$XDq$06?75s2y@itw&x zgmobeW{vJ1hEczZ!T7%=GN4jj&N3deTQjG2ui{SPK1hv=0 z++i3jos0j&Jby`@?DZi84;S;O8pL3q`$ zhy7t{8;H=(K?r}`+~|S9^4c|+?-Qt|wgJ$$8H%JA$0C2tPE?gwYSzA6Al|CGh23lO zp?}a<0O$vcmx;lX1B`$ruOpDj3vKVyJ9K~8Lw@|s&X0GXx}r+6xQtYa1zz$^@f~{k z>?JoqY-qq?5&nz<6yu`-ie5(mMLZsYn5QB!vS&1+pA55xSea+d9SjI;?ITD}A?oXz zht|BT&5k|WPGg^mMut8e`Je1`*+@#`lEIY3l{u0oy%>+I#Dz{lpzlcSKhfz}>*ucJ zZ%_r|`D5n<>zsgq2Yi&nrcnJuzD#1auE@oaf?|9yc{u|g+DQgTkvoIh=@Hq@g0m%O znoWQv=!$`CKkna$OI3mB3|3fY4%eWgG(A5s*zF*45PElUW}l@RvTY zJZ5q_sDG;=m@;rOjtTNZB#79kL4-~sII^BAywv~xK@4{J^flZ*Cr$0|H^=ft|5r(5hln>I1?CBWBUM18!`na3yKopZ*qf=Wuq8HD?=&M=Fx8l+BJieZrfLu+q1CGPSrQ68u6VTEDt84$@=A9>wD(E^ zk;bEMkV+0kcDguz0Y>~f0wEo(ofz`IQN3bCp3B3{>o-+XdFsq88=uA99m=ij(PBZ^ zlO0+pW1fq38APSfC`WJ{d4{9wWIR_vB<~>u)1OLS-;$h2U@8$foy6WKWYP;1?qZ&f z!sf-BPBT3ENk0#r)`bBBus3 zVLt)VHupcrE zGjQ`-1wT-@1;%H`YQf+&aBlK zCsuae(p*tX=3&HdA~-}#4FPJTy9y!!r4~d-fJ-#pks;-3Mo*U*o(8fJ#8?KASST4; z$_>>ws~JG52?zhIKl~pU(xk8G`XcH1coYkdB%y9hX3$K$7xxc*_V%Zk6O!3j6PDxD zp_3T-+Yutn>RSXNeSlg+Ibw?huCuZ1YsQv<=qS&sA#Bc=ZZi<44oVgEn}s_yBLwN# zwD5DjdEwZ3-Y*Pj?Q=)HNY73gFu9rW>T2tF=YsmKi^neDGNLf=05XEoIp30UNcE!0 zM7a#2T7sdJcL-cEoKi_(zuMgak@BltXm$i9{U(K7CGzHI!7_+cx5Wsf`u^fI;W5Lp zWmzuYJXLrCV|&MOUbC+}tBK-m%(`n%F1lLc}2nq5eI zVGMlk8z|_16uxY%;i%7<^g=x6N&EVbK^!oVNe&5l-Hwm8W0sgCDV{TMxBvJGBdhv2B3JiTy+kIUN^IUf{m#+P89q$NCE< zItI8w(iVP~nLYPlO=y2@B`X_&y`C zE9Yx|SL(ge_S9gVH&&;8h~o#2V$tY-Lf_gKGyKx<`l~63>JiEdg$#80%q5S2NFQ$- zO5JTPD|xpkL2T*w$~D1tw#hZ|`7s!%dxgnNz6i0Boc{h4_J6St`@h_WZyU8lu+qBf zTE0)YZ~eTrB1{hF{5dmlIs-L*NGj*SX+Bf9=%=0js2<@sD9BEIUA;#>%9cDR)rJJF z+{UX?n3l%&B#25isv4Cm`gOKD`cxVW737A1ND=w0;Ilm_J6ERIp*eo=7?zD+g5ghw zv8RS}Yt7m;r;;MJXB6HLNt#0I5K*SA$;?63jmj3UOiKJ}YePpxytCRv0kv@8xF1eHWXm5(B12H6elNJ9~ zgE^e?v5iiqrWPKx+~}AGl^sNKE}gm5qVPiCIr97gYOQim=m#hX4Qo07*qoM6N<$g7zRBSpWb4 diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp index b18c74019b469d6521e93058944c872f797aea44..9c944724e33db17ad0aef19c1aeddd58adb0ace6 100644 GIT binary patch literal 51014 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 O3&yNpW2Qf~u=qdE_AmDU literal 132552 zcmeHw1(;mNmG0Tymt<{cgAUjMD`;n(#Ooxs^EMoZ#G_%9Mk9@IEQS#?qlK2m%q&@G zF*AcDSErF6g-xKf&%&Mv(Mz-oqKZQ@(sCo>XMu~cv^O?*exq2t&)Yq7R#76q+NU`>5|byx>f8YeXI4C59$wDcA6 ze$FO2xaku)edvr_IeSHJUArw0A3T(T&kE!*eqZZk^&HrZfd}^<$n}fY73TJ=*(fRR3jdsq(WLlJnE*lKrDxsaT?lRQzET zsr=JwQsuQ8lKXm1srhCd$$P7TH2X(OX`k3ddS>^Lq1Y3XyH1rwBbLaf1zY6Ej!)J8 zxqbb%+E;duOFu8R_R5``cjefgW3n08S~B`$8QEft^v>-st;)2M_uj5A6@QQ;X)k9< z(l^p2<)utX{#J%0eKSMSzEe@X=ijL>W#OKR>RS4DD+wF_PQ~|9zMZM==RK)>|BWH-@|jN{k)bm_)}BR{2nr(_F$ROcb2T5yHWP7-!E6rU2)NI%`fP4EC2=`+JW^VeY$Mg*$WwSt{zirnSH!cTsa|x~6mAP?wwdoLyo0uLKP9uFZ|q~{_bW@| zKj(v&?;~>t&6iy(cgyul*EPmt4dal%&Kx-_tEaD3XL}=HBCA9Wc!4ZnB~#%z1^7t^ z?KFeGNPdSr4RM}SxCc|g4^{g`Z6%*h?J-^UZ#*dE%VUXF#oAc!+_)p#mTZ?%EyqgJ zzqOD`KdR!wFz7L9GBFZKOxpchPv|+uqIh)dQ=UCtp?mpg=ps3L^qj_bF{0trmr?F( z4;@>TpVb6U;li<7HnSUFPI;c<(G|avDH-3ZEOq~HLmAn8jOW7uw2b#sTjRt<%C}xe`@5VTFkeQGv+Q)a64RbeX9^9eW{_N3ba{l-QrT5Bx zy_O`sn67jfM%O)-?kC0-zM)U)oYqbDuG*DROowSm;FC{73Lq0m< zxUis;c2Zv{XU2auMd`yQbebfWA#amz#G2l$sK!fLLLPeHdmkuUTm`I!lkgGMeffSR zC6ko@uSDg$vSra$xq0=L_PGi(?Y<2i^qQILr3z$v(rD6{jPGY_T-$kO;LOYTUbdp$ z313Z>-c{aLzE_$zvEM)H(St{F^1vzSS9740|F0xTd@)VUeN@v%JFyssXA#@f3zq+4 zqU5|&W(Kzt`au8jX$D(K1} z_?w^7euNhJl1ryAE8QLGa{}g7V>vQd_MT_*dZgXuKv!!2rk?Crwo~YjUfgJCxW_{| z{P6Z8(z;wbiTiT0vK5kUc+a=~JAyc;t_h8DO$v0W)UDpQbVFl1MB07t&VAW5f3u1= zA#a!Z5^RN9f9IGz?cz&Pm7Fsof0WWqg`3Vr`}66qFlW#_$%5}ZGMq=@VGB0sra?y`%Y-O?T2n($C<`h!LnaWP)uvm$@8c+^sP6yx@H`uw*p*8%#Y1o)C_UfL-bHQNvR zQD&B?EX&3(7y1mFIlH6%JD1N~mR4okOW7CVUG{LT$BP=iBM|Nxt509|;T zEY__U(pkILg>*aNYiY_K@W7^n#ZHc-@9vm36QshIbqs*r*m3&vh;90mFc0U26BmjP zwhJCZHeR889ciC(`a0y6m5D7LqsL+-3x~=WAC1^%uB;A;omHINQ#cF98W-Y-*yY@DAGu=@7-Q{jjPbR*xu30G;R8h7 zt;!<|KYaE_joovfg=73t@=V&H)M?yd7&{*xKUoJhT=i+e(waHj_H?TP|M@EEE>5)dLfq*X*v5& zd^7$yR%tis5YMlY|EHWRpRm&L{0QR`nO~axhtlcU#8;|$fIfwOe~G9`k^lD=GNaEd zIlB9p!*J|B#{~V`cCFf@YJg?`Bv;D(X9cAv;@E86|6$HKf(!X%xqNCSw z3-XFF*T2$#*fhT!e>`~R(!c@h70pELAnIA1MVI~K*;hZeE#0AN-;s8g2Y=$`t-^sH zCqFaumC923^KsHCr7QSDXXY%XPO|B{%@wV-MgIX>PZ^`^^RBos=B{8)L|-_G#%otE zTvKsxqyuH4*Ht`;P3N1FvFzP9${xh_y4mX;$B(d9=gjwKOB`ZtSqH!>u3c+fQA&Nj zyk!44SLO}*NXdKAh~Hp+UOH}>R6<=x?q9BXtnu6&FL}#KKdCB=oeDNzk^G!F#AL^hNY&pA2acThOxD+BeNxtH zWURN(`H2u_1O7Jq1{*GI1?82VHA%?`%n@(8-*_g+&S#QFI$?eGKv(UyjaZ^J7#n58 zlHfh4i{7{4fFs5isW~Qn7}0FB@_8gLN7=%Y9;&%@0N#}i75l65PjjUz>tw%H9j`T2 ztw8r@0r!QUy~*(r*Xe{bE=@eCv|p&wKdVFE_5< zl*Xv@^sbaty4_Ncr#xFC^kT%j=e$Moy&HS1b;8>1Cy|5l80xy7*mqL8W%d^4Ti`mH z?Gw*x>W5fc)z|z)>e{;58-#T)cm|mr3%|#?h{yTMbz6X1gRz_^f5)<2(yzuK>051p zvd2*mq*|>($|r!etj)^h-t^!5?_kg6{mPg6jrUN`=V_huAo%G~Z)pYB!~%7?Em8Nl zsA}=CPD9%YjOoH2#duBQn!FWkPt;GpUt>U#pFxqL3I2YEx+T^aq1~T0W_P=B<(7W=fZU|YR1<_UcNI=Xe#MY|Js9W!8Lhz z=FZ)`VC$3T`)$oe@OUG^g6X)}#!@>-a4=9jGVRs%V-rTFNl?VfXDXLM`h zxTY*eyI#HDHCDFZaqT9^*tX-JZn!qC!$j$l(L)mHEAOZFup8Iaewim1PCgwUFsROl zY8|c8YhsCeu<2i$N1SHgfv-=elYIpnv9eWp$i+< zbcEFXT_c4@f8R55o$_bO%b6;lzuok~-}6YT_pRR#|I1{{HMltEnbc*fv?|?J`5Mv3h`ETEbDw_FlyA&7K7;2Z{jWIx)o>=ahoAZE0dwWV z{*z(L1!D!*!=`o$sWKgX@+5_}7Jmw3djGVgmZ{@m{~ zd2V|($`SP6k5vBn+t+W)`_%`)J{E6{uP!`qsIQ$2`Wa}xL-~yBPWs9Gm8^kY_W25G z&N<&)2k&{a`Zu4M24AdXJfC}nx}5BvRFhFH#wedvyM5*#J_NmPWsY7y!F3Ry&}E22 zWnPznxc0)I)p_*y{j`@VN=4XVBc<>Cbk|X3D<}OUz4h0xP_8pRJ?}U5<>)SJetFEb zGqKAQMMHV!DjNZGELQs$${2W$`W?`*#IL7A{*9A5@YCIoGpztI%c1N^fA_>ic?HRuL0_C9K5gVU<2}Yldq;-DA?Kt`rM^^N|8EmHxSY!f4>>*`qFVLq!eT# z+VQ!5fqpaMpFs~x|A~p6rkEbz`D5o*93XW@s=gndX>=S4*T^m2JLi32os&Rwx^n93 z(D`fhg|VchasC?fn59|3HFHPv87)h-MQ(=M0s9_kT!B7g9mQ^$y_9@p6+^VcP%qIP z`P|LQSC>v*M2`GCW&bKt-oxLzVNH@C)7Sb{9q0nDm|7G1+Bf}MOO;c|D4yN-yXkc= z)Xk-jJZrpq>-cz$@jNS_3oRRh+(=y?eQW!}2Kr&+;qb$Iwhhl8B|R(ml`Po(dB3|q zMqharWR=K~-K+PQn!`Yt=4YfGl#?kNS;aMDZpnvC?O{$2LV1d36Jx0|EchcBonxc- zb4`*#YZt;-FWCJ0`keJzx>xEAImCSJO0E@kPIY0I83TLF_zsg$6LaEIjn^i2nk-$? zdpyx!`Wq|H+IZBLu7SK{x2^@|u^2a989E}ybDG5r^-hfEAJb->?e-1wAZur?Q~G_{ zIsJ_})ayK3Dx&5W>)H8Q&tTU`cN+Ymsq%d@?HlQj&f0jLyaRpGdw~ZCHYR_ck7z#H z60W%>-20>>%7+SZ;EVXj83S10^XxK^!8UT1dan>4Nk^|D1Rsmd?I;l#$sKu zIqrbA4*CzOcqJR?BkK~^`c+-!2j*`*16|*_e3v>mxR*oSOGR}bX$@`IwDkoVlfTcX zen;6AQSeyi8tX`^P&>&7pU{+cl zlW-1skJaeklrx(Bqg7D*m;3j^+W9{$4tEnL3A^ zvWK6-^{JJ?F*~`$$~($cD^lBG(6b z&erAHtMlFcOeepR9#DU@YT6o8<6Spvoy$fI{*Ran)FLqtMS*LME8)ddm8kNS&#FY=g>f906Je!B-k2KXk@>n(C|7+Ff+v+$%{XT6A^iiKPV4kV* zZeFnYi5`t|iT{@7!oQ93fv+(Z6|U(olJi;(IlSXjQ}gJJ>r2SbRpZU~)O`9Hr_pQF zwNoE54gP!HzZJ^g`_>;&_BN|Jf1~|2dp~_uD6>sOE#Xkc=Y7w%CEFo4!cPk|o2iHJ z*>L{xy4vgH6K&uX{f+ktu76%zE}y*|a7>gNEB)9yf6cxq8x7)D77Sk$@Hf5Z&)45P z^YS^&P|B1>96Py=Qv#0Cax*R^31$@<8Ht)oj7n>$rhGlPYTZ<`i3)qb};*r zFD!drqpp78h{Z}z<6bALuS!P`JqGdV`CFmBpFd=Qi?_Bx-)MC#p?u%Xca4O;F4Qra zy>B*n9qQD$?}Oo*bb&llNDaKB=U9{Ry-GjIl|jgjIHK7o@RZLs`il3i`o1uylPx?W z&LHw&P2X)P=U_`QJ4gH;{ha#b_EUPA^zU2OgK%!#I-9Mi5oM-t6X91)-(SypcJh0k zbCf4&moqb7Bj1@0TUAK721ZEJmHivEHz7bHf5ZNBA3S9%pgmRb`)TTP-s9bpL0_%< zTs&D@^qId$I}dAM7?~IEd#_)*AvOO8G8*^4P4WnzML*@e>-L%I+i=haC+Ty8&C3&9 z!`AFQzjpsUt@q53a83MmfIVW%;;n_gf}8N_yX{)BOQs{oC-Vd(;Cr6f=2;Z11)Cou zpYv>?e;aeHn4PKYfnqPj1D}!w5zK-J1Zus7Iwfas~Mih*6^$qCIA6 zPn>I*13Pg|pG*3RGY`AbKJk8yYu}jW+=LC+$lL7*Tr1fz4K+`iEBt(B0@n}jKR`Z@ zfl9Wp6W8Rgt5UzN>9whS9f%gh0j&*NQ!^A>&bxlLGmXc`oiE--o}s@OPbdM(R|o_=NkyywZojcTwv@ z{PPq3)+E^VSim*q@MQQv&FC{*E+aQgusQMm{0Qvuv@J2l$`?M(UZdQYS)#IRMa>TH z-wfq%<^_pL{k4Pie1_#lr|{RH*GeY>Kj$&6#+j1Q=<7;ehR-pJVPD^K*&8bO+{{l)NKrDo}^aHS}(F>VkvKKlNb)Y7G|VsP@K3 zu)kMKTBYotw&NP}!nIyF+=_olcyiqYn@=;JI~CWg4;Tys?$39^HpBR)l8CeM9ji-U zLhJQcLYZIXp91?u=d^CJZWe0NK&~*-ruCW`lAl2+eet}<#UG{1W|TFj^_uadP47JmxeceN&xmKwxexSya9vkERlEF%{LU%%4gFf`zTME2 zk0f>1Tob>~H;D=2nt5w`AkI3_Jo)_$wqMpbr`^f!J!kh=`MgNtdPd*bA^C^!EGNxl z&K=c|6NYt**vg{zE9)iD---ER{H}w?`CouF8IU*Fp8VHAaK*mUuaCAp=1UKyf1dYr zN$>vu{nUf}mQg&o;u~8Eb69%*W~lF3dtAjgey`|iQiM9@NaA|V!1*fAK6&6&xw|CiO!oV*v zpGB=V5s$w2q~U&Xo_9h%r~gaZ%i-tcLdCDY`>f*n{D}*ye(Cu3lVn22$v)d8#Ntfu zI!)TgcUHbLtZBfUe8HN^-31(z2DWnAe0=06W zvw6R%C&Q6voq2A?vNnOA#xsw3nzDgk#$UR5I>+N0bXM8Yp?7Ris*Pb>H-@~a;)y~y z7mQ+o@s0F3pWMxyPK5j%dCAhxA>We+tufkEDd zauInkNJHsA;jcYH-r>uzDOdkRo|41d^XPb71CPny%vAAZP5#!xFs|$UzH!)eY2^E; zTknp%w`TKX(#~HU`T3aJ(UJN23h9AWTr<8j>jybOWq9JUH1bQfkM9(6J?87kSx_DM z$XvBhUA#y%;F|lJIo})nv58?^*Z+N!pmS-K-f;~mJJvz{(bI=Q*Cl!LBTL3CQ#>TG z<32~t_95a$f40OC`{B;IElK zkKec44?no(a~Utk{F7#54BT^m{nB;VbjK*3UHRsaFTwMjK)<67*WeMU|0e%R-64HL zHhr`uVB3h#+ZE~_Qoual|c38`p=>rbiudIQdr6SMqkOdE~~Z*;mH*&4E=3cSZntd&Fk#)f~&moo-@5dz_Z zxqx;o-w7X`5y+9qJ1I`G~ zxeDcdKhziFc&zpz;P=TZfo3yKU`qFCrs9hOjfHhASSxhH+>J7K@O+sFd)+A17-v1^ zNHyj?8i|}Itbr7$ul_!JaQC5HIDSFZi#UIbug|tCXRaU@^+i=5wGn6p>s$GIp67MO zbbISV0wDOp2;zjW|#kBlGH>UmIE8j;joPRMzXrK%_Q{TAJN-B4I#wemcMfv7 zkWY)mI=k1~>MQjb`TuAk%-d#kEmgb>?3Iz=n=;^QL-~<$cid030UPaatl!T$8`@}u zssTiK-<2o(*_?T<&)nD3mET`9VVd-s`Kmgnb~nY_QFqCG5eZy#{}S8Oe^&ZoRp^w= z)l-UPY`bthTuMVHLhRBvC|HZ+`dX#Yp5N#ADF5w3Jh9O=KeF?vD}OpZX6?UJ*m0R3GFXcyI_-%&o<$>@kCCIhj~T`YeFt)0s~$F= zKF@x--z(V#>rwJ^<)rRA4N;5Ic)W3}V*4pvL*MM4)8h6@9Usq`neWdrRrii{y_@~B zrAwxWq@1kiOt$K2_>N>F-k1ao>y?V4nQa&&5ftU)NE- zIHzo~xknRjgY`8ga1B~V+cax`Ub}G3RK4^9#9A>&weoj~pzYt+xj?#2+f8}+l5n3j z`g1<;Jyi~GJFI!{!h8p@fNNs0!k1H2?53F)LIpiF#&?vn_I+P@z1@cm#!S z?AzM#aqUyRzbqNOOg@EP@*!gO+TT3xzbkidMY`QnzezdVJ+DSzd3HWVV=Snz#^;f59M*V*s`pJ@ShQpKnf_zl zY44|B`1m&rQ1PY+FEAypJNKwCl8#Io~WnNHKT`g%j)H`F?SX}%R{^ZgJ;@G(=q~WC7%I_X|9Jset?oZ4G^(jvp z{IKbZ9jO*a|7+L)2O7v<>PgS{uH6r;rVF3*WDK6;;d}a$U6&S0?6*q7iGf0Ssw4%oM%e zk9zPKuOOcu_%8Anfm*cW1UG{p&LipTlCjH7&7(KwStoB0V!q>$ODJk^?Z&qQUfq0> z**LIJ^M{zhN;G|k=Wn%N=E=d$hit($d2Hs@WW3;0G|&N2tmKe+oqx}^0`F}C!R z_VwHPn(y_~xb{6SM)1N~HkE#ugPae$ZKKu1I&E1ir>s_Si0Lm|@28P5Mf<%P*Vgeu znK>W%Y_6WaW-G3V?Q_S@t5_DE2U>m%eXTUEL!T>OG>ked+L*_oF3e-trTp;}X0KB( z(ib_$%DsSGRq)sF)dzj;*)`O-es)fb;6(8tKdveVkXP0$b_0EnHkz%Aw<&!e{ZEYa zEtc=qxVDCC>i1fg>mavp+zAV=iTUfuH&GMyGZ+u7<;T$0OXE7UdGba3ICm-V3s^AJ zT&>SQblUSX`peDgKNoeQ;4cCjp0B>>YfsOM#`V+lVFVv3s1L$?RFv&JaTt#G$MzhD zJsR;iT7C>^Uu#^O#5FMn9%OL+4l{KPDXX+54FV z@B`krZlCgfre0C&Mgr3#O|Jvbk1xK2x;^?hbxG}JD(2i9v!VWd>*_7ko$BJ!`Dy!O zK)S7QZ35TICpArWp-yM0n6&G@oy&JCogaNhG|l$Eb{g0I=f)SU<~8c}nj;p2HWRz> z8tQYHTe<`Mt61CB$#v%Z&0VCfYg`+{wL5-b)BK{#(YSl{9`M;oDzB8L*}m6LR{)4}M#`<-QYh$=(EcPA;DvvcB;)*)_>F`6Ayx|+&Q=BBlFy*@wde7fr>a-Y^kys-9R_1ewK>Tiwfz_=#wN}r7EALpw4MOJC7-QQOK${Q)~ALav^7-W^%Ej6VREZLjMu>rDRz@dt*fWP<>(5=r!s`vVW4R?EKMy zy>RxCc%;9>fZBtFwWwGNH{^EuvTRiw>0=G0f8;+{r?cK4njmk& zRa0k}Q95hq{j{<7uF_BIM<~DI+@&l{AFdpR zc@yl!u)k+f_s2T)6~2l%U+mLpnESBx5!mLsavnl%h4+W8PZ87^amsn`pRBUYmKwncF1hu^mAiIcYC&-P2yGC?!8%UPiSV6VVu$aPEovA*#f`(y0Ae~0 z`DW_>zKNXu^juW)9=@=B@Af?z(qOpqZ=r0jd6F2Q+o09deN_2bbveBKNYu)SzVPgM z?e_KCN{?F_a(*n)tXLf@^MYlS$U%+!=&`+c;?>CeTi0$W-*MLUh}HEj?&IcJOrK@y z3U)5vrE2gQ!AP{;d-3E&X;Z$VD}GGpLn~hUo4R`V2PJ$x9dvq=rTU@Ki0{*fP7Cd6 zjAv8y3-eLj=~%HJAJ#A#c_Qi0v|{qAsPX%-d;gsJmx0$0U z`CI9-e$K|Ix4T%y`jxX+q<3yVWiO_Wxz>|JC$^a%DHC-jcO#aZxzerTqBwm2*0tNN zT$ac`to$)GPZB*m8To0@>B{im+`M3G%<>-o_91;qruLknaGms`&W#ooyf`qO@M5ae zd8eTq+3~4khQ-kB$DV)OnHy6c^vjsKBT}yCv6#HRhQY>Dmd1=(B33VTwJa|evLs!E2qkm&@q*DRw_^-_rU!rMu1oeQhho^#%R<(o><1nJxXt{9WqQQxJ=z?eNC<6E$C~l?ZzQTg_k9mH9&!2z@TybFE)P*W=kWSIjZ9eBw%JTcM-! zBO|>b@2%EL^Cy1!lMKuaZ7cM>i~mZBWW7>Z#YeC^_Ojpr!9 zvp3F}Q|SD$^C}*xUyVU3e`5k{X7txl_8rpi;zq+U9))G_&dhhocqH;1jsBc3a|X>* z^;>SDUb6RG>Axe-Us#=U`cg4}@v*(fW%hu%l8?NPTzlGum5s-3pO0pYV>~>6sM9Bw z6|aH(!UOUKsd(^n*x&b{L$W%T`uonrKl5Q;I(= zTX@!}JjCz~OTZaKUV}LRyJhuMIwHy%^lPWwq4DTUJlef3tYvcN<{gzQfA`8gs6{nN zPq*s-`vJ$bfjEBAf-%;&r7aKSZ zv@eKp+SRBR_+-l=Sw3l{d{A$wiUT42BaV`gH-LO<5^`dsd^=0wJ)Cr%v7W>%&yPgZ zH6$&jT{R6n6YZ>>Qo6}3@KoDB-XUj>oK-qH%FBVqsXvQdtQQm%s90*&=O#~1oBhhk zt7SsR$b78BpH>y2~7+)Yb4_^2Ms* z`+VgyvR=uN+Hcj9_K98O!^Xp8?x6Xyd(|Gf09zn+&7{ei$B135TBTFO4(mk_>sQWQ zRXTF!C0{drt;`uPPlm&Pvro1D(z0}0X@Gp+d2iK~8gINORex4fs=QW1a$c+cOv`<} zmehK)uGIN$LuvGveCeFtU8u8})OD&X8o5;Q|NMw8Uq>w8Uq>w8Uq>w8Uq>w8Uv3- Date: Fri, 25 Sep 2020 10:05:10 -0400 Subject: [PATCH 0427/1888] Ban previous versions up to and including 1.0.5.8 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 34013bd5e9..cd2882af15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5722,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } - if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/" || pfrom->strSubVer == "/DAPS:1.0.4.6/") { + if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/" || pfrom->strSubVer == "/DAPS:1.0.4.6/" || pfrom->strSubVer == "/DAPS:1.0.5.7/" || pfrom->strSubVer == "/DAPS:1.0.5.8/") { // disconnect from peers other than these sub versions LogPrintf("partner %s using obsolete version %s; banning and disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); state->fShouldBan = true; From 6e81fb90a462db6d448e841ccdba112bf5c3dfee Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 25 Sep 2020 10:41:09 -0400 Subject: [PATCH 0428/1888] Missed colors --- src/qt/res/css/Dark.css | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 61935bc473..476e4cf6c7 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -255,7 +255,7 @@ QTextEdit:focus { QToolTip { color: white; - background-color: #5E1C5A; + background-color: #1e1824; border: 1px solid white; border-radius:5px; } @@ -280,7 +280,7 @@ QPushButton { } QPushButton:hover { - background-color: #4e0049; + background-color: #272c42; color: #b0fcff; font-style: bold; } @@ -288,7 +288,7 @@ QPushButton:hover { QPushButton:pressed { background-color: #5e0057; border-style: solid; - border-color: #4e0049; + border-color: #272c42; border-width: 10px; } @@ -451,7 +451,7 @@ ToggleButton > QPushButton:enabled:checked { } QTabWidget::pane { /* The tab widget frame */ -border-top: 2px solid #5E1C5A; +border-top: 2px solid #1e1824; } QTabWidget::tab-bar { left: 5px; /* move to the right by 5px */ @@ -460,7 +460,7 @@ left: 5px; /* move to the right by 5px */ QTabBar::tab { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3); border: 2px solid #C4C4C3; -border-bottom-color: #5E1C5A; /* same as the pane color */ +border-bottom-color: #1e1824; /* same as the pane color */ border-top-left-radius: 4px; border-top-right-radius: 4px; min-width: 8ex; @@ -471,12 +471,12 @@ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fafafa, stop: 0 } QTabBar::tab:selected { border-color: #9B9B9B; -border-bottom-color: #5E1C5A; /* same as pane color */ +border-bottom-color: #1e1824; /* same as pane color */ } QTabBar::tab:!selected { margin-top: 2px; /* make non-selected tabs look smaller */ } -QTabBar::tab { color: #5E1C5A; } +QTabBar::tab { color: #1e1824; } QTabBar::tab:selected { color: gray; } /* From 2554d75164eca2b166d6a952cbfc663d43cf1e07 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 25 Sep 2020 10:43:20 -0400 Subject: [PATCH 0429/1888] Fix Medium link --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 8bf906ce1f..55bde753c1 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -859,7 +859,7 @@ void BitcoinGUI::telegramLoungeActionClicked() } void BitcoinGUI::mediumActionClicked() { - QDesktopServices::openUrl(QUrl("https://medium.com/DAPScoin")); + QDesktopServices::openUrl(QUrl("https://medium.com/@DAPScoin")); } void BitcoinGUI::instagramActionClicked() { From 32d7c4465dd09f5471d297ef3db392125136d7df Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 27 Sep 2020 20:28:08 -0400 Subject: [PATCH 0430/1888] Fix for fresh sync --- src/main.cpp | 4 ++-- src/poa.cpp | 10 +++++++--- src/poa.h | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d5b747a3d9..c2b67d7895 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2916,8 +2916,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): PoA block should contain only non-audited recent PoS blocks")); } - if (!CheckNumberOfAuditedPoSBlocks(block)) { - return state.DoS(100, error("ConnectBlock(): A PoA block should audit at least 59 PoS blocks")); + if (!CheckNumberOfAuditedPoSBlocks(block, pindex)) { + return state.DoS(100, error("ConnectBlock(): A PoA block should audit at least 59 PoS blocks and no more than 120 PoS blocks")); } if (!CheckPoABlockNotContainingPoABlockInfo(block)) { diff --git a/src/poa.cpp b/src/poa.cpp index a768aa4f97..63411aabcb 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -290,12 +290,16 @@ bool CheckPoAContainRecentHash(const CBlock& block) return ret; } -bool CheckNumberOfAuditedPoSBlocks(const CBlock& block) +bool CheckNumberOfAuditedPoSBlocks(const CBlock& block, const CBlockIndex* pindex) { + bool ret = true; if (block.posBlocksAudited.size() < (size_t)Params().MIN_NUM_POS_BLOCKS_AUDITED() || block.posBlocksAudited.size() > (size_t)Params().MAX_NUM_POS_BLOCKS_AUDITED() ) { - return false; + ret = false; } - return true; + if (pindex->nHeight <= Params().HardFork()) { + ret = true; + } + return ret; } //Check whether the block is successfully mined and the mined hash satisfy the difficulty diff --git a/src/poa.h b/src/poa.h index ec28a8f764..f7ba5fcd50 100644 --- a/src/poa.h +++ b/src/poa.h @@ -40,7 +40,7 @@ bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate = NULL); bool CheckPoABlockMinedHash(const CBlockHeader& block); bool CheckPoAContainRecentHash(const CBlock& block); -bool CheckNumberOfAuditedPoSBlocks(const CBlock& block); +bool CheckNumberOfAuditedPoSBlocks(const CBlock& block, const CBlockIndex* pindex); bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block); bool CheckPoAblockTime(const CBlock& block); From f8eb0675b13d56006e2606c488d5813d758e3b41 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 28 Sep 2020 17:43:55 -0400 Subject: [PATCH 0431/1888] Minor corrections to error logs --- src/main.cpp | 18 +++++++++--------- src/poa.cpp | 28 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c2b67d7895..22be88c0e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1712,7 +1712,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // Check for non-standard pay-to-script-hash in inputs if (Params().RequireStandard() && !AreInputsStandard(tx, view)) - return error("AcceptToMemoryPool: : nonstandard transaction input"); + return error("AcceptToMemoryPool: nonstandard transaction input"); // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction // itself can contain sigops MAX_TX_SIGOPS is less than @@ -1772,7 +1772,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) { - return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString()); + return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); } // Check again against just the consensus-critical mandatory script // verification flags, in case of bugs in the standard flags that cause @@ -1785,7 +1785,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // can be exploited as a DoS attack. if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) { return error( - "AcceptToMemoryPool: : BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", + "AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } // Store transaction in memory @@ -1826,11 +1826,11 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact const int chainHeight = chainActive.Height(); if (!CheckTransaction(tx, false, true, state)) - return error("AcceptableInputs: : CheckTransaction failed"); + return error("AcceptableInputs: CheckTransaction failed"); // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.DoS(100, error("AcceptableInputs: : coinbase as individual tx"), + return state.DoS(100, error("AcceptableInputs: coinbase as individual tx"), REJECT_INVALID, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) @@ -1975,14 +1975,14 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) - return error("AcceptableInputs: : insane fees %s, %d > %d", + return error("AcceptableInputs: insane fees %s, %d > %d", hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize) * 10000); // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, false, STANDARD_SCRIPT_VERIFY_FLAGS, true)) { - return error("AcceptableInputs: : ConnectInputs failed %s", hash.ToString()); + return error("AcceptableInputs: ConnectInputs failed %s", hash.ToString()); } // Check again against just the consensus-critical mandatory script @@ -2925,10 +2925,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } if (!CheckPoABlockRewardAmount(block, pindex)) { - return state.DoS(100, error("ConnectBlock(): This PoA block reward does not match the value it should.")); + return state.DoS(100, error("ConnectBlock(): This PoA block reward does not match the value it should")); } if (block.GetBlockTime() >= GetAdjustedTime() + 2 * 60 * 60) { - return state.DoS(100, error("ConnectBlock(): A PoA block should not be in the future.")); + return state.DoS(100, error("ConnectBlock(): A PoA block should not be in the future")); } } diff --git a/src/poa.cpp b/src/poa.cpp index 63411aabcb..d1a8886ca6 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -144,11 +144,11 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) - return error("CheckProofOfWork() : nBits below minimum work"); + return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount if (hash > bnTarget) - return error("CheckProofOfWork() : hash doesn't match nBits"); + return error("CheckProofOfWork(): hash doesn't match nBits"); return true; } @@ -179,7 +179,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) //block.Merkle CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; if (!currentTip) { - return error("CheckPoAContainRecentHash() : Previous block not found"); + return error("CheckPoAContainRecentHash(): Previous block not found"); } //Find the previous PoA block CBlockIndex* pindex = currentTip; @@ -197,7 +197,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) PoSBlockSummary pos = block.posBlocksAudited.at(index); CBlockIndex* pidxInChain = mapBlockIndex[pos.hash]; if (!pidxInChain) { - return error("CheckPoAContainRecentHash() : Audited blocks not found"); + return error("CheckPoAContainRecentHash(): Audited blocks not found"); } if (pos.hash != pidxInChain->GetBlockHash() || pos.nTime != pidxInChain->nTime || pos.height != (uint32_t)pidxInChain->nHeight) { ret = false; @@ -222,13 +222,13 @@ bool CheckPoAContainRecentHash(const CBlock& block) PoSBlockSummary lastAuditedPoSBlockInfo = prevPoablock.posBlocksAudited.back(); uint256 lastAuditedPoSHash = lastAuditedPoSBlockInfo.hash; if (mapBlockIndex.count(lastAuditedPoSHash) < 1) { - return error("CheckPoAContainRecentHash() : Audited blocks not found"); + return error("CheckPoAContainRecentHash(): Audited blocks not found"); } uint256 currentFirstPoSAuditedHash = block.posBlocksAudited[0].hash; uint256 currentLastPoSAuditedHash = block.posBlocksAudited.back().hash; if (mapBlockIndex.count(currentFirstPoSAuditedHash) < 1 || mapBlockIndex.count(currentLastPoSAuditedHash) < 1) { - return error("CheckPoAContainRecentHash() : Being audited blocks not found"); + return error("CheckPoAContainRecentHash(): Being audited blocks not found"); } CBlockIndex* pCurrentFirstPoSAuditedIndex = mapBlockIndex[currentFirstPoSAuditedHash]; CBlockIndex* pCurrentLastPoSAuditedIndex = mapBlockIndex[currentLastPoSAuditedHash]; @@ -236,7 +236,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) //check lastAuditedPoSHash and currentFirstPoSAuditedHash must be on the same fork //that lastAuditedPoSHash must be parent block of currentFirstPoSAuditedHash if (pCurrentFirstPoSAuditedIndex->GetAncestor(lastAuditedPoSBlockInfo.height)->GetBlockHash() != lastAuditedPoSHash) { - return error("CheckPoAContainRecentHash() : PoA block is not on the same fork with the previous poa block"); + return error("CheckPoAContainRecentHash(): PoA block is not on the same fork with the previous poa block"); } //check there is no pos block between lastAuditedPoSHash and currentFirstPoSAuditedHash @@ -245,25 +245,25 @@ bool CheckPoAContainRecentHash(const CBlock& block) pIndexLoop = pIndexLoop->pprev; } if (!pIndexLoop || pIndexLoop->GetBlockHash() != lastAuditedPoSHash) { - return error("CheckPoAContainRecentHash() : Some PoS block between %s and %s is not audited\n", lastAuditedPoSHash.GetHex(), currentFirstPoSAuditedHash.GetHex()); + return error("CheckPoAContainRecentHash(): Some PoS block between %s and %s is not audited\n", lastAuditedPoSHash.GetHex(), currentFirstPoSAuditedHash.GetHex()); } //alright, check all pos blocks audited in the block is conseutive in the chain for(size_t i = block.posBlocksAudited.size() - 1; i > 0; i--) { uint256 thisPoSAduditedHash = block.posBlocksAudited[i].hash; if (mapBlockIndex.count(thisPoSAduditedHash) < 1) { - return error("CheckPoAContainRecentHash() : PoS block %s not found\n", thisPoSAduditedHash.GetHex()); + return error("CheckPoAContainRecentHash(): PoS block %s not found\n", thisPoSAduditedHash.GetHex()); } CBlockIndex* thisPoSAuditedIndex = mapBlockIndex[thisPoSAduditedHash]; CBlockIndex* previousPoSIndex = FindPrevPoSBlock(thisPoSAuditedIndex); if (!previousPoSIndex) { - return error("CheckPoAContainRecentHash() : Failed to find previous PoS block for block %s\n", thisPoSAduditedHash.GetHex()); + return error("CheckPoAContainRecentHash(): Failed to find previous PoS block for block %s\n", thisPoSAduditedHash.GetHex()); } PoSBlockSummary previousSummary = block.posBlocksAudited[i - 1]; if (previousPoSIndex->GetBlockHash() != previousSummary.hash || (uint32_t)previousPoSIndex->nHeight != previousSummary.height || previousPoSIndex->GetBlockTime() != previousSummary.nTime) { - return error("CheckPoAContainRecentHash() : PoS block info not matched for %s\n", thisPoSAduditedHash.GetHex()); + return error("CheckPoAContainRecentHash(): PoS block info not matched for %s\n", thisPoSAduditedHash.GetHex()); } bool auditResult = ReVerifyPoSBlock(thisPoSAuditedIndex); if (!auditResult) { @@ -317,12 +317,12 @@ bool CheckPoABlockMinedHash(const CBlockHeader& block) return true; bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - LogPrintf("Target:%s, minedHash:%s\n", bnTarget.GetHex(), minedHash.GetHex()); + LogPrintf("Target: %s, minedHash: %s\n", bnTarget.GetHex(), minedHash.GetHex()); // Check proof of work matches claimed amount if (minedHash > bnTarget) { LogPrintf("Block mined hash not satisfied\n"); - return error("CheckProofOfWork() : hash doesn't match nBits"); + return error("CheckPoABlockMinedHash(): hash doesn't match nBits"); } return true; @@ -335,7 +335,7 @@ bool CheckPrevPoABlockHash(const CBlockHeader& block) { CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; if (!currentTip) { - return error("CheckPoAContainRecentHash() : Previous block not found"); + return error("CheckPrevPoABlockHash(): Previous block not found"); } //Find the previous PoA block CBlockIndex* pindex = currentTip; From 6512eca8c0f56a80415ca90f6b511f9d1427ef87 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 28 Sep 2020 21:31:58 -0400 Subject: [PATCH 0432/1888] gui: add NodeID to the peer table from https://github.com/bitcoin/bitcoin/commit/531214fb100c14e62921085cd68cabe2b20ee0eb --- src/qt/guiutil.cpp | 8 ++++---- src/qt/guiutil.h | 2 +- src/qt/peertablemodel.cpp | 6 +++++- src/qt/peertablemodel.h | 7 ++++--- src/qt/rpcconsole.cpp | 4 ++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index fd7711590e..9187a3a7da 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -245,16 +245,16 @@ void copyEntryData(QAbstractItemView* view, int column, int role) } } -QString getEntryData(QAbstractItemView *view, int column, int role) +QVariant getEntryData(QAbstractItemView *view, int column, int role) { if(!view || !view->selectionModel()) - return QString(); + return QVariant(); QModelIndexList selection = view->selectionModel()->selectedRows(column); if(!selection.isEmpty()) { // Return first item - return (selection.at(0).data(role).toString()); + return (selection.at(0).data(role)); } - return QString(); + return QVariant(); } QString getSaveFileName(QWidget* parent, const QString& caption, const QString& dir, const QString& filter, QString* selectedSuffixOut) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 9673142bee..203808c658 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -75,7 +75,7 @@ void copyEntryData(QAbstractItemView* view, int column, int role = Qt::EditRole) @param[in] role Data role to extract from the model @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress */ -QString getEntryData(QAbstractItemView *view, int column, int role); +QVariant getEntryData(QAbstractItemView *view, int column, int role); void setClipboard(const QString& str); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 131d4c86f0..d482a97027 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -26,6 +26,8 @@ bool NodeLessThan::operator()(const CNodeCombinedStats& left, const CNodeCombine std::swap(pLeft, pRight); switch (column) { + case PeerTableModel::NetNodeId: + return pLeft->nodeid < pRight->nodeid; case PeerTableModel::Address: return pLeft->addrName.compare(pRight->addrName) < 0; case PeerTableModel::Subversion: @@ -111,7 +113,7 @@ PeerTableModel::PeerTableModel(ClientModel* parent) : QAbstractTableModel(parent clientModel(parent), timer(0) { - columns << tr("Address/Hostname") << tr("Version") << tr("Ping Time"); + columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); priv = new PeerTablePriv(); // default to unsorted priv->sortColumn = -1; @@ -161,6 +163,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const if (role == Qt::DisplayRole) { switch (index.column()) { + case NetNodeId: + return rec->nodeStats.nodeid; case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 55133881c6..fdfe6ed202 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -52,9 +52,10 @@ class PeerTableModel : public QAbstractTableModel void stopAutoRefresh(); enum ColumnIndex { - Address = 0, - Subversion = 1, - Ping = 2 + NetNodeId = 0, + Address = 1, + Subversion = 2, + Ping = 3 }; /** @name Methods overridden from QAbstractTableModel diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 691b104cc0..8b7976e172 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -991,7 +991,7 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point) void RPCConsole::disconnectSelectedNode() { // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address); + QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); // Find the node, disconnect it and clear the selected node if (CNode *bannedNode = FindNode(strNode.toStdString())) { bannedNode->CloseSocketDisconnect(); @@ -1026,7 +1026,7 @@ void RPCConsole::unbanSelectedNode() if (!clientModel) return; // Get currently selected ban address - QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address); + QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address).toString(); CSubNet possibleSubnet(strNode.toStdString()); if (possibleSubnet.IsValid()) { From f2057420cd735cf9f709d1b6785776179ad7d4c4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 28 Sep 2020 21:42:38 -0400 Subject: [PATCH 0433/1888] move human-readable byte formatting to guiutil --- src/qt/guiutil.cpp | 11 +++++++++++ src/qt/guiutil.h | 2 ++ src/qt/rpcconsole.cpp | 20 ++++---------------- src/qt/rpcconsole.h | 1 - 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9187a3a7da..5742bbf338 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -967,5 +967,16 @@ QString formatTimeOffset(int64_t nTimeOffset) return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10)); } +QString formatBytes(uint64_t bytes) +{ + if(bytes < 1024) + return QString(QObject::tr("%1 B")).arg(bytes); + if(bytes < 1024 * 1024) + return QString(QObject::tr("%1 KB")).arg(bytes / 1024); + if(bytes < 1024 * 1024 * 1024) + return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024); + + return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024); +} } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 203808c658..1ee47b808d 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -260,6 +260,8 @@ QString formatPingTime(double dPingTime); /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); +QString formatBytes(uint64_t bytes); + #if defined(Q_OS_MAC) // workaround for Qt OSX Bug: // https://bugreports.qt-project.org/browse/QTBUG-15631 diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 8b7976e172..4b224d5292 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -763,18 +763,6 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value) setTrafficGraphRange(mins); } -QString RPCConsole::FormatBytes(quint64 bytes) -{ - if (bytes < 1024) - return QString(tr("%1 B")).arg(bytes); - if (bytes < 1024 * 1024) - return QString(tr("%1 KB")).arg(bytes / 1024); - if (bytes < 1024 * 1024 * 1024) - return QString(tr("%1 MB")).arg(bytes / 1024 / 1024); - - return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024); -} - void RPCConsole::setTrafficGraphRange(int mins) { ui->trafficGraph->setGraphRangeMins(mins); @@ -783,8 +771,8 @@ void RPCConsole::setTrafficGraphRange(int mins) void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut) { - ui->lblBytesIn->setText(FormatBytes(totalBytesIn)); - ui->lblBytesOut->setText(FormatBytes(totalBytesOut)); + ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn)); + ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut)); } void RPCConsole::showInfo() @@ -903,8 +891,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats* stats) ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices)); ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastSend) : tr("never")); ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastRecv) : tr("never")); - ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes)); - ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes)); + ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes)); + ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes)); ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime)); ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait)); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 487d82e05c..d02e1b9daf 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -130,7 +130,6 @@ public Q_SLOTS: void handleRestart(QStringList args); private: - static QString FormatBytes(quint64 bytes); void startExecutor(); void setTrafficGraphRange(int mins); /** Build parameter list for restart */ From caf52fbdf471ab69e1f8b45f8ed01b02333ca317 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 28 Sep 2020 21:57:14 -0400 Subject: [PATCH 0434/1888] Add Sent and Received information to the debug menu peer list --- src/qt/peertablemodel.cpp | 20 +++++++++++++++++--- src/qt/peertablemodel.h | 6 ++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index d482a97027..b5213bd549 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -34,6 +34,10 @@ bool NodeLessThan::operator()(const CNodeCombinedStats& left, const CNodeCombine return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; case PeerTableModel::Ping: return pLeft->dPingTime < pRight->dPingTime; + case PeerTableModel::Sent: + return pLeft->nSendBytes < pRight->nSendBytes; + case PeerTableModel::Received: + return pLeft->nRecvBytes < pRight->nRecvBytes; } return false; @@ -113,7 +117,7 @@ PeerTableModel::PeerTableModel(ClientModel* parent) : QAbstractTableModel(parent clientModel(parent), timer(0) { - columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); + columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv = new PeerTablePriv(); // default to unsorted priv->sortColumn = -1; @@ -172,10 +176,20 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const return QString::fromStdString(rec->nodeStats.cleanSubVer); case Ping: return GUIUtil::formatPingTime(rec->nodeStats.dPingTime); + case Sent: + return GUIUtil::formatBytes(rec->nodeStats.nSendBytes); + case Received: + return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes); } } else if (role == Qt::TextAlignmentRole) { - if (index.column() == Ping) - return (int)(Qt::AlignRight | Qt::AlignVCenter); + switch (index.column()) { + case Ping: + case Sent: + case Received: + return QVariant(Qt::AlignRight | Qt::AlignVCenter); + default: + return QVariant(); + } } return QVariant(); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index fdfe6ed202..e89c432fc7 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -54,8 +54,10 @@ class PeerTableModel : public QAbstractTableModel enum ColumnIndex { NetNodeId = 0, Address = 1, - Subversion = 2, - Ping = 3 + Ping = 2, + Sent = 3, + Received = 4, + Subversion = 5 }; /** @name Methods overridden from QAbstractTableModel From 153cfb9f11e127e8bcdb9cbdec9268441d3fbd14 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 10:05:40 -0400 Subject: [PATCH 0435/1888] Fix "Disconnect" button --- src/qt/rpcconsole.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4b224d5292..dbef9e0974 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -978,10 +978,20 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point) void RPCConsole::disconnectSelectedNode() { + if (!clientModel) + return; + + if(cachedNodeid == -1) + return; + // Get currently selected peer address - QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString(); + int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeid); + if(detailNodeRow < 0) + return; + + const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); // Find the node, disconnect it and clear the selected node - if (CNode *bannedNode = FindNode(strNode.toStdString())) { + if (CNode *bannedNode = FindNode(stats->nodeStats.addr.ToString())) { bannedNode->CloseSocketDisconnect(); clearSelectedNode(); } From 846e51c53f71367feaa4962bc01285d7d1886d07 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 10:09:38 -0400 Subject: [PATCH 0436/1888] Fix "Masternodes" tab text cut off when selected --- src/qt/res/css/Dark.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 476e4cf6c7..8f899f2aed 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -128,7 +128,7 @@ QToolBar > QToolButton { } QToolBar > QToolButton:checked { color: #83faff; - font-size: 18px; + font-size: 17px; font-weight: bold; } #dapsico { From ddd0ed97473f2ef61684e43ae65b7934714c4454 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 10:11:40 -0400 Subject: [PATCH 0437/1888] Change main icon size and drop padding to bring back Masternodes tab on smaller resolution screens --- src/qt/bitcoingui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 624440de2a..f5f9fe582f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -613,7 +613,7 @@ void BitcoinGUI::createToolBars() } toolbar->setMovable(false); // remove unused icon in upper left corner overviewAction->setChecked(true); - toolbar->setStyleSheet("QToolBar{spacing:20px;}"); + toolbar->setStyleSheet("QToolBar{spacing:18px;}"); // Create NavBar QToolBar* bottomToolbar = new QToolBar(this); @@ -642,7 +642,7 @@ void BitcoinGUI::createToolBars() bottomToolbar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); toolbar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); QLabel* dapsico = new QLabel; - dapsico->setPixmap(QIcon(":icons/dapsico").pixmap(130, 130)); + dapsico->setPixmap(QIcon(":icons/dapsico").pixmap(117, 117)); dapsico->setObjectName("dapsico"); navLayout->addWidget(dapsico); From 62e40c0839f5ca2aa1a1e683b6137bb1de15548c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 12:59:04 -0400 Subject: [PATCH 0438/1888] Remove Light Theme --- src/Makefile.qt.include | 1 - src/qt/dapscoin.qrc | 1 - src/qt/optionsmodel.cpp | 2 +- src/qt/optionspage.cpp | 11 - src/qt/optionspage.h | 1 - src/qt/res/css/Light.css | 482 --------------------------------------- 6 files changed, 1 insertion(+), 497 deletions(-) delete mode 100644 src/qt/res/css/Light.css diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 57610e51d5..f8b873d2aa 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -383,7 +383,6 @@ RES_IMAGES = \ qt/res/images/walletFrame_bg.png RES_CSS = \ - qt/res/css/Light.css \ qt/res/css/Dark.css RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png) diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index bee2294500..51438f74bc 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -78,7 +78,6 @@ res/icons/onion.png - res/css/Light.css res/css/Dark.css diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 187b2b690f..3a3712bae0 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -128,7 +128,7 @@ void OptionsModel::Init() // Display if (!settings.contains("digits")) settings.setValue("digits", "2"); - if (!settings.contains("theme")) + if (settings.value("theme") != "dark") settings.setValue("theme", "dark"); if (!settings.contains("fCSSexternal")) settings.setValue("fCSSexternal", false); diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 5d0a1cd412..2d90dd0ba5 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -46,9 +46,6 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); - ui->toggleTheme->setState(settings.value("theme")!="light"); - connect(ui->toggleTheme, SIGNAL(stateChanged(ToggleButton*)), this, SLOT(changeTheme(ToggleButton*))); - connect(ui->lineEditNewPass, SIGNAL(textChanged(const QString &)), this, SLOT(validateNewPass())); connect(ui->lineEditNewPassRepeat, SIGNAL(textChanged(const QString &)), this, SLOT(validateNewPassRepeat())); connect(ui->lineEditOldPass, SIGNAL(textChanged(const QString &)), this, SLOT(onOldPassChanged())); @@ -684,14 +681,6 @@ void OptionsPage::dialogIsFinished(int result) { ui->toggle2FA->setState(false); } -void OptionsPage::changeTheme(ToggleButton* widget) -{ - if (widget->getState()) - settings.setValue("theme", "dark"); - else settings.setValue("theme", "light"); - GUIUtil::refreshStyleSheet(); -} - void OptionsPage::disable2FA() { ui->code_1->setText(""); ui->code_2->setText(""); diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 382714a607..2d47c6b338 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -84,7 +84,6 @@ private Q_SLOTS: void on_pushButtonPassword_clicked(); void on_pushButtonPasswordClear_clicked(); void on_pushButtonBackup_clicked(); - void changeTheme(ToggleButton* widget); void on_Enable2FA(ToggleButton* widget); void on_pushButtonSave_clicked(); void on_pushButtonDisable_clicked(); diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css deleted file mode 100644 index 79cb841962..0000000000 --- a/src/qt/res/css/Light.css +++ /dev/null @@ -1,482 +0,0 @@ -/*************************************************/ -/* Global CSS */ -QWidget, -QHeaderView::section { - background: transparent; - alternate-background-color: transparent; - selection-background-color: transparent; - selection-color: #83faff; - border-style: none; - outline-style: none; - font-size: 15px; - color: black; - font-family: Roboto; - font-weight: 300; -} - -QWidget:disabled { - color: slategrey; -} -QAbstractButton:disabled, -QAbstractSpinBox:disabled, -QLineEdit:disabled, -.QValidatedLineEdit:disabled, -QComboBox:disabled, -/*QSlider::handle:horizontal:disabled { - background: rgb(62, 78, 78); - border: 1px solid rgb(51, 54, 54); -}*/ - -#line_1, #line_2, #line_3, -#line_4, #line_5, #line_6 { - border-bottom: 1px solid gray; - max-height: 5px; - margin: 5px; -} - -#stakingState { - font-size: 11px; - font-style: italic; - padding-left: 60px; - color: white; -} -#connectionCount { - font-size: 11px; - font-style: italic; - padding-left: 52px; - color: white; -} -#blockCount { - font-size: 11px; - font-style: italic; - padding-left: 68px; - color: white; -} - -QDialog { - min-width: 500px; - background-color: white; -} - -#lblRecentTransaction { - font-size: 18px; -} - -/*************************************************/ -/* Nav Bar CSS */ -#navLayout { - background: qlineargradient( - x1: 0 y1: 0, - x2: 1.5 y2: 3, - stop: 0 #5e0057, - stop: 1 #83faff - ); - padding: 3px; -} -QToolBar > QToolButton { - font-size: 15px; - font-weight: 500; - min-width: 160px; - padding: 12px 7px; - color: white; -} -QToolBar > QToolButton:checked { - color: #83faff; - font-size: 18px; - font-weight: bold; -} - -#dapsico { - padding: 25px; -} -#bottomToolbar > QToolButton { - font-size: 12px; - padding: 0; - padding-left: 10px; -} - -/*************************************************/ -/* Element CSS */ -QMessageBox QAbstractButton, -QMessageBox QFrame { - border: 1px solid #83faff; - padding: 10px 20px 10px 20px; - border-radius: 20px; - margin: 15px; - border-width: 2px; -} -QMessageBox QFrame { - padding: 0 40px 0 40px; - border-radius: 50px; - min-height: 100px; - background: rgba(0,0,0,30%); - border-width: 3px; -} -QTableWidget { - alternate-background-color: #f7f7f7; - selection-background-color: rgba(0, 0, 0, 20%); -} -QHeaderView::section, -QCalendar::section, QCalendar QHeaderView::section { - min-height: 55px; -} -QTableView::item, -QTableWidgetView::item, -QHeaderView::item, -QTableView::selectrows { - padding: 25px; -} - -#labelRecoveryDescription { - font-size: 12px; -} - -/*** Check Boxes and Radio ***/ -.QRadioButton::indicator, -QCheckBox::indicator { - height: 25px; - width: 25px; - border-radius: 12px; - background-color: whitesmoke; - margin: 7px; -} -.QRadioButton::indicator:checked, -QCheckBox::indicator:checked { - height: 20px; - width: 20px; - background-color: #5e2059; - border-style: solid; - border-radius: 13px; - border-color: whitesmoke; - border-width: 3px; - margin: 7px; -} - -QGroupBox { - font: bold; - border: 1px solid black; - border-radius: 6px; - margin-top: 6px; -} - -QGroupBox::title { - subcontrol-origin: margin; - left: 7px; - padding: 0px 5px 0px 5px; -} - -/*** Line Edits, ComboBoxes ***/ -.QValidatedLineEdit, -.QLineEdit, -QAbstractSpinBox, -QComboBox, -/* QListView, */ -QComboBox QAbstractItemView, -QCalendar QCalendarWidget QWidget, -QCalendarWidget, -QCalendarWidget QWidget#qt_calendar_navigationbar, -QCalendarWidget QMenu, -QCalendarWidget QAbstractItemView:enabled, -QTextEdit { - /* padding-left: 10px; */ - padding: 5px; - border-radius: 10px; - border-width: 1px; - border-color: #83faff; - border-style: solid; - background: #f7f7f7; - background-color: #f7f7f7; - alternate-background-color: #f7f7f7; - margin: 5px; -} -/* QCalendarWidget QWidget { alternate-background-color: green; } */ -.QValidatedLineEdit:focus, -.QLineEdit:focus, -QAbstractSpinBox:focus, -QComboBox:focus, -QComboBox::item:selected, -QMenu::item:selected, -QTextEdit:focus { - border-width: 4px; - background: #a7a7a7; -} - -QMenuBar { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 lightgray, stop:1 darkgray); - spacing: 3px; /* spacing between menu bar items */ -} - -QMenuBar::item { - padding: 1px 4px; - background: transparent; - border-radius: 4px; -} - -QMenuBar::item:selected { /* when selected using mouse or keyboard */ - background: #a7a7a7; -} - -QMenuBar::item:pressed { - background: #888888; -} - -QToolTip { - color: white; - background-color: #5E1C5A; - border: 1px solid white; - border-radius:5px; -} - -QMenu::item { - padding: 2px 25px 2px 20px; - border: 1px solid transparent; /* reserve space for selection border */ - color: black; - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 lightgray, stop:1 darkgray); -} - -QMenu::separator { - background: black; - width: 1px; /* when vertical */ - height: 1px; /* when horizontal */ -} - -QComboBox:checked { - color: #83faff; -} -QComboBox::indicator { - background-color: transparent; -} - -/*** Buttons ***/ -QPushButton { - height: 25px; - border-radius: 10px; - background-color: #b57fb1; - color: white; - font-size: 20px; - font-weight: 400; - padding: 5px 5px; - max-width: 200px; - border: 1px solid gray; -} - -QPushButton:hover { - background-color: #9d6f9a; - color: #b0fcff; - font-style: bold; -} - -QPushButton:pressed { - background-color: #a975a5; - border-style: solid; - border-color: #b57fb1; - border-width: 10px; -} - -QPushButton:disabled { - background-color: gray; - color: white; -} - -QPushButton#btn_rescan{ - font-size: 19px; -} - -QPushButton#btn_resync{ - font-size: 15px; -} - -QPushButton#btn_day,QPushButton#btn_month,QPushButton#btn_week{ - min-height: 35px; -} - -QPushButton#btnLockUnlock{ - margin-right: 9px; - width: 20px; - height:25px; - background-color: transparent; - border: 0; - border-radius: 0; -} - -/*** Spin Boxes, Combo Boxes ***/ -QWidget::up-button { - border-radius: 10px 10px 0 0; - subcontrol-origin: border; - subcontrol-position: top right; - width: 21px; - padding-right: 1px; - padding-left: 5px; - padding-top: 2px; - background: transparent; - alternate-background-color: transparent; -} - -QWidget::down-button, -QWidget::drop-down { - border-radius: 0 0 10px 10px; - subcontrol-origin: border; - subcontrol-position: bottom right; - padding-right: 1px; - padding-left: 5px; - padding-bottom: 2px; - width: 21px; - background: transparent; - alternate-background-color: transparent; -} - -QWidget::up-arrow { - image: url(":/images/upArrow_small"); -} -QWidget::up-arrow:disabled { - image: url(":/images/upArrow_small_dark"); -} - -QWidget::down-arrow { - image: url(":/images/downArrow_small"); -} -QWidget::down-arrow:disabled { - image: url(":/images/downArrow_small_dark"); -} - -QWidget::left-arrow { - image: url(":/images/leftArrow_small"); -} -QWidget::left-arrow:disabled { - image: url(":/images/leftArrow_small_dark"); -} - -QWidget::right-arrow { - image: url(":/images/rightArrow_small"); -} -QWidget::right-arrow:disabled { - image: url(":/images/rightArrow_small_dark"); -} - -/*** Sliders ***/ -/*QWidget::horizontal { - height: 45px; -}*/ - -/*** Toggle Buttons ***/ -ToggleButton > QPushButton { - font-size: 10px; - padding-right: 15px; - border-radius: 10px; -} - -ToggleButton > QPushButton:enabled:checked { - background-color: black; - color: #93faff; - padding: 0; - text-align: center; - border: 1px solid #93faff; -} -#TxEntry, -#TxEntry QTableView::item, -#TxEntry QTableWidgetView::item, -#TxEntry QHeaderView::section, -#TxEntry QTableView::selectrows { - padding: 0px; - margin: 0px; -} -#TxEntry QPushButton { - border-radius:0; - border: none; - background: transparent; -} - -#secondaryTxEntry, -#secondaryTxEntry QTableView::item, -#secondaryTxEntry QTableWidgetView::item, -#secondaryTxEntry QHeaderView::section, -#secondaryTxEntry QTableView::selectrows { - padding: 0px; - margin: 0px; -} -#secondaryTxEntry QPushButton { - border-radius:0; - border: none; - background: transparent; -} - -#secondaryTxEntry > #bkg_widget { - background-color: #f7f7f7; -} - -#code_1, -#code_2, -#code_3, -#code_4, -#code_5, -#code_6 { - border-bottom-width: 1px; - border-bottom-style: solid; - border-radius: 0px; - border-color: black; -} - -#txtcode_1, -#txtcode_2, -#txtcode_3, -#txtcode_4, -#txtcode_5, -#txtcode_6 { - border-width: 0 0 1px 0; - border-style: solid; - border-radius: 0px; - border-color: black; - - padding: 0px; - background: transparent; - background-color: transparent; - alternate-background-color: transparent; - margin: 0px; -} - -QDialog .QTabWidget QTabBar::tab { - background-color:#FFFFFF; - color:#000000; - padding-left:10px; - padding-right:10px; - padding-top:5px; - padding-bottom:5px; - border-top: 1px solid #d7d7d7; -} - -QDialog .QTabWidget QTabBar::tab:selected, QDialog .QTabWidget QTabBar::tab:hover { - background-color:#31398c; - color:#FFFFFF; -} - -QTabWidget::pane { /* The tab widget frame */ -border-top: 2px solid #5E1C5A; -} -QTabWidget::tab-bar { -left: 5px; /* move to the right by 5px */ -} -/* Style the tab using the tab sub-control. Note that it reads QTabBar _not_ QTabWidget */ -QTabBar::tab { -background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3); -border: 2px solid #C4C4C3; -border-bottom-color: #5E1C5A; /* same as the pane color */ -border-top-left-radius: 4px; -border-top-right-radius: 4px; -min-width: 8ex; -padding: 2px; -} -QTabBar::tab:selected, QTabBar::tab:hover { -background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fafafa, stop: 0.4 #f4f4f4, stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); -} -QTabBar::tab:selected { -border-color: #9B9B9B; -border-bottom-color: #5E1C5A; /* same as pane color */ -} -QTabBar::tab:!selected { -margin-top: 2px; /* make non-selected tabs look smaller */ -} -QTabBar::tab { color: #5E1C5A; } -QTabBar::tab:selected { color: gray; } -QLineEdit#lineEdit { color: white; } From 643f9511f76237c06203af6bef133ae79f76b8b0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 12:59:15 -0400 Subject: [PATCH 0439/1888] Disable Theme toggle (to be removed) --- src/qt/forms/optionspage.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index ede9bf0864..9b6ccbb136 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -135,6 +135,9 @@ + + false + 0 @@ -151,6 +154,9 @@ + + false + 0 From 4e276298de6b06f75db55a65d108ec6e39239f28 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 29 Sep 2020 17:53:36 -0400 Subject: [PATCH 0440/1888] Theme updates --- src/qt/res/css/Dark.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 8f899f2aed..865a9514b4 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -189,7 +189,7 @@ QCheckBox::indicator { QCheckBox::indicator:checked { height: 20px; width: 20px; - background-color: #5e2059; + background-color: #272c42; border-style: solid; border-radius: 13px; border-color: whitesmoke; @@ -286,10 +286,10 @@ QPushButton:hover { } QPushButton:pressed { - background-color: #5e0057; + background-color: #272c42; border-style: solid; - border-color: #272c42; - border-width: 10px; + border-color: #1e1824; + border-width: 2px; } QPushButton#btn_rescan{ From e2c63b50e3ba04caa913d1ad46e015edce794ddf Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 30 Sep 2020 11:09:11 -0400 Subject: [PATCH 0441/1888] net: define NodeId as an int64_t This should make occurances of NodeId wrapping essentially impossible for real-world usage. --- src/net.h | 2 +- src/qt/peertablemodel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net.h b/src/net.h index c58584ecf3..72de1944d1 100644 --- a/src/net.h +++ b/src/net.h @@ -87,7 +87,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler); bool StopNode(); void SocketSendData(CNode* pnode); -typedef int NodeId; +typedef int64_t NodeId; // Signals for message handling struct CNodeSignals { diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index b5213bd549..9a0f844152 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -168,7 +168,7 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const if (role == Qt::DisplayRole) { switch (index.column()) { case NetNodeId: - return rec->nodeStats.nodeid; + return (qint64)rec->nodeStats.nodeid; case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName); From 38ed279708d229de74c62b9c9805feb1267ca186 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 30 Sep 2020 11:42:20 -0400 Subject: [PATCH 0442/1888] Remove Theme Selection/Adjust alignment on Settings screen --- src/qt/forms/optionspage.ui | 61 ++----------------------------------- 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 9b6ccbb136..89752542ac 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -45,7 +45,7 @@ 0 - + @@ -58,7 +58,7 @@ - + @@ -128,63 +128,6 @@ - - - - 0 - - - - - false - - - - 0 - 0 - - - - Theme Selection: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - false - - - - 0 - 0 - - - - Switch between Dark and Light theme - - - Qt::LeftToRight - - - Dark - - - Light - - - - 100 - 55 - - - - - - From aba4f20ba7a12bc56f8a99051ba626a73bfc0662 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 2 Oct 2020 11:44:02 -0400 Subject: [PATCH 0443/1888] Restore Copy button to Mnemonic Recovery Phrase box --- src/qt/optionspage.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 2d90dd0ba5..7f6bb1bf5a 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -858,11 +858,19 @@ void OptionsPage::onShowMnemonic() { QString mPhrase = std::string(mnemonic.begin(), mnemonic.end()).c_str(); QMessageBox msgBox; + QPushButton *copyButton = msgBox.addButton(tr("Copy"), QMessageBox::ActionRole); + copyButton->setStyleSheet("background:transparent;"); + copyButton->setIcon(QIcon(":/icons/editcopy")); msgBox.setWindowTitle("Mnemonic Recovery Phrase"); msgBox.setText("Below is your Mnemonic Recovery Phrase, consisting of 24 seed words. Please copy/write these words down in order. We strongly recommend keeping multiple copies in different locations."); msgBox.setInformativeText("\n" + mPhrase + ""); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.exec(); + + if (msgBox.clickedButton() == copyButton) { + //Copy Mnemonic Recovery Phrase to clipboard + GUIUtil::setClipboard(std::string(mnemonic.begin(), mnemonic.end()).c_str()); + } } void OptionsPage::setAutoConsolidate(int state) { From c9b242fc8b2e675cec5aade27362307d5ccfc245 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 2 Oct 2020 12:09:16 -0400 Subject: [PATCH 0444/1888] Update translations --- src/qt/dapscoinstrings.cpp | 18 +- src/qt/locale/dapscoin_en.ts | 496 ++++++++++------------------------- 2 files changed, 143 insertions(+), 371 deletions(-) diff --git a/src/qt/dapscoinstrings.cpp b/src/qt/dapscoinstrings.cpp index 80ee4ae271..75706c47bd 100644 --- a/src/qt/dapscoinstrings.cpp +++ b/src/qt/dapscoinstrings.cpp @@ -13,6 +13,9 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "(1 = keep tx meta data e.g. account owner and payment request information, 2 " "= drop tx meta data)"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"Accept connections from outside (default: 1 if no -proxy or -connect/-" +"noconnect)"), +QT_TRANSLATE_NOOP("dapscoin-core", "" "Allow JSON-RPC connections from specified source. Valid for are a " "single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or " "a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"), @@ -32,6 +35,9 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Change automatic finalized budget voting behavior. mode=auto: Vote for only " "exact finalized budget match to my generated budget. (string, default: auto)"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"Connect only to the specified node(s); -noconnect or -connect=0 alone to " +"disable automatic connections"), +QT_TRANSLATE_NOOP("dapscoin-core", "" "Continuously rate-limit free transactions to *1000 bytes per minute " "(default:%u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -109,7 +115,7 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Output debugging information (default: %u, supplying is optional)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "Query for peer addresses via DNS lookup, if low on addresses (default: 1 " -"unless -connect)"), +"unless -connect/-noconnect)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "Randomize credentials for every proxy connection. This enables Tor stream " "isolation (default: %u)"), @@ -193,10 +199,10 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "sent, or sending the same total value in two separate transactions will " "usually work around this limitation."), QT_TRANSLATE_NOOP("dapscoin-core", "" -"You have attempted to send more than 50 UTXOs in a single transaction. This " -"is a rare occurrence, and to work around this limitation, please either " -"lower the total amount of the transaction, or send two separate transactions " -"with 50% of your total desired amount."), +"You have attempted to send more than 50 UTXOs in a single transaction. To " +"work around this limitation, please either lower the total amount of the " +"transaction or send two separate transactions with 50% of your total desired " +"amount."), QT_TRANSLATE_NOOP("dapscoin-core", "" "You must specify a masternodeprivkey in the configuration. Please see " "documentation for help."), @@ -206,7 +212,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "(default: 1)"), QT_TRANSLATE_NOOP("dapscoin-core", "(must be 53572 for mainnet)"), QT_TRANSLATE_NOOP("dapscoin-core", " can be:"), QT_TRANSLATE_NOOP("dapscoin-core", "Accept command line and JSON-RPC commands"), -QT_TRANSLATE_NOOP("dapscoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"), QT_TRANSLATE_NOOP("dapscoin-core", "Accept public REST requests (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "Add a node to connect to and attempt to keep the connection open"), QT_TRANSLATE_NOOP("dapscoin-core", "All inputs should have the same number of decoys"), @@ -228,7 +233,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Cannot parse the commitment for inputs"), QT_TRANSLATE_NOOP("dapscoin-core", "Cannot parse the commitment for transaction fee"), QT_TRANSLATE_NOOP("dapscoin-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Cannot write default address"), -QT_TRANSLATE_NOOP("dapscoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("dapscoin-core", "Connect through SOCKS5 proxy"), QT_TRANSLATE_NOOP("dapscoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), QT_TRANSLATE_NOOP("dapscoin-core", "Connection options:"), diff --git a/src/qt/locale/dapscoin_en.ts b/src/qt/locale/dapscoin_en.ts index c3868fe544..11a70753e5 100644 --- a/src/qt/locale/dapscoin_en.ts +++ b/src/qt/locale/dapscoin_en.ts @@ -476,7 +476,7 @@ BitcoinGUI - + Node Node @@ -655,43 +655,13 @@ Show the list of used receiving addresses and labels Show the list of used receiving addresses and labels - - - &Multisignature creation... - - - - - Create a new multisignature address and add it to this wallet - - - - - &Multisignature spending... - - - - - Spend from a multisignature address - - - - - &Multisignature signing... - - - - - Sign with a multisignature address - - Open &URI... Open &URI... - + %n Active Connections @@ -738,12 +708,12 @@ Confirmations: %5 - + &File &File - + &Settings &Settings @@ -798,12 +768,12 @@ Confirmations: %5 - + &Blockchain Explorer - + &Tools &Tools @@ -813,12 +783,12 @@ Confirmations: %5 &Help - + DAPS - + &Masternodes @@ -863,7 +833,7 @@ Confirmations: %5 - + Open a DAPS: URI or payment request @@ -1043,17 +1013,17 @@ Confirmations: %5 - + Social - + DAPS client - + Up to date Up to date @@ -1349,7 +1319,7 @@ Confirmations: %5 Priority - + Copy address Copy address @@ -1415,7 +1385,17 @@ Confirmations: %5 Copy change - + + Select all + + + + + Unselect all + + + + Please switch to "List mode" to use this function. @@ -1440,13 +1420,13 @@ Confirmations: %5 medium-high - + Can vary +/- %1 duff(s) per input. Can vary +/- %1 duff(s) per input. - + medium medium @@ -1476,7 +1456,7 @@ Confirmations: %5 (%1 locked) - + none none @@ -1524,7 +1504,7 @@ Confirmations: %5 - + (no label) (no label) @@ -2203,228 +2183,6 @@ Please check the address and try again. - - MultisigDialog - - - Multisignature Address Interactions - - - - - Create MultiSignature &Address - - - - - How many people must sign to verify a transaction - - - - - Enter the minimum number of signatures required to sign transactions - - - - - Address Label: - - - - - Add another address that could sign to verify a transaction from the multisig address. - - - - - &Add Address / Key - - - - - Local addresses or public keys that can sign: - - - - - Create a new multisig address - - - - - C&reate - - - - - - - Status: - - - - - Use below to quickly import an address by its redeem. Don't forget to add a label before clicking import! -Keep in mind, the wallet will rescan the blockchain to find transactions containing the new address. -Please be patient after clicking import. - - - - - &Import Redeem - - - - - &Create MultiSignature Tx - - - - - Inputs: - - - - - Coin Control - - - - - Quantity Selected: - - - - - - 0 - - - - - Amount: - Amount: - - - - Add an input to fund the outputs - - - - - Add a Raw Input - - - - - Address / Amount: - - - - - Add destinations to send DAPS to - - - - - Add &Destination - - - - - Create a transaction object using the given inputs to the given outputs - - - - - Cr&eate - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - - - - &Sign MultiSignature Tx - - - - - Transaction Hex: - - - - - Sign the transaction from this wallet or from provided private keys - - - - - S&ign - - - - - <html><head/><body><p>DISABLED until transaction has been signed enough times.</p></body></html> - - - - - Co&mmit - - - - - Add private keys to sign the transaction with - - - - - Add Private &Key - - - - - Sign with only private keys (Not Recommened) - - - - - Invalid Tx Hash. - - - - - Vout position must be positive. - - - - - Maximum possible addresses reached. (16) - - - - - Vout Position: - - - - - Amount: - - - - - Maximum (15) - - - OpenURIDialog @@ -2774,24 +2532,24 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + On - - + + Off - + Staking Mode: - + Backup Wallet Backup Wallet @@ -2801,27 +2559,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - Theme Selection: - - - - - Switch between Dark and Light theme - - - - - Dark - - - - - Light - - - - + Change current passphrase @@ -2940,6 +2678,11 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsWallet Data (*.dat) Wallet Data (*.dat) + + + Copy + + OverviewPage @@ -2965,7 +2708,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + + (loading) + + + + Balance @@ -2990,7 +2738,12 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsTotal of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - + + (syncing) + + + + Recent Transactions @@ -3130,19 +2883,34 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations PeerTableModel - - Address/Hostname - Address/Hostname + + NodeId + - Version - Version + Node/Service + - Ping Time - Ping Time + Ping + + + + + Sent + Sent + + + + Received + Received + + + + User Agent + @@ -3203,6 +2971,26 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations%1 ms %1 ms + + + %1 B + %1 B + + + + %1 KB + %1 KB + + + + %1 MB + %1 MB + + + + %1 GB + %1 GB + QRImageWidget @@ -3407,7 +3195,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3607,7 +3395,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsRebuild index - + In: In: @@ -3700,27 +3488,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - - %1 B - %1 B - - - - %1 KB - %1 KB - - - - %1 MB - %1 MB - - - - %1 GB - %1 GB - - - + (node id: %1) @@ -4140,7 +3908,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsBalance: - + Copy quantity Copy quantity @@ -4180,7 +3948,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translationsCopy change - + Destination @@ -4205,7 +3973,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + Copy @@ -5365,7 +5133,7 @@ Please try again. WalletModel - + Send Coins Send Coins @@ -5373,7 +5141,7 @@ Please try again. WalletView - + &Export &Export @@ -5388,7 +5156,7 @@ Please try again. Selected amount: - + Backup Wallet Backup Wallet @@ -5426,7 +5194,7 @@ Please try again. (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) - + Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times @@ -5456,7 +5224,7 @@ Please try again. Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto) - + Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:%u) Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:%u) @@ -5581,12 +5349,7 @@ Please try again. Output debugging information (default: %u, supplying <category> is optional) - - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) - - - + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) @@ -5711,12 +5474,7 @@ Please try again. - - You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount. - - - - + You must specify a masternodeprivkey in the configuration. Please see documentation for help. You must specify a masternodeprivkey in the configuration. Please see documentation for help. @@ -5745,11 +5503,6 @@ Please try again. Accept command line and JSON-RPC commands Accept command line and JSON-RPC commands - - - Accept connections from outside (default: 1 if no -proxy or -connect) - Accept connections from outside (default: 1 if no -proxy or -connect) - Accept public REST requests (default: %u) @@ -5795,11 +5548,6 @@ Please try again. Cannot write default address Cannot write default address - - - Connect only to the specified node(s) - Connect only to the specified node(s) - Connect through SOCKS5 proxy @@ -6061,12 +5809,22 @@ Please try again. - + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! - + + Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect) + + + + + Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections + + + + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) @@ -6076,17 +5834,27 @@ Please try again. - + + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect) + + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. - + + You have attempted to send more than 50 UTXOs in a single transaction. To work around this limitation, please either lower the total amount of the transaction or send two separate transactions with 50% of your total desired amount. + + + + <category> can be: - + All inputs should have the same number of decoys @@ -6146,7 +5914,7 @@ Please try again. - + Copyright (C) 2015-%i The PIVX Core Developers From 3eaec3e063f571ae288b30cca2b6b065bf34c13a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 2 Oct 2020 12:37:55 -0400 Subject: [PATCH 0445/1888] Add OK button to Mnemonic Recovery Phrase box --- src/qt/optionspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 7f6bb1bf5a..85a6182fa4 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -859,6 +859,7 @@ void OptionsPage::onShowMnemonic() { QString mPhrase = std::string(mnemonic.begin(), mnemonic.end()).c_str(); QMessageBox msgBox; QPushButton *copyButton = msgBox.addButton(tr("Copy"), QMessageBox::ActionRole); + QPushButton *okButton = msgBox.addButton(tr("OK"), QMessageBox::ActionRole); copyButton->setStyleSheet("background:transparent;"); copyButton->setIcon(QIcon(":/icons/editcopy")); msgBox.setWindowTitle("Mnemonic Recovery Phrase"); From a4a7347e36e93e8f99b2c44be46477ae0eedc3ab Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 2 Oct 2020 12:38:20 -0400 Subject: [PATCH 0446/1888] Bump version to v1.0.8.1 --- configure.ac | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 40566740c9..6ca00baf3e 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 8) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index 91bccd652f..46e7b55d3c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.8.0 \ No newline at end of file +1.0.8.1 \ No newline at end of file From 47b85fe5b9300306375d903d51c31bd82cbef7da Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 11 Oct 2020 21:08:26 -0400 Subject: [PATCH 0447/1888] [RPC] Throw immediately if RPC is used when the server is in warmup --- src/rpc/server.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 391d3d9b4e..ad5616d3eb 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -554,6 +554,12 @@ std::string JSONRPCExecBatch(const UniValue &vReq) { } UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms) const { + // Return immediately if in warmup + std::string strWarmupStatus; + if (RPCIsInWarmup(&strWarmupStatus)) { + throw JSONRPCError(RPC_IN_WARMUP, "RPC in warm-up: " + strWarmupStatus); + } + // Find method const CRPCCommand *pcmd = tableRPC[strMethod]; if (!pcmd) From 2c829fc98bdb74a905568117012d95398d377ce7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 11 Oct 2020 21:09:57 -0400 Subject: [PATCH 0448/1888] [Cleanup] Remove unneeded "fix" for segfault with getinfo on startup --- src/rpc/misc.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 36195dd025..3b74649432 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -92,13 +92,6 @@ UniValue getinfo(const UniValue ¶ms, bool fHelp) { obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double) GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); - - // During inital block verification chainActive.Tip() might be not yet initialized - if (chainActive.Tip() == NULL) { - obj.push_back(Pair("status", "Blockchain information not yet available")); - return obj; - } - obj.push_back(Pair("moneysupply",ValueFromAmount(chainActive.Tip()->nMoneySupply))); #ifdef ENABLE_WALLET From 170d8262fc3aa3cb4561a39ee86edfffcc4f34f4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 12:31:42 -0400 Subject: [PATCH 0449/1888] Add check for synced before allowing Staking toggle --- src/qt/optionspage.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 85a6182fa4..a91cf56fa5 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -11,6 +11,7 @@ #include "guiutil.h" #include "guiconstants.h" #include "bitcoingui.h" +#include "masternode-sync.h" #include "optionsmodel.h" #include "receiverequestdialog.h" #include "recentrequeststablemodel.h" @@ -420,6 +421,15 @@ bool OptionsPage::matchNewPasswords() void OptionsPage::on_EnableStaking(ToggleButton* widget) { + if (!masternodeSync.IsSynced()) { + QMessageBox msgBox; + msgBox.setWindowTitle("Staking Disabled - Syncing"); + msgBox.setText("Enable Staking is disabled when you are still syncing the wallet. Please allow the wallet to fully sync before attempting to Enable Staking."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } int status = model->getEncryptionStatus(); if (status == WalletModel::Locked || status == WalletModel::UnlockedForAnonymizationOnly) { QMessageBox msgBox; From 276904e6393812ecbe0746347d9daf5731340738 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 13:09:53 -0400 Subject: [PATCH 0450/1888] Add IsUnsupportedVersion for banned versions Returns: - /DAPScoin:0.27.5.1/ - /DAPScoin:1.0.0/ - /DAPScoin:1.0.1/ - /DAPS:1.0.1.3/ - /DAPS:1.0.2/ - /DAPS:1.0.3.4/ - /DAPS:1.0.4.6/ - /DAPS:1.0.5.7/ - /DAPS:1.0.5.8/ --- src/main.cpp | 2 +- src/net.cpp | 4 ++++ src/net.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 22be88c0e1..d8dcff5487 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5761,7 +5761,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } - if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/" || pfrom->strSubVer == "/DAPS:1.0.4.6/" || pfrom->strSubVer == "/DAPS:1.0.5.7/" || pfrom->strSubVer == "/DAPS:1.0.5.8/") { + if (IsUnsupportedVersion(pfrom->strSubVer)) { // disconnect from peers other than these sub versions LogPrintf("partner %s using obsolete version %s; banning and disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); state->fShouldBan = true; diff --git a/src/net.cpp b/src/net.cpp index 3b6d1725db..14584fef2f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -125,6 +125,10 @@ unsigned short GetListenPort() { return (unsigned short) (GetArg("-port", Params().GetDefaultPort())); } +bool IsUnsupportedVersion(std::string strSubVer) { + return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/"); +} + // find 'best' local address for a particular peer bool GetLocal(CService &addr, const CNetAddr *paddrPeer) { if (!fListen) diff --git a/src/net.h b/src/net.h index 72de1944d1..5427f167fd 100644 --- a/src/net.h +++ b/src/net.h @@ -770,5 +770,6 @@ class CBanDB bool Read(banmap_t& banSet); }; void DumpBanlist(); +bool IsUnsupportedVersion(std::string strSubVer); #endif // BITCOIN_NET_H From a930615795caf20a3c0e5a66dc6ffde2308ffb2e Mon Sep 17 00:00:00 2001 From: ALEEF02 Date: Mon, 12 Oct 2020 10:26:40 -0700 Subject: [PATCH 0451/1888] Remove light theme to resolve branch conflicts --- src/qt/res/css/Light.css | 486 --------------------------------------- 1 file changed, 486 deletions(-) delete mode 100644 src/qt/res/css/Light.css diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css deleted file mode 100644 index 76342e3d2b..0000000000 --- a/src/qt/res/css/Light.css +++ /dev/null @@ -1,486 +0,0 @@ -/*************************************************/ -/* Global CSS */ -QWidget, -QHeaderView::section { - background: transparent; - alternate-background-color: transparent; - selection-background-color: transparent; - selection-color: #83faff; - border-style: none; - outline-style: none; - font-size: 15px; - color: black; - font-family: Roboto; - font-weight: 300; -} - -QWidget:disabled { - color: slategrey; -} -QAbstractButton:disabled, -QAbstractSpinBox:disabled, -QLineEdit:disabled, -.QValidatedLineEdit:disabled, -QComboBox:disabled, -/*QSlider::handle:horizontal:disabled { - background: rgb(62, 78, 78); - border: 1px solid rgb(51, 54, 54); -}*/ - -#line_1, #line_2, #line_3, #line_4, -#line_5, #line_6, #line_7, #line_8 { - border-bottom: 1px solid gray; - max-height: 5px; - margin: 5px; -} - -#stakingState { - font-size: 11px; - font-style: italic; - padding-left: 60px; - color: white; -} -#connectionCount { - font-size: 11px; - font-style: italic; - padding-left: 52px; - color: white; -} -#blockCount { - font-size: 11px; - font-style: italic; - padding-left: 68px; - color: white; -} - -QDialog { - min-width: 500px; - background-color: white; -} - -#lblRecentTransaction { - font-size: 18px; -} - -/*************************************************/ -/* Nav Bar CSS */ -#navLayout { - background: qlineargradient( - x1: 0 y1: 0, - x2: 1.5 y2: 3, - stop: 0 #5e0057, - stop: 1 #83faff - ); - padding: 3px; -} -QToolBar > QToolButton { - font-size: 15px; - font-weight: 500; - min-width: 160px; - padding: 12px 7px; - color: white; -} -QToolBar > QToolButton:checked { - color: #83faff; - font-size: 18px; - font-weight: bold; -} - -#dapsico { - padding: 25px; -} -#bottomToolbar > QToolButton { - font-size: 12px; - padding: 0; - padding-left: 10px; -} - -/*************************************************/ -/* Element CSS */ -QMessageBox QAbstractButton, -QMessageBox QFrame { - border: 1px solid #83faff; - padding: 10px 20px 10px 20px; - border-radius: 20px; - margin: 15px; - border-width: 2px; -} -QMessageBox QFrame { - padding: 0 40px 0 40px; - border-radius: 50px; - min-height: 100px; - background: rgba(0,0,0,30%); - border-width: 3px; -} -QTableWidget { - alternate-background-color: #f7f7f7; - selection-background-color: rgba(0, 0, 0, 20%); -} -QHeaderView::section, -QCalendar::section, QCalendar QHeaderView::section { - min-height: 55px; -} -QTableView::item, -QTableWidgetView::item, -QHeaderView::item, -QTableView::selectrows { - padding: 25px; -} - -#labelRecoveryDescription { - font-size: 12px; -} - -/*** Check Boxes and Radio ***/ -.QRadioButton::indicator, -QCheckBox::indicator { - height: 25px; - width: 25px; - border-radius: 12px; - background-color: whitesmoke; - margin: 7px; -} -.QRadioButton::indicator:checked, -QCheckBox::indicator:checked { - height: 20px; - width: 20px; - background-color: #5e2059; - border-style: solid; - border-radius: 13px; - border-color: whitesmoke; - border-width: 3px; - margin: 7px; -} - -QGroupBox { - font: bold; - border: 1px solid black; - border-radius: 6px; - margin-top: 6px; -} - -QGroupBox::title { - subcontrol-origin: margin; - left: 7px; - padding: 0px 5px 0px 5px; -} - -/*** Line Edits, ComboBoxes ***/ -.QValidatedLineEdit, -.QLineEdit, -QAbstractSpinBox, -QComboBox, -/* QListView, */ -QComboBox QAbstractItemView, -QCalendar QCalendarWidget QWidget, -QCalendarWidget, -QCalendarWidget QWidget#qt_calendar_navigationbar, -QCalendarWidget QMenu, -QCalendarWidget QAbstractItemView:enabled, -QTextEdit { - /* padding-left: 10px; */ - padding: 5px; - border-radius: 10px; - border-width: 1px; - border-color: #83faff; - border-style: solid; - background: #f7f7f7; - background-color: #f7f7f7; - alternate-background-color: #f7f7f7; - margin: 5px; -} -/* QCalendarWidget QWidget { alternate-background-color: green; } */ -.QValidatedLineEdit:focus, -.QLineEdit:focus, -QAbstractSpinBox:focus, -QComboBox:focus, -QComboBox::item:selected, -QMenu::item:selected, -QTextEdit:focus { - border-width: 4px; - background: #a7a7a7; -} - -QMenuBar { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 lightgray, stop:1 darkgray); - spacing: 3px; /* spacing between menu bar items */ -} - -QMenuBar::item { - padding: 1px 4px; - background: transparent; - border-radius: 4px; -} - -QMenuBar::item:selected { /* when selected using mouse or keyboard */ - background: #a7a7a7; -} - -QMenuBar::item:pressed { - background: #888888; -} - -QToolTip { - color: white; - background-color: #5E1C5A; - border: 1px solid white; - border-radius:5px; -} - -QMenu::item { - padding: 2px 25px 2px 20px; - border: 1px solid transparent; /* reserve space for selection border */ - color: black; - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 lightgray, stop:1 darkgray); -} - -QMenu::separator { - background: black; - width: 1px; /* when vertical */ - height: 1px; /* when horizontal */ -} - -QComboBox:checked { - color: #83faff; -} -QComboBox::indicator { - background-color: transparent; -} - -/*** Buttons ***/ -QPushButton { - height: 25px; - border-radius: 10px; - background-color: #b57fb1; - color: white; - font-size: 20px; - font-weight: 400; - padding: 5px 5px; - max-width: 200px; - border: 1px solid gray; -} - -QPushButton:hover { - background-color: #9d6f9a; - color: #b0fcff; - font-style: bold; -} - -QPushButton:pressed { - background-color: #a975a5; - border-style: solid; - border-color: #b57fb1; - border-width: 10px; -} - -QPushButton:disabled { - background-color: gray; - color: white; -} - -QPushButton#btn_rescan{ - font-size: 19px; -} - -QPushButton#btn_resync{ - font-size: 15px; -} - -QPushButton#btn_day,QPushButton#btn_month,QPushButton#btn_week{ - min-height: 35px; -} - -QPushButton#btnLockUnlock{ - margin-right: 9px; - width: 20px; - height:25px; - background-color: transparent; - border: 0; - border-radius: 0; -} - -/*** Spin Boxes, Combo Boxes ***/ -QWidget::up-button { - border-radius: 10px 10px 0 0; - subcontrol-origin: border; - subcontrol-position: top right; - width: 21px; - padding-right: 1px; - padding-left: 5px; - padding-top: 2px; - background: transparent; - alternate-background-color: transparent; -} - -QWidget::down-button, -QWidget::drop-down { - border-radius: 0 0 10px 10px; - subcontrol-origin: border; - subcontrol-position: bottom right; - padding-right: 1px; - padding-left: 5px; - padding-bottom: 2px; - width: 21px; - background: transparent; - alternate-background-color: transparent; -} - -QWidget::up-arrow { - image: url(":/images/upArrow_small"); -} -QWidget::up-arrow:disabled { - image: url(":/images/upArrow_small_dark"); -} - -QWidget::down-arrow { - image: url(":/images/downArrow_small"); -} -QWidget::down-arrow:disabled { - image: url(":/images/downArrow_small_dark"); -} - -QWidget::left-arrow { - image: url(":/images/leftArrow_small"); -} -QWidget::left-arrow:disabled { - image: url(":/images/leftArrow_small_dark"); -} - -QWidget::right-arrow { - image: url(":/images/rightArrow_small"); -} -QWidget::right-arrow:disabled { - image: url(":/images/rightArrow_small_dark"); -} - -/*** Sliders ***/ -/*QWidget::horizontal { - height: 45px; -}*/ - -/*** Toggle Buttons ***/ -ToggleButton > QPushButton { - font-size: 10px; - padding-right: 15px; - border-radius: 10px; -} - -ToggleButton > QPushButton:enabled:checked { - background-color: black; - color: #93faff; - padding: 0; - text-align: center; - border: 1px solid #93faff; -} -#TxEntry, -#TxEntry QTableView::item, -#TxEntry QTableWidgetView::item, -#TxEntry QHeaderView::section, -#TxEntry QTableView::selectrows { - padding: 0px; - margin: 0px; -} -#TxEntry QPushButton { - border-radius:0; - border: none; - background: transparent; -} - -#secondaryTxEntry, -#secondaryTxEntry QTableView::item, -#secondaryTxEntry QTableWidgetView::item, -#secondaryTxEntry QHeaderView::section, -#secondaryTxEntry QTableView::selectrows { - padding: 0px; - margin: 0px; -} -#secondaryTxEntry QPushButton { - border-radius:0; - border: none; - background: transparent; -} - -#secondaryTxEntry > #bkg_widget { - background-color: #f7f7f7; -} - -#code_1, -#code_2, -#code_3, -#code_4, -#code_5, -#code_6, -#code_7, -#code_8 { - border-bottom-width: 1px; - border-bottom-style: solid; - border-radius: 0px; - border-color: black; -} - -#txtcode_1, -#txtcode_2, -#txtcode_3, -#txtcode_4, -#txtcode_5, -#txtcode_6, -#txtcode_7, -#txtcode_8 { - border-width: 0 0 1px 0; - border-style: solid; - border-radius: 0px; - border-color: black; - - padding: 0px; - background: transparent; - background-color: transparent; - alternate-background-color: transparent; - margin: 0px; -} - -QDialog .QTabWidget QTabBar::tab { - background-color:#FFFFFF; - color:#000000; - padding-left:10px; - padding-right:10px; - padding-top:5px; - padding-bottom:5px; - border-top: 1px solid #d7d7d7; -} - -QDialog .QTabWidget QTabBar::tab:selected, QDialog .QTabWidget QTabBar::tab:hover { - background-color:#31398c; - color:#FFFFFF; -} - -QTabWidget::pane { /* The tab widget frame */ -border-top: 2px solid #5E1C5A; -} -QTabWidget::tab-bar { -left: 5px; /* move to the right by 5px */ -} -/* Style the tab using the tab sub-control. Note that it reads QTabBar _not_ QTabWidget */ -QTabBar::tab { -background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3); -border: 2px solid #C4C4C3; -border-bottom-color: #5E1C5A; /* same as the pane color */ -border-top-left-radius: 4px; -border-top-right-radius: 4px; -min-width: 8ex; -padding: 2px; -} -QTabBar::tab:selected, QTabBar::tab:hover { -background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fafafa, stop: 0.4 #f4f4f4, stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); -} -QTabBar::tab:selected { -border-color: #9B9B9B; -border-bottom-color: #5E1C5A; /* same as pane color */ -} -QTabBar::tab:!selected { -margin-top: 2px; /* make non-selected tabs look smaller */ -} -QTabBar::tab { color: #5E1C5A; } -QTabBar::tab:selected { color: gray; } -QLineEdit#lineEdit { color: white; } From 3c24ea514a4613ed19027424767353c95b2ca10e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 14:05:19 -0400 Subject: [PATCH 0452/1888] Update log text for IsUnsupportedVersion --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d8dcff5487..1a101d91a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5763,7 +5763,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (IsUnsupportedVersion(pfrom->strSubVer)) { // disconnect from peers other than these sub versions - LogPrintf("partner %s using obsolete version %s; banning and disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); + LogPrintf("peer %s using unsupported version %s; disconnecting and banning\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); state->fShouldBan = true; pfrom->fDisconnect = true; return false; From 2f825a93f6ea620ba39bf152f2ed449b9f859bc6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 12:27:26 -0400 Subject: [PATCH 0453/1888] Change RPC for showing stealth address to only return the address Affects: showstealthaddress getstealthaddress getaccountaddress --- src/wallet/rpcwallet.cpp | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 838778cb36..fc5186c8bb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2519,36 +2519,9 @@ UniValue showstealthaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_PRIVACY_WALLET_EXISTED, "Error: There is no privacy wallet, please use createprivacyaccount to create one."); } - - CWalletDB walletdb(pwalletMain->strWalletFile); - UniValue ret(UniValue::VOBJ); - int i = 0; - while (i < 10) { - std::string viewAccountLabel = "viewaccount"; - std::string spendAccountLabel = "spendaccount"; - - CAccount viewAccount; - walletdb.ReadAccount(viewAccountLabel, viewAccount); - if (!viewAccount.vchPubKey.IsValid()) { - std::string viewAccountAddress = GetHDAccountAddress(viewAccountLabel, 0).ToString(); - } - - CAccount spendAccount; - walletdb.ReadAccount(spendAccountLabel, spendAccount); - if (!spendAccount.vchPubKey.IsValid()) { - std::string spendAccountAddress = GetHDAccountAddress(spendAccountLabel, 1).ToString(); - } - if (viewAccount.vchPubKey.GetHex() == "" || spendAccount.vchPubKey.GetHex() == "") { - i++; - continue; - } - std::string stealthAddr; - if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); - } - break; - } - return ret; + std::string address; + pwalletMain->ComputeStealthPublicAddress("masteraccount", address); + return address; } UniValue generateintegratedaddress(const UniValue& params, bool fHelp) From c68d3d8dc0615f1a51af8750ce9d8d050b84b86e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 17:48:24 -0400 Subject: [PATCH 0454/1888] Update dapscoin-qt.pro with missing files --- contrib/dapscoin-qt.pro | 43 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index d3a9978ee8..1dabddfd33 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -27,12 +27,15 @@ DEPENDPATH += . \ src/qt/test \ src/secp256k1/include \ src/secp256k1/src \ + src/secp256k1-mw/include \ + src/secp256k1-mw/src \ src/test/data \ src/leveldb/doc/bench \ src/leveldb/helpers/memenv \ src/leveldb/include/leveldb \ src/leveldb/port/win \ - src/secp256k1/src/java + src/secp256k1/src/java \ + src/secp256k1-mw/src/java INCLUDEPATH += . \ src \ src/config \ @@ -47,12 +50,15 @@ INCLUDEPATH += . \ src/qt/forms \ src/compat \ src/secp256k1/include \ + src/secp256k1-mw/include \ src/leveldb/helpers/memenv \ src/test/data \ src/test \ src/qt/test \ src/secp256k1/src \ - src/secp256k1/src/java + src/secp256k1/src/java \ + src/secp256k1-mw/src \ + src/secp256k1-mw/src/java # Input HEADERS += src/activemasternode.h \ @@ -359,24 +365,37 @@ HEADERS += src/activemasternode.h \ src/secp256k1/src/secp256k1.c FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/askpassphrasedialog.ui \ + src/qt/forms/2faconfirmdialog.ui \ + src/qt/forms/2fadialog.ui \ + src/qt/forms/2faqrdialog.ui \ + src/qt/forms/addressbookpage.ui \ + src/qt/forms/askpassphrasedialog.ui \ + src/qt/forms/bip38tooldialog.ui \ + src/qt/forms/blockexplorer.ui \ src/qt/forms/coincontroldialog.ui \ src/qt/forms/editaddressdialog.ui \ + src/qt/forms/encryptdialog.ui \ + src/qt/forms/entermnemonics.ui \ src/qt/forms/helpmessagedialog.ui \ src/qt/forms/historypage.ui \ + src/qt/forms/importorcreate.ui \ src/qt/forms/intro.ui \ + src/qt/forms/masternodelist.ui \ + src/qt/forms/multisenddialog.ui \ src/qt/forms/openuridialog.ui \ src/qt/forms/optionsdialog.ui \ src/qt/forms/optionspage.ui \ src/qt/forms/overviewpage.ui \ src/qt/forms/receivecoinsdialog.ui \ src/qt/forms/receiverequestdialog.ui \ + src/qt/forms/revealtxdialog.ui \ src/qt/forms/rpcconsole.ui \ src/qt/forms/sendcoinsdialog.ui \ src/qt/forms/sendcoinsentry.ui \ src/qt/forms/signverifymessagedialog.ui \ src/qt/forms/togglebutton.ui \ - src/qt/forms/txentry.ui \ src/qt/forms/transactiondescdialog.ui \ + src/qt/forms/txentry.ui \ SOURCES += src/activemasternode.cpp \ src/addrman.cpp \ src/allocators.cpp \ @@ -693,18 +712,34 @@ SOURCES += src/activemasternode.cpp \ RESOURCES += src/qt/dapscoin.qrc src/qt/dapscoin_locale.qrc TRANSLATIONS += src/qt/locale/dapscoin_bg.ts \ + src/qt/locale/dapscoin_ca.ts \ + src/qt/locale/dapscoin_cs.ts \ + src/qt/locale/dapscoin_da.ts \ src/qt/locale/dapscoin_de.ts \ src/qt/locale/dapscoin_en.ts \ + src/qt/locale/dapscoin_en_US.ts \ + src/qt/locale/dapscoin_eo.ts \ src/qt/locale/dapscoin_es.ts \ + src/qt/locale/dapscoin_es_ES.ts \ src/qt/locale/dapscoin_fi.ts \ - src/qt/locale/dapscoin_fr.ts \ + src/qt/locale/dapscoin_fr_FR.ts \ + src/qt/locale/dapscoin_hi_IN.ts \ + src/qt/locale/dapscoin_hr.ts \ + src/qt/locale/dapscoin_hr_HR.ts \ src/qt/locale/dapscoin_it.ts \ src/qt/locale/dapscoin_ja.ts \ + src/qt/locale/dapscoin_ko_KR.ts \ + src/qt/locale/dapscoin_lt_LT.ts \ + src/qt/locale/dapscoin_nl.ts \ src/qt/locale/dapscoin_pl.ts \ src/qt/locale/dapscoin_pt.ts \ + src/qt/locale/dapscoin_pt_BR.ts \ + src/qt/locale/dapscoin_ro_RO.ts \ src/qt/locale/dapscoin_ru.ts \ src/qt/locale/dapscoin_sk.ts \ src/qt/locale/dapscoin_sv.ts \ + src/qt/locale/dapscoin_tr.ts \ + src/qt/locale/dapscoin_uk.ts \ src/qt/locale/dapscoin_vi.ts \ src/qt/locale/dapscoin_zh_CN.ts \ src/qt/locale/dapscoin_zh_TW.ts From ae4b774cdda2895d980fcc77831d7ad6a658a8a6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 18:03:16 -0400 Subject: [PATCH 0455/1888] Update bootstrap link --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index f5f9fe582f..586a2be264 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -902,7 +902,7 @@ void BitcoinGUI::openBlockExplorerAPIClicked() void BitcoinGUI::openBootStrapClicked() { - QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/BootStrap/releases/tag/latest")); + QDesktopServices::openUrl(QUrl("https://bootstrap.dapscoin.com")); } void BitcoinGUI::openTGTechSupportClicked() From 6fbca9fb633bbccfaca09798476ce8b0df3eae7c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 18:03:41 -0400 Subject: [PATCH 0456/1888] Add GitHub Wiki link --- src/qt/bitcoingui.cpp | 9 +++++++++ src/qt/bitcoingui.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 586a2be264..d2d47a60b4 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -463,6 +463,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) // Help Links openFAQAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Frequently Asked Questions"), this); openFAQAction->setStatusTip(tr("Frequently Asked Questions")); + openGitWikiAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&GitHub Wiki"), this); + openGitWikiAction->setStatusTip(tr("GitHub Wiki")); openBlockExplorerAPIAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Blockhain Explorer API"), this); openBlockExplorerAPIAction->setStatusTip(tr("Blockhain Explorer API")); openBootStrapAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&BootStrap"), this); @@ -483,6 +485,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); connect(openFAQAction, SIGNAL(triggered()), this, SLOT(openFAQClicked())); + connect(openGitWikiAction, SIGNAL(triggered()), this, SLOT(openGitWikiClicked())); connect(openBlockExplorerAPIAction, SIGNAL(triggered()), this, SLOT(openBlockExplorerAPIClicked())); connect(openBootStrapAction, SIGNAL(triggered()), this, SLOT(openBootStrapClicked())); connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); @@ -580,6 +583,7 @@ void BitcoinGUI::createMenuBar() help->addAction(showHelpMessageAction); help->addSeparator(); help->addAction(openFAQAction); + help->addAction(openGitWikiAction); help->addSeparator(); help->addAction(openBlockExplorerAPIAction); help->addAction(openBootStrapAction); @@ -895,6 +899,11 @@ void BitcoinGUI::openFAQClicked() QDesktopServices::openUrl(QUrl("https://officialdapscoin.com/faq")); } +void BitcoinGUI::openGitWikiClicked() +{ + QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/DAPSCoin/wiki")); +} + void BitcoinGUI::openBlockExplorerAPIClicked() { QDesktopServices::openUrl(QUrl("https://explorer.dapscoin.com/api/getblockcount")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 1200181511..856845ca01 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -262,6 +262,7 @@ private Q_SLOTS: /** Show help message dialog */ void showHelpMessageClicked(); void openFAQClicked(); + void openGitWikiClicked(); void openBlockExplorerAPIClicked(); void openBootStrapClicked(); void openTGTechSupportClicked(); From 6827c08cacf5bbe154fa23cecf5bd9db6efaf963 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 18:35:53 -0400 Subject: [PATCH 0457/1888] Add dapscoin-qt.desktop for AppImage --- contrib/dapscoin-qt.desktop | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 contrib/dapscoin-qt.desktop diff --git a/contrib/dapscoin-qt.desktop b/contrib/dapscoin-qt.desktop new file mode 100644 index 0000000000..d2b50d0df8 --- /dev/null +++ b/contrib/dapscoin-qt.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=DAPScoin-qt +Comment=DAPScoin QT Wallet +Exec=dapscoin-qt +Icon=dapscoin +Categories=Utility; From bc7f81576792738a7d46ddbe1167849ade3801be Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 12 Oct 2020 19:23:27 -0400 Subject: [PATCH 0458/1888] Fix compile error --- src/qt/bitcoingui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 856845ca01..9d65361dab 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -132,6 +132,7 @@ class BitcoinGUI : public QMainWindow QAction* redditAction; QAction* showHelpMessageAction; QAction* openFAQAction; + QAction* openGitWikiAction; QAction* openBlockExplorerAPIAction; QAction* openBootStrapAction; QAction* openTGTechSupportAction; From ff1166806ac0ac67f6f272d22112ec0f5e540ef4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 23 Oct 2020 12:02:15 -0400 Subject: [PATCH 0459/1888] Remove now unused image files from https://github.com/PIVX-Project/PIVX/pull/863/commits/38e92f3a2678571cae2908d2140bb2f41e339143 We already do not use the walletFrame images anywhere, may as well remove --- src/Makefile.qt.include | 5 +---- src/qt/dapscoin.qrc | 2 -- src/qt/res/images/walletFrame.png | Bin 3038 -> 0 bytes src/qt/res/images/walletFrame_bg.png | Bin 997 -> 0 bytes 4 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 src/qt/res/images/walletFrame.png delete mode 100644 src/qt/res/images/walletFrame_bg.png diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index f8b873d2aa..2072e83030 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -377,10 +377,7 @@ RES_IMAGES = \ qt/res/images/rightArrow_small.png \ qt/res/images/qtreeview_selected.png \ qt/res/images/syncb.png \ - qt/res/images/syncp.png \ - qt/res/images/walletFrame.png \ - qt/res/images/walletFrame_bg.png \ - qt/res/images/walletFrame_bg.png + qt/res/images/syncp.png RES_CSS = \ qt/res/css/Dark.css diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 51438f74bc..2cc6f58b0f 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -92,8 +92,6 @@ res/images/qtreeview_selected.png res/images/syncb.png res/images/syncp.png - res/images/walletFrame_bg.png - res/images/walletFrame.png res/images/splash.png res/images/splash_testnet.png res/images/lock.png diff --git a/src/qt/res/images/walletFrame.png b/src/qt/res/images/walletFrame.png deleted file mode 100644 index efa4b9755e26ba96dd5ff874d7af447ac21736d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3038 zcmeAS@N?(olHy`uVBq!ia0y~y;9ShWz*@-&6krHBzSj*%v7|ftIx;Y9?C1WI$O_~$ zC3(BMFfiWj5?%u2v6p!Iy0Sm!l;LN$-gmZ;g@J)v$kW9!q~g}w3y!=D3IYcV{;al9 zU(i^~;ki2D=B=37Uw1ulUne>WM?+vV1V%$(Gz3ONU^E0qLtr!nMnhn@hCngHnRu
      RdP`(kYX@0FtpS)u+%lO2r)FZGBCF?1#(TS3=F&v{@jhC cAvZrIGp!Q02CF%a>_80+p00i_>zopr0K2Jevj6}9 diff --git a/src/qt/res/images/walletFrame_bg.png b/src/qt/res/images/walletFrame_bg.png deleted file mode 100644 index 5fdff44b9158ff8b17a17d3348588e61f87cd9f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 997 zcmeAS@N?(olHy`uVBq!ia0y~yV13EJz`TPID8P`X=x`WFv7|ftIx;Y9?C1WI$O_~$ zC3(BMFfiWj5?%u2v6p!Iy0Sm!l;LN$-gmZ;1*lun)5S5Q;?~=9j=T&CJPaE>k6V5| z&>nM1>&2Z-#{1cSMgIEr%X1WuhQY{61MmN`*73-BAKd1~3(PmFC9V-ADTyViR>?)F zK#IZ0z|d0Hz*5)9BE- Date: Sat, 24 Oct 2020 12:26:48 -0400 Subject: [PATCH 0460/1888] Always require OS randomness when generating secret keys --- src/init.cpp | 4 ---- src/key.cpp | 3 +-- src/main.cpp | 1 - src/random.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++- src/random.h | 11 ++++++---- src/wallet/wallet.cpp | 6 ++---- 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2cd06a68cc..e85f4131fb 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1616,8 +1616,6 @@ bool AppInit2(bool isDaemon) if (fFirstRun) { // Create new keyUser and set as default key - RandAddSeedPerfmon(); - if (!pwalletMain->IsHDEnabled()) { if (!isDaemon) { uiInterface.ShowRecoveryDialog(); @@ -1897,8 +1895,6 @@ bool AppInit2(bool isDaemon) if (!strErrors.str().empty()) return InitError(strErrors.str()); - RandAddSeedPerfmon(); - //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("chainActive.Height() = %d\n", chainActive.Height()); diff --git a/src/key.cpp b/src/key.cpp index 8adb383725..dc90f8f186 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -39,9 +39,8 @@ bool CKey::Check(const unsigned char* vch) void CKey::MakeNewKey(bool fCompressedIn) { - RandAddSeedPerfmon(); do { - GetRandBytes(vch, sizeof(vch)); + GetStrongRandBytes(vch, sizeof(vch)); } while (!Check(vch)); fValid = true; fCompressed = fCompressedIn; diff --git a/src/main.cpp b/src/main.cpp index 1a101d91a2..718334afc6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5729,7 +5729,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CNodeState* state = State(pfrom->GetId()); if (state == NULL) return false; - RandAddSeedPerfmon(); if (fDebug) LogPrintf("received: %s (%u bytes) peer=%d, chainheight=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id, chainActive.Height()); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { diff --git a/src/random.cpp b/src/random.cpp index a95c9b7def..09e31e7071 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -5,8 +5,10 @@ #include "random.h" +#include "crypto/sha512.h" #ifdef WIN32 #include "compat.h" // for Windows API +#include #endif #include "serialize.h" // for begin_ptr(vec) #include "util.h" // for LogPrint() @@ -43,7 +45,7 @@ void RandAddSeed() OPENSSL_cleanse((void*)&nCounter, sizeof(nCounter)); } -void RandAddSeedPerfmon() +static void RandAddSeedPerfmon() { RandAddSeed(); @@ -83,6 +85,29 @@ void RandAddSeedPerfmon() #endif } +/** Get 32 bytes of system entropy. */ +static void GetOSRand(unsigned char *ent32) +{ +#ifdef WIN32 + HCRYPTPROV hProvider; + int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + assert(ret); + ret = CryptGenRandom(hProvider, 32, ent32); + assert(ret); + CryptReleaseContext(hProvider, 0); +#else + int f = open("/dev/urandom", O_RDONLY); + assert(f != -1); + int have = 0; + do { + ssize_t n = read(f, ent32 + have, 32 - have); + assert(n > 0 && n <= 32 - have); + have += n; + } while (have < 32); + close(f); +#endif +} + void GetRandBytes(unsigned char* buf, int num) { if (RAND_bytes(buf, num) != 1) { @@ -91,6 +116,27 @@ void GetRandBytes(unsigned char* buf, int num) } } +void GetStrongRandBytes(unsigned char* out, int num) +{ + assert(num <= 32); + CSHA512 hasher; + unsigned char buf[64]; + + // First source: OpenSSL's RNG + RandAddSeedPerfmon(); + GetRandBytes(buf, 32); + hasher.Write(buf, 32); + + // Second source: OS RNG + GetOSRand(buf); + hasher.Write(buf, 32); + + // Produce output + hasher.Finalize(buf); + memcpy(out, buf, num); + OPENSSL_cleanse(buf, 64); +} + uint64_t GetRand(uint64_t nMax) { if (nMax == 0) diff --git a/src/random.h b/src/random.h index aa55ca2b6f..fdddce2fdd 100644 --- a/src/random.h +++ b/src/random.h @@ -10,11 +10,8 @@ #include -/** - * Seed OpenSSL PRNG with additional entropy data - */ +/* Seed OpenSSL PRNG with additional entropy data */ void RandAddSeed(); -void RandAddSeedPerfmon(); /** * Functions to gather random data via the OpenSSL PRNG @@ -24,6 +21,12 @@ uint64_t GetRand(uint64_t nMax); int GetRandInt(int nMax); uint256 GetRandHash(); +/** + * Function to gather random data from multiple sources, failing whenever any + * of those source fail to provide a result. + */ +void GetStrongRandBytes(unsigned char* buf, int num); + /** * Seed insecure_rand using the random pool. * @param Deterministic Use a deterministic seed diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index af72849284..a603a4617b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -878,16 +878,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return false; CKeyingMaterial vMasterKey; - RandAddSeedPerfmon(); vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); - GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); + GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); CMasterKey kMasterKey; - RandAddSeedPerfmon(); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); - GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); + GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); CCrypter crypter; int64_t nStartTime = GetTimeMillis(); From d114fd7da9ab5f9c8d9351b6fedd52d58d1af71c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 12:28:39 -0400 Subject: [PATCH 0461/1888] Don't use assert for catching randomness failures --- src/random.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 09e31e7071..86d833f97b 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -14,6 +14,7 @@ #include "util.h" // for LogPrint() #include "utilstrencodings.h" // for GetTime() +#include #include #ifndef WIN32 @@ -24,6 +25,12 @@ #include #include +static void RandFailure() +{ + LogPrintf("Failed to read randomness, aborting\n"); + abort(); +} + static inline int64_t GetPerformanceCounter() { int64_t nCounter = 0; @@ -91,17 +98,25 @@ static void GetOSRand(unsigned char *ent32) #ifdef WIN32 HCRYPTPROV hProvider; int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - assert(ret); + if (!ret) { + RandFailure(); + } ret = CryptGenRandom(hProvider, 32, ent32); - assert(ret); + if (!ret) { + RandFailure(); + } CryptReleaseContext(hProvider, 0); #else int f = open("/dev/urandom", O_RDONLY); - assert(f != -1); + if (f == -1) { + RandFailure(); + } int have = 0; do { ssize_t n = read(f, ent32 + have, 32 - have); - assert(n > 0 && n <= 32 - have); + if (n <= 0 || n + have > 32) { + RandFailure(); + } have += n; } while (have < 32); close(f); @@ -111,8 +126,7 @@ static void GetOSRand(unsigned char *ent32) void GetRandBytes(unsigned char* buf, int num) { if (RAND_bytes(buf, num) != 1) { - LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL)); - assert(false); + RandFailure(); } } From 901247f66ea31295fef160ed52ebbd51535f3b45 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 12:53:45 -0400 Subject: [PATCH 0462/1888] util: Specific GetOSRandom for Linux/FreeBSD/OpenBSD These are available in sandboxes without access to files or devices. Also [they are safer and more straightforward](https://en.wikipedia.org/wiki/Entropy-supplying_system_calls) to use than `/dev/urandom` as reading from a file has quite a few edge cases: - Linux: `getrandom(buf, buflen, 0)`. [getrandom(2)](http://man7.org/linux/man-pages/man2/getrandom.2.html) was introduced in version 3.17 of the Linux kernel. - OpenBSD: `getentropy(buf, buflen)`. The [getentropy(2)](http://man.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2) function appeared in OpenBSD 5.6. - FreeBSD and NetBSD: `sysctl(KERN_ARND)`. Not sure when this was added but it has existed for quite a while. Alternatives: - Linux has sysctl `CTL_KERN` / `KERN_RANDOM` / `RANDOM_UUID` which gives 16 bytes of randomness. This may be available on older kernels, however [sysctl is deprecated on Linux](https://lwn.net/Articles/605392/) and even removed in some distros so we shouldn't use it. Add tests for `GetOSRand()`: - Test that no error happens (otherwise `RandFailure()` which aborts) - Test that all 32 bytes are overwritten (initialize with zeros, try multiple times) Discussion: - When to use these? Currently they are always used when available. Another option would be to use them only when `/dev/urandom` is not available. But this would mean these code paths receive less testing, and I'm not sure there is any reason to prefer `/dev/urandom`. Closes: bitcoin#9676 --- configure.ac | 26 ++++++++++++++++++ src/random.cpp | 57 ++++++++++++++++++++++++++++++++++----- src/random.h | 12 +++++++++ src/test/random_tests.cpp | 46 +++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 7 deletions(-) create mode 100644 src/test/random_tests.cpp diff --git a/configure.ac b/configure.ac index 6ca00baf3e..27a226bacf 100644 --- a/configure.ac +++ b/configure.ac @@ -535,6 +535,32 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ ] ) +# Check for different ways of gathering OS randomness +AC_MSG_CHECKING(for Linux getrandom syscall) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include + #include ]], + [[ syscall(SYS_getrandom, nullptr, 32, 0); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYS_GETRANDOM, 1,[Define this symbol if the Linux getrandom system call is available]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING(for getentropy) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ getentropy(nullptr, 32) ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY, 1,[Define this symbol if the BSD getentropy system call is available]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING(for sysctl KERN_ARND) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[ static const int name[2] = {CTL_KERN, KERN_ARND}; + sysctl(name, 2, nullptr, nullptr, nullptr, 0); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL_ARND, 1,[Define this symbol if the BSD sysctl(KERN_ARND) is available]) ], + [ AC_MSG_RESULT(no)] +) + if test x$use_reduce_exports != xno; then AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], [ diff --git a/src/random.cpp b/src/random.cpp index 86d833f97b..eda7e9fa98 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -21,7 +21,17 @@ #include #endif -#include +#ifdef HAVE_SYS_GETRANDOM +#include +#include +#endif +#ifdef HAVE_GETENTROPY +#include +#endif +#ifdef HAVE_SYSCTL_ARND +#include +#endif + #include #include @@ -93,32 +103,65 @@ static void RandAddSeedPerfmon() } /** Get 32 bytes of system entropy. */ -static void GetOSRand(unsigned char *ent32) +void GetOSRand(unsigned char *ent32) { -#ifdef WIN32 +#if defined(WIN32) HCRYPTPROV hProvider; int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); if (!ret) { RandFailure(); } - ret = CryptGenRandom(hProvider, 32, ent32); + ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32); if (!ret) { RandFailure(); } CryptReleaseContext(hProvider, 0); +#elif defined(HAVE_SYS_GETRANDOM) + /* Linux. From the getrandom(2) man page: + * "If the urandom source has been initialized, reads of up to 256 bytes + * will always return as many bytes as requested and will not be + * interrupted by signals." + */ + if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) { + RandFailure(); + } +#elif defined(HAVE_GETENTROPY) + /* On OpenBSD this can return up to 256 bytes of entropy, will return an + * error if more are requested. + * The call cannot return less than the requested number of bytes. + */ + if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { + RandFailure(); + } +#elif defined(HAVE_SYSCTL_ARND) + /* FreeBSD and similar. It is possible for the call to return less + * bytes than requested, so need to read in a loop. + */ + static const int name[2] = {CTL_KERN, KERN_ARND}; + int have = 0; + do { + size_t len = NUM_OS_RANDOM_BYTES - have; + if (sysctl(name, ARRAYLEN(name), ent32 + have, &len, NULL, 0) != 0) { + RandFailure(); + } + have += len; + } while (have < NUM_OS_RANDOM_BYTES); #else + /* Fall back to /dev/urandom if there is no specific method implemented to + * get system entropy for this OS. + */ int f = open("/dev/urandom", O_RDONLY); if (f == -1) { RandFailure(); } int have = 0; do { - ssize_t n = read(f, ent32 + have, 32 - have); - if (n <= 0 || n + have > 32) { + ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); + if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { RandFailure(); } have += n; - } while (have < 32); + } while (have < NUM_OS_RANDOM_BYTES); close(f); #endif } diff --git a/src/random.h b/src/random.h index fdddce2fdd..70cebdfcd9 100644 --- a/src/random.h +++ b/src/random.h @@ -49,4 +49,16 @@ static inline uint32_t insecure_rand(void) return (insecure_rand_Rw << 16) + insecure_rand_Rz; } +/* Number of random bytes returned by GetOSRand. + * When changing this constant make sure to change all call sites, and make + * sure that the underlying OS APIs for all platforms support the number. + * (many cap out at 256 bytes). + */ +static const ssize_t NUM_OS_RANDOM_BYTES = 32; + +/** Get 32 bytes of system entropy. Do not use this in application code: use + * GetStrongRandBytes instead. + */ +void GetOSRand(unsigned char *ent32); + #endif // BITCOIN_RANDOM_H diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp new file mode 100644 index 0000000000..4f67415c7c --- /dev/null +++ b/src/test/random_tests.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "random.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup) + +static const ssize_t MAX_TRIES = 1024; + +BOOST_AUTO_TEST_CASE(osrandom_tests) +{ + /* This does not measure the quality of randomness, but it does test that + * OSRandom() overwrites all 32 bytes of the output given a maximum + * number of tries. + */ + uint8_t data[NUM_OS_RANDOM_BYTES]; + bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */ + int num_overwritten; + int tries = 0; + /* Loop until all bytes have been overwritten at least once */ + do { + memset(data, 0, NUM_OS_RANDOM_BYTES); + GetOSRand(data); + for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { + overwritten[x] |= (data[x] != 0); + } + + num_overwritten = 0; + for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { + if (overwritten[x]) { + num_overwritten += 1; + } + } + + tries += 1; + } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); + BOOST_CHECK(num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ +} + +BOOST_AUTO_TEST_SUITE_END() + From 9cf35bd257d0386d0806de978a3664467e756e6b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 12:55:56 -0400 Subject: [PATCH 0463/1888] sanity: Move OS random to sanity check function Move the OS random test to a sanity check function that is called every time bitcoind is initialized. Keep `src/test/random_tests.cpp` for the case that later random tests are added, and keep a rudimentary test that just calls the sanity check. --- src/init.cpp | 6 ++++++ src/random.cpp | 31 +++++++++++++++++++++++++++++++ src/random.h | 5 +++++ src/test/random_tests.cpp | 29 +---------------------------- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index e85f4131fb..c4ca74ceb7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -719,9 +719,15 @@ bool InitSanityCheck(void) "information, visit https://en.bitcoin.it/wiki/OpenSSL_and_EC_Libraries"); return false; } + if (!glibc_sanity_test() || !glibcxx_sanity_test()) return false; + if (!Random_SanityCheck()) { + InitError("OS cryptographic RNG sanity check failure. Aborting."); + return false; + } + return true; } diff --git a/src/random.cpp b/src/random.cpp index eda7e9fa98..633498a5c3 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -240,3 +240,34 @@ void seed_insecure_rand(bool fDeterministic) insecure_rand_Rw = tmp; } } + +bool Random_SanityCheck() +{ + /* This does not measure the quality of randomness, but it does test that + * OSRandom() overwrites all 32 bytes of the output given a maximum + * number of tries. + */ + static const ssize_t MAX_TRIES = 1024; + uint8_t data[NUM_OS_RANDOM_BYTES]; + bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */ + int num_overwritten; + int tries = 0; + /* Loop until all bytes have been overwritten at least once, or max number tries reached */ + do { + memset(data, 0, NUM_OS_RANDOM_BYTES); + GetOSRand(data); + for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { + overwritten[x] |= (data[x] != 0); + } + + num_overwritten = 0; + for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { + if (overwritten[x]) { + num_overwritten += 1; + } + } + + tries += 1; + } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); + return (num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ +} diff --git a/src/random.h b/src/random.h index 70cebdfcd9..0586efd112 100644 --- a/src/random.h +++ b/src/random.h @@ -61,4 +61,9 @@ static const ssize_t NUM_OS_RANDOM_BYTES = 32; */ void GetOSRand(unsigned char *ent32); +/** Check that OS randomness is available and returning the requested number + * of bytes. + */ +bool Random_SanityCheck(); + #endif // BITCOIN_RANDOM_H diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 4f67415c7c..d2c46c0daa 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -10,36 +10,9 @@ BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup) -static const ssize_t MAX_TRIES = 1024; - BOOST_AUTO_TEST_CASE(osrandom_tests) { - /* This does not measure the quality of randomness, but it does test that - * OSRandom() overwrites all 32 bytes of the output given a maximum - * number of tries. - */ - uint8_t data[NUM_OS_RANDOM_BYTES]; - bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */ - int num_overwritten; - int tries = 0; - /* Loop until all bytes have been overwritten at least once */ - do { - memset(data, 0, NUM_OS_RANDOM_BYTES); - GetOSRand(data); - for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { - overwritten[x] |= (data[x] != 0); - } - - num_overwritten = 0; - for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) { - if (overwritten[x]) { - num_overwritten += 1; - } - } - - tries += 1; - } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); - BOOST_CHECK(num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ + BOOST_CHECK(Random_SanityCheck()); } BOOST_AUTO_TEST_SUITE_END() From 7b09ab58ff61ef5e464ef97bfdbe743ae5055d8c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 12:58:15 -0400 Subject: [PATCH 0464/1888] random: Add fallback if getrandom syscall not available If the code was compiled with newer (>=3.17) kernel headers but executed on a system without the system call, every use of random would crash the program. Add a fallback for that case. --- src/random.cpp | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 633498a5c3..c8478a0c44 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -102,6 +102,28 @@ static void RandAddSeedPerfmon() #endif } +#ifndef WIN32 +/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most + * compatible way to get cryptographic randomness on UNIX-ish platforms. + */ +void GetDevURandom(unsigned char *ent32) +{ + int f = open("/dev/urandom", O_RDONLY); + if (f == -1) { + RandFailure(); + } + int have = 0; + do { + ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); + if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { + RandFailure(); + } + have += n; + } while (have < NUM_OS_RANDOM_BYTES); + close(f); +} +#endif + /** Get 32 bytes of system entropy. */ void GetOSRand(unsigned char *ent32) { @@ -122,8 +144,17 @@ void GetOSRand(unsigned char *ent32) * will always return as many bytes as requested and will not be * interrupted by signals." */ - if (syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) { - RandFailure(); + int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0); + if (rv != NUM_OS_RANDOM_BYTES) { + if (rv < 0 && errno == ENOSYS) { + /* Fallback for kernel <3.17: the return value will be -1 and errno + * ENOSYS if the syscall is not available, in that case fall back + * to /dev/urandom. + */ + GetDevURandom(ent32); + } else { + RandFailure(); + } } #elif defined(HAVE_GETENTROPY) /* On OpenBSD this can return up to 256 bytes of entropy, will return an @@ -150,19 +181,7 @@ void GetOSRand(unsigned char *ent32) /* Fall back to /dev/urandom if there is no specific method implemented to * get system entropy for this OS. */ - int f = open("/dev/urandom", O_RDONLY); - if (f == -1) { - RandFailure(); - } - int have = 0; - do { - ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); - if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { - RandFailure(); - } - have += n; - } while (have < NUM_OS_RANDOM_BYTES); - close(f); + GetDevURandom(ent32); #endif } From fcef2deeb891dc93eef2543e63208337b773b9e2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 13:03:14 -0400 Subject: [PATCH 0465/1888] Maintain state across GetStrongRandBytes calls --- src/random.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/random.cpp b/src/random.cpp index c8478a0c44..6bc2d7d29d 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -32,6 +32,8 @@ #include #endif +#include + #include #include @@ -192,6 +194,10 @@ void GetRandBytes(unsigned char* buf, int num) } } +static std::mutex cs_rng_state; +static unsigned char rng_state[32] = {0}; +static uint64_t rng_counter = 0; + void GetStrongRandBytes(unsigned char* out, int num) { assert(num <= 32); @@ -207,8 +213,17 @@ void GetStrongRandBytes(unsigned char* out, int num) GetOSRand(buf); hasher.Write(buf, 32); + // Combine with and update state + { + std::unique_lock lock(cs_rng_state); + hasher.Write(rng_state, sizeof(rng_state)); + hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); + ++rng_counter; + hasher.Finalize(buf); + memcpy(rng_state, buf + 32, 32); + } + // Produce output - hasher.Finalize(buf); memcpy(out, buf, num); OPENSSL_cleanse(buf, 64); } From 6615f1b585ed26e23605e8cfa4ed907f2deb3c03 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 13:50:55 -0400 Subject: [PATCH 0466/1888] Kill insecure_random and associated global state There are only a few uses of `insecure_random` outside the tests. This PR replaces uses of insecure_random (and its accompanying global state) in the core code with an FastRandomContext that is automatically seeded on creation. This is meant to be used for inner loops. The FastRandomContext can be in the outer scope, or the class itself, then rand32() is used inside the loop. Useful e.g. for pushing addresses in CNode or the fee rounding, or randomization for coin selection. As a context is created per purpose, thus it gets rid of cross-thread unprotected shared usage of a single set of globals, this should also get rid of the potential race conditions. - I'd say TxMempool::check is not called enough to warrant using a special fast random context, this is switched to GetRand() (open for discussion...) - The use of `insecure_rand` in ConnectThroughProxy has been replaced by an atomic integer counter. The only goal here is to have a different credentials pair for each connection to go on a different Tor circuit, it does not need to be random nor unpredictable. - To avoid having a FastRandomContext on every CNode, the context is passed into PushAddress as appropriate. There remains an insecure_random for test usage in `test_random.h`. --- src/addrman.cpp | 8 ++++---- src/addrman.h | 3 +++ src/main.cpp | 14 ++++++++------ src/net.cpp | 3 ++- src/net.h | 4 ++-- src/netbase.cpp | 4 ++-- src/random.cpp | 10 ++++------ src/random.h | 33 +++++++++++++++------------------ src/test/coins_tests.cpp | 2 +- src/test/crypto_tests.cpp | 2 +- src/test/pmt_tests.cpp | 1 + src/test/scheduler_tests.cpp | 4 +--- src/test/sighash_tests.cpp | 2 +- src/test/skiplist_tests.cpp | 2 +- src/test/test_dapscoin.cpp | 2 ++ src/test/test_random.h | 23 +++++++++++++++++++++++ src/test/util_tests.cpp | 2 +- src/txmempool.h | 1 + src/wallet/wallet.cpp | 4 ++-- 19 files changed, 75 insertions(+), 49 deletions(-) create mode 100644 src/test/test_random.h diff --git a/src/addrman.cpp b/src/addrman.cpp index 79f8031450..cf6a5f462a 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -349,8 +349,8 @@ CAddrInfo CAddrMan::Select_() int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); while (vvTried[nKBucket][nKBucketPos] == -1) { - nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; - nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + nKBucket = (nKBucket + insecure_rand.rand32()) % ADDRMAN_TRIED_BUCKET_COUNT; + nKBucketPos = (nKBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE; } int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); @@ -366,8 +366,8 @@ CAddrInfo CAddrMan::Select_() int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); while (vvNew[nUBucket][nUBucketPos] == -1) { - nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; - nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; + nUBucket = (nUBucket + insecure_rand.rand32()) % ADDRMAN_NEW_BUCKET_COUNT; + nUBucketPos = (nUBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE; } int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); diff --git a/src/addrman.h b/src/addrman.h index 3769090dc8..5c2778510b 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -200,6 +200,9 @@ class CAddrMan int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; protected: + //! Source of random numbers for randomization in inner loops + FastRandomContext insecure_rand; + //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL); diff --git a/src/main.cpp b/src/main.cpp index 718334afc6..0513e8daae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5495,7 +5495,6 @@ bool static AlreadyHave(const CInv& inv) return true; } - void static ProcessGetData(CNode* pfrom) { AssertLockNotHeld(cs_main); @@ -5803,11 +5802,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Advertise our address if (fListen && !IsInitialBlockDownload()) { CAddress addr = GetLocalAddress(&pfrom->addr); + FastRandomContext insecure_rand; if (addr.IsRoutable()) { - pfrom->PushAddress(addr); + pfrom->PushAddress(addr, insecure_rand); } else if (IsPeerAddrLocalGood(pfrom)) { addr.SetIP(pfrom->addrLocal); - pfrom->PushAddress(addr); + pfrom->PushAddress(addr, insecure_rand); } } @@ -5898,9 +5898,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapMix.insert(make_pair(hashKey, pnode)); } int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) + FastRandomContext insecure_rand; for (multimap::iterator mi = mapMix.begin(); - mi != mapMix.end() && nRelayNodes-- > 0; ++mi) - ((*mi).second)->PushAddress(addr); + mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + ((*mi).second)->PushAddress(addr, insecure_rand); } } // Do not store addresses outside our network @@ -6335,8 +6336,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if ((strCommand == "getaddr") && (pfrom->fInbound)) { pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); + FastRandomContext insecure_rand; for (const CAddress& addr : vAddr) - pfrom->PushAddress(addr); + pfrom->PushAddress(addr, insecure_rand); } else if (strCommand == "mempool") { LOCK2(cs_main, pfrom->cs_filter); diff --git a/src/net.cpp b/src/net.cpp index 14584fef2f..726b127e25 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -233,7 +233,8 @@ void AdvertiseLocal(CNode* pnode) } if (addrLocal.IsRoutable()) { LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); - pnode->PushAddress(addrLocal); + FastRandomContext insecure_rand; + pnode->PushAddress(addrLocal, insecure_rand); } } } diff --git a/src/net.h b/src/net.h index 5427f167fd..dd02dd0171 100644 --- a/src/net.h +++ b/src/net.h @@ -447,14 +447,14 @@ class CNode setAddrKnown.insert(addr); } - void PushAddress(const CAddress& addr) + void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand) { // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. if (addr.IsValid() && !setAddrKnown.count(addr)) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { - vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; + vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr; } else { vAddrToSend.push_back(addr); } diff --git a/src/netbase.cpp b/src/netbase.cpp index cc12e952ff..bac29ace20 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -601,8 +601,8 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string strDes // do socks negotiation if (proxy.randomize_credentials) { ProxyCredentials random_auth; - random_auth.username = strprintf("%i", insecure_rand()); - random_auth.password = strprintf("%i", insecure_rand()); + static std::atomic_int counter; + random_auth.username = random_auth.password = strprintf("%i", counter++); if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) return false; } else { diff --git a/src/random.cpp b/src/random.cpp index 6bc2d7d29d..8d7c688b87 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -255,23 +255,21 @@ uint256 GetRandHash() return hash; } -uint32_t insecure_rand_Rz = 11; -uint32_t insecure_rand_Rw = 11; -void seed_insecure_rand(bool fDeterministic) +FastRandomContext::FastRandomContext(bool fDeterministic) { // The seed values have some unlikely fixed points which we avoid. if (fDeterministic) { - insecure_rand_Rz = insecure_rand_Rw = 11; + Rz = Rw = 11; } else { uint32_t tmp; do { GetRandBytes((unsigned char*)&tmp, 4); } while (tmp == 0 || tmp == 0x9068ffffU); - insecure_rand_Rz = tmp; + Rz = tmp; do { GetRandBytes((unsigned char*)&tmp, 4); } while (tmp == 0 || tmp == 0x464fffffU); - insecure_rand_Rw = tmp; + Rw = tmp; } } diff --git a/src/random.h b/src/random.h index 0586efd112..75417d1d04 100644 --- a/src/random.h +++ b/src/random.h @@ -28,26 +28,23 @@ uint256 GetRandHash(); void GetStrongRandBytes(unsigned char* buf, int num); /** - * Seed insecure_rand using the random pool. - * @param Deterministic Use a deterministic seed + * Fast randomness source. This is seeded once with secure random data, but + * is completely deterministic and insecure after that. + * This class is not thread-safe. */ -void seed_insecure_rand(bool fDeterministic = false); +class FastRandomContext { +public: + explicit FastRandomContext(bool fDeterministic=false); -/** - * MWC RNG of George Marsaglia - * This is intended to be fast. It has a period of 2^59.3, though the - * least significant 16 bits only have a period of about 2^30.1. - * - * @return random value - */ -extern uint32_t insecure_rand_Rz; -extern uint32_t insecure_rand_Rw; -static inline uint32_t insecure_rand(void) -{ - insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16); - insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16); - return (insecure_rand_Rw << 16) + insecure_rand_Rz; -} + uint32_t rand32() { + Rz = 36969 * (Rz & 65535) + (Rz >> 16); + Rw = 18000 * (Rw & 65535) + (Rw >> 16); + return (Rw << 16) + Rz; + } + + uint32_t Rz; + uint32_t Rw; +}; /* Number of random bytes returned by GetOSRand. * When changing this constant make sure to change all call sites, and make diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index a89e1dffa0..9b53438a3c 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "coins.h" -#include "random.h" +#include "test_random.h" #include "uint256.h" #include diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 12f507108a..463af900ed 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -9,7 +9,7 @@ #include "crypto/sha512.h" #include "crypto/hmac_sha256.h" #include "crypto/hmac_sha512.h" -#include "random.h" +#include "test_random.h" #include "utilstrencodings.h" #include diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index ba1f1ab87f..09011d68f9 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -7,6 +7,7 @@ #include "streams.h" #include "uint256.h" #include "version.h" +#include "test_random.h" #include diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 9e1c01b3d5..ca2f232544 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -49,8 +49,6 @@ static void MicroSleep(uint64_t n) { BOOST_AUTO_TEST_CASE(manythreads) { - seed_insecure_rand(false); - // Stress test: hundreds of microsecond-scheduled tasks, // serviced by 10 threads. // @@ -65,7 +63,7 @@ BOOST_AUTO_TEST_CASE(manythreads) boost::mutex counterMutex[10]; int counter[10] = { 0 }; - boost::random::mt19937 rng(insecure_rand()); + boost::random::mt19937 rng(42); boost::random::uniform_int_distribution<> zeroToNine(0, 9); boost::random::uniform_int_distribution<> randomMsec(-11, 1000); boost::random::uniform_int_distribution<> randomDelta(-1000, 1000); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 35122ac31c..0b2f699bac 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -4,7 +4,7 @@ #include "data/sighash.json.h" #include "main.h" -#include "random.h" +#include "test_random.h" #include "serialize.h" #include "script/script.h" #include "script/interpreter.h" diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 14ee3e8f4f..c6dce99dee 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "main.h" -#include "random.h" +#include "test_random.h" #include "util.h" #include diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index 3b37897488..4d16016dbf 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -21,6 +21,8 @@ extern CClientUIInterface uiInterface; extern CWallet* pwalletMain; +FastRandomContext insecure_rand_ctx(true); + extern bool fPrintToConsole; extern void noui_connect(); diff --git a/src/test/test_random.h b/src/test/test_random.h new file mode 100644 index 0000000000..e61b92b7bc --- /dev/null +++ b/src/test/test_random.h @@ -0,0 +1,23 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TEST_RANDOM_H +#define BITCOIN_TEST_RANDOM_H + +#include "random.h" + +extern FastRandomContext insecure_rand_ctx; + +static inline void seed_insecure_rand(bool fDeterministic = false) +{ + insecure_rand_ctx = FastRandomContext(fDeterministic); +} + +static inline uint32_t insecure_rand(void) +{ + return insecure_rand_ctx.rand32(); +} + +#endif diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index cb5861f368..fb45aab0b2 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -6,7 +6,7 @@ #include "clientversion.h" #include "primitives/transaction.h" -#include "random.h" +#include "test_random.h" #include "sync.h" #include "utilstrencodings.h" #include "utilmoneystr.h" diff --git a/src/txmempool.h b/src/txmempool.h index c71fe193b6..56be34e7cf 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -14,6 +14,7 @@ #include "coins.h" #include "primitives/transaction.h" #include "sync.h" +#include "random.h" class CAutoFile; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a603a4617b..e05822b31d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2035,7 +2035,7 @@ static CAmount ApproximateBestSubset(int numOut, int ringSize, vector Date: Sat, 24 Oct 2020 13:52:24 -0400 Subject: [PATCH 0467/1888] Add ChaCha20 --- src/Makefile.am | 2 + src/crypto/chacha20.cpp | 180 ++++++++++++++++++++++++++++++++++++++ src/crypto/chacha20.h | 26 ++++++ src/test/crypto_tests.cpp | 44 ++++++++++ 4 files changed, 252 insertions(+) create mode 100644 src/crypto/chacha20.cpp create mode 100644 src/crypto/chacha20.h diff --git a/src/Makefile.am b/src/Makefile.am index 82f538abf3..2af5deb51b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -292,6 +292,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha1.cpp \ crypto/sha256.cpp \ crypto/sha512.cpp \ + crypto/chacha20.h \ + crypto/chacha20.cpp \ crypto/hmac_sha256.cpp \ crypto/rfc6979_hmac_sha256.cpp \ crypto/hmac_sha512.cpp \ diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp new file mode 100644 index 0000000000..816ae870e1 --- /dev/null +++ b/src/crypto/chacha20.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Based on the public domain implementation 'merged' by D. J. Bernstein +// See https://cr.yp.to/chacha.html. + +#include "crypto/common.h" +#include "crypto/chacha20.h" + +#include + +constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); } + +#define QUARTERROUND(a,b,c,d) \ + a += b; d = rotl32(d ^ a, 16); \ + c += d; b = rotl32(b ^ c, 12); \ + a += b; d = rotl32(d ^ a, 8); \ + c += d; b = rotl32(b ^ c, 7); + +static const unsigned char sigma[] = "expand 32-byte k"; +static const unsigned char tau[] = "expand 16-byte k"; + +void ChaCha20::SetKey(const unsigned char* k, size_t keylen) +{ + const unsigned char *constants; + + input[4] = ReadLE32(k + 0); + input[5] = ReadLE32(k + 4); + input[6] = ReadLE32(k + 8); + input[7] = ReadLE32(k + 12); + if (keylen == 32) { /* recommended */ + k += 16; + constants = sigma; + } else { /* keylen == 16 */ + constants = tau; + } + input[8] = ReadLE32(k + 0); + input[9] = ReadLE32(k + 4); + input[10] = ReadLE32(k + 8); + input[11] = ReadLE32(k + 12); + input[0] = ReadLE32(constants + 0); + input[1] = ReadLE32(constants + 4); + input[2] = ReadLE32(constants + 8); + input[3] = ReadLE32(constants + 12); + input[12] = 0; + input[13] = 0; + input[14] = 0; + input[15] = 0; +} + +ChaCha20::ChaCha20() +{ + memset(input, 0, sizeof(input)); +} + +ChaCha20::ChaCha20(const unsigned char* k, size_t keylen) +{ + SetKey(k, keylen); +} + +void ChaCha20::SetIV(uint64_t iv) +{ + input[14] = iv; + input[15] = iv >> 32; +} + +void ChaCha20::Seek(uint64_t pos) +{ + input[12] = pos; + input[13] = pos >> 32; +} + +void ChaCha20::Output(unsigned char* c, size_t bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + unsigned char *ctarget = NULL; + unsigned char tmp[64]; + unsigned int i; + + if (!bytes) return; + + j0 = input[0]; + j1 = input[1]; + j2 = input[2]; + j3 = input[3]; + j4 = input[4]; + j5 = input[5]; + j6 = input[6]; + j7 = input[7]; + j8 = input[8]; + j9 = input[9]; + j10 = input[10]; + j11 = input[11]; + j12 = input[12]; + j13 = input[13]; + j14 = input[14]; + j15 = input[15]; + + for (;;) { + if (bytes < 64) { + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + ++j12; + if (!j12) ++j13; + + WriteLE32(c + 0, x0); + WriteLE32(c + 4, x1); + WriteLE32(c + 8, x2); + WriteLE32(c + 12, x3); + WriteLE32(c + 16, x4); + WriteLE32(c + 20, x5); + WriteLE32(c + 24, x6); + WriteLE32(c + 28, x7); + WriteLE32(c + 32, x8); + WriteLE32(c + 36, x9); + WriteLE32(c + 40, x10); + WriteLE32(c + 44, x11); + WriteLE32(c + 48, x12); + WriteLE32(c + 52, x13); + WriteLE32(c + 56, x14); + WriteLE32(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + input[12] = j12; + input[13] = j13; + return; + } + bytes -= 64; + c += 64; + } +} diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h new file mode 100644 index 0000000000..a305977bcd --- /dev/null +++ b/src/crypto/chacha20.h @@ -0,0 +1,26 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_CHACHA20_H +#define BITCOIN_CRYPTO_CHACHA20_H + +#include +#include + +/** A PRNG class for ChaCha20. */ +class ChaCha20 +{ +private: + uint32_t input[16]; + +public: + ChaCha20(); + ChaCha20(const unsigned char* key, size_t keylen); + void SetKey(const unsigned char* key, size_t keylen); + void SetIV(uint64_t iv); + void Seek(uint64_t pos); + void Output(unsigned char* output, size_t bytes); +}; + +#endif // BITCOIN_CRYPTO_CHACHA20_H diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 463af900ed..40696aa2ac 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "crypto/rfc6979_hmac_sha256.h" +#include "crypto/chacha20.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" @@ -64,6 +65,19 @@ void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const s TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout)); } +void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) +{ + std::vector key = ParseHex(hexkey); + ChaCha20 rng(key.data(), key.size()); + rng.SetIV(nonce); + rng.Seek(seek); + std::vector out = ParseHex(hexout); + std::vector outres; + outres.resize(out.size()); + rng.Output(outres.data(), outres.size()); + BOOST_CHECK(out == outres); +} + std::string LongTestString(void) { std::string ret; for (int i=0; i<200000; i++) { @@ -283,5 +297,35 @@ BOOST_AUTO_TEST_CASE(rfc6979_hmac_sha256) ("7597887cbd76321f32e30440679a22cf7f8d9d2eac390e581fea091ce202ba94")); } +BOOST_AUTO_TEST_CASE(chacha20_testvector) +{ + // Test vector from RFC 7539 + TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, + "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb" + "a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a" + "832c89c167eacd901d7e2bf363"); + + // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 + TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0, + "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b" + "8f41518a11cc387b669b2ee6586"); + TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0, + "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79" + "2b1c43fea817e9ad275ae546963"); + TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0, + "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770" + "62eb7a0433e445f41e3"); + TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0, + "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4" + "97a0b466e7d6bbdb0041b2f586b"); + TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0, + "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b" + "e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1" + "18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5" + "a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5" + "360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78" + "fab78c9"); +} + BOOST_AUTO_TEST_SUITE_END() #endif \ No newline at end of file From 97cc4ba8e79da9726ed4e3ff18833d4445264b2c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 13:53:21 -0400 Subject: [PATCH 0468/1888] Introduce FastRandomContext::randbool() --- src/random.h | 4 ++++ src/wallet/wallet.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/random.h b/src/random.h index 75417d1d04..65f079d447 100644 --- a/src/random.h +++ b/src/random.h @@ -42,6 +42,10 @@ class FastRandomContext { return (Rw << 16) + Rz; } + bool randbool() { + return rand32() & 1; + } + uint32_t Rz; uint32_t Rw; }; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e05822b31d..66e63f6b78 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2050,7 +2050,7 @@ static CAmount ApproximateBestSubset(int numOut, int ringSize, vector Date: Sat, 24 Oct 2020 18:15:53 -0400 Subject: [PATCH 0469/1888] Switch FastRandomContext to ChaCha20 --- src/addrman.cpp | 8 ++--- src/addrman.h | 11 +++++-- src/random.cpp | 33 ++++++++++--------- src/random.h | 67 +++++++++++++++++++++++++++++++++----- src/test/random_tests.cpp | 21 +++++++++++- src/test/test_dapscoin.cpp | 3 +- src/test/test_random.h | 8 ++++- 7 files changed, 117 insertions(+), 34 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index cf6a5f462a..d31129187a 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -349,8 +349,8 @@ CAddrInfo CAddrMan::Select_() int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); while (vvTried[nKBucket][nKBucketPos] == -1) { - nKBucket = (nKBucket + insecure_rand.rand32()) % ADDRMAN_TRIED_BUCKET_COUNT; - nKBucketPos = (nKBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE; + nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT; + nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE; } int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); @@ -366,8 +366,8 @@ CAddrInfo CAddrMan::Select_() int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); while (vvNew[nUBucket][nUBucketPos] == -1) { - nUBucket = (nUBucket + insecure_rand.rand32()) % ADDRMAN_NEW_BUCKET_COUNT; - nUBucketPos = (nUBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE; + nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT; + nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE; } int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); diff --git a/src/addrman.h b/src/addrman.h index 5c2778510b..ed76e969fb 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -128,13 +128,13 @@ class CAddrInfo : public CAddress */ //! total number of buckets for tried addresses -#define ADDRMAN_TRIED_BUCKET_COUNT 256 +#define ADDRMAN_TRIED_BUCKET_COUNT_LOG2 8 //! total number of buckets for new addresses -#define ADDRMAN_NEW_BUCKET_COUNT 1024 +#define ADDRMAN_NEW_BUCKET_COUNT_LOG2 10 //! maximum allowed number of entries in buckets for new and tried addresses -#define ADDRMAN_BUCKET_SIZE 64 +#define ADDRMAN_BUCKET_SIZE_LOG2 6 //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8 @@ -163,6 +163,11 @@ class CAddrInfo : public CAddress //! the maximum number of nodes to return in a getaddr call #define ADDRMAN_GETADDR_MAX 2500 +//! Convenience +#define ADDRMAN_TRIED_BUCKET_COUNT (1 << ADDRMAN_TRIED_BUCKET_COUNT_LOG2) +#define ADDRMAN_NEW_BUCKET_COUNT (1 << ADDRMAN_NEW_BUCKET_COUNT_LOG2) +#define ADDRMAN_BUCKET_SIZE (1 << ADDRMAN_BUCKET_SIZE_LOG2) + /** * Stochastical (IP) address manager */ diff --git a/src/random.cpp b/src/random.cpp index 8d7c688b87..fce7dce3c3 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -255,22 +255,16 @@ uint256 GetRandHash() return hash; } -FastRandomContext::FastRandomContext(bool fDeterministic) +void FastRandomContext::RandomSeed() { - // The seed values have some unlikely fixed points which we avoid. - if (fDeterministic) { - Rz = Rw = 11; - } else { - uint32_t tmp; - do { - GetRandBytes((unsigned char*)&tmp, 4); - } while (tmp == 0 || tmp == 0x9068ffffU); - Rz = tmp; - do { - GetRandBytes((unsigned char*)&tmp, 4); - } while (tmp == 0 || tmp == 0x464fffffU); - Rw = tmp; - } + uint256 seed = GetRandHash(); + rng.SetKey(seed.begin(), 32); + requires_seed = false; +} + +FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0) +{ + rng.SetKey(seed.begin(), 32); } bool Random_SanityCheck() @@ -303,3 +297,12 @@ bool Random_SanityCheck() } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); return (num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ } + +FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) +{ + if (!fDeterministic) { + return; + } + uint256 seed; + rng.SetKey(seed.begin(), 32); +} diff --git a/src/random.h b/src/random.h index 65f079d447..a000238bc2 100644 --- a/src/random.h +++ b/src/random.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_RANDOM_H #define BITCOIN_RANDOM_H +#include "crypto/chacha20.h" +#include "crypto/common.h" #include "uint256.h" #include @@ -33,21 +35,68 @@ void GetStrongRandBytes(unsigned char* buf, int num); * This class is not thread-safe. */ class FastRandomContext { +private: + bool requires_seed; + ChaCha20 rng; + + unsigned char bytebuf[64]; + int bytebuf_size; + + uint64_t bitbuf; + int bitbuf_size; + + void RandomSeed(); + + void FillByteBuffer() + { + if (requires_seed) { + RandomSeed(); + } + rng.Output(bytebuf, sizeof(bytebuf)); + bytebuf_size = sizeof(bytebuf); + } + + void FillBitBuffer() + { + bitbuf = rand64(); + bitbuf_size = 64; + } + public: - explicit FastRandomContext(bool fDeterministic=false); + explicit FastRandomContext(bool fDeterministic = false); - uint32_t rand32() { - Rz = 36969 * (Rz & 65535) + (Rz >> 16); - Rw = 18000 * (Rw & 65535) + (Rw >> 16); - return (Rw << 16) + Rz; + /** Initialize with explicit seed (only for testing) */ + explicit FastRandomContext(const uint256& seed); + + /** Generate a random 64-bit integer. */ + uint64_t rand64() + { + if (bytebuf_size < 8) FillByteBuffer(); + uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); + bytebuf_size -= 8; + return ret; } - bool randbool() { - return rand32() & 1; + /** Generate a random (bits)-bit integer. */ + uint64_t randbits(int bits) { + if (bits == 0) { + return 0; + } else if (bits > 32) { + return rand64() >> (64 - bits); + } else { + if (bitbuf_size < bits) FillBitBuffer(); + uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits)); + bitbuf >>= bits; + bitbuf_size -= bits; + return ret; + } } - uint32_t Rz; - uint32_t Rw; + /** Generate a random 32-bit integer. */ + uint32_t rand32() { return randbits(32); } + + /** Generate a random boolean. */ + bool randbool() { return randbits(1); } }; /* Number of random bytes returned by GetOSRand. diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index d2c46c0daa..7ff607b166 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -15,5 +15,24 @@ BOOST_AUTO_TEST_CASE(osrandom_tests) BOOST_CHECK(Random_SanityCheck()); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_CASE(fastrandom_tests) +{ + // Check that deterministic FastRandomContexts are deterministic + FastRandomContext ctx1(true); + FastRandomContext ctx2(true); + + BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); + BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); + BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64()); + BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); + BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7)); + BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); + BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); + + // Check that a nondeterministic ones are not + FastRandomContext ctx3; + FastRandomContext ctx4; + BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal +} +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index 4d16016dbf..6da5a08c44 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -21,7 +21,8 @@ extern CClientUIInterface uiInterface; extern CWallet* pwalletMain; -FastRandomContext insecure_rand_ctx(true); +uint256 insecure_rand_seed = GetRandHash(); +FastRandomContext insecure_rand_ctx(insecure_rand_seed); extern bool fPrintToConsole; extern void noui_connect(); diff --git a/src/test/test_random.h b/src/test/test_random.h index e61b92b7bc..d1fae70458 100644 --- a/src/test/test_random.h +++ b/src/test/test_random.h @@ -8,11 +8,17 @@ #include "random.h" +extern uint256 insecure_rand_seed; extern FastRandomContext insecure_rand_ctx; static inline void seed_insecure_rand(bool fDeterministic = false) { - insecure_rand_ctx = FastRandomContext(fDeterministic); + if (fDeterministic) { + insecure_rand_seed = uint256(); + } else { + insecure_rand_seed = GetRandHash(); + } + insecure_rand_ctx = FastRandomContext(insecure_rand_seed); } static inline uint32_t insecure_rand(void) From 319dea127acc23d85ee96730d3c5963c3bdfc940 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:22:57 -0400 Subject: [PATCH 0470/1888] Add a FastRandomContext::randrange and use it --- configure.ac | 8 ++++++++ src/crypto/common.h | 21 +++++++++++++++++++++ src/net.h | 2 +- src/random.h | 11 +++++++++++ src/test/crypto_tests.cpp | 23 +++++++++++++++++++++++ src/test/random_tests.cpp | 17 ++++++++++++++++- 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 27a226bacf..9bb01830d1 100644 --- a/configure.ac +++ b/configure.ac @@ -514,6 +514,14 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [ AC_MSG_RESULT(no)] ) +dnl Check for MSG_DONTWAIT +AC_MSG_CHECKING(for MSG_DONTWAIT) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ int f = MSG_DONTWAIT; ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ], + [ AC_MSG_RESULT(no)] +) + AC_SEARCH_LIBS([clock_gettime],[rt]) AC_MSG_CHECKING([for visibility attribute]) diff --git a/src/crypto/common.h b/src/crypto/common.h index 8d5452d151..f585f2fea3 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -113,4 +113,25 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x) #endif } +/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */ +uint64_t static inline CountBits(uint64_t x) +{ +#ifdef HAVE_DECL___BUILTIN_CLZL + if (sizeof(unsigned long) >= sizeof(uint64_t)) { + return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0; + } +#endif +#ifdef HAVE_DECL___BUILTIN_CLZLL + if (sizeof(unsigned long long) >= sizeof(uint64_t)) { + return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0; + } +#endif + int ret = 0; + while (x) { + x >>= 1; + ++ret; + } + return ret; +} + #endif // BITCOIN_CRYPTO_COMMON_H diff --git a/src/net.h b/src/net.h index dd02dd0171..2177f5a9cc 100644 --- a/src/net.h +++ b/src/net.h @@ -454,7 +454,7 @@ class CNode // after addresses were pushed. if (addr.IsValid() && !setAddrKnown.count(addr)) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { - vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr; + vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr; } else { vAddrToSend.push_back(addr); } diff --git a/src/random.h b/src/random.h index a000238bc2..46fc76e4a9 100644 --- a/src/random.h +++ b/src/random.h @@ -92,6 +92,17 @@ class FastRandomContext { } } + /** Generate a random integer in the range [0..range). */ + uint64_t randrange(uint64_t range) + { + --range; + int bits = CountBits(range); + while (true) { + uint64_t ret = randbits(bits); + if (ret <= range) return ret; + } + } + /** Generate a random 32-bit integer. */ uint32_t rand32() { return randbits(32); } diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 40696aa2ac..b8d2ae37ae 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -11,6 +11,7 @@ #include "crypto/hmac_sha256.h" #include "crypto/hmac_sha512.h" #include "test_random.h" +#include "random.h" #include "utilstrencodings.h" #include @@ -327,5 +328,27 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector) "fab78c9"); } +BOOST_AUTO_TEST_CASE(countbits_tests) +{ + FastRandomContext ctx; + for (int i = 0; i <= 64; ++i) { + if (i == 0) { + // Check handling of zero. + BOOST_CHECK_EQUAL(CountBits(0), 0); + } else if (i < 10) { + for (uint64_t j = 1 << (i - 1); (j >> i) == 0; ++j) { + // Exhaustively test up to 10 bits + BOOST_CHECK_EQUAL(CountBits(j), i); + } + } else { + for (int k = 0; k < 1000; k++) { + // Randomly test 1000 samples of each length above 10 bits. + uint64_t j = ((uint64_t)1) << (i - 1) | ctx.randbits(i - 1); + BOOST_CHECK_EQUAL(CountBits(j), i); + } + } + } +} + BOOST_AUTO_TEST_SUITE_END() #endif \ No newline at end of file diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 7ff607b166..ee077d3ed3 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -4,7 +4,7 @@ #include "random.h" -#include "test/test_bitcoin.h" +#include "test/test_dapscoin.h" #include @@ -35,4 +35,19 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal } +BOOST_AUTO_TEST_CASE(fastrandom_randbits) +{ + FastRandomContext ctx1; + FastRandomContext ctx2; + for (int bits = 0; bits < 63; ++bits) { + for (int j = 0; j < 1000; ++j) { + uint64_t rangebits = ctx1.randbits(bits); + BOOST_CHECK_EQUAL(rangebits >> bits, 0); + uint64_t range = ((uint64_t)1) << bits | rangebits; + uint64_t rand = ctx2.randrange(range); + BOOST_CHECK(rand < range); + } + } +} + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From f01299e138e14c7d0bd4e1ad3616d2d1e233104f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:23:57 -0400 Subject: [PATCH 0471/1888] random: only use getentropy on openbsd --- src/random.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/random.cpp b/src/random.cpp index fce7dce3c3..7b0b4ff330 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -158,10 +158,12 @@ void GetOSRand(unsigned char *ent32) RandFailure(); } } -#elif defined(HAVE_GETENTROPY) +#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__) /* On OpenBSD this can return up to 256 bytes of entropy, will return an * error if more are requested. * The call cannot return less than the requested number of bytes. + getentropy is explicitly limited to openbsd here, as a similar (but not + the same) function may exist on other platforms via glibc. */ if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { RandFailure(); From 3ca567ed7cd08dd327a428046b6f8ba239fb50ef Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:30:36 -0400 Subject: [PATCH 0472/1888] [Random] Fix compilation --- src/Makefile.test.include | 1 + src/netbase.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8acad71485..4b0189b86f 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -66,6 +66,7 @@ BITCOIN_TESTS =\ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/test_dapscoin.cpp \ + test/test_random.h \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ diff --git a/src/netbase.cpp b/src/netbase.cpp index bac29ace20..a4f46e9336 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -16,6 +16,8 @@ #include "util.h" #include "utilstrencodings.h" +#include + #ifdef HAVE_GETADDRINFO_A #include #endif From 796bb4faff3ac95ea7648c6231514c6829ef57de Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:31:58 -0400 Subject: [PATCH 0473/1888] Use hardware timestamps in RNG seeding --- src/random.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 7b0b4ff330..01e1e6085b 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -16,6 +16,7 @@ #include #include +#include #ifndef WIN32 #include @@ -45,15 +46,22 @@ static void RandFailure() static inline int64_t GetPerformanceCounter() { - int64_t nCounter = 0; -#ifdef WIN32 - QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); + // Read the hardware time stamp counter when available. + // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information. +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + return __rdtsc(); +#elif !defined(_MSC_VER) && defined(__i386__) + uint64_t r = 0; + __asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair. + return r; +#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__)) + uint64_t r1 = 0, r2 = 0; + __asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx. + return (r2 << 32) | r1; #else - timeval t; - gettimeofday(&t, NULL); - nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec); + // Fall back to using C++11 clock (usually microsecond or nanosecond precision) + return std::chrono::high_resolution_clock::now().time_since_epoch().count(); #endif - return nCounter; } void RandAddSeed() From 0f8f5eebbd858ac658704625d2af660af3e84404 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:35:52 -0400 Subject: [PATCH 0474/1888] Test that GetPerformanceCounter() increments --- src/random.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/random.cpp b/src/random.cpp index 01e1e6085b..4d3f7ceecd 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifndef WIN32 #include @@ -279,6 +280,8 @@ FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false) bool Random_SanityCheck() { + uint64_t start = GetPerformanceCounter(); + /* This does not measure the quality of randomness, but it does test that * OSRandom() overwrites all 32 bytes of the output given a maximum * number of tries. @@ -305,7 +308,14 @@ bool Random_SanityCheck() tries += 1; } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); - return (num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ + if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */ + + // Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep. + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + uint64_t stop = GetPerformanceCounter(); + if (stop == start) return false; + + return true; } FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) From 618acfdbd18ede5b0faf8fb120e45dc06c341a64 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:37:54 -0400 Subject: [PATCH 0475/1888] Use sanity check timestamps as entropy --- src/random.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index 4d3f7ceecd..7c2edf544f 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -315,6 +315,10 @@ bool Random_SanityCheck() uint64_t stop = GetPerformanceCounter(); if (stop == start) return false; + // We called GetPerformanceCounter. Use it as entropy. + RAND_add((const unsigned char*)&start, sizeof(start), 1); + RAND_add((const unsigned char*)&stop, sizeof(stop), 1); + return true; } From a270605659c6413f444c3ec3aa38eff07b3c3cab Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 18:51:46 -0400 Subject: [PATCH 0476/1888] Add internal method to add new random data to our internal RNG state --- src/random.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index 7c2edf544f..0b86a1440e 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -209,6 +209,22 @@ static std::mutex cs_rng_state; static unsigned char rng_state[32] = {0}; static uint64_t rng_counter = 0; +static void AddDataToRng(void* data, size_t len) { + CSHA512 hasher; + hasher.Write((const unsigned char*)&len, sizeof(len)); + hasher.Write((const unsigned char*)data, len); + unsigned char buf[64]; + { + std::unique_lock lock(cs_rng_state); + hasher.Write(rng_state, sizeof(rng_state)); + hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter)); + ++rng_counter; + hasher.Finalize(buf); + memcpy(rng_state, buf + 32, 32); + } + OPENSSL_cleanse(buf, 64); +} + void GetStrongRandBytes(unsigned char* out, int num) { assert(num <= 32); From d4327508bfc6e0a76e0af7edfce7361bca346bec Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:00:29 -0400 Subject: [PATCH 0477/1888] Add perf counter data to GetStrongRandBytes state in scheduler --- src/random.cpp | 16 ++++++++++++++++ src/random.h | 7 +++++++ src/scheduler.cpp | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index 0b86a1440e..addc68a5f5 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -205,6 +205,22 @@ void GetRandBytes(unsigned char* buf, int num) } } +static void AddDataToRng(void* data, size_t len); + +void RandAddSeedSleep() +{ + int64_t nPerfCounter1 = GetPerformanceCounter(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + int64_t nPerfCounter2 = GetPerformanceCounter(); + + // Combine with and update state + AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1)); + AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2)); + + OPENSSL_cleanse(&nPerfCounter1, sizeof(nPerfCounter1)); + OPENSSL_cleanse(&nPerfCounter2, sizeof(nPerfCounter2)); +} + static std::mutex cs_rng_state; static unsigned char rng_state[32] = {0}; static uint64_t rng_counter = 0; diff --git a/src/random.h b/src/random.h index 46fc76e4a9..e09e833fda 100644 --- a/src/random.h +++ b/src/random.h @@ -23,6 +23,13 @@ uint64_t GetRand(uint64_t nMax); int GetRandInt(int nMax); uint256 GetRandHash(); +/** + * Add a little bit of randomness to the output of GetStrongRangBytes. + * This sleeps for a millisecond, so should only be called when there is + * no other work to be done. + */ +void RandAddSeedSleep(); + /** * Function to gather random data from multiple sources, failing whenever any * of those source fail to provide a result. diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 5f6ca46579..7d3f8cce7b 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "scheduler.h" +#include "random.h" #include "reverselock.h" #include #include @@ -33,6 +34,11 @@ void CScheduler::serviceQueue() { // is called. while (!shouldStop()) { try { + if (!shouldStop() && taskQueue.empty()) { + reverse_lock > rlock(lock); + // Use this chance to get a tiny bit more entropy + RandAddSeedSleep(); + } while (!shouldStop() && taskQueue.empty()) { // Wait until there is something to do. newTaskScheduled.wait(lock); From 74da5f9714c037ca90c5cf01ec42a87ef0cb3aa0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:04:37 -0400 Subject: [PATCH 0478/1888] Add FastRandomContext::rand256() and ::randbytes() FastRandomContext now provides all functionality that the real Rand* functions provide. --- src/random.cpp | 20 ++++++++++++++++++++ src/random.h | 6 ++++++ src/test/random_tests.cpp | 7 +++++++ 3 files changed, 33 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index addc68a5f5..9d13409b79 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -305,6 +305,26 @@ void FastRandomContext::RandomSeed() requires_seed = false; } +uint256 FastRandomContext::rand256() +{ + if (bytebuf_size < 32) { + FillByteBuffer(); + } + uint256 ret; + memcpy(ret.begin(), bytebuf + 64 - bytebuf_size, 32); + bytebuf_size -= 32; + return ret; +} + +std::vector FastRandomContext::randbytes(size_t len) +{ + std::vector ret(len); + if (len > 0) { + rng.Output(&ret[0], len); + } + return ret; +} + FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0) { rng.SetKey(seed.begin(), 32); diff --git a/src/random.h b/src/random.h index e09e833fda..e9517dab24 100644 --- a/src/random.h +++ b/src/random.h @@ -110,9 +110,15 @@ class FastRandomContext { } } + /** Generate random bytes. */ + std::vector randbytes(size_t len); + /** Generate a random 32-bit integer. */ uint32_t rand32() { return randbits(32); } + /** generate a random uint256. */ + uint256 rand256(); + /** Generate a random boolean. */ bool randbool() { return randbits(1); } }; diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index ee077d3ed3..59896a42c6 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -25,14 +25,21 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64()); BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); + BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17)); + BOOST_CHECK(ctx1.rand256() == ctx2.rand256()); BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7)); + BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128)); BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); + BOOST_CHECK(ctx1.rand256() == ctx2.rand256()); + BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); // Check that a nondeterministic ones are not FastRandomContext ctx3; FastRandomContext ctx4; BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal + BOOST_CHECK(ctx3.rand256() != ctx4.rand256()); + BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7)); } BOOST_AUTO_TEST_CASE(fastrandom_randbits) From 72d60016f9580edf5235a8f728a40337b7729f05 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:12:30 -0400 Subject: [PATCH 0479/1888] [Random / tests] scripted-diff: use insecure_rand256/randrange more -BEGIN VERIFY SCRIPT- sed -i "s/\::iterator it; - it = mapOrphanTransactions.lower_bound(GetRandHash()); + it = mapOrphanTransactions.lower_bound(insecure_rand256()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); return it->second.tx; @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 9b53438a3c..e92d606778 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -26,7 +26,7 @@ class CCoinsViewTest : public CCoinsView return false; } coins = it->second; - if (coins.IsPruned() && insecure_rand() % 2 == 0) { + if (coins.IsPruned() && insecure_randrange(2) == 0) { // Randomly return false in case of an empty entry. return false; } @@ -45,7 +45,7 @@ class CCoinsViewTest : public CCoinsView { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) { map_[it->first] = it->second.coins; - if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { + if (it->second.coins.IsPruned() && insecure_randrange(3) == 0) { // Randomly delete empty entries on write. map_.erase(it->first); } @@ -97,7 +97,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) std::vector txids; txids.resize(NUM_SIMULATION_ITERATIONS / 8); for (unsigned int i = 0; i < txids.size(); i++) { - txids[i] = GetRandHash(); + txids[i] = insecure_rand256(); } for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) CCoins& coins = result[txid]; CCoinsModifier entry = stack.back()->ModifyCoins(txid); BOOST_CHECK(coins == *entry); - if (insecure_rand() % 5 == 0 || coins.IsPruned()) { + if (insecure_randrange(5) == 0 || coins.IsPruned()) { if (coins.IsPruned()) { added_an_entry = true; } else { @@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) } // Once every 1000 iterations and at the end, verify the full cache. - if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (insecure_randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { for (std::map::iterator it = result.begin(); it != result.end(); it++) { const CCoins* coins = stack.back()->AccessCoins(it->first); if (coins) { @@ -138,14 +138,14 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) } } - if (insecure_rand() % 100 == 0) { + if (insecure_randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && insecure_rand() % 2 == 0) { + if (stack.size() > 0 && insecure_randrange(2) == 0) { stack.back()->Flush(); delete stack.back(); stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + if (stack.size() == 0 || (stack.size() < 4 && insecure_randrange(2))) { CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back(); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 0b2f699bac..d8c76b7420 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -85,7 +85,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un void static RandomScript(CScript &script) { static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); - int ops = (insecure_rand() % 10); + int ops = (insecure_randrange(10)); for (int i=0; i Date: Sat, 24 Oct 2020 19:19:04 -0400 Subject: [PATCH 0480/1888] Replace more rand() % NUM by randranges --- src/test/crypto_tests.cpp | 2 +- src/test/pmt_tests.cpp | 4 ++-- src/test/sighash_tests.cpp | 4 ++-- src/test/skiplist_tests.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index b8d2ae37ae..1b171a8ab9 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -37,7 +37,7 @@ void TestVector(const Hasher &h, const In &in, const Out &out) { Hasher hasher(h); size_t pos = 0; while (pos < in.size()) { - size_t len = insecure_rand() % ((in.size() - pos + 1) / 2 + 1); + size_t len = insecure_randrange((in.size() - pos + 1) / 2 + 1); hasher.Write((unsigned char*)&in[pos], len); pos += len; if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) { diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 09011d68f9..28603a219a 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -20,8 +20,8 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree public: // flip one bit in one of the hashes - this should break the authentication void Damage() { - unsigned int n = rand() % vHash.size(); - int bit = rand() % 256; + unsigned int n = insecure_randrange(vHash.size()); + int bit = insecure_randrange(256); uint256 &hash = vHash[n]; hash ^= ((uint256)1 << bit); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index d8c76b7420..95c67bcecf 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -87,7 +87,7 @@ void static RandomScript(CScript &script) { script = CScript(); int ops = (insecure_randrange(10)); for (int i=0; i Date: Sat, 24 Oct 2020 19:21:43 -0400 Subject: [PATCH 0481/1888] Replace rand() & ((1 << N) - 1) with randbits(N) --- src/test/pmt_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 28603a219a..36b24a052c 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) std::vector vMatch(nTx, false); std::vector vMatchTxid1; for (unsigned int j=0; j Date: Sat, 24 Oct 2020 19:24:11 -0400 Subject: [PATCH 0482/1888] [Random / tests] scripted-diff: Use randbits/bool instead of randrange -BEGIN VERIFY SCRIPT- sed -i 's/insecure_randbits(1)/insecure_randbool()/g' src/test/*_tests.cpp sed -i 's/insecure_randrange(2)/insecure_randbool()/g' src/test/*_tests.cpp sed -i 's/insecure_randrange(4)/insecure_randbits(2)/g' src/test/*_tests.cpp sed -i 's/insecure_randrange(32)/insecure_randbits(5)/g' src/test/*_tests.cpp sed -i 's/insecure_randrange(256)/insecure_randbits(8)/g' src/test/*_tests.cpp -END VERIFY SCRIPT- --- src/test/coins_tests.cpp | 6 +++--- src/test/pmt_tests.cpp | 2 +- src/test/sighash_tests.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index e92d606778..3c94fc8307 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -26,7 +26,7 @@ class CCoinsViewTest : public CCoinsView return false; } coins = it->second; - if (coins.IsPruned() && insecure_randrange(2) == 0) { + if (coins.IsPruned() && insecure_randbool() == 0) { // Randomly return false in case of an empty entry. return false; } @@ -140,12 +140,12 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) if (insecure_randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && insecure_randrange(2) == 0) { + if (stack.size() > 0 && insecure_randbool() == 0) { stack.back()->Flush(); delete stack.back(); stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && insecure_randrange(2))) { + if (stack.size() == 0 || (stack.size() < 4 && insecure_randbool())) { CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back(); diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 36b24a052c..658f4114bc 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -21,7 +21,7 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree // flip one bit in one of the hashes - this should break the authentication void Damage() { unsigned int n = insecure_randrange(vHash.size()); - int bit = insecure_randrange(256); + int bit = insecure_randbits(8); uint256 &hash = vHash[n]; hash ^= ((uint256)1 << bit); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 95c67bcecf..f013d9d72e 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -94,16 +94,16 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { tx.nVersion = insecure_rand(); tx.vin.clear(); tx.vout.clear(); - tx.nLockTime = (insecure_randrange(2)) ? insecure_rand() : 0; - int ins = (insecure_randrange(4)) + 1; - int outs = fSingle ? ins : (insecure_randrange(4)) + 1; + tx.nLockTime = (insecure_randbool()) ? insecure_rand() : 0; + int ins = (insecure_randbits(2)) + 1; + int outs = fSingle ? ins : (insecure_randbits(2)) + 1; for (int in = 0; in < ins; in++) { tx.vin.push_back(CTxIn()); CTxIn &txin = tx.vin.back(); txin.prevout.hash = insecure_rand256(); - txin.prevout.n = insecure_randrange(4); + txin.prevout.n = insecure_randbits(2); RandomScript(txin.scriptSig); - txin.nSequence = (insecure_randrange(2)) ? insecure_rand() : (unsigned int)-1; + txin.nSequence = (insecure_randbool()) ? insecure_rand() : (unsigned int)-1; } for (int out = 0; out < outs; out++) { tx.vout.push_back(CTxOut()); From 894b536ec98f6804a472a31d5c413f05a50da6b1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:33:12 -0400 Subject: [PATCH 0483/1888] Use rdrand as entropy source on supported platforms --- src/init.cpp | 2 ++ src/random.cpp | 67 ++++++++++++++++++++++++++++++++++++++ src/random.h | 3 ++ src/test/test_dapscoin.cpp | 1 + 4 files changed, 73 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index c4ca74ceb7..4d43ad21ae 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1046,6 +1046,8 @@ bool AppInit2(bool isDaemon) // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + RandomInit(); + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. DAPS is shutting down.")); diff --git a/src/random.cpp b/src/random.cpp index 9d13409b79..230e1ff824 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -65,6 +65,63 @@ static inline int64_t GetPerformanceCounter() #endif } +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) +static std::atomic hwrand_initialized{false}; +static bool rdrand_supported = false; +static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; +static void RDRandInit() +{ + //! When calling cpuid function #1, ecx register will have this set if RDRAND is available. + // Avoid clobbering ebx, as that is used for PIC on x86. + uint32_t eax, tmp, ecx, edx; + __asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1)); + if (ecx & CPUID_F1_ECX_RDRAND) { + LogPrintf("Using RdRand as entropy source\n"); + rdrand_supported = true; + } + hwrand_initialized.store(true); +} +#else +static void RDRandInit() {} +#endif + +static bool GetHWRand(unsigned char* ent32) { +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) + assert(hwrand_initialized.load(std::memory_order_relaxed)); + if (rdrand_supported) { + uint8_t ok; + // Not all assemblers support the rdrand instruction, write it in hex. +#ifdef __i386__ + for (int iter = 0; iter < 4; ++iter) { + uint32_t r1, r2; + __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax + ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx + "setc %2" : + "=a"(r1), "=d"(r2), "=q"(ok) :: "cc"); + if (!ok) return false; + WriteLE32(ent32 + 8 * iter, r1); + WriteLE32(ent32 + 8 * iter + 4, r2); + } +#else + uint64_t r1, r2, r3, r4; + __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax + "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx + "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx + "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx + "setc %4" : + "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc"); + if (!ok) return false; + WriteLE64(ent32, r1); + WriteLE64(ent32 + 8, r2); + WriteLE64(ent32 + 16, r3); + WriteLE64(ent32 + 24, r4); +#endif + return true; + } +#endif + return false; +} + void RandAddSeed() { // Seed with CPU performance counter @@ -256,6 +313,11 @@ void GetStrongRandBytes(unsigned char* out, int num) GetOSRand(buf); hasher.Write(buf, 32); + // Third source: HW RNG, if available. + if (GetHWRand(buf)) { + hasher.Write(buf, 32); + } + // Combine with and update state { std::unique_lock lock(cs_rng_state); @@ -382,3 +444,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete uint256 seed; rng.SetKey(seed.begin(), 32); } + +void RandomInit() +{ + RDRandInit(); +} diff --git a/src/random.h b/src/random.h index e9517dab24..4b32ea8026 100644 --- a/src/random.h +++ b/src/random.h @@ -140,4 +140,7 @@ void GetOSRand(unsigned char *ent32); */ bool Random_SanityCheck(); +/** Initialize the RNG. */ +void RandomInit(); + #endif // BITCOIN_RANDOM_H diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index 6b0884c91a..686e4c65fd 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -33,6 +33,7 @@ struct TestingSetup { boost::thread_group threadGroup; TestingSetup() { + RandomInit(); SetupEnvironment(); fPrintToDebugLog = true; // don't want to write to debug.log file fCheckBlockIndex = false; From 568995cb812c445829c42644977f0a9ffa9d386b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:34:27 -0400 Subject: [PATCH 0484/1888] random: fix crash on some 64bit platforms rbx needs to be stashed in a 64bit register on 64bit platforms. With this crash in particular, it was holding a stack canary which was not properly restored after the cpuid. Split out the x86+PIC case so that x86_64 doesn't have to worry about it. --- src/random.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 230e1ff824..fc47ad2d7e 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -71,10 +71,16 @@ static bool rdrand_supported = false; static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; static void RDRandInit() { - //! When calling cpuid function #1, ecx register will have this set if RDRAND is available. + uint32_t eax, ecx, edx; +#if defined(__i386__) && ( defined(__PIC__) || defined(__PIE__)) // Avoid clobbering ebx, as that is used for PIC on x86. - uint32_t eax, tmp, ecx, edx; + uint32_t tmp; __asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1)); +#else + uint32_t ebx; + __asm__ ("cpuid": "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1)); +#endif + //! When calling cpuid function #1, ecx register will have this set if RDRAND is available. if (ecx & CPUID_F1_ECX_RDRAND) { LogPrintf("Using RdRand as entropy source\n"); rdrand_supported = true; From 0218f0e85d48e973df74cebeb1530fa9b669e748 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:37:08 -0400 Subject: [PATCH 0485/1888] Use cpuid intrinsics instead of asm code --- src/random.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index fc47ad2d7e..c11e8adc20 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -36,6 +36,10 @@ #include +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) +#include +#endif + #include #include @@ -71,17 +75,8 @@ static bool rdrand_supported = false; static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; static void RDRandInit() { - uint32_t eax, ecx, edx; -#if defined(__i386__) && ( defined(__PIC__) || defined(__PIE__)) - // Avoid clobbering ebx, as that is used for PIC on x86. - uint32_t tmp; - __asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1)); -#else - uint32_t ebx; - __asm__ ("cpuid": "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1)); -#endif - //! When calling cpuid function #1, ecx register will have this set if RDRAND is available. - if (ecx & CPUID_F1_ECX_RDRAND) { + uint32_t eax, ebx, ecx, edx; + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) { LogPrintf("Using RdRand as entropy source\n"); rdrand_supported = true; } From 2e6b852b08da2cfd6cdd5bf83fabd6427e76f6af Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:38:04 -0400 Subject: [PATCH 0486/1888] Clarify entropy source --- src/random.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/random.cpp b/src/random.cpp index c11e8adc20..4112be6ada 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -77,7 +77,7 @@ static void RDRandInit() { uint32_t eax, ebx, ecx, edx; if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) { - LogPrintf("Using RdRand as entropy source\n"); + LogPrintf("Using RdRand as an additional entropy source\n"); rdrand_supported = true; } hwrand_initialized.store(true); From bebd756d38c27980c8d58cbdc5853d953765c2d4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:38:30 -0400 Subject: [PATCH 0487/1888] Fix resource leak --- src/random.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/random.cpp b/src/random.cpp index 4112be6ada..4710f4ecd9 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -185,6 +185,7 @@ void GetDevURandom(unsigned char *ent32) do { ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have); if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) { + close(f); RandFailure(); } have += n; From ac3f282d95b1ea1b427b8112d7046b349426a37f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:40:16 -0400 Subject: [PATCH 0488/1888] Add attribute [[noreturn]] (C++11) to functions that will not return Rationale: * Reduce the number of false positives from static analyzers * Potentially enable additional compiler optimizations --- src/random.cpp | 4 ++-- src/test/test_dapscoin.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 4710f4ecd9..fc8a6aba4a 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -43,10 +43,10 @@ #include #include -static void RandFailure() +[[noreturn]] static void RandFailure() { LogPrintf("Failed to read randomness, aborting\n"); - abort(); + std::abort(); } static inline int64_t GetPerformanceCounter() diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index 686e4c65fd..b6da679475 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -130,14 +130,14 @@ struct TestingSetup { BOOST_GLOBAL_FIXTURE(TestingSetup); -// void Shutdown(void* parg) +// [[noreturn]] void Shutdown(void* parg) // { -// exit(0); +// std::exit(0); // } -// void StartShutdown() +// [[noreturn]] void StartShutdown() // { -// exit(0); +// std::exit(0); // } // bool ShutdownRequested() From ab28c48da93f2ad235f373a1b5237c9ef16cc6dd Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:43:00 -0400 Subject: [PATCH 0489/1888] Check if sys/random.h is required for getentropy on OSX. --- configure.ac | 8 ++++++++ src/random.cpp | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9bb01830d1..207f302d8b 100644 --- a/configure.ac +++ b/configure.ac @@ -560,6 +560,14 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [ AC_MSG_RESULT(no)] ) +AC_MSG_CHECKING(for getentropy via random.h) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[ getentropy(nullptr, 32) ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY_RAND, 1,[Define this symbol if the BSD getentropy system call is available with sys/random.h]) ], + [ AC_MSG_RESULT(no)] +) + AC_MSG_CHECKING(for sysctl KERN_ARND) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], diff --git a/src/random.cpp b/src/random.cpp index fc8a6aba4a..15c3e8017d 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -27,9 +27,12 @@ #include #include #endif -#ifdef HAVE_GETENTROPY +#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)) #include #endif +#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) +#include +#endif #ifdef HAVE_SYSCTL_ARND #include #endif @@ -236,6 +239,15 @@ void GetOSRand(unsigned char *ent32) if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { RandFailure(); } +#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) + // We need a fallback for OSX < 10.12 + if (&getentropy != NULL) { + if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { + RandFailure(); + } + } else { + GetDevURandom(ent32); + } #elif defined(HAVE_SYSCTL_ARND) /* FreeBSD and similar. It is possible for the call to return less * bytes than requested, so need to read in a loop. From 1e97b6085059762b9e863ebbd7d496987434d342 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:51:05 -0400 Subject: [PATCH 0490/1888] Bugfix: randbytes should seed when needed (non reachable issue) --- src/random.cpp | 1 + src/test/random_tests.cpp | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 15c3e8017d..3bf69f16cb 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -394,6 +394,7 @@ uint256 FastRandomContext::rand256() std::vector FastRandomContext::randbytes(size_t len) { + if (requires_seed) RandomSeed(); std::vector ret(len); if (len > 0) { rng.Output(&ret[0], len); diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 59896a42c6..313b2efab3 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -35,11 +35,18 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); // Check that a nondeterministic ones are not - FastRandomContext ctx3; - FastRandomContext ctx4; - BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal - BOOST_CHECK(ctx3.rand256() != ctx4.rand256()); - BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7)); + { + FastRandomContext ctx3, ctx4; + BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal + } + { + FastRandomContext ctx3, ctx4; + BOOST_CHECK(ctx3.rand256() != ctx4.rand256()); + } + { + FastRandomContext ctx3, ctx4; + BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7)); + } } BOOST_AUTO_TEST_CASE(fastrandom_randbits) From 19de48f3c1c8192e1948edaea53d6d0948fb4f34 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:55:00 -0400 Subject: [PATCH 0491/1888] Do not permit copying FastRandomContexts --- src/random.cpp | 14 ++++++++++++++ src/random.h | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index 3bf69f16cb..0c565ca66c 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -460,6 +460,20 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete rng.SetKey(seed.begin(), 32); } +FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept +{ + requires_seed = from.requires_seed; + rng = from.rng; + std::copy(std::begin(from.bytebuf), std::end(from.bytebuf), std::begin(bytebuf)); + bytebuf_size = from.bytebuf_size; + bitbuf = from.bitbuf; + bitbuf_size = from.bitbuf_size; + from.requires_seed = true; + from.bytebuf_size = 0; + from.bitbuf_size = 0; + return *this; +} + void RandomInit() { RDRandInit(); diff --git a/src/random.h b/src/random.h index 4b32ea8026..b034bdd12e 100644 --- a/src/random.h +++ b/src/random.h @@ -75,6 +75,14 @@ class FastRandomContext { /** Initialize with explicit seed (only for testing) */ explicit FastRandomContext(const uint256& seed); + // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded). + FastRandomContext(const FastRandomContext&) = delete; + FastRandomContext(FastRandomContext&&) = delete; + FastRandomContext& operator=(const FastRandomContext&) = delete; + + /** Move a FastRandomContext. If the original one is used again, it will be reseeded. */ + FastRandomContext& operator=(FastRandomContext&& from) noexcept; + /** Generate a random 64-bit integer. */ uint64_t rand64() { From b07e24dee009f3d4aec8fc35962a524eefbd9548 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:56:15 -0400 Subject: [PATCH 0492/1888] [Random] Add a missing include --- src/random.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/random.cpp b/src/random.cpp index 0c565ca66c..31a2a13669 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -40,6 +40,7 @@ #include #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) +#include #include #endif From 9d5cb56fa0cc26beea3fa760ddfb4b94671b6075 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:58:42 -0400 Subject: [PATCH 0493/1888] [Refactor] Use arrays instead of unic vars in Chacha20 Makes the code shorter and more concise. Might allow for some compiler optimisations. --- src/crypto/chacha20.cpp | 110 +++++++++++----------------------------- 1 file changed, 29 insertions(+), 81 deletions(-) diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp index 816ae870e1..70c472b74b 100644 --- a/src/crypto/chacha20.cpp +++ b/src/crypto/chacha20.cpp @@ -73,105 +73,53 @@ void ChaCha20::Seek(uint64_t pos) void ChaCha20::Output(unsigned char* c, size_t bytes) { - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; - unsigned char *ctarget = NULL; + uint32_t x[16]; + uint32_t j[16]; + unsigned char *ctarget = nullptr; unsigned char tmp[64]; unsigned int i; if (!bytes) return; - j0 = input[0]; - j1 = input[1]; - j2 = input[2]; - j3 = input[3]; - j4 = input[4]; - j5 = input[5]; - j6 = input[6]; - j7 = input[7]; - j8 = input[8]; - j9 = input[9]; - j10 = input[10]; - j11 = input[11]; - j12 = input[12]; - j13 = input[13]; - j14 = input[14]; - j15 = input[15]; + for (uint32_t i=0; i<16; i++) { + j[i] = input[i]; + } for (;;) { if (bytes < 64) { ctarget = c; c = tmp; } - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; + for (uint32_t i=0; i<16; i++) { + x[i] = j[i]; + } for (i = 20;i > 0;i -= 2) { - QUARTERROUND( x0, x4, x8,x12) - QUARTERROUND( x1, x5, x9,x13) - QUARTERROUND( x2, x6,x10,x14) - QUARTERROUND( x3, x7,x11,x15) - QUARTERROUND( x0, x5,x10,x15) - QUARTERROUND( x1, x6,x11,x12) - QUARTERROUND( x2, x7, x8,x13) - QUARTERROUND( x3, x4, x9,x14) + QUARTERROUND( x[0], x[4], x[8],x[12]) + QUARTERROUND( x[1], x[5], x[9],x[13]) + QUARTERROUND( x[2], x[6],x[10],x[14]) + QUARTERROUND( x[3], x[7],x[11],x[15]) + QUARTERROUND( x[0], x[5],x[10],x[15]) + QUARTERROUND( x[1], x[6],x[11],x[12]) + QUARTERROUND( x[2], x[7], x[8],x[13]) + QUARTERROUND( x[3], x[4], x[9],x[14]) + } + for (uint32_t i=0; i<16; i++) { + x[i] += j[i]; + } + + ++j[12]; + if (!j[12]) ++j[13]; + + for (uint32_t i=0; i<16; i++) { + WriteLE32(c + 4*i, x[i]); } - x0 += j0; - x1 += j1; - x2 += j2; - x3 += j3; - x4 += j4; - x5 += j5; - x6 += j6; - x7 += j7; - x8 += j8; - x9 += j9; - x10 += j10; - x11 += j11; - x12 += j12; - x13 += j13; - x14 += j14; - x15 += j15; - - ++j12; - if (!j12) ++j13; - - WriteLE32(c + 0, x0); - WriteLE32(c + 4, x1); - WriteLE32(c + 8, x2); - WriteLE32(c + 12, x3); - WriteLE32(c + 16, x4); - WriteLE32(c + 20, x5); - WriteLE32(c + 24, x6); - WriteLE32(c + 28, x7); - WriteLE32(c + 32, x8); - WriteLE32(c + 36, x9); - WriteLE32(c + 40, x10); - WriteLE32(c + 44, x11); - WriteLE32(c + 48, x12); - WriteLE32(c + 52, x13); - WriteLE32(c + 56, x14); - WriteLE32(c + 60, x15); if (bytes <= 64) { if (bytes < 64) { for (i = 0;i < bytes;++i) ctarget[i] = c[i]; } - input[12] = j12; - input[13] = j13; + input[12] = j[12]; + input[13] = j[13]; return; } bytes -= 64; From daad23b9e820e6bbbc0dede20984321687a39b62 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 24 Oct 2020 19:58:51 -0400 Subject: [PATCH 0494/1888] [Log] Replace a string by the function name in a log --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net.cpp b/src/net.cpp index 726b127e25..58d2b72452 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -232,7 +232,7 @@ void AdvertiseLocal(CNode* pnode) addrLocal.SetIP(pnode->addrLocal); } if (addrLocal.IsRoutable()) { - LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); + LogPrintf("%s: advertising address %s\n", __func__, addrLocal.ToString()); FastRandomContext insecure_rand; pnode->PushAddress(addrLocal, insecure_rand); } From bc52018c59875ff57e60e94bb31b3f4bb180d166 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 25 Oct 2020 17:36:47 -0400 Subject: [PATCH 0495/1888] custom wallet backup paths from https://github.com/PIVX-Project/PIVX/pull/582/commits/8046a528a053fd7d792cbe893a7b158d6c9bced8 --- src/init.cpp | 3 +- src/qt/walletmodel.cpp | 33 ++++++++++- src/qt/walletmodel.h | 1 + src/qt/walletview.cpp | 8 +-- src/wallet/wallet.cpp | 11 ++++ src/wallet/wallet.h | 4 ++ src/wallet/walletdb.cpp | 127 ++++++++++++++++++++++++++++++++++------ src/wallet/walletdb.h | 3 +- 8 files changed, 162 insertions(+), 28 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2cd06a68cc..a3015c7fc4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -382,6 +382,7 @@ std::string HelpMessage(HelpMessageMode mode) #endif } strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); + strUsage += HelpMessageOpt("-backuppath=<(dir/file)>", _("Specify custom backup path to add a copy of any wallet backup. If set as dir, every backup generates a timestamped file. If set as file, will rewrite to that file every backup.")); strUsage += HelpMessageOpt("-dbcache=", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); strUsage += HelpMessageOpt("-maxreorg=", strprintf(_("Set the Maximum reorg depth (default: %u)"), Params(CBaseChainParams::MAIN).MaxReorganizationDepth())); @@ -1122,7 +1123,7 @@ bool AppInit2(bool isDaemon) sourceFile.make_preferred(); backupFile.make_preferred(); if (boost::filesystem::exists(sourceFile)) { -#if BOOST_VERSION >= 158000 +#if BOOST_VERSION >= 105800 try { boost::filesystem::copy_file(sourceFile, backupFile); LogPrintf("Creating backup of %s -> %s\n", sourceFile, backupFile); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 691a8d0526..d51e4316a0 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -453,7 +453,12 @@ bool WalletModel::changePassphrase(const SecureString& oldPass, const SecureStri bool WalletModel::backupWallet(const QString& filename) { - return BackupWallet(*wallet, filename.toLocal8Bit().data()); + //attempt regular backup + if(!BackupWallet(*wallet, filename.toLocal8Bit().data())) { + return error("ERROR: Failed to backup wallet!"); + } + + return true; } // Handlers for core signals @@ -509,6 +514,30 @@ static void NotifyWatchonlyChanged(WalletModel* walletmodel, bool fHaveWatchonly Q_ARG(bool, fHaveWatchonly)); } +static void NotifyWalletBacked(WalletModel* model, const bool& fSuccess, const string& filename) +{ + std::string message; + string title = "Backup "; + CClientUIInterface::MessageBoxFlags method; + + if (fSuccess) { + title += "Successful: "; + method = CClientUIInterface::MessageBoxFlags::MSG_INFORMATION; + } else { + message = "There was an error trying to save the wallet data to "; + title += "Failed: "; + method = CClientUIInterface::MessageBoxFlags::MSG_ERROR; + } + + message += _(filename.data()); + + + QMetaObject::invokeMethod(model, "message", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(title)), + Q_ARG(QString, QString::fromStdString(message)), + Q_ARG(unsigned int, (unsigned int)method)); +} + void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet @@ -517,6 +546,7 @@ void WalletModel::subscribeToCoreSignals() wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1)); + wallet->NotifyWalletBacked.connect(boost::bind(NotifyWalletBacked, this, _1, _2)); } void WalletModel::unsubscribeFromCoreSignals() @@ -527,6 +557,7 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1)); + wallet->NotifyWalletBacked.disconnect(boost::bind(NotifyWalletBacked, this, _1, _2)); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index c580974536..ca3b97db32 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -223,6 +223,7 @@ class WalletModel : public QObject void unlockCoin(COutPoint& output); void listLockedCoins(std::vector& vOutpts); + string GetUniqueWalletBackupName(); void loadReceiveRequests(std::vector& vReceiveRequests); bool saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 958df8f3ca..655045bd83 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -263,13 +263,7 @@ void WalletView::backupWallet() if (filename.isEmpty()) return; - if (!walletModel->backupWallet(filename)) { - Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), - CClientUIInterface::MSG_ERROR); - } else { - Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), - CClientUIInterface::MSG_INFORMATION); - } + walletModel->backupWallet(filename); } void WalletView::changePassphrase() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index af72849284..6ce08383cd 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "masternodeconfig.h" @@ -5702,6 +5703,16 @@ bool CMerkleTx::IsTransactionLockTimedOut() const return false; } +string CWallet::GetUniqueWalletBackupName() const +{ + posix_time::ptime timeLocal = posix_time::second_clock::local_time(); + stringstream ssDateTime; + + + ssDateTime << gregorian::to_iso_extended_string(timeLocal.date()) << "-" << timeLocal.time_of_day(); + return strprintf("wallet%s.dat%s", "", DateTimeStrFormat(".%Y-%m-%d-%H-%M", GetTime())); +} + CWallet::CWallet() { SetNull(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dd37e212c4..9de7e2d266 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -276,6 +276,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool WriteAutoConsolidateSettingTime(uint32_t settingTime); uint32_t ReadAutoConsolidateSettingTime(); bool IsAutoConsolidateOn(); + string GetUniqueWalletBackupName() const; /* * Main wallet lock. * This lock protects all the fields added by CWallet @@ -593,6 +594,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /** Watch-only address added */ boost::signals2::signal NotifyWatchonlyChanged; + /** notify wallet file backed up */ + boost::signals2::signal NotifyWalletBacked; + bool ComputeStealthPublicAddress(const std::string& accountName, std::string& pubAddress); bool ComputeIntegratedPublicAddress(const uint64_t paymentID, const std::string& accountName, std::string& pubAddress); bool EncodeStealthPublicAddress(const std::vector& pubViewKey, const std::vector& pubSpendKey, std::string& pubAddr); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 2e91b6cca0..4fd74eaff6 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1037,10 +1037,32 @@ void ThreadFlushWalletDB(const string& strFile) } } -bool BackupWallet(const CWallet& wallet, const string& strDest) +bool BackupWallet(const CWallet& wallet, const filesystem::path& strDest, bool fEnableCustom) { - if (!wallet.fFileBacked) + filesystem::path pathCustom; + filesystem::path pathWithFile; + if (!wallet.fFileBacked) { return false; + } else if(fEnableCustom) { + pathWithFile = GetArg("-backuppath", ""); + if(!pathWithFile.empty()) { + if(!pathWithFile.has_extension()) { + pathCustom = pathWithFile; + filesystem::create_directories(pathCustom); + if(access(pathCustom.string().data(), W_OK) != 0) { + string msg = strprintf("Error: failed to backup wallet to %s - Access denied\n", pathCustom.string()); + LogPrintf(msg.data()); + pathCustom = ""; + wallet.NotifyWalletBacked(false, msg); + } else { + pathWithFile /= wallet.GetUniqueWalletBackupName(); + } + } else { + pathCustom = pathWithFile.parent_path(); + } + } + } + while (true) { { LOCK(bitdb.cs_db); @@ -1051,25 +1073,70 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) bitdb.mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat - filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; filesystem::path pathDest(strDest); - if (filesystem::is_directory(pathDest)) + filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; + if (is_directory(pathDest)) { + if(!exists(pathDest)) create_directory(pathDest); pathDest /= wallet.strWalletFile; - - try { -#if BOOST_VERSION >= 158000 - filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); -#else - std::ifstream src(pathSrc.string(), std::ios::binary); - std::ofstream dst(pathDest.string(), std::ios::binary); - dst << src.rdbuf(); -#endif - LogPrintf("copied wallet.dat to %s\n", pathDest.string()); - return true; - } catch (const filesystem::filesystem_error& e) { - LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what()); - return false; } + bool defaultPath = AttemptBackupWallet(wallet, pathSrc.string(), pathDest.string()); + + if(defaultPath && !pathCustom.empty()) { + string strThreshold = GetArg("-custombackupthreshold", ""); + int nThreshold = 0; + if (strThreshold != "") { + nThreshold = atoi(strThreshold); + + typedef std::multimap folder_set_t; + folder_set_t folderSet; + filesystem::directory_iterator end_iter; + + pathCustom.make_preferred(); + // Build map of backup files for current(!) wallet sorted by last write time + + filesystem::path currentFile; + for (filesystem::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) { + // Only check regular files + if (filesystem::is_regular_file(dir_iter->status())) { + currentFile = dir_iter->path().filename(); + // Only add the backups for the current wallet, e.g. wallet.dat.* + if (dir_iter->path().stem().string() == wallet.strWalletFile) { + folderSet.insert(folder_set_t::value_type(filesystem::last_write_time(dir_iter->path()), *dir_iter)); + } + } + } + + int counter = 0; + for (auto entry : folderSet) { + counter++; + if(entry.second == pathWithFile) { + pathWithFile += "(1)"; + } + } + + if (counter >= nThreshold) { + std::time_t oldestBackup = 0; + for(auto entry : folderSet) { + if(oldestBackup == 0 || entry.first < oldestBackup) { + oldestBackup = entry.first; + } + } + + try { + auto entry = folderSet.find(oldestBackup); + if (entry != folderSet.end()) { + filesystem::remove(entry->second); + LogPrintf("Old backup deleted: %s\n", (*entry).second); + } + } catch (filesystem::filesystem_error& error) { + LogPrintf("Failed to delete backup %s\n", error.what()); + } + } + } + AttemptBackupWallet(wallet, pathSrc.string(), pathWithFile.string()); + } + + return defaultPath; } } MilliSleep(100); @@ -1077,6 +1144,30 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) return false; } +bool AttemptBackupWallet(const CWallet& wallet, const filesystem::path& pathSrc, const filesystem::path& pathDest) +{ + bool retStatus; + try { +#if BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ + filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); +#else + std::ifstream src(pathSrc, std::ios::binary | std::ios::in); + std::ofstream dst(pathDest, std::ios::binary | std::ios::out | std::ios::trunc); + dst << src.rdbuf(); + dst.flush(); + src.close(); + dst.close(); +#endif + LogPrintf("copied wallet.dat to %s\n", pathDest.string()); + retStatus = true; + } catch (const filesystem::filesystem_error& e) { + retStatus = false; + LogPrintf("error copying wallet.dat to %s - %s\n", pathDest, e.what()); + } + wallet.NotifyWalletBacked(retStatus, pathDest.string()); + return retStatus; +} + // // Try to (very carefully!) recover wallet.dat if there is a problem. // diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index ee22ced4ca..a6d78c32d2 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -196,6 +196,7 @@ class CWalletDB : public CDB bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry); }; -bool BackupWallet(const CWallet& wallet, const std::string& strDest); +bool BackupWallet(const CWallet& wallet, const boost::filesystem::path& strDest, bool fEnableCustom = true); +bool AttemptBackupWallet(const CWallet& wallet, const boost::filesystem::path& pathSrc, const boost::filesystem::path& pathDest); #endif // BITCOIN_WALLETDB_H From 77863b3bd491bfdce3f4bbb1e6ca8c49729abb85 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 31 Oct 2020 11:18:40 -0400 Subject: [PATCH 0496/1888] Ban previous versions up to and including 1.0.7.1 --- src/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net.cpp b/src/net.cpp index 14584fef2f..cf338c6898 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -126,7 +126,7 @@ unsigned short GetListenPort() { } bool IsUnsupportedVersion(std::string strSubVer) { - return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/"); + return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/"); } // find 'best' local address for a particular peer From c5f442bb9a91f863eb34f5ac3741c4ff18f8a694 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 31 Oct 2020 16:58:01 -0400 Subject: [PATCH 0497/1888] Bypass bad blocks --- src/main.cpp | 2 +- src/poa.cpp | 10 +++++++++- src/poa.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1a101d91a2..2aba74f06a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2920,7 +2920,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): A PoA block should audit at least 59 PoS blocks and no more than 120 PoS blocks")); } - if (!CheckPoABlockNotContainingPoABlockInfo(block)) { + if (!CheckPoABlockNotContainingPoABlockInfo(block, pindex)) { return state.DoS(100, error("ConnectBlock(): A PoA block should not audit any existing PoA blocks")); } diff --git a/src/poa.cpp b/src/poa.cpp index d1a8886ca6..ea12e8aedc 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -215,6 +215,10 @@ bool CheckPoAContainRecentHash(const CBlock& block) } } else { if (pindex->nHeight >= Params().START_POA_BLOCK()) { + // Bypass bad block + if (pindex->nHeight == 719390) { + return true; + } CBlock prevPoablock; CBlockIndex* pblockindex = pindex; if (!ReadBlockFromDisk(prevPoablock, pblockindex)) @@ -372,8 +376,12 @@ bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate) } //A PoA block cannot contain information of any PoA block information (hash, height, timestamp) -bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block) +bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block, const CBlockIndex* pindex) { + // Bypass bad block + if (pindex->nHeight == 719456) { + return true; + } uint32_t numOfPoSBlocks = block.posBlocksAudited.size(); for (uint32_t i = 0; i < numOfPoSBlocks; i++) { PoSBlockSummary pos = block.posBlocksAudited.at(i); diff --git a/src/poa.h b/src/poa.h index f7ba5fcd50..2ef9a4ece2 100644 --- a/src/poa.h +++ b/src/poa.h @@ -41,7 +41,7 @@ bool CheckPoABlockMinedHash(const CBlockHeader& block); bool CheckPoAContainRecentHash(const CBlock& block); bool CheckNumberOfAuditedPoSBlocks(const CBlock& block, const CBlockIndex* pindex); -bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block); +bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block, const CBlockIndex* pindex); bool CheckPoAblockTime(const CBlock& block); bool CheckPoABlockNotAuditingOverlap(const CBlock& block); From ad7bf519e95ef21bb77b28e7fa78a48a2bde71e9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 31 Oct 2020 16:59:02 -0400 Subject: [PATCH 0498/1888] Add checkpoints surrounding the bad block --- src/chainparams.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0b516f92de..a6acc5bb0b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -136,13 +136,16 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (300000, uint256("28fe81715aa6450890103e65fbfa3e9d0b4bac3baf86a480ce0c630e82a32e62")) (458733, uint256("51d7f917147f3bec3f2e6767fd70c14730a0b0773a7b967e827336e936cf50e2")) (458734, uint256("35ff8e3884036187ed56e7d4a4adda3e0f75eac5655afd4cef8605954b28362f")) + (719455, uint256("ff67a6645a36a82a3885c989951680917c9e2de90f59665c8130701ccdcbb9f9")) + (719456, uint256("d56f2e69ab04a02ad766d45c98916c85aac3fa4d2b03a8f4a73a67d81c5260b3")) + (719457, uint256("2cda22a56c901fc8bb9ef7ae9690756a8107845ab3086c4ab4a97f1c0688a41d")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1582819136, // * UNIX timestamp of last checkpoint block - 741138, // * total number of transactions between genesis and last checkpoint + 1604141839, // * UNIX timestamp of last checkpoint block + 1765448, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint + 1440 // * estimated number of transactions per day after checkpoint }; static Checkpoints::MapCheckpoints mapCheckpointsTestnet = From f54279d4e28c78845649699c8bd89de947b99870 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 31 Oct 2020 16:59:56 -0400 Subject: [PATCH 0499/1888] Bump version to v1.0.8.2 --- configure.ac | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6ca00baf3e..9c97bf79e5 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 8) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index 46e7b55d3c..34c9ca2938 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.8.1 \ No newline at end of file +1.0.8.2 \ No newline at end of file From d6dd295fc9e2c969df1504450d01e69e61f08e74 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Nov 2020 16:51:24 -0500 Subject: [PATCH 0500/1888] Add 2FA digits settings/options (6 or 8) --- src/qt/2faconfirmdialog.cpp | 40 +++++++++++++++++++------- src/qt/2fadialog.cpp | 38 ++++++++++++++++++------- src/qt/2faqrdialog.cpp | 8 +++++- src/qt/forms/2faconfirmdialog.ui | 2 +- src/qt/forms/2fadialog.ui | 2 +- src/qt/forms/optionspage.ui | 30 ++++++++++++++++++- src/qt/optionsmodel.cpp | 4 +++ src/qt/optionspage.cpp | 49 +++++++++++++++++++++++++++++++- src/qt/optionspage.h | 1 + src/qt/qgoogleauth.cpp | 14 +++++++-- src/qt/res/css/Dark.css | 7 +++-- 11 files changed, 163 insertions(+), 32 deletions(-) diff --git a/src/qt/2faconfirmdialog.cpp b/src/qt/2faconfirmdialog.cpp index bbc63faaa6..0889f528e3 100644 --- a/src/qt/2faconfirmdialog.cpp +++ b/src/qt/2faconfirmdialog.cpp @@ -12,6 +12,9 @@ TwoFAConfirmDialog::TwoFAConfirmDialog(QWidget *parent) : { ui->setupUi(this); + ui->txtcode_7->setVisible(false); + ui->txtcode_8->setVisible(false); + QIntValidator *intVal_1 = new QIntValidator(0, 9, ui->txtcode_1); intVal_1->setLocale(QLocale::C); ui->txtcode_1->setValidator(intVal_1); @@ -41,16 +44,25 @@ TwoFAConfirmDialog::TwoFAConfirmDialog(QWidget *parent) : intVal_6->setLocale(QLocale::C); ui->txtcode_6->setValidator(intVal_6); ui->txtcode_6->setAlignment(Qt::AlignCenter); - - QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); - intVal_7->setLocale(QLocale::C); - ui->txtcode_7->setValidator(intVal_7); - ui->txtcode_7->setAlignment(Qt::AlignCenter); - - QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); - intVal_8->setLocale(QLocale::C); - ui->txtcode_8->setValidator(intVal_8); - ui->txtcode_8->setAlignment(Qt::AlignCenter); + + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + ui->label->setText("Please enter an eight digit 2FA code:"); + ui->txtcode_7->setVisible(true); + ui->txtcode_8->setVisible(true); + + QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); + intVal_7->setLocale(QLocale::C); + ui->txtcode_7->setValidator(intVal_7); + ui->txtcode_7->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); + intVal_8->setLocale(QLocale::C); + ui->txtcode_8->setValidator(intVal_8); + ui->txtcode_8->setAlignment(Qt::AlignCenter); + } + connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_acceptCode())); connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); @@ -141,7 +153,13 @@ void TwoFAConfirmDialog::on_acceptCode() chrlist = input.toUtf8().data(); code8 = chrlist[0]; - code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); + } else if (digits == 6) { + code.sprintf("%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6); + } QString result = ""; QString secret = QString::fromStdString(pwalletMain->Read2FASecret()); diff --git a/src/qt/2fadialog.cpp b/src/qt/2fadialog.cpp index 9019248fdd..70c398554a 100644 --- a/src/qt/2fadialog.cpp +++ b/src/qt/2fadialog.cpp @@ -11,6 +11,9 @@ TwoFADialog::TwoFADialog(QWidget *parent) : { ui->setupUi(this); + ui->txtcode_7->setVisible(false); + ui->txtcode_8->setVisible(false); + QIntValidator *intVal_1 = new QIntValidator(0, 9, ui->txtcode_1); intVal_1->setLocale(QLocale::C); ui->txtcode_1->setValidator(intVal_1); @@ -40,16 +43,23 @@ TwoFADialog::TwoFADialog(QWidget *parent) : intVal_6->setLocale(QLocale::C); ui->txtcode_6->setValidator(intVal_6); ui->txtcode_6->setAlignment(Qt::AlignCenter); - - QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); - intVal_7->setLocale(QLocale::C); - ui->txtcode_7->setValidator(intVal_7); - ui->txtcode_7->setAlignment(Qt::AlignCenter); - - QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); - intVal_8->setLocale(QLocale::C); - ui->txtcode_8->setValidator(intVal_8); - ui->txtcode_8->setAlignment(Qt::AlignCenter); + + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + ui->label_3->setText("Please enter an eight digit 2FA code:"); + ui->txtcode_7->setVisible(true); + ui->txtcode_8->setVisible(true); + QIntValidator *intVal_7 = new QIntValidator(0, 9, ui->txtcode_7); + intVal_7->setLocale(QLocale::C); + ui->txtcode_7->setValidator(intVal_7); + ui->txtcode_7->setAlignment(Qt::AlignCenter); + + QIntValidator *intVal_8 = new QIntValidator(0, 9, ui->txtcode_8); + intVal_8->setLocale(QLocale::C); + ui->txtcode_8->setValidator(intVal_8); + ui->txtcode_8->setAlignment(Qt::AlignCenter); + } connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_acceptCode())); connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); @@ -146,7 +156,13 @@ void TwoFADialog::on_acceptCode() chrlist = input.toUtf8().data(); code8 = chrlist[0]; - code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + code.sprintf("%c%c%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6, code7, code8); + } else if (digits == 6) { + code.sprintf("%c%c%c%c%c%c", code1, code2, code3, code4, code5, code6); + } QString result = ""; QString secret = QString::fromStdString(pwalletMain->Read2FASecret()); diff --git a/src/qt/2faqrdialog.cpp b/src/qt/2faqrdialog.cpp index fb21f2343d..e7b82207a2 100644 --- a/src/qt/2faqrdialog.cpp +++ b/src/qt/2faqrdialog.cpp @@ -70,8 +70,14 @@ void TwoFAQRDialog::update() } pwalletMain->Write2FASecret(addr); + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + uri.sprintf("otpauth://totp/DAPS:QT%20Wallet?secret=%s&issuer=dapscoin&algorithm=SHA1&digits=8&period=30", addr.c_str()); + } else if (digits == 6) { + uri.sprintf("otpauth://totp/DAPS:QT%20Wallet?secret=%s&issuer=dapscoin&algorithm=SHA1&digits=6&period=30", addr.c_str()); + } - uri.sprintf("otpauth://totp/DAPS:QT%20Wallet?secret=%s&issuer=dapscoin&algorithm=SHA1&digits=8&period=30", addr.c_str()); infoText = "Recovery Key: "; ui->lblURI->setText(infoText + addr.c_str()); diff --git a/src/qt/forms/2faconfirmdialog.ui b/src/qt/forms/2faconfirmdialog.ui index 7efa703a36..c808d00df6 100644 --- a/src/qt/forms/2faconfirmdialog.ui +++ b/src/qt/forms/2faconfirmdialog.ui @@ -42,7 +42,7 @@ - Please enter an eight digit 2FA code: + Please enter a six digit 2FA code: Qt::AlignCenter diff --git a/src/qt/forms/2fadialog.ui b/src/qt/forms/2fadialog.ui index c4ac288ee3..103cd0e7de 100644 --- a/src/qt/forms/2fadialog.ui +++ b/src/qt/forms/2fadialog.ui @@ -78,7 +78,7 @@ - Please enter an eight digit 2FA code: + Please enter a six digit 2FA code: Qt::AlignCenter diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 89752542ac..dc3fc21e2f 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -34,7 +34,7 @@ 0 0 806 - 541 + 565 @@ -179,6 +179,34 @@ + + + + + + Number of digits to use: + + + + + + + 2 + + + + 6 + + + + + 8 + + + + + + diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 3a3712bae0..50385ed6e8 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -138,6 +138,10 @@ void OptionsModel::Init() addOverriddenOption("-lang"); language = settings.value("language").toString(); + + // 2FA Digits Setting + if (!settings.contains("2fadigits")) + settings.setValue("2fadigits", "6"); } void OptionsModel::Reset() diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index a91cf56fa5..ae6a3ceb0e 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -117,7 +117,14 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->toggle2FA->setState(twoFAStatus); connect(ui->toggle2FA, SIGNAL(stateChanged(ToggleButton*)), this, SLOT(on_Enable2FA(ToggleButton*))); - + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + if (digits == 8) { + ui->comboBox->setCurrentIndex(1); + } else if (digits == 6) { + ui->comboBox->setCurrentIndex(0); + } + connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeDigits(int))); connect(ui->btn_day, SIGNAL(clicked()), this, SLOT(on_day())); connect(ui->btn_week, SIGNAL(clicked()), this, SLOT(on_week())); connect(ui->btn_month, SIGNAL(clicked()), this, SLOT(on_month())); @@ -940,3 +947,43 @@ void OptionsPage::minimizeOnClose_clicked(int state) settings.setValue("fMinimizeOnClose", false); } } + +void OptionsPage::changeDigits(int digit) +{ + int status = model->getEncryptionStatus(); + if (status == WalletModel::Locked || status == WalletModel::UnlockedForAnonymizationOnly) { + QMessageBox msgBox; + msgBox.setWindowTitle("2FA Digit Settings"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText("Please unlock the keychain wallet with your passphrase before attempting to change this setting."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); + return; + } + bool twofastatus = pwalletMain->Read2FA(); + if (twofastatus) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "Are You Sure?", "2FA is currently activated. Are you sure you would like to change the number of digits anyway?\nThis is not recommended unless you know what you are doing.", QMessageBox::Yes|QMessageBox::No); + if (reply == QMessageBox::Yes) { + digit = ui->comboBox->currentText().toInt(); + settings.setValue("2fadigits", digit); + QMessageBox msgBox; + msgBox.setWindowTitle("2FA Digit Settings"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText("2FA Digit Settings have been changed successfully."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); + return; + } else { + QMessageBox msgBox; + msgBox.setWindowTitle("2FA Digit Settings"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText("2FA Digit Settings have not been changed."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); + return; + } + } + digit = ui->comboBox->currentText().toInt(); + settings.setValue("2fadigits", digit); +} diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 2d47c6b338..d901a29321 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -99,6 +99,7 @@ private Q_SLOTS: void mapPortUpnp_clicked(int); void minimizeToTray_clicked(int); void minimizeOnClose_clicked(int); + void changeDigits(int); }; #endif // BITCOIN_QT_OPTIONSPAGE_H diff --git a/src/qt/qgoogleauth.cpp b/src/qt/qgoogleauth.cpp index cf883d03f9..f912737aff 100644 --- a/src/qt/qgoogleauth.cpp +++ b/src/qt/qgoogleauth.cpp @@ -2,6 +2,7 @@ #include #include #include +#include QGoogleAuth::QGoogleAuth() { @@ -98,7 +99,14 @@ QString QGoogleAuth::generatePin(const QByteArray key) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | (hmac[offset + 3] & 0xff); - - int password = binary % 100000000; - return QString("%1").arg(password, 8, 10, QChar('0')); + QSettings settings; + int digits = settings.value("2fadigits").toInt(); + int password; + if (digits == 8) { + password = binary % 100000000; + return QString("%1").arg(password, 8, 10, QChar('0')); + } else if (digits == 6) { + password = binary % 1000000; + return QString("%1").arg(password, 6, 10, QChar('0')); + } } diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 8e15bb2f44..c088736852 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -238,8 +238,6 @@ QTextEdit { .QValidatedLineEdit:focus, .QLineEdit:focus, QAbstractSpinBox:focus, -QComboBox:focus, -QComboBox::item:selected, QMenuBar::item:selected, QMenu::item:selected, QTextEdit:focus { @@ -247,6 +245,11 @@ QTextEdit:focus { background: #31398c; } +QComboBox:focus, +QComboBox::item:selected { + background: #31398c; +} + #messagesWidget { border-width: 4px; background: #1e223a; From f07b7c29eded2324d9f2ff43c862f0d5d5dbe812 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Nov 2020 12:54:11 -0500 Subject: [PATCH 0501/1888] Bump version to v1.0.9.0 --- configure.ac | 4 ++-- version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 9c97bf79e5..bbf2b821c1 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 8) -define(_CLIENT_VERSION_BUILD, 2) +define(_CLIENT_VERSION_REVISION, 9) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index 34c9ca2938..c92efd02dc 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.8.2 \ No newline at end of file +1.0.9.0 \ No newline at end of file From 7e6c59a8cf8ba8dc4350669002922fe15db376a3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 5 Nov 2020 16:51:49 -0500 Subject: [PATCH 0502/1888] Add fix for PoA --- src/chainparams.cpp | 1 + src/chainparams.h | 2 ++ src/poa.cpp | 15 ++++++++++++--- src/poa.h | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a6acc5bb0b..4e74eeee68 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -204,6 +204,7 @@ class CMainParams : public CChainParams nMaxNumPoSBlocks = 120; nSoftForkBlock = 125000; // Soft fork block for difficulty change nHardForkBlock = 670000; // Hard fork block for PoA updates + nPoAFixTime = 1606780800; // Hard fork time for PoA fix - Tuesday, December 1, 2020 12:00:00 AM (GMT) /** * Build the genesis block. Note that the output of the genesis coinbase cannot diff --git a/src/chainparams.h b/src/chainparams.h index 8f21203022..0cfe04252a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -105,6 +105,7 @@ class CChainParams int Block_Enforce_Invalid() const { return nBlockEnforceInvalidUTXO; } int SoftFork() const { return nSoftForkBlock;} int HardFork() const { return nHardForkBlock;} + int PoAFixTime() const { return nPoAFixTime;} //For PoA block time int POA_BLOCK_TIME() const { return nPoABlockTime; } @@ -134,6 +135,7 @@ class CChainParams int nStartPOABlock; int nSoftForkBlock; int nHardForkBlock; + int nPoAFixTime; int nMasternodeCountDrift; int nMaturity; int nModifierUpdateBlock; diff --git a/src/poa.cpp b/src/poa.cpp index ea12e8aedc..99d8c80996 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -236,10 +236,10 @@ bool CheckPoAContainRecentHash(const CBlock& block) } CBlockIndex* pCurrentFirstPoSAuditedIndex = mapBlockIndex[currentFirstPoSAuditedHash]; CBlockIndex* pCurrentLastPoSAuditedIndex = mapBlockIndex[currentLastPoSAuditedHash]; - + uint256 fixedPoSAuditedHash = pCurrentFirstPoSAuditedIndex->GetAncestor(lastAuditedPoSBlockInfo.height)->GetBlockHash(); //check lastAuditedPoSHash and currentFirstPoSAuditedHash must be on the same fork //that lastAuditedPoSHash must be parent block of currentFirstPoSAuditedHash - if (pCurrentFirstPoSAuditedIndex->GetAncestor(lastAuditedPoSBlockInfo.height)->GetBlockHash() != lastAuditedPoSHash) { + if (pCurrentFirstPoSAuditedIndex->GetAncestor(lastAuditedPoSBlockInfo.height)->GetBlockHash() != lastAuditedPoSHash && !IsFixedAudit(fixedPoSAuditedHash.GetHex())) { return error("CheckPoAContainRecentHash(): PoA block is not on the same fork with the previous poa block"); } @@ -248,7 +248,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) while(pIndexLoop && !pIndexLoop->IsProofOfStake()) { pIndexLoop = pIndexLoop->pprev; } - if (!pIndexLoop || pIndexLoop->GetBlockHash() != lastAuditedPoSHash) { + if (!pIndexLoop || pIndexLoop->GetBlockHash() != lastAuditedPoSHash && !IsFixedAudit(fixedPoSAuditedHash.GetHex())) { return error("CheckPoAContainRecentHash(): Some PoS block between %s and %s is not audited\n", lastAuditedPoSHash.GetHex(), currentFirstPoSAuditedHash.GetHex()); } @@ -470,3 +470,12 @@ bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex) } return ret; } + +bool IsFixedAudit(std::string txid) { + std::time_t fixedTime = std::time(0); + if (fixedTime >= Params().PoAFixTime()) { + //Currently only one + return (txid == "ff67a6645a36a82a3885c989951680917c9e2de90f59665c8130701ccdcbb9f9"); + } + return (txid == ""); +} diff --git a/src/poa.h b/src/poa.h index 2ef9a4ece2..4540c0862f 100644 --- a/src/poa.h +++ b/src/poa.h @@ -46,6 +46,6 @@ bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block, const CBlockInd bool CheckPoAblockTime(const CBlock& block); bool CheckPoABlockNotAuditingOverlap(const CBlock& block); bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex); - +bool IsFixedAudit(std::string txid); #endif // BITCOIN_POA_H From a5a915fd66965c8a536e82c9ff2dc54eae3b1e04 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Nov 2020 12:51:49 -0500 Subject: [PATCH 0503/1888] Use PoAFixTime for banning all previous versions --- src/net.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/net.cpp b/src/net.cpp index cf338c6898..9b2bef6815 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -126,6 +126,10 @@ unsigned short GetListenPort() { } bool IsUnsupportedVersion(std::string strSubVer) { + std::time_t banningTime = std::time(0); // t is an integer type + if (banningTime >= Params().PoAFixTime()) { + return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/" || strSubVer == "/DAPS:1.0.8/" || strSubVer == "/DAPS:1.0.8.1/" || strSubVer == "/DAPS:1.0.8.2/"); + } return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/"); } From d0b83905aa9921f3d17e668df74e17c14d7f89b6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Nov 2020 16:54:11 -0500 Subject: [PATCH 0504/1888] [Build] Update build system from upstream --- Makefile.am | 6 +- build-aux/m4/ax_boost_program_options.m4 | 7 +- build-aux/m4/ax_check_compile_flag.m4 | 12 +- build-aux/m4/ax_check_link_flag.m4 | 13 +- build-aux/m4/ax_check_preproc_flag.m4 | 12 +- build-aux/m4/ax_cxx_compile_stdcxx.m4 | 7 +- build-aux/m4/ax_gcc_func_attribute.m4 | 8 +- build-aux/m4/ax_pthread.m4 | 385 +++++++++++++++------- build-aux/m4/bitcoin_find_bdb48.m4 | 124 +++---- build-aux/m4/bitcoin_subdir_to_include.m4 | 4 + configure.ac | 294 ++++++++++++----- depends/config.site.in | 2 +- src/Makefile.am | 159 +++++---- src/Makefile.qt.include | 26 +- src/Makefile.qttest.include | 8 +- src/Makefile.test.include | 5 + 16 files changed, 692 insertions(+), 380 deletions(-) diff --git a/Makefile.am b/Makefile.am index 4c5cd4b932..9914b005be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,9 +6,13 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 SUBDIRS = src .PHONY: deploy FORCE -GZIP_ENV="-9n" export PYTHONPATH +if BUILD_BITCOIN_LIBS +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libbitcoinconsensus.pc +endif + BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) diff --git a/build-aux/m4/ax_boost_program_options.m4 b/build-aux/m4/ax_boost_program_options.m4 index f591441854..2bdb593716 100644 --- a/build-aux/m4/ax_boost_program_options.m4 +++ b/build-aux/m4/ax_boost_program_options.m4 @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 22 +#serial 24 AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], [ @@ -63,9 +63,9 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_CACHE_CHECK([whether the Boost::Program_Options library is available], ax_cv_boost_program_options, [AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::program_options::options_description generic("Generic options"); + [[boost::program_options::error err("Error message"); return 0;]])], ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no) AC_LANG_POP([C++]) @@ -74,7 +74,6 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` if test "x$ax_boost_user_program_options_lib" = "x"; then - ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4 index c3a8d695a1..ca3639715e 100644 --- a/build-aux/m4/ax_check_compile_flag.m4 +++ b/build-aux/m4/ax_check_compile_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 index e2d0d363e4..eb01a6ce13 100644 --- a/build-aux/m4/ax_check_link_flag.m4 +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # EXTRA-FLAGS FLAG". This can for example be used to force the linker to # issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. # @@ -53,18 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_LINK_FLAG], -[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ ax_check_save_flags=$LDFLAGS LDFLAGS="$LDFLAGS $4 $1" - AC_LINK_IFELSE([AC_LANG_PROGRAM()], + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) LDFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4 index b1cfef6b86..ca1d5ee2b6 100644 --- a/build-aux/m4/ax_check_preproc_flag.m4 +++ b/build-aux/m4/ax_check_preproc_flag.m4 @@ -4,7 +4,7 @@ # # SYNOPSIS # -# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # @@ -19,6 +19,8 @@ # "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the # preprocessor to issue an error when a bad flag is given. # +# INPUT gives an alternative input source to AC_PREPROC_IFELSE. +# # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG. # @@ -53,19 +55,19 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 4 AC_DEFUN([AX_CHECK_PREPROC_FLAG], -[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [ ax_check_save_flags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $4 $1" - AC_PREPROC_IFELSE([AC_LANG_PROGRAM()], + AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) CPPFLAGS=$ax_check_save_flags]) -AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], +AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4 index 2c18e49c56..3d45bae9d7 100644 --- a/build-aux/m4/ax_cxx_compile_stdcxx.m4 +++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4 @@ -57,8 +57,13 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + m4_if([$4], [], [ax_cxx_compile_cxx$1_try_default=true], + [$4], [default], [ax_cxx_compile_cxx$1_try_default=true], + [$4], [nodefault], [ax_cxx_compile_cxx$1_try_default=false], + [m4_fatal([invalid fourth argument `$4' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$4], [nodefault], [], [dnl AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, ax_cv_cxx_compile_cxx$1, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], @@ -66,7 +71,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [ax_cv_cxx_compile_cxx$1=no])]) if test x$ax_cv_cxx_compile_cxx$1 = xyes; then ac_success=yes - fi + fi]) m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then diff --git a/build-aux/m4/ax_gcc_func_attribute.m4 b/build-aux/m4/ax_gcc_func_attribute.m4 index 275ca63a2c..c788ca9bd4 100644 --- a/build-aux/m4/ax_gcc_func_attribute.m4 +++ b/build-aux/m4/ax_gcc_func_attribute.m4 @@ -31,6 +31,7 @@ # cold # const # constructor +# constructor_priority for constructor attribute with priority # deprecated # destructor # dllexport @@ -73,7 +74,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 2 +#serial 3 AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) @@ -103,6 +104,9 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [const], [ int foo( void ) __attribute__(($1)); ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], [constructor], [ int foo( void ) __attribute__(($1)); ], @@ -180,6 +184,8 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ [visibility], [ int foo_def( void ) __attribute__(($1("default"))); int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); ], [warning], [ int foo( void ) __attribute__(($1(""))); diff --git a/build-aux/m4/ax_pthread.m4 b/build-aux/m4/ax_pthread.m4 index d383ad5c6d..4c4051ea37 100644 --- a/build-aux/m4/ax_pthread.m4 +++ b/build-aux/m4/ax_pthread.m4 @@ -19,10 +19,10 @@ # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with +# but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # -# If you are only building threads programs, you may wish to use these +# If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" @@ -30,8 +30,8 @@ # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with @@ -82,35 +82,40 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 +#serial 23 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then + if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -123,7 +128,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -132,82 +137,225 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case ${host_os} in +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" ;; - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" ;; esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" +fi # $ax_pthread_clang = yes -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do - case $flag in + case $ax_pthread_try_flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we @@ -218,7 +366,11 @@ for flag in $ax_pthread_flags; do # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; @@ -227,16 +379,14 @@ for flag in $ax_pthread_flags; do pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) + [ax_pthread_ok=yes], + []) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) PTHREAD_LIBS="" PTHREAD_CFLAGS="" @@ -244,71 +394,74 @@ done fi # Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then + if test "x$GCC" != "xyes"; then case $host_os in aix*) AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi @@ -321,7 +474,7 @@ AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then +if test "x$ax_pthread_ok" = "xyes"; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4 index f3b14461eb..ea9c795daa 100644 --- a/build-aux/m4/bitcoin_find_bdb48.m4 +++ b/build-aux/m4/bitcoin_find_bdb48.m4 @@ -1,66 +1,78 @@ +dnl Copyright (c) 2013-2015 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + AC_DEFUN([BITCOIN_FIND_BDB48],[ - AC_MSG_CHECKING([for Berkeley DB C++ headers]) - BDB_CPPFLAGS= - BDB_LIBS= - bdbpath=X - bdb48path=X - bdbdirlist= - for _vn in 4.8 48 4 5 ''; do - for _pfx in b lib ''; do - bdbdirlist="$bdbdirlist ${_pfx}db${_vn}" + AC_ARG_VAR(BDB_CFLAGS, [C compiler flags for BerkeleyDB, bypasses autodetection]) + AC_ARG_VAR(BDB_LIBS, [Linker flags for BerkeleyDB, bypasses autodetection]) + + if test "x$BDB_CFLAGS" = "x"; then + AC_MSG_CHECKING([for Berkeley DB C++ headers]) + BDB_CPPFLAGS= + bdbpath=X + bdb48path=X + bdbdirlist= + for _vn in 4.8 48 4 5 5.3 ''; do + for _pfx in b lib ''; do + bdbdirlist="$bdbdirlist ${_pfx}db${_vn}" + done done - done - for searchpath in $bdbdirlist ''; do - test -n "${searchpath}" && searchpath="${searchpath}/" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <${searchpath}db_cxx.h> - ]],[[ - #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4) - #error "failed to find bdb 4.8+" - #endif - ]])],[ - if test "x$bdbpath" = "xX"; then - bdbpath="${searchpath}" - fi - ],[ - continue - ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #include <${searchpath}db_cxx.h> - ]],[[ - #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8) - #error "failed to find bdb 4.8" - #endif - ]])],[ - bdb48path="${searchpath}" - break - ],[]) - done - if test "x$bdbpath" = "xX"; then - AC_MSG_RESULT([no]) - AC_MSG_ERROR(libdb_cxx headers missing) - elif test "x$bdb48path" = "xX"; then - BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) - AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[ - AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!]) - ],[ - AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)]) - ]) + for searchpath in $bdbdirlist ''; do + test -n "${searchpath}" && searchpath="${searchpath}/" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <${searchpath}db_cxx.h> + ]],[[ + #if !((DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || DB_VERSION_MAJOR > 4) + #error "failed to find bdb 4.8+" + #endif + ]])],[ + if test "x$bdbpath" = "xX"; then + bdbpath="${searchpath}" + fi + ],[ + continue + ]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <${searchpath}db_cxx.h> + ]],[[ + #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 8) + #error "failed to find bdb 4.8" + #endif + ]])],[ + bdb48path="${searchpath}" + break + ],[]) + done + if test "x$bdbpath" = "xX"; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([libdb_cxx headers missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + elif test "x$bdb48path" = "xX"; then + BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdbpath}],db_cxx) + AC_ARG_WITH([incompatible-bdb],[AS_HELP_STRING([--with-incompatible-bdb], [allow using a bdb version other than 4.8])],[ + AC_MSG_WARN([Found Berkeley DB other than 4.8; wallets opened by this build will not be portable!]) + ],[ + AC_MSG_ERROR([Found Berkeley DB other than 4.8, required for portable wallets (--with-incompatible-bdb to ignore or --disable-wallet to disable wallet functionality)]) + ]) + else + BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx) + bdbpath="${bdb48path}" + fi else - BITCOIN_SUBDIR_TO_INCLUDE(BDB_CPPFLAGS,[${bdb48path}],db_cxx) - bdbpath="${bdb48path}" + BDB_CPPFLAGS=${BDB_CFLAGS} fi AC_SUBST(BDB_CPPFLAGS) - # TODO: Ideally this could find the library version and make sure it matches the headers being used - for searchlib in db_cxx-4.8 db_cxx; do - AC_CHECK_LIB([$searchlib],[main],[ - BDB_LIBS="-l${searchlib}" - break - ]) - done if test "x$BDB_LIBS" = "x"; then - AC_MSG_ERROR([libdb_cxx missing, Bitcoin Core requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + # TODO: Ideally this could find the library version and make sure it matches the headers being used + for searchlib in db_cxx-4.8 db_cxx db4_cxx; do + AC_CHECK_LIB([$searchlib],[main],[ + BDB_LIBS="-l${searchlib}" + break + ]) + done + if test "x$BDB_LIBS" = "x"; then + AC_MSG_ERROR([libdb_cxx missing, ]AC_PACKAGE_NAME[ requires this library for wallet functionality (--disable-wallet to disable wallet functionality)]) + fi fi AC_SUBST(BDB_LIBS) ]) diff --git a/build-aux/m4/bitcoin_subdir_to_include.m4 b/build-aux/m4/bitcoin_subdir_to_include.m4 index 66f106c7d4..7841042ac8 100644 --- a/build-aux/m4/bitcoin_subdir_to_include.m4 +++ b/build-aux/m4/bitcoin_subdir_to_include.m4 @@ -1,3 +1,7 @@ +dnl Copyright (c) 2013-2014 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + dnl BITCOIN_SUBDIR_TO_INCLUDE([CPPFLAGS-VARIABLE-NAME],[SUBDIRECTORY-NAME],[HEADER-FILE]) dnl SUBDIRECTORY-NAME must end with a path separator AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[ diff --git a/configure.ac b/configure.ac index bbf2b821c1..781e38194a 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,12 @@ BITCOIN_GUI_NAME=dapscoin-qt BITCOIN_CLI_NAME=dapscoin-cli BITCOIN_TX_NAME=dapscoin-tx +dnl Unless the user specified ARFLAGS, force it to be cr +AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to if not set]) +if test "x${ARFLAGS+set}" != "xset"; then + ARFLAGS="cr" +fi + AC_CANONICAL_HOST AH_TOP([#ifndef DAPS_CONFIG_H]) @@ -44,7 +50,6 @@ else CXXFLAGS_overridden=no fi AC_PROG_CXX -dnl ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX]) dnl By default, libtool for mingw refuses to link static libs into a dll for dnl fear of mixing pic/non-pic objects, and import/export complications. Since @@ -55,7 +60,9 @@ case $host in ;; esac dnl Require C++14 compiler (no GNU extensions) -AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory]) +AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory], [nodefault]) +dnl Check if -latomic is required for +CHECK_ATOMIC dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures dnl that we get the same -std flags for both. @@ -75,8 +82,8 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -AC_PATH_PROG(JAVA, java) -AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python]) +dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) +AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -90,8 +97,8 @@ AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files) # Enable wallet AC_ARG_ENABLE([wallet], - [AS_HELP_STRING([--enable-wallet], - [enable wallet (default is yes)])], + [AS_HELP_STRING([--disable-wallet], + [disable wallet (enabled by default)])], [enable_wallet=$enableval], [enable_wallet=yes]) @@ -108,7 +115,7 @@ AC_ARG_ENABLE([upnp-default], [use_upnp_default=no]) AC_ARG_ENABLE(tests, - AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), + AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]), [use_tests=$enableval], [use_tests=yes]) @@ -129,32 +136,32 @@ AC_ARG_WITH([qrencode], [use_qr=auto]) AC_ARG_ENABLE([hardening], - [AS_HELP_STRING([--enable-hardening], - [attempt to harden the resulting executables (default is yes)])], + [AS_HELP_STRING([--disable-hardening], + [do not attempt to harden the resulting executables (default is to harden)])], [use_hardening=$enableval], [use_hardening=yes]) AC_ARG_ENABLE([reduce-exports], [AS_HELP_STRING([--enable-reduce-exports], - [attempt to reduce exported symbols in the resulting executables (default is yes)])], + [attempt to reduce exported symbols in the resulting executables (default is no)])], [use_reduce_exports=$enableval], - [use_reduce_exports=auto]) + [use_reduce_exports=no]) AC_ARG_ENABLE([ccache], - [AS_HELP_STRING([--enable-ccache], - [use ccache for building (default is yes if ccache is found)])], + [AS_HELP_STRING([--disable-ccache], + [do not use ccache for building (default is to use if found)])], [use_ccache=$enableval], [use_ccache=auto]) AC_ARG_ENABLE([lcov], [AS_HELP_STRING([--enable-lcov], [enable lcov testing (default is no)])], - [use_lcov=yes], + [use_lcov=$enableval], [use_lcov=no]) AC_ARG_ENABLE([glibc-back-compat], [AS_HELP_STRING([--enable-glibc-back-compat], - [enable backwards compatibility with glibc and libstdc++])], + [enable backwards compatibility with glibc])], [use_glibc_compat=$enableval], [use_glibc_compat=no]) @@ -179,24 +186,55 @@ AC_ARG_ENABLE([debug], [use debug compiler flags and macros (default is no)])], [enable_debug=$enableval], [enable_debug=no]) + +# Turn warnings into errors +AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--enable-werror], + [Treat certain compiler warnings as errors (default is no)])], + [enable_werror=$enableval], + [enable_werror=no]) + +AC_LANG_PUSH([C++]) +AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""]) if test "x$enable_debug" = xyes; then + CPPFLAGS="$CPPFLAGS -DDEBUG -DDEBUG_LOCKORDER" if test "x$GCC" = xyes; then - CFLAGS="-g3 -O0 -DDEBUG" + CFLAGS="$CFLAGS -g3 -O0" fi if test "x$GXX" = xyes; then - CXXFLAGS="-g3 -O0 -DDEBUG" + CXXFLAGS="$CXXFLAGS -g3 -O0" fi fi -## TODO: Remove these hard-coded paths and flags. They are here for the sake of -## compatibility with the legacy buildsystem. -## +ERROR_CXXFLAGS= +if test "x$enable_werror" = "xyes"; then + if test "x$CXXFLAG_WERROR" = "x"; then + AC_MSG_ERROR("enable-werror set but -Werror is not usable") + fi + AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Werror=thread-safety-analysis],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=thread-safety-analysis"],,[[$CXXFLAG_WERROR]]) +fi + if test "x$CXXFLAGS_overridden" = "xno"; then - CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter" + AX_CHECK_COMPILE_FLAG([-Wall],[CXXFLAGS="$CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wextra],[CXXFLAGS="$CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[CXXFLAGS="$CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]]) + + ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all + ## unknown options if any other warning is produced. Test the -Wfoo case, and + ## set the -Wno-foo case if it works. + AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[CXXFLAGS="$CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wself-assign],[CXXFLAGS="$CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[CXXFLAGS="$CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) fi -CPPFLAGS="$CPPFLAGS -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" +CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], @@ -216,8 +254,6 @@ AC_ARG_WITH([daemon], [build_bitcoind=$withval], [build_bitcoind=yes]) -AC_LANG_PUSH([C++]) - #AX_CXX_CHECK_LIB([boost_regex-mt],[boost::regex::generic_category()],[BOOST_LIB_SUFFIX="-mt"],[BOOST_LIB_SUFFIX=""]) use_pkgconfig=yes @@ -348,6 +384,7 @@ case $host in AX_CHECK_LINK_FLAG([[-Wl,-headerpad_max_install_names]], [LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names"]) CPPFLAGS="$CPPFLAGS -DMAC_OSX" + OBJCXXFLAGS="$CXXFLAGS" ;; *android*) dnl make sure android stays above linux for hosts like *linux-android* @@ -391,18 +428,19 @@ if test x$use_lcov = xyes; then if test x$GCOV = x; then AC_MSG_ERROR("lcov testing requested but gcov not found") fi - if test x$JAVA = x; then - AC_MSG_ERROR("lcov testing requested but java not found") + if test x$PYTHON = x; then + AC_MSG_ERROR("lcov testing requested but python not found") fi if test x$GENHTML = x; then AC_MSG_ERROR("lcov testing requested but genhtml not found") fi - if test x$use_comparison_tool = x; then - AC_MSG_ERROR("lcov testing requested but comparison tool was not specified") - fi LCOV="$LCOV --gcov-tool=$GCOV" + AX_CHECK_LINK_FLAG([[--coverage]], [LDFLAGS="$LDFLAGS --coverage"], + [AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")]) AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"], [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) + AC_DEFINE(USE_COVERAGE, 1, [Define this symbol if coverage is enabled]) + CXXFLAGS="$CXXFLAGS -Og" fi dnl Require little endian @@ -438,6 +476,10 @@ AX_GCC_FUNC_ATTRIBUTE([dllimport]) if test x$use_glibc_compat != xno; then + #glibc absorbed clock_gettime in 2.17. librt (its previous location) is safe to link + #in anyway for back-compat. + AC_CHECK_LIB([rt],[clock_gettime],, AC_MSG_ERROR(lib missing)) + #__fdelt_chk's params and return type have changed from long unsigned int to long int. # See which one is present here. AC_MSG_CHECKING(__fdelt_chk type) @@ -453,7 +495,8 @@ if test x$use_glibc_compat != xno; then AC_DEFINE_UNQUOTED(FDELT_TYPE, $fdelt_type,[parameter and return value type for __fdelt_chk]) AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"]) AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"]) - +else + AC_SEARCH_LIBS([clock_gettime],[rt]) fi if test x$use_hardening != xno; then @@ -469,12 +512,12 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"]) AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"]) + AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"]) AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"]) AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) if test x$TARGET_OS != xwindows; then - # All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_COMPILE_FLAG([-fPIC],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIC"]) + AX_CHECK_COMPILE_FLAG([-fPIC],[PIE_FLAGS="-fPIC"]) AX_CHECK_LINK_FLAG([[-pic]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pic"]) fi @@ -483,11 +526,6 @@ if test x$use_hardening != xno; then AC_CHECK_LIB([ssp], [main],, AC_MSG_ERROR(lib missing)) ;; esac - - CXXFLAGS="$CXXFLAGS $HARDENED_CXXFLAGS" - CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" - LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" - OBJCXXFLAGS="$CXXFLAGS" fi dnl this flag screws up non-darwin gcc even when the check fails. special-case it. @@ -501,6 +539,9 @@ AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define AC_CHECK_DECLS([strnlen]) +# Check for daemon(3), unrelated to --with-daemon (although used by it) +AC_CHECK_DECLS([daemon]) + AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,, [#if HAVE_ENDIAN_H #include @@ -514,7 +555,29 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [ AC_MSG_RESULT(no)] ) -AC_SEARCH_LIBS([clock_gettime],[rt]) +dnl Check for MSG_DONTWAIT +AC_MSG_CHECKING(for MSG_DONTWAIT) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ int f = MSG_DONTWAIT; ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ], + [ AC_MSG_RESULT(no)] +) + +dnl Check for malloc_info (for memory statistics information in getmemoryinfo) +AC_MSG_CHECKING(for getmemoryinfo) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ int f = malloc_info(0, NULL); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOC_INFO, 1,[Define this symbol if you have malloc_info]) ], + [ AC_MSG_RESULT(no)] +) + +dnl Check for mallopt(M_ARENA_MAX) (to set glibc arenas) +AC_MSG_CHECKING(for mallopt M_ARENA_MAX) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ mallopt(M_ARENA_MAX, 1); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOPT_ARENA_MAX, 1,[Define this symbol if you have mallopt with M_ARENA_MAX]) ], + [ AC_MSG_RESULT(no)] +) AC_MSG_CHECKING([for visibility attribute]) AC_LINK_IFELSE([AC_LANG_SOURCE([ @@ -528,22 +591,37 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ [ AC_MSG_RESULT(no) if test x$use_reduce_exports = xyes; then - AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduced-exports.]) + AC_MSG_ERROR([Cannot find a working visibility attribute. Use --disable-reduce-exports.]) fi - AC_MSG_WARN([Cannot find a working visibility attribute. Disabling reduced exports.]) - use_reduce_exports=no ] ) -if test x$use_reduce_exports != xno; then - AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], +TEMP_LDFLAGS="$LDFLAGS" +LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS" +AC_MSG_CHECKING([for thread_local support]) +AC_LINK_IFELSE([AC_LANG_SOURCE([ + #include + static thread_local int foo = 0; + static void run_thread() { foo++;} + int main(){ + for(int i = 0; i < 10; i++) { std::thread(run_thread).detach();} + return foo; + } + ])], [ - if test x$use_reduce_exports = xyes; then - AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduced-exports.]) - fi - AC_MSG_WARN([Cannot set default symbol visibility. Disabling reduced exports.]) - use_reduce_exports=no - ]) + AC_DEFINE(HAVE_THREAD_LOCAL,1,[Define if thread_local is supported.]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] +) +LDFLAGS="$TEMP_LDFLAGS" + +# Check for reduced exports +if test x$use_reduce_exports = xyes; then + AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], + [AC_MSG_ERROR([Cannot set default symbol visibility. Use --disable-reduce-exports.])]) fi LEVELDB_CPPFLAGS= @@ -579,22 +657,13 @@ else use_boost=yes fi -if test x$bitcoin_enable_qt = xyes; then -dnl enable tradingdialog - AC_MSG_CHECKING([if the trading dialog should be enabled]) - if test x$bitcoin_qt_got_major_vers = x5; then - AC_MSG_RESULT(yes) - AC_DEFINE_UNQUOTED([HAVE_QT5],[1],[Define to 1 to enable trading dialog]) - - else - AC_MSG_RESULT(no) - fi -fi - if test x$use_boost = xyes; then +dnl Minimum required Boost version +define(MINIMUM_REQUIRED_BOOST, 1.47.0) + dnl Check for boost libs -AX_BOOST_BASE +AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST]) AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM AX_BOOST_PROGRAM_OPTIONS @@ -602,8 +671,12 @@ AX_BOOST_THREAD AX_BOOST_CHRONO AX_BOOST_REGEX +dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic +dnl counter implementations. In 1.63 and later the std::atomic approach is default. +m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro +BOOST_CPPFLAGS="-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS" -if test x$use_reduce_exports != xno; then +if test x$use_reduce_exports = xyes; then AC_MSG_CHECKING([for working boost reduced exports]) TEMP_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS" @@ -617,25 +690,14 @@ if test x$use_reduce_exports != xno; then #endif ]])],[ AC_MSG_RESULT(yes) - ],[: - if test x$use_reduce_exports = xauto; then - use_reduce_exports=no - else - if test x$use_reduce_exports = xyes; then - AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduced-exports.]) - fi - fi - AC_MSG_RESULT(no) - AC_MSG_WARN([boost versions < 1.49 are known to have symbol visibility issues. Disabling reduced exports.]) + ],[ + AC_MSG_ERROR([boost versions < 1.49 are known to be broken with reduced exports. Use --disable-reduce-exports.]) ]) CPPFLAGS="$TEMP_CPPFLAGS" fi - -elif test x$use_reduce_exports = xauto; then - use_reduce_exports=yes fi -if test x$use_reduce_exports != xno; then +if test x$use_reduce_exports = xyes; then CXXFLAGS="$CXXFLAGS $RE_CXXFLAGS" AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]], [RELDFLAGS="-Wl,--exclude-libs,ALL"]) fi @@ -674,7 +736,42 @@ fi if test x$use_boost = xyes; then -BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_REGEX_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB" +BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB" + +dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums +dnl using c++98 constructs. Unfortunately, this implementation detail leaked into +dnl the abi. This was fixed in 1.57. + +dnl When building against that installed version using c++11, the headers pick up +dnl on the native c++11 scoped enum support and enable it, however it will fail to +dnl link. This can be worked around by disabling c++11 scoped enums if linking will +dnl fail. +dnl BOOST_NO_SCOPED_ENUMS was changed to BOOST_NO_CXX11_SCOPED_ENUMS in 1.51. + +TEMP_LIBS="$LIBS" +LIBS="$BOOST_LIBS $LIBS" +TEMP_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" +AC_MSG_CHECKING([for mismatched boost c++11 scoped enums]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700 + #define BOOST_NO_SCOPED_ENUMS + #define BOOST_NO_CXX11_SCOPED_ENUMS + #define CHECK + #endif + #include + ]],[[ + #if defined(CHECK) + boost::filesystem::copy_file("foo", "bar"); + #else + choke; + #endif + ]])], + [AC_MSG_RESULT(mismatched); BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS"], [AC_MSG_RESULT(ok)]) +LIBS="$TEMP_LIBS" +CPPFLAGS="$TEMP_CPPFLAGS" dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if @@ -749,6 +846,7 @@ if test x$use_pkgconfig = xyes; then PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)]) fi fi + if test "x$use_zmq" = "xyes"; then PKG_CHECK_MODULES([ZMQ],[libzmq >= 4], [AC_DEFINE([ENABLE_ZMQ],[1],[Define to 1 to enable ZMQ functions])], @@ -758,7 +856,6 @@ if test x$use_pkgconfig = xyes; then else AC_DEFINE_UNQUOTED([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions]) fi - ] ) else @@ -777,15 +874,15 @@ else fi if test "x$use_zmq" = "xyes"; then - AC_CHECK_HEADER([zmq.h], - [AC_DEFINE([ENABLE_ZMQ],[1],[Define to 1 to enable ZMQ functions])], - [AC_MSG_WARN([zmq.h not found, disabling zmq support]) - use_zmq=no - AC_DEFINE([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions])]) - AC_CHECK_LIB([zmq],[zmq_ctx_shutdown],ZMQ_LIBS=-lzmq, - [AC_MSG_WARN([libzmq >= 4.0 not found, disabling zmq support]) - use_zmq=no - AC_DEFINE([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions])]) + AC_CHECK_HEADER([zmq.h], + [AC_DEFINE([ENABLE_ZMQ],[1],[Define to 1 to enable ZMQ functions])], + [AC_MSG_WARN([zmq.h not found, disabling zmq support]) + use_zmq=no + AC_DEFINE([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions])]) + AC_CHECK_LIB([zmq],[zmq_ctx_shutdown],ZMQ_LIBS=-lzmq, + [AC_MSG_WARN([libzmq >= 4.0 not found, disabling zmq support]) + use_zmq=no + AC_DEFINE([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions])]) else AC_DEFINE_UNQUOTED([ENABLE_ZMQ],[0],[Define to 1 to enable ZMQ functions]) fi @@ -986,7 +1083,7 @@ else fi AC_MSG_CHECKING([whether to reduce exports]) -if test x$use_reduce_exports != xno; then +if test x$use_reduce_exports = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) @@ -1006,9 +1103,8 @@ AM_CONDITIONAL([HAVE_QT5], [test x$bitcoin_qt_got_major_vers = x5]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) -AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno]) -AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) +AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AM_CONDITIONAL([USE_LIBSECP256K1],[test x$use_libsecp256k1 = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) @@ -1029,6 +1125,12 @@ AC_SUBST(BITCOIN_CLI_NAME) AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) +AC_SUBST(ERROR_CXXFLAGS) +AC_SUBST(HARDENED_CXXFLAGS) +AC_SUBST(HARDENED_CPPFLAGS) +AC_SUBST(HARDENED_LDFLAGS) +AC_SUBST(PIC_FLAGS) +AC_SUBST(PIE_FLAGS) AC_SUBST(COMPAT_LDFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) @@ -1099,6 +1201,14 @@ case $host in ;; esac +dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows +case ${OS} in + *Windows*) + sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' test/config.ini > test/config-2.ini + mv test/config-2.ini test/config.ini + ;; +esac + echo echo "Options used to compile and link:" echo " with wallet = $enable_wallet" @@ -1111,6 +1221,7 @@ echo " with test = $use_tests" dnl echo " with bench = $use_bench" echo " with upnp = $use_upnp" echo " debug enabled = $enable_debug" +echo " werror = $enable_werror" echo echo " target os = $TARGET_OS" echo " build os = $BUILD_OS" @@ -1121,6 +1232,7 @@ echo " CPPFLAGS = $CPPFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $CXXFLAGS" echo " LDFLAGS = $LDFLAGS" +echo " ARFLAGS = $ARFLAGS" echo " PIC_FLAGS = $PIC_FLAGS" echo " QT_PIE_FLAGS = $QT_PIE_FLAGS" echo diff --git a/depends/config.site.in b/depends/config.site.in index 9842a672e6..7cadfa705f 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -62,7 +62,7 @@ PKG_CONFIG="`which pkg-config` --static" # avoid ruining the cache. Sigh. export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig if test -z "@allow_host_packages@"; then - export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig + export PKGCONFIG_LIBDIR= fi CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" diff --git a/src/Makefile.am b/src/Makefile.am index 82f538abf3..1e5c75b4c2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,7 @@ +# 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 secp256k1-mw univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) @@ -26,7 +30,7 @@ $(LIBLEVELDB): $(LIBMEMENV) $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(CXXFLAGS) $(CPPFLAGS)" + OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config @@ -38,7 +42,6 @@ BITCOIN_INCLUDES += -I$(srcdir)/zxcvbn BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) LIBBITCOIN_SERVER=libbitcoin_server.a -LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a @@ -46,6 +49,17 @@ LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la LIBSECP256K1_2=secp256k1-mw/libsecp256k1_2.la +LIBBITCOIN_ZXCVBN=libbitcoin_zxcvbn.a + +if ENABLE_ZMQ +LIBBITCOIN_ZMQ=libbitcoin_zmq.a +endif +if BUILD_BITCOIN_LIBS +LIBBITCOINCONSENSUS=libbitcoinconsensus.la +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) @@ -54,31 +68,20 @@ $(LIBSECP256K1_2): $(wildcard secp256k1-mw/src/*) $(wildcard secp256k1-mw/includ # 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 = \ - crypto/libbitcoin_crypto.a \ - libbitcoin_util.a \ - libbitcoin_common.a \ - libbitcoin_server.a \ - libbitcoin_cli.a -if ENABLE_WALLET -BITCOIN_INCLUDES += $(BDB_CPPFLAGS) -EXTRA_LIBRARIES += libbitcoin_wallet.a -EXTRA_LIBRARIES += libboost_regex.a -endif - -if ENABLE_ZMQ -EXTRA_LIBRARIES += libbitcoin_zmq.a -endif -EXTRA_LIBRARIES += libbitcoin_zxcvbn.a +EXTRA_LIBRARIES += \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_CLI) \ + $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_ZMQ) \ + $(LIBBITCOIN_ZXCVBN) -if BUILD_BITCOIN_LIBS -lib_LTLIBRARIES = libbitcoinconsensus.la -LIBBITCOIN_CONSENSUS=libbitcoinconsensus.la -else -LIBBITCOIN_CONSENSUS= -endif +lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) bin_PROGRAMS = +noinst_PROGRAMS = TESTS = if BUILD_BITCOIND @@ -188,17 +191,17 @@ BITCOIN_CORE_H = \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h \ zmq/zmqnotificationinterface.h \ - zmq/zmqpublishnotifier.h \ - compat/sanity.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) + @$(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 dapscoind and dapscoin-qt -libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +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 \ bloom.cpp \ @@ -232,8 +235,6 @@ libbitcoin_server_a_SOURCES = \ $(BITCOIN_CORE_H) if ENABLE_ZMQ -LIBBITCOIN_ZMQ=libbitcoin_zmq.a - libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ @@ -242,8 +243,6 @@ libbitcoin_zmq_a_SOURCES = \ zmq/zmqpublishnotifier.cpp endif -LIBBITCOIN_ZXCVBN=libbitcoin_zxcvbn.a - libbitcoin_zxcvbn_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_zxcvbn_a_CXXFLAGS = $(AM_CXXFLAGS) libbitcoin_zxcvbn_a_SOURCES = \ @@ -261,8 +260,8 @@ libbitcoin_zxcvbn_a_SOURCES = \ # wallet: shared between dapscoind and dapscoin-qt, but only linked # when wallet enabled -libbitcoin_wallet_a_CFLAGS = -fPIC -libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ activemasternode.cpp \ bip38.cpp \ @@ -286,8 +285,8 @@ libbitcoin_wallet_a_SOURCES = \ $(BITCOIN_CORE_H) # crypto primitives library -crypto_libbitcoin_crypto_a_CFLAGS = -fPIC -crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES) +crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) +crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sha1.cpp \ crypto/sha256.cpp \ @@ -322,7 +321,8 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sph_types.h # common: shared between dapscoind, and dapscoin-qt and non-server tools -libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) +libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ allocators.cpp \ amount.cpp \ @@ -356,7 +356,8 @@ libbitcoin_common_a_SOURCES = \ # 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 = $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ allocators.cpp \ compat/strnlen.cpp \ @@ -377,12 +378,12 @@ libbitcoin_util_a_SOURCES = \ if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp -libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp AM_LDFLAGS += $(COMPAT_LDFLAGS) endif # cli: shared between dapscoin-cli and dapscoin-qt -libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES) +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) @@ -390,77 +391,76 @@ libbitcoin_cli_a_SOURCES = \ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # -# bitcoind binary # +# dapscoind binary # +dapscoind_SOURCES = dapscoind.cpp +dapscoind_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +dapscoind_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +dapscoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if TARGET_WINDOWS +dapscoind_SOURCES += dapscoind-res.rc +endif dapscoind_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_WALLET) \ + $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ $(LIBSECP256K1_2) -if ENABLE_ZMQ -dapscoind_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif +dapscoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) -if ENABLE_WALLET -dapscoind_LDADD += libbitcoin_wallet.a $(LIBBITCOIN_ZXCVBN) -endif -dapscoind_SOURCES = dapscoind.cpp -# +# dapscoin-cli binary # +dapscoin_cli_SOURCES = dapscoin-cli.cpp +dapscoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +dapscoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +dapscoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) if TARGET_WINDOWS -dapscoind_SOURCES += dapscoind-res.rc +dapscoin_cli_SOURCES += dapscoin-cli-res.rc endif -dapscoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) -dapscoind_CPPFLAGS = $(BITCOIN_INCLUDES) -dapscoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) - - -# dapscoin-cli binary # dapscoin_cli_LDADD = \ $(LIBBITCOIN_CLI) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ - $(BOOST_LIBS) \ - $(SSL_LIBS) \ - $(CRYPTO_LIBS) \ - $(EVENT_LIBS) \ $(LIBSECP256K1) \ $(LIBSECP256K1_2) dapscoin_cli_SOURCES = \ dapscoin-cli.cpp -dapscoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +dapscoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # # dapscoin-tx binary # +dapscoin_tx_SOURCES = dapscoin-tx.cpp +dapscoin_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +dapscoin_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +dapscoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if TARGET_WINDOWS +dapscoin_tx_SOURCES += dapscoin-tx-res.rc +endif + dapscoin_tx_LDADD = \ $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) \ - $(BOOST_LIBS) \ - $(CRYPTO_LIBS) \ $(LIBSECP256K1_2) -dapscoin_tx_SOURCES = dapscoin-tx.cpp -dapscoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES) +dapscoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # -dapscoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) - -if TARGET_WINDOWS -dapscoin_cli_SOURCES += dapscoin-cli-res.rc -endif -dapscoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +# bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h libbitcoinconsensus_la_SOURCES = \ @@ -484,10 +484,9 @@ libbitcoinconsensus_la_SOURCES = \ if GLIBC_BACK_COMPAT libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp - libbitcoinconsensus_la_SOURCES += compat/glibcxx_compat.cpp endif -libbitcoinconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) +libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) libbitcoinconsensus_la_LIBADD = $(CRYPTO_LIBS) $(BOOST_LIBS) libbitcoinconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL if USE_LIBSECP256K1 @@ -496,7 +495,8 @@ libbitcoinconsensus_la_LIBADD += secp256k1-mw/libsecp256k1_2.la endif endif -CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a +CLEANFILES = $(EXTRA_LIBRARIES) +CLEANFILES += leveldb/libleveldb.a leveldb/libmemenv.a CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno @@ -504,8 +504,7 @@ CLEANFILES += primitives/*.gcda primitives/*.gcno CLEANFILES += script/*.gcda script/*.gcno CLEANFILES += univalue/*.gcda univalue/*.gcno CLEANFILES += zmq/*.gcda zmq/*.gcno - -DISTCLEANFILES = obj/build.h +CLEANFILES += obj/build.h EXTRA_DIST = leveldb @@ -529,13 +528,9 @@ clean-local: ## 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) $(CXXFLAGS) -c -o $@ $< - %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) - $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $( locale/foo.qm QT_QM=$(QT_TS:.ts=.qm) -.SECONDARY: $(QT_QM) +SECONDARY: $(QT_QM) -qt/dapscoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) +$(srcdir)/qt/dapscoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_util_a_SOURCES) @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) $(PYTHON) ../share/qt/extract_strings_qt.py $^ + $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" $(PYTHON) ../share/qt/extract_strings_qt.py $^ -translate: qt/dapscoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/dapscoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts qt/locale/dapscoin_en.ts + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/dapscoin_en.ts $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) - @test -f $(@D)/$( $@ + @rm $(@D)/temp_$( $@ -CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno +CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_dapscoin_locale.qrc CLEANFILES += $(CLEAN_QT) @@ -481,11 +487,11 @@ ui_%.h: %.ui $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false) %.moc: %.cpp - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES) $(MOC_DEFS) $< | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ moc_%.cpp: %.h - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES) $(MOC_DEFS) $< | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ %.qm: %.ts diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index ffb495606b..d17d4e2ed2 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -1,3 +1,6 @@ +# 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. bin_PROGRAMS += qt/test/test_dapscoin-qt TESTS += qt/test/test_dapscoin-qt @@ -12,7 +15,7 @@ TEST_QT_H = \ qt/test/paymentrequestdata.h \ qt/test/paymentservertests.h -qt_test_test_dapscoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ +qt_test_test_dapscoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_dapscoin_qt_SOURCES = \ @@ -36,8 +39,9 @@ endif qt_test_test_dapscoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ - $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) + $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_test_test_dapscoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8acad71485..3e9e16d62e 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,3 +1,6 @@ +# 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. TESTS += test/test_dapscoin test/bitcoin-util-test.py bin_PROGRAMS += test/test_dapscoin TEST_SRCDIR = test @@ -33,6 +36,7 @@ RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) +# test_dapscoin binary # BITCOIN_TESTS =\ test/allocator_tests.cpp \ test/base32_tests.cpp \ @@ -89,6 +93,7 @@ test_test_dapscoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C if ENABLE_WALLET test_test_dapscoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBSECP256K1) $(LIBSECP256K1_2) endif +test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_dapscoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(ZMQ_LIBS) test_test_dapscoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static From 03889d7499eab8c205b1661f47195dde031b4675 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Nov 2020 18:59:08 -0500 Subject: [PATCH 0505/1888] Fix VLA error in hash.h Prior updates to the build system now treat VLAs as errors, so we need to fix `src/hash.h` --- src/hash.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hash.h b/src/hash.h index 45aecf343a..9397803203 100644 --- a/src/hash.h +++ b/src/hash.h @@ -40,9 +40,9 @@ class CHash256 void Finalize(unsigned char hash[OUTPUT_SIZE]) { - unsigned char buf[sha.OUTPUT_SIZE]; + unsigned char buf[CSHA256::OUTPUT_SIZE]; sha.Finalize(buf); - sha.Reset().Write(buf, sha.OUTPUT_SIZE).Finalize(hash); + sha.Reset().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash); } CHash256& Write(const unsigned char* data, size_t len) @@ -100,9 +100,9 @@ class CHash160 void Finalize(unsigned char hash[OUTPUT_SIZE]) { - unsigned char buf[sha.OUTPUT_SIZE]; + unsigned char buf[CSHA256::OUTPUT_SIZE]; sha.Finalize(buf); - CRIPEMD160().Write(buf, sha.OUTPUT_SIZE).Finalize(hash); + CRIPEMD160().Write(buf, CSHA256::OUTPUT_SIZE).Finalize(hash); } CHash160& Write(const unsigned char* data, size_t len) From 3605afe884ffa36948b78ecdf210976836a6c3e6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Nov 2020 19:02:19 -0500 Subject: [PATCH 0506/1888] Use and define `strnlen` if not already defined `strnlen()` is defined on a number of systems already, however older versions of OS X don't define it. Rather than using a custom `strnlen_int()` function to avoid double-declaration, wrap our own declaration in a precompiler conditional instead. --- src/compat.h | 4 +++- src/compat/strnlen.cpp | 7 ++++--- src/protocol.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/compat.h b/src/compat.h index 7af7acc22e..9e583c8529 100644 --- a/src/compat.h +++ b/src/compat.h @@ -88,7 +88,9 @@ typedef u_int SOCKET; #define THREAD_PRIORITY_ABOVE_NORMAL (-2) #endif -size_t strnlen_int(const char* start, size_t max_len); +#if HAVE_DECL_STRNLEN == 0 +size_t strnlen( const char *start, size_t max_len); +#endif // HAVE_DECL_STRNLEN bool static inline IsSelectableSocket(SOCKET s) { diff --git a/src/compat/strnlen.cpp b/src/compat/strnlen.cpp index cad027e501..ee41986bbc 100644 --- a/src/compat/strnlen.cpp +++ b/src/compat/strnlen.cpp @@ -7,11 +7,12 @@ #endif #include -// OSX 10.6 is missing strnlen at runtime, but builds targetting it will still -// succeed. Define our own version here to avoid a crash. -size_t strnlen_int( const char *start, size_t max_len) + +#if HAVE_DECL_STRNLEN == 0 +size_t strnlen( const char *start, size_t max_len) { const char *end = (const char *)memchr(start, '\0', max_len); return end ? (size_t)(end - start) : max_len; } +#endif // HAVE_DECL_STRNLEN \ No newline at end of file diff --git a/src/protocol.cpp b/src/protocol.cpp index 73040b742a..c1e06e9640 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -51,7 +51,7 @@ CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSize std::string CMessageHeader::GetCommand() const { - return std::string(pchCommand, pchCommand + strnlen_int(pchCommand, COMMAND_SIZE)); + return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE)); } bool CMessageHeader::IsValid() const From 811fabff7f4ab66c1bd529486b6784164e27ae63 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Nov 2020 19:18:39 -0500 Subject: [PATCH 0507/1888] mac: update macdeployqtplus and Info.plist.in Removed an unused variable from `macdeployqtplus`, typos fixed, and added two keys to the Mac `Info.plist.in` file. --- contrib/macdeploy/macdeployqtplus | 10 ++++------ share/qt/Info.plist.in | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 8365853a15..6003f2a591 100644 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -302,7 +302,6 @@ def copyFramework(framework, path, verbose): if os.path.exists(fromContentsDir): toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory) shutil.copytree(fromContentsDir, toContentsDir, symlinks=True) - contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory) if verbose >= 3: print("Copied Contents:", fromContentsDir) print(" to:", toContentsDir) @@ -340,7 +339,7 @@ def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploym # install_name_tool the new id into the binary changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose) - # Copy farmework to app bundle. + # Copy framework to app bundle. deployedBinaryPath = copyFramework(framework, bundlePath, verbose) # Skip the rest if already was deployed. if deployedBinaryPath is None: @@ -492,7 +491,7 @@ ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, h ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool") ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") -ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace") +ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's resources; the language list must be separated with commas, not with whitespace") ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translation files") ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument") ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg") @@ -675,9 +674,8 @@ else: if verbose >= 2: print("+ Installing qt.conf +") -f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") -f.write(qt_conf.encode()) -f.close() +with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f: + f.write(qt_conf.encode()) # ------------------------------------------------ diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index a0c4745b9d..b60277d3aa 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -30,6 +30,12 @@ CFBundleExecutable DAPScoin-Qt + + CFBundleName + DAPScoin-Qt + + LSHasLocalizedDisplayName + CFBundleIdentifier io.dapscoin.Dapscoin-Qt From b56e5c9026b3832b65474d4c5fc464b8d54c1cac Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Nov 2020 19:38:11 -0500 Subject: [PATCH 0508/1888] travis: switch to minimal travis image Also increase timeout for tests --- .travis.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4bd872a314..3b6eb2cd9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,8 @@ sudo: required dist: trusty -#workaround for https://github.com/travis-ci/travis-ci/issues/5227 -addons: - hostname: dapscoin-tester - os: linux -language: generic +language: minimal cache: directories: - depends/built @@ -24,7 +20,6 @@ env: - CCACHE_COMPRESS=1 - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out - SDK_URL=https://bitcoincore.org/depends-sources/sdks - - PYTHON_DEBUG=1 - WINEDEBUG=fixme-all matrix: # ARM @@ -37,24 +32,22 @@ env: - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" # dapscoind - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" PYZMQ=true - # No wallet # - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" # Cross-Mac - - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" + - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" before_install: - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") install: - if [ "$PYZMQ" = "true" ]; then pip install pyzmq --user ; fi - - if [ -n "$PPA" ]; then travis_retry sudo add-apt-repository "$PPA" -y; fi - if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi before_script: - - unset CC; unset CXX - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi - if [ "$CHECK_LOGPRINT" = 1 ]; then contrib/devtools/logprint-scanner.py; fi + - unset CC; unset CXX - mkdir -p depends/SDKs depends/sdk-sources - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi @@ -72,7 +65,7 @@ script: - ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi + - if [ "$RUN_TESTS" = "true" ]; then travis_wait 30 make $MAKEJOBS check VERBOSE=1; fi #- if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi after_script: - echo $TRAVIS_COMMIT_RANGE From 410c62068254dce25740c4b4dd4ca3133e042279 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 24 Nov 2020 21:10:51 -0500 Subject: [PATCH 0509/1888] Remove EXTRA_LIBRARIES for libqgoogleauth.a --- src/Makefile.qt.include | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 2b49152225..61840bee79 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -4,7 +4,6 @@ bin_PROGRAMS += qt/dapscoin-qt EXTRA_LIBRARIES += qt/libbitcoinqt.a -EXTRA_LIBRARIES += qt/lib/libqgoogleauth.a # dapscoin qt core # QT_TS = \ From 8a890c22e0c32cb4f7b856f1193e02f6b889abbf Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Nov 2020 11:27:43 -0500 Subject: [PATCH 0510/1888] remove univalue sources, prepare for subtree merge --- src/univalue/.gitignore | 32 -- src/univalue/.travis.yml | 52 -- src/univalue/COPYING | 19 - src/univalue/Makefile.am | 115 ----- src/univalue/README.md | 32 -- src/univalue/TODO | 10 - src/univalue/autogen.sh | 9 - src/univalue/build-aux/m4/.gitignore | 1 - src/univalue/configure.ac | 69 --- src/univalue/include/univalue.h | 296 ------------ src/univalue/lib/.gitignore | 2 - src/univalue/lib/univalue.cpp | 359 -------------- src/univalue/lib/univalue_escapes.h | 262 ---------- src/univalue/lib/univalue_read.cpp | 454 ------------------ src/univalue/lib/univalue_utffilter.h | 119 ----- src/univalue/lib/univalue_write.cpp | 115 ----- src/univalue/pc/libunivalue-uninstalled.pc.in | 9 - src/univalue/pc/libunivalue.pc.in | 10 - src/univalue/test/fail1.json | 1 - src/univalue/test/fail10.json | 1 - src/univalue/test/fail11.json | 1 - src/univalue/test/fail12.json | 1 - src/univalue/test/fail13.json | 1 - src/univalue/test/fail14.json | 1 - src/univalue/test/fail15.json | 1 - src/univalue/test/fail16.json | 1 - src/univalue/test/fail17.json | 1 - src/univalue/test/fail18.json | 1 - src/univalue/test/fail19.json | 1 - src/univalue/test/fail2.json | 1 - src/univalue/test/fail20.json | 1 - src/univalue/test/fail21.json | 1 - src/univalue/test/fail22.json | 1 - src/univalue/test/fail23.json | 1 - src/univalue/test/fail24.json | 1 - src/univalue/test/fail25.json | 1 - src/univalue/test/fail26.json | 1 - src/univalue/test/fail27.json | 2 - src/univalue/test/fail28.json | 2 - src/univalue/test/fail29.json | 1 - src/univalue/test/fail3.json | 1 - src/univalue/test/fail30.json | 1 - src/univalue/test/fail31.json | 1 - src/univalue/test/fail32.json | 1 - src/univalue/test/fail33.json | 1 - src/univalue/test/fail34.json | 1 - src/univalue/test/fail35.json | 1 - src/univalue/test/fail36.json | 1 - src/univalue/test/fail37.json | 1 - src/univalue/test/fail38.json | 1 - src/univalue/test/fail39.json | 1 - src/univalue/test/fail4.json | 1 - src/univalue/test/fail40.json | 1 - src/univalue/test/fail41.json | 1 - src/univalue/test/fail42.json | Bin 37 -> 0 bytes src/univalue/test/fail44.json | 1 - src/univalue/test/fail5.json | 1 - src/univalue/test/fail6.json | 1 - src/univalue/test/fail7.json | 1 - src/univalue/test/fail8.json | 1 - src/univalue/test/fail9.json | 1 - src/univalue/test/no_nul.cpp | 8 - src/univalue/test/object.cpp | 365 -------------- src/univalue/test/pass1.json | 58 --- src/univalue/test/pass2.json | 1 - src/univalue/test/pass3.json | 6 - src/univalue/test/round1.json | 1 - src/univalue/test/round2.json | 1 - src/univalue/test/round3.json | 1 - src/univalue/test/round4.json | 1 - src/univalue/test/round5.json | 1 - src/univalue/test/round6.json | 1 - src/univalue/test/round7.json | 1 - src/univalue/test/test_json.cpp | 24 - src/univalue/test/unitester.cpp | 170 ------- 75 files changed, 2648 deletions(-) delete mode 100644 src/univalue/.gitignore delete mode 100644 src/univalue/.travis.yml delete mode 100644 src/univalue/COPYING delete mode 100644 src/univalue/Makefile.am delete mode 100644 src/univalue/README.md delete mode 100644 src/univalue/TODO delete mode 100644 src/univalue/autogen.sh delete mode 100644 src/univalue/build-aux/m4/.gitignore delete mode 100644 src/univalue/configure.ac delete mode 100644 src/univalue/include/univalue.h delete mode 100644 src/univalue/lib/.gitignore delete mode 100644 src/univalue/lib/univalue.cpp delete mode 100644 src/univalue/lib/univalue_escapes.h delete mode 100644 src/univalue/lib/univalue_read.cpp delete mode 100644 src/univalue/lib/univalue_utffilter.h delete mode 100644 src/univalue/lib/univalue_write.cpp delete mode 100644 src/univalue/pc/libunivalue-uninstalled.pc.in delete mode 100644 src/univalue/pc/libunivalue.pc.in delete mode 100644 src/univalue/test/fail1.json delete mode 100644 src/univalue/test/fail10.json delete mode 100644 src/univalue/test/fail11.json delete mode 100644 src/univalue/test/fail12.json delete mode 100644 src/univalue/test/fail13.json delete mode 100644 src/univalue/test/fail14.json delete mode 100644 src/univalue/test/fail15.json delete mode 100644 src/univalue/test/fail16.json delete mode 100644 src/univalue/test/fail17.json delete mode 100644 src/univalue/test/fail18.json delete mode 100644 src/univalue/test/fail19.json delete mode 100644 src/univalue/test/fail2.json delete mode 100644 src/univalue/test/fail20.json delete mode 100644 src/univalue/test/fail21.json delete mode 100644 src/univalue/test/fail22.json delete mode 100644 src/univalue/test/fail23.json delete mode 100644 src/univalue/test/fail24.json delete mode 100644 src/univalue/test/fail25.json delete mode 100644 src/univalue/test/fail26.json delete mode 100644 src/univalue/test/fail27.json delete mode 100644 src/univalue/test/fail28.json delete mode 100644 src/univalue/test/fail29.json delete mode 100644 src/univalue/test/fail3.json delete mode 100644 src/univalue/test/fail30.json delete mode 100644 src/univalue/test/fail31.json delete mode 100644 src/univalue/test/fail32.json delete mode 100644 src/univalue/test/fail33.json delete mode 100644 src/univalue/test/fail34.json delete mode 100644 src/univalue/test/fail35.json delete mode 100644 src/univalue/test/fail36.json delete mode 100644 src/univalue/test/fail37.json delete mode 100644 src/univalue/test/fail38.json delete mode 100644 src/univalue/test/fail39.json delete mode 100644 src/univalue/test/fail4.json delete mode 100644 src/univalue/test/fail40.json delete mode 100644 src/univalue/test/fail41.json delete mode 100644 src/univalue/test/fail42.json delete mode 100644 src/univalue/test/fail44.json delete mode 100644 src/univalue/test/fail5.json delete mode 100644 src/univalue/test/fail6.json delete mode 100644 src/univalue/test/fail7.json delete mode 100644 src/univalue/test/fail8.json delete mode 100644 src/univalue/test/fail9.json delete mode 100644 src/univalue/test/no_nul.cpp delete mode 100644 src/univalue/test/object.cpp delete mode 100644 src/univalue/test/pass1.json delete mode 100644 src/univalue/test/pass2.json delete mode 100644 src/univalue/test/pass3.json delete mode 100644 src/univalue/test/round1.json delete mode 100644 src/univalue/test/round2.json delete mode 100644 src/univalue/test/round3.json delete mode 100644 src/univalue/test/round4.json delete mode 100644 src/univalue/test/round5.json delete mode 100644 src/univalue/test/round6.json delete mode 100644 src/univalue/test/round7.json delete mode 100644 src/univalue/test/test_json.cpp delete mode 100644 src/univalue/test/unitester.cpp diff --git a/src/univalue/.gitignore b/src/univalue/.gitignore deleted file mode 100644 index 19e42f814a..0000000000 --- a/src/univalue/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -.deps/ -INSTALL -Makefile -Makefile.in -aclocal.m4 -autom4te.cache/ -compile -config.log -config.status -config.guess -config.sub -configure -depcomp -install-sh -missing -stamp-h1 -univalue-config.h* -test-driver -libtool -ltmain.sh -test-suite.log - -*.a -*.la -*.lo -*.logs -*.o -*.pc -*.trs - -.dirstamp -.libs diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml deleted file mode 100644 index 132743d349..0000000000 --- a/src/univalue/.travis.yml +++ /dev/null @@ -1,52 +0,0 @@ -language: cpp - -compiler: - - clang - - gcc - -os: - - linux - - osx - -sudo: false - -env: - global: - - MAKEJOBS=-j3 - - RUN_TESTS=true - - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out - -cache: - apt: true - -addons: - apt: - packages: - - pkg-config - -before_script: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi - - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi - - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh - -script: - - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi - - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST - - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" - - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) - - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) - - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi - -matrix: - fast_finish: true - include: - - os: linux - compiler: gcc - env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false - addons: - apt: - packages: - - g++-mingw-w64-x86-64 - - gcc-mingw-w64-x86-64 - - binutils-mingw-w64-x86-64 diff --git a/src/univalue/COPYING b/src/univalue/COPYING deleted file mode 100644 index 1fb429f356..0000000000 --- a/src/univalue/COPYING +++ /dev/null @@ -1,19 +0,0 @@ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am deleted file mode 100644 index 287bb97fec..0000000000 --- a/src/univalue/Makefile.am +++ /dev/null @@ -1,115 +0,0 @@ -ACLOCAL_AMFLAGS = -I build-aux/m4 -.PHONY: gen -.INTERMEDIATE: $(GENBIN) - -include_HEADERS = include/univalue.h -noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h - -lib_LTLIBRARIES = libunivalue.la - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = pc/libunivalue.pc - -libunivalue_la_SOURCES = \ - lib/univalue.cpp \ - lib/univalue_read.cpp \ - lib/univalue_write.cpp - -libunivalue_la_LDFLAGS = \ - -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ - -no-undefined -libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include - -TESTS = test/object test/unitester test/no_nul - -GENBIN = gen/gen$(BUILD_EXEEXT) -GEN_SRCS = gen/gen.cpp - -$(GENBIN): $(GEN_SRCS) - @echo Building $@ - $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< - -gen: lib/univalue_escapes.h $(GENBIN) - @echo Updating $< - $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h - -noinst_PROGRAMS = $(TESTS) test/test_json - -TEST_DATA_DIR=test - -test_unitester_SOURCES = test/unitester.cpp -test_unitester_LDADD = libunivalue.la -test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" -test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_test_json_SOURCES = test/test_json.cpp -test_test_json_LDADD = libunivalue.la -test_test_json_CXXFLAGS = -I$(top_srcdir)/include -test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_no_nul_SOURCES = test/no_nul.cpp -test_no_nul_LDADD = libunivalue.la -test_no_nul_CXXFLAGS = -I$(top_srcdir)/include -test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -test_object_SOURCES = test/object.cpp -test_object_LDADD = libunivalue.la -test_object_CXXFLAGS = -I$(top_srcdir)/include -test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) - -TEST_FILES = \ - $(TEST_DATA_DIR)/fail10.json \ - $(TEST_DATA_DIR)/fail11.json \ - $(TEST_DATA_DIR)/fail12.json \ - $(TEST_DATA_DIR)/fail13.json \ - $(TEST_DATA_DIR)/fail14.json \ - $(TEST_DATA_DIR)/fail15.json \ - $(TEST_DATA_DIR)/fail16.json \ - $(TEST_DATA_DIR)/fail17.json \ - $(TEST_DATA_DIR)/fail18.json \ - $(TEST_DATA_DIR)/fail19.json \ - $(TEST_DATA_DIR)/fail1.json \ - $(TEST_DATA_DIR)/fail20.json \ - $(TEST_DATA_DIR)/fail21.json \ - $(TEST_DATA_DIR)/fail22.json \ - $(TEST_DATA_DIR)/fail23.json \ - $(TEST_DATA_DIR)/fail24.json \ - $(TEST_DATA_DIR)/fail25.json \ - $(TEST_DATA_DIR)/fail26.json \ - $(TEST_DATA_DIR)/fail27.json \ - $(TEST_DATA_DIR)/fail28.json \ - $(TEST_DATA_DIR)/fail29.json \ - $(TEST_DATA_DIR)/fail2.json \ - $(TEST_DATA_DIR)/fail30.json \ - $(TEST_DATA_DIR)/fail31.json \ - $(TEST_DATA_DIR)/fail32.json \ - $(TEST_DATA_DIR)/fail33.json \ - $(TEST_DATA_DIR)/fail34.json \ - $(TEST_DATA_DIR)/fail35.json \ - $(TEST_DATA_DIR)/fail36.json \ - $(TEST_DATA_DIR)/fail37.json \ - $(TEST_DATA_DIR)/fail38.json \ - $(TEST_DATA_DIR)/fail39.json \ - $(TEST_DATA_DIR)/fail40.json \ - $(TEST_DATA_DIR)/fail41.json \ - $(TEST_DATA_DIR)/fail42.json \ - $(TEST_DATA_DIR)/fail44.json \ - $(TEST_DATA_DIR)/fail3.json \ - $(TEST_DATA_DIR)/fail4.json \ - $(TEST_DATA_DIR)/fail5.json \ - $(TEST_DATA_DIR)/fail6.json \ - $(TEST_DATA_DIR)/fail7.json \ - $(TEST_DATA_DIR)/fail8.json \ - $(TEST_DATA_DIR)/fail9.json \ - $(TEST_DATA_DIR)/pass1.json \ - $(TEST_DATA_DIR)/pass2.json \ - $(TEST_DATA_DIR)/pass3.json \ - $(TEST_DATA_DIR)/round1.json \ - $(TEST_DATA_DIR)/round2.json \ - $(TEST_DATA_DIR)/round3.json \ - $(TEST_DATA_DIR)/round4.json \ - $(TEST_DATA_DIR)/round5.json \ - $(TEST_DATA_DIR)/round6.json \ - $(TEST_DATA_DIR)/round7.json - -EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) diff --git a/src/univalue/README.md b/src/univalue/README.md deleted file mode 100644 index 36aa786a4c..0000000000 --- a/src/univalue/README.md +++ /dev/null @@ -1,32 +0,0 @@ - -# UniValue - -## Summary - -A universal value class, with JSON encoding and decoding. - -UniValue is an abstract data type that may be a null, boolean, string, -number, array container, or a key/value dictionary container, nested to -an arbitrary depth. - -This class is aligned with the JSON standard, [RFC -7159](https://tools.ietf.org/html/rfc7159.html). - -## Installation - -This project is a standard GNU -[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) -project. Build and install instructions are available in the `INSTALL` -file provided with GNU autotools. - -``` -$ ./autogen.sh -$ ./configure -$ make -``` - -## Design - -UniValue provides a single dynamic RAII C++ object class, -and minimizes template use (contra json_spirit). - diff --git a/src/univalue/TODO b/src/univalue/TODO deleted file mode 100644 index 5530048e92..0000000000 --- a/src/univalue/TODO +++ /dev/null @@ -1,10 +0,0 @@ - -Rearrange tree for easier 'git subtree' style use - -Move towards C++11 etc. - -Namespace support - must come up with useful shorthand, avoiding -long Univalue::Univalue::Univalue usages forced upon library users. - -Improve test suite - diff --git a/src/univalue/autogen.sh b/src/univalue/autogen.sh deleted file mode 100644 index 4b38721faa..0000000000 --- a/src/univalue/autogen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -set -e -srcdir="$(dirname $0)" -cd "$srcdir" -if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then - LIBTOOLIZE="${GLIBTOOLIZE}" - export LIBTOOLIZE -fi -autoreconf --install --force diff --git a/src/univalue/build-aux/m4/.gitignore b/src/univalue/build-aux/m4/.gitignore deleted file mode 100644 index f063686524..0000000000 --- a/src/univalue/build-aux/m4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.m4 diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac deleted file mode 100644 index 8298332ac1..0000000000 --- a/src/univalue/configure.ac +++ /dev/null @@ -1,69 +0,0 @@ -m4_define([libunivalue_major_version], [1]) -m4_define([libunivalue_minor_version], [1]) -m4_define([libunivalue_micro_version], [3]) -m4_define([libunivalue_interface_age], [3]) -# If you need a modifier for the version number. -# Normally empty, but can be used to make "fixup" releases. -m4_define([libunivalue_extraversion], []) - -dnl libtool versioning from libunivalue -m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) -m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) -m4_define([libunivalue_revision], [libunivalue_interface_age]) -m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) -m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) - - -AC_INIT([univalue], [1.0.3], - [http://github.com/jgarzik/univalue/]) - -dnl make the compilation flags quiet unless V=1 is used -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -AC_PREREQ(2.60) -AC_CONFIG_SRCDIR([lib/univalue.cpp]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) -AC_CONFIG_HEADERS([univalue-config.h]) -AM_INIT_AUTOMAKE([subdir-objects foreign]) - -LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version -LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version -LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version -LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age - -# ABI version -# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -LIBUNIVALUE_CURRENT=libunivalue_current -LIBUNIVALUE_REVISION=libunivalue_revision -LIBUNIVALUE_AGE=libunivalue_age - -AC_SUBST(LIBUNIVALUE_CURRENT) -AC_SUBST(LIBUNIVALUE_REVISION) -AC_SUBST(LIBUNIVALUE_AGE) - -LT_INIT -LT_LANG([C++]) - -case $host in - *mingw*) - LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" - ;; -esac - -BUILD_EXEEXT= -case $build in - *mingw*) - BUILD_EXEEXT=".exe" - ;; -esac - -AC_CONFIG_FILES([ - Makefile - pc/libunivalue.pc - pc/libunivalue-uninstalled.pc]) - -AC_SUBST(LIBTOOL_APP_LDFLAGS) -AC_SUBST(BUILD_EXEEXT) -AC_OUTPUT - diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h deleted file mode 100644 index cc92cd2a9c..0000000000 --- a/src/univalue/include/univalue.h +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Copyright 2015 Bitcoin Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef __UNIVALUE_H__ -#define __UNIVALUE_H__ - -#include - -#include -#include -#include -#include - -#include // .get_int64() -#include // std::pair - -class UniValue { -public: - enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; - - UniValue() { typ = VNULL; } - UniValue(UniValue::VType initialType, const std::string& initialStr = "") { - typ = initialType; - val = initialStr; - } - UniValue(uint64_t val_) { - setInt(val_); - } - UniValue(int64_t val_) { - setInt(val_); - } - UniValue(bool val_) { - setBool(val_); - } - UniValue(int val_) { - setInt(val_); - } - UniValue(double val_) { - setFloat(val_); - } - UniValue(const std::string& val_) { - setStr(val_); - } - UniValue(const char *val_) { - std::string s(val_); - setStr(s); - } - ~UniValue() {} - - void clear(); - - bool setNull(); - bool setBool(bool val); - bool setNumStr(const std::string& val); - bool setInt(uint64_t val); - bool setInt(int64_t val); - bool setInt(int val_) { return setInt((int64_t)val_); } - bool setFloat(double val); - bool setStr(const std::string& val); - bool setArray(); - bool setObject(); - - enum VType getType() const { return typ; } - const std::string& getValStr() const { return val; } - bool empty() const { return (values.size() == 0); } - - size_t size() const { return values.size(); } - - bool getBool() const { return isTrue(); } - bool checkObject(const std::map& memberTypes); - const UniValue& operator[](const std::string& key) const; - const UniValue& operator[](size_t index) const; - bool exists(const std::string& key) const { size_t i; return findKey(key, i); } - - bool isNull() const { return (typ == VNULL); } - bool isTrue() const { return (typ == VBOOL) && (val == "1"); } - bool isFalse() const { return (typ == VBOOL) && (val != "1"); } - bool isBool() const { return (typ == VBOOL); } - bool isStr() const { return (typ == VSTR); } - bool isNum() const { return (typ == VNUM); } - bool isArray() const { return (typ == VARR); } - bool isObject() const { return (typ == VOBJ); } - - bool push_back(const UniValue& val); - bool push_back(const std::string& val_) { - UniValue tmpVal(VSTR, val_); - return push_back(tmpVal); - } - bool push_back(const char *val_) { - std::string s(val_); - return push_back(s); - } - bool push_back(uint64_t val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(int64_t val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_back(int val_) { - UniValue tmpVal(val_); - return push_back(tmpVal); - } - bool push_backV(const std::vector& vec); - - bool pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const std::string& val_) { - UniValue tmpVal(VSTR, val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, const char *val_) { - std::string _val(val_); - return pushKV(key, _val); - } - bool pushKV(const std::string& key, int64_t val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, uint64_t val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, int val_) { - UniValue tmpVal((int64_t)val_); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, double val_) { - UniValue tmpVal(val_); - return pushKV(key, tmpVal); - } - bool pushKVs(const UniValue& obj); - - std::string write(unsigned int prettyIndent = 0, - unsigned int indentLevel = 0) const; - - bool read(const char *raw, size_t len); - bool read(const char *raw); - bool read(const std::string& rawStr) { - return read(rawStr.data(), rawStr.size()); - } - -private: - UniValue::VType typ; - std::string val; // numbers are stored as C++ strings - std::vector keys; - std::vector values; - - bool findKey(const std::string& key, size_t& retIdx) const; - void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; - void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; - -public: - // Strict type-specific getters, these throw std::runtime_error if the - // value is of unexpected type - const std::vector& getKeys() const; - const std::vector& getValues() const; - bool get_bool() const; - const std::string& get_str() const; - int get_int() const; - int64_t get_int64() const; - double get_real() const; - const UniValue& get_obj() const; - const UniValue& get_array() const; - - enum VType type() const { return getType(); } - bool push_back(std::pair pear) { - return pushKV(pear.first, pear.second); - } - friend const UniValue& find_value( const UniValue& obj, const std::string& name); -}; - -// -// The following were added for compatibility with json_spirit. -// Most duplicate other methods, and should be removed. -// -static inline std::pair Pair(const char *cKey, const char *cVal) -{ - std::string key(cKey); - UniValue uVal(cVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, std::string strVal) -{ - std::string key(cKey); - UniValue uVal(strVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, uint64_t u64Val) -{ - std::string key(cKey); - UniValue uVal(u64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int64_t i64Val) -{ - std::string key(cKey); - UniValue uVal(i64Val); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, bool iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, int iVal) -{ - std::string key(cKey); - UniValue uVal(iVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, double dVal) -{ - std::string key(cKey); - UniValue uVal(dVal); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(const char *cKey, const UniValue& uVal) -{ - std::string key(cKey); - return std::make_pair(key, uVal); -} - -static inline std::pair Pair(std::string key, const UniValue& uVal) -{ - return std::make_pair(key, uVal); -} - -enum jtokentype { - JTOK_ERR = -1, - JTOK_NONE = 0, // eof - JTOK_OBJ_OPEN, - JTOK_OBJ_CLOSE, - JTOK_ARR_OPEN, - JTOK_ARR_CLOSE, - JTOK_COLON, - JTOK_COMMA, - JTOK_KW_NULL, - JTOK_KW_TRUE, - JTOK_KW_FALSE, - JTOK_NUMBER, - JTOK_STRING, -}; - -extern enum jtokentype getJsonToken(std::string& tokenVal, - unsigned int& consumed, const char *raw, const char *end); -extern const char *uvTypeName(UniValue::VType t); - -static inline bool jsonTokenIsValue(enum jtokentype jtt) -{ - switch (jtt) { - case JTOK_KW_NULL: - case JTOK_KW_TRUE: - case JTOK_KW_FALSE: - case JTOK_NUMBER: - case JTOK_STRING: - return true; - - default: - return false; - } - - // not reached -} - -static inline bool json_isspace(int ch) -{ - switch (ch) { - case 0x20: - case 0x09: - case 0x0a: - case 0x0d: - return true; - - default: - return false; - } - - // not reached -} - -extern const UniValue NullUniValue; - -const UniValue& find_value( const UniValue& obj, const std::string& name); - -#endif // __UNIVALUE_H__ diff --git a/src/univalue/lib/.gitignore b/src/univalue/lib/.gitignore deleted file mode 100644 index ee7fc2851c..0000000000 --- a/src/univalue/lib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gen -.libs diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp deleted file mode 100644 index b9491a967b..0000000000 --- a/src/univalue/lib/univalue.cpp +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Copyright 2015 Bitcoin Core Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "univalue.h" - -namespace -{ -static bool ParsePrechecks(const std::string& str) -{ - if (str.empty()) // No empty string allowed - return false; - if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed - return false; - if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed - return false; - return true; -} - -bool ParseInt32(const std::string& str, int32_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtol will not set errno if valid - long int n = strtol(str.c_str(), &endp, 10); - if(out) *out = (int32_t)n; - // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit - // platforms the size of these types may be different. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseInt64(const std::string& str, int64_t *out) -{ - if (!ParsePrechecks(str)) - return false; - char *endp = NULL; - errno = 0; // strtoll will not set errno if valid - long long int n = strtoll(str.c_str(), &endp, 10); - if(out) *out = (int64_t)n; - // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow - // we still have to check that the returned value is within the range of an *int64_t*. - return endp && *endp == 0 && !errno && - n >= std::numeric_limits::min() && - n <= std::numeric_limits::max(); -} - -bool ParseDouble(const std::string& str, double *out) -{ - if (!ParsePrechecks(str)) - return false; - if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed - return false; - std::istringstream text(str); - text.imbue(std::locale::classic()); - double result; - text >> result; - if(out) *out = result; - return text.eof() && !text.fail(); -} -} - -using namespace std; - -const UniValue NullUniValue; - -void UniValue::clear() -{ - typ = VNULL; - val.clear(); - keys.clear(); - values.clear(); -} - -bool UniValue::setNull() -{ - clear(); - return true; -} - -bool UniValue::setBool(bool val_) -{ - clear(); - typ = VBOOL; - if (val_) - val = "1"; - return true; -} - -static bool validNumStr(const string& s) -{ - string tokenVal; - unsigned int consumed; - enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size()); - return (tt == JTOK_NUMBER); -} - -bool UniValue::setNumStr(const string& val_) -{ - if (!validNumStr(val_)) - return false; - - clear(); - typ = VNUM; - val = val_; - return true; -} - -bool UniValue::setInt(uint64_t val_) -{ - ostringstream oss; - - oss << val_; - - return setNumStr(oss.str()); -} - -bool UniValue::setInt(int64_t val_) -{ - ostringstream oss; - - oss << val_; - - return setNumStr(oss.str()); -} - -bool UniValue::setFloat(double val_) -{ - ostringstream oss; - - oss << std::setprecision(16) << val_; - - bool ret = setNumStr(oss.str()); - typ = VNUM; - return ret; -} - -bool UniValue::setStr(const string& val_) -{ - clear(); - typ = VSTR; - val = val_; - return true; -} - -bool UniValue::setArray() -{ - clear(); - typ = VARR; - return true; -} - -bool UniValue::setObject() -{ - clear(); - typ = VOBJ; - return true; -} - -bool UniValue::push_back(const UniValue& val_) -{ - if (typ != VARR) - return false; - - values.push_back(val_); - return true; -} - -bool UniValue::push_backV(const std::vector& vec) -{ - if (typ != VARR) - return false; - - values.insert(values.end(), vec.begin(), vec.end()); - - return true; -} - -bool UniValue::pushKV(const std::string& key, const UniValue& val_) -{ - if (typ != VOBJ) - return false; - - keys.push_back(key); - values.push_back(val_); - return true; -} - -bool UniValue::pushKVs(const UniValue& obj) -{ - if (typ != VOBJ || obj.typ != VOBJ) - return false; - - for (unsigned int i = 0; i < obj.keys.size(); i++) { - keys.push_back(obj.keys[i]); - values.push_back(obj.values.at(i)); - } - - return true; -} - -bool UniValue::findKey(const std::string& key, size_t& retIdx) const -{ - for (size_t i = 0; i < keys.size(); i++) { - if (keys[i] == key) { - retIdx = i; - return true; - } - } - - return false; -} - -bool UniValue::checkObject(const std::map& t) -{ - for (std::map::const_iterator it = t.begin(); - it != t.end(); ++it) { - size_t idx = 0; - if (!findKey(it->first, idx)) - return false; - - if (values.at(idx).getType() != it->second) - return false; - } - - return true; -} - -const UniValue& UniValue::operator[](const std::string& key) const -{ - if (typ != VOBJ) - return NullUniValue; - - size_t index = 0; - if (!findKey(key, index)) - return NullUniValue; - - return values.at(index); -} - -const UniValue& UniValue::operator[](size_t index) const -{ - if (typ != VOBJ && typ != VARR) - return NullUniValue; - if (index >= values.size()) - return NullUniValue; - - return values.at(index); -} - -const char *uvTypeName(UniValue::VType t) -{ - switch (t) { - case UniValue::VNULL: return "null"; - case UniValue::VBOOL: return "bool"; - case UniValue::VOBJ: return "object"; - case UniValue::VARR: return "array"; - case UniValue::VSTR: return "string"; - case UniValue::VNUM: return "number"; - } - - // not reached - return NULL; -} - -const UniValue& find_value(const UniValue& obj, const std::string& name) -{ - for (unsigned int i = 0; i < obj.keys.size(); i++) - if (obj.keys[i] == name) - return obj.values.at(i); - - return NullUniValue; -} - -const std::vector& UniValue::getKeys() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return keys; -} - -const std::vector& UniValue::getValues() const -{ - if (typ != VOBJ && typ != VARR) - throw std::runtime_error("JSON value is not an object or array as expected"); - return values; -} - -bool UniValue::get_bool() const -{ - if (typ != VBOOL) - throw std::runtime_error("JSON value is not a boolean as expected"); - return getBool(); -} - -const std::string& UniValue::get_str() const -{ - if (typ != VSTR) - throw std::runtime_error("JSON value is not a string as expected"); - return getValStr(); -} - -int UniValue::get_int() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int32_t retval; - if (!ParseInt32(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -int64_t UniValue::get_int64() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not an integer as expected"); - int64_t retval; - if (!ParseInt64(getValStr(), &retval)) - throw std::runtime_error("JSON integer out of range"); - return retval; -} - -double UniValue::get_real() const -{ - if (typ != VNUM) - throw std::runtime_error("JSON value is not a number as expected"); - double retval; - if (!ParseDouble(getValStr(), &retval)) - throw std::runtime_error("JSON double out of range"); - return retval; -} - -const UniValue& UniValue::get_obj() const -{ - if (typ != VOBJ) - throw std::runtime_error("JSON value is not an object as expected"); - return *this; -} - -const UniValue& UniValue::get_array() const -{ - if (typ != VARR) - throw std::runtime_error("JSON value is not an array as expected"); - return *this; -} - diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h deleted file mode 100644 index 9219979d30..0000000000 --- a/src/univalue/lib/univalue_escapes.h +++ /dev/null @@ -1,262 +0,0 @@ -// Automatically generated file. Do not modify. -#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H -#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H -static const char *escapes[256] = { - "\\u0000", - "\\u0001", - "\\u0002", - "\\u0003", - "\\u0004", - "\\u0005", - "\\u0006", - "\\u0007", - "\\b", - "\\t", - "\\n", - "\\u000b", - "\\f", - "\\r", - "\\u000e", - "\\u000f", - "\\u0010", - "\\u0011", - "\\u0012", - "\\u0013", - "\\u0014", - "\\u0015", - "\\u0016", - "\\u0017", - "\\u0018", - "\\u0019", - "\\u001a", - "\\u001b", - "\\u001c", - "\\u001d", - "\\u001e", - "\\u001f", - NULL, - NULL, - "\\\"", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\\\", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\u007f", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, -}; -#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp deleted file mode 100644 index 2bd83238b4..0000000000 --- a/src/univalue/lib/univalue_read.cpp +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include "univalue.h" -#include "univalue_utffilter.h" - -using namespace std; - -static bool json_isdigit(int ch) -{ - return ((ch >= '0') && (ch <= '9')); -} - -// convert hexadecimal string to unsigned integer -static const char *hatoui(const char *first, const char *last, - unsigned int& out) -{ - unsigned int result = 0; - for (; first != last; ++first) - { - int digit; - if (json_isdigit(*first)) - digit = *first - '0'; - - else if (*first >= 'a' && *first <= 'f') - digit = *first - 'a' + 10; - - else if (*first >= 'A' && *first <= 'F') - digit = *first - 'A' + 10; - - else - break; - - result = 16 * result + digit; - } - out = result; - - return first; -} - -enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, - const char *raw, const char *end) -{ - tokenVal.clear(); - consumed = 0; - - const char *rawStart = raw; - - while (raw < end && (json_isspace(*raw))) // skip whitespace - raw++; - - if (raw >= end) - return JTOK_NONE; - - switch (*raw) { - - case '{': - raw++; - consumed = (raw - rawStart); - return JTOK_OBJ_OPEN; - case '}': - raw++; - consumed = (raw - rawStart); - return JTOK_OBJ_CLOSE; - case '[': - raw++; - consumed = (raw - rawStart); - return JTOK_ARR_OPEN; - case ']': - raw++; - consumed = (raw - rawStart); - return JTOK_ARR_CLOSE; - - case ':': - raw++; - consumed = (raw - rawStart); - return JTOK_COLON; - case ',': - raw++; - consumed = (raw - rawStart); - return JTOK_COMMA; - - case 'n': - case 't': - case 'f': - if (!strncmp(raw, "null", 4)) { - raw += 4; - consumed = (raw - rawStart); - return JTOK_KW_NULL; - } else if (!strncmp(raw, "true", 4)) { - raw += 4; - consumed = (raw - rawStart); - return JTOK_KW_TRUE; - } else if (!strncmp(raw, "false", 5)) { - raw += 5; - consumed = (raw - rawStart); - return JTOK_KW_FALSE; - } else - return JTOK_ERR; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - // part 1: int - string numStr; - - const char *first = raw; - - const char *firstDigit = first; - if (!json_isdigit(*firstDigit)) - firstDigit++; - if ((*firstDigit == '0') && json_isdigit(firstDigit[1])) - return JTOK_ERR; - - numStr += *raw; // copy first char - raw++; - - if ((*first == '-') && (raw < end) && (!json_isdigit(*raw))) - return JTOK_ERR; - - while (raw < end && json_isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - - // part 2: frac - if (raw < end && *raw == '.') { - numStr += *raw; // copy . - raw++; - - if (raw >= end || !json_isdigit(*raw)) - return JTOK_ERR; - while (raw < end && json_isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - } - - // part 3: exp - if (raw < end && (*raw == 'e' || *raw == 'E')) { - numStr += *raw; // copy E - raw++; - - if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/- - numStr += *raw; - raw++; - } - - if (raw >= end || !json_isdigit(*raw)) - return JTOK_ERR; - while (raw < end && json_isdigit(*raw)) { // copy digits - numStr += *raw; - raw++; - } - } - - tokenVal = numStr; - consumed = (raw - rawStart); - return JTOK_NUMBER; - } - - case '"': { - raw++; // skip " - - string valStr; - JSONUTF8StringFilter writer(valStr); - - while (true) { - if (raw >= end || (unsigned char)*raw < 0x20) - return JTOK_ERR; - - else if (*raw == '\\') { - raw++; // skip backslash - - if (raw >= end) - return JTOK_ERR; - - switch (*raw) { - case '"': writer.push_back('\"'); break; - case '\\': writer.push_back('\\'); break; - case '/': writer.push_back('/'); break; - case 'b': writer.push_back('\b'); break; - case 'f': writer.push_back('\f'); break; - case 'n': writer.push_back('\n'); break; - case 'r': writer.push_back('\r'); break; - case 't': writer.push_back('\t'); break; - - case 'u': { - unsigned int codepoint; - if (raw + 1 + 4 >= end || - hatoui(raw + 1, raw + 1 + 4, codepoint) != - raw + 1 + 4) - return JTOK_ERR; - writer.push_back_u(codepoint); - raw += 4; - break; - } - default: - return JTOK_ERR; - - } - - raw++; // skip esc'd char - } - - else if (*raw == '"') { - raw++; // skip " - break; // stop scanning - } - - else { - writer.push_back(*raw); - raw++; - } - } - - if (!writer.finalize()) - return JTOK_ERR; - tokenVal = valStr; - consumed = (raw - rawStart); - return JTOK_STRING; - } - - default: - return JTOK_ERR; - } -} - -enum expect_bits { - EXP_OBJ_NAME = (1U << 0), - EXP_COLON = (1U << 1), - EXP_ARR_VALUE = (1U << 2), - EXP_VALUE = (1U << 3), - EXP_NOT_VALUE = (1U << 4), -}; - -#define expect(bit) (expectMask & (EXP_##bit)) -#define setExpect(bit) (expectMask |= EXP_##bit) -#define clearExpect(bit) (expectMask &= ~EXP_##bit) - -bool UniValue::read(const char *raw, size_t size) -{ - clear(); - - uint32_t expectMask = 0; - vector stack; - - string tokenVal; - unsigned int consumed; - enum jtokentype tok = JTOK_NONE; - enum jtokentype last_tok = JTOK_NONE; - const char* end = raw + size; - do { - last_tok = tok; - - tok = getJsonToken(tokenVal, consumed, raw, end); - if (tok == JTOK_NONE || tok == JTOK_ERR) - return false; - raw += consumed; - - bool isValueOpen = jsonTokenIsValue(tok) || - tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN; - - if (expect(VALUE)) { - if (!isValueOpen) - return false; - clearExpect(VALUE); - - } else if (expect(ARR_VALUE)) { - bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); - if (!isArrValue) - return false; - - clearExpect(ARR_VALUE); - - } else if (expect(OBJ_NAME)) { - bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); - if (!isObjName) - return false; - - } else if (expect(COLON)) { - if (tok != JTOK_COLON) - return false; - clearExpect(COLON); - - } else if (!expect(COLON) && (tok == JTOK_COLON)) { - return false; - } - - if (expect(NOT_VALUE)) { - if (isValueOpen) - return false; - clearExpect(NOT_VALUE); - } - - switch (tok) { - - case JTOK_OBJ_OPEN: - case JTOK_ARR_OPEN: { - VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR); - if (!stack.size()) { - if (utyp == VOBJ) - setObject(); - else - setArray(); - stack.push_back(this); - } else { - UniValue tmpVal(utyp); - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - UniValue *newTop = &(top->values.back()); - stack.push_back(newTop); - } - - if (utyp == VOBJ) - setExpect(OBJ_NAME); - else - setExpect(ARR_VALUE); - break; - } - - case JTOK_OBJ_CLOSE: - case JTOK_ARR_CLOSE: { - if (!stack.size() || (last_tok == JTOK_COMMA)) - return false; - - VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); - UniValue *top = stack.back(); - if (utyp != top->getType()) - return false; - - stack.pop_back(); - clearExpect(OBJ_NAME); - setExpect(NOT_VALUE); - break; - } - - case JTOK_COLON: { - if (!stack.size()) - return false; - - UniValue *top = stack.back(); - if (top->getType() != VOBJ) - return false; - - setExpect(VALUE); - break; - } - - case JTOK_COMMA: { - if (!stack.size() || - (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) - return false; - - UniValue *top = stack.back(); - if (top->getType() == VOBJ) - setExpect(OBJ_NAME); - else - setExpect(ARR_VALUE); - break; - } - - case JTOK_KW_NULL: - case JTOK_KW_TRUE: - case JTOK_KW_FALSE: { - UniValue tmpVal; - switch (tok) { - case JTOK_KW_NULL: - // do nothing more - break; - case JTOK_KW_TRUE: - tmpVal.setBool(true); - break; - case JTOK_KW_FALSE: - tmpVal.setBool(false); - break; - default: /* impossible */ break; - } - - if (!stack.size()) { - *this = tmpVal; - break; - } - - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - setExpect(NOT_VALUE); - break; - } - - case JTOK_NUMBER: { - UniValue tmpVal(VNUM, tokenVal); - if (!stack.size()) { - *this = tmpVal; - break; - } - - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - - setExpect(NOT_VALUE); - break; - } - - case JTOK_STRING: { - if (expect(OBJ_NAME)) { - UniValue *top = stack.back(); - top->keys.push_back(tokenVal); - clearExpect(OBJ_NAME); - setExpect(COLON); - } else { - UniValue tmpVal(VSTR, tokenVal); - if (!stack.size()) { - *this = tmpVal; - break; - } - UniValue *top = stack.back(); - top->values.push_back(tmpVal); - } - - setExpect(NOT_VALUE); - break; - } - - default: - return false; - } - } while (!stack.empty ()); - - /* Check that nothing follows the initial construct (parsed above). */ - tok = getJsonToken(tokenVal, consumed, raw, end); - if (tok != JTOK_NONE) - return false; - - return true; -} - -bool UniValue::read(const char *raw) { - return read(raw, strlen(raw)); -} diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h deleted file mode 100644 index b4a9ddc0a3..0000000000 --- a/src/univalue/lib/univalue_utffilter.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2016 Wladimir J. van der Laan -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef UNIVALUE_UTFFILTER_H -#define UNIVALUE_UTFFILTER_H - -#include - -/** - * Filter that generates and validates UTF-8, as well as collates UTF-16 - * surrogate pairs as specified in RFC4627. - */ -class JSONUTF8StringFilter -{ -public: - JSONUTF8StringFilter(std::string &s): - str(s), is_valid(true), codepoint(0), state(0), surpair(0) - { - } - // Write single 8-bit char (may be part of UTF-8 sequence) - void push_back(unsigned char ch) - { - if (state == 0) { - if (ch < 0x80) // 7-bit ASCII, fast direct pass-through - str.push_back(ch); - else if (ch < 0xc0) // Mid-sequence character, invalid in this state - is_valid = false; - else if (ch < 0xe0) { // Start of 2-byte sequence - codepoint = (ch & 0x1f) << 6; - state = 6; - } else if (ch < 0xf0) { // Start of 3-byte sequence - codepoint = (ch & 0x0f) << 12; - state = 12; - } else if (ch < 0xf8) { // Start of 4-byte sequence - codepoint = (ch & 0x07) << 18; - state = 18; - } else // Reserved, invalid - is_valid = false; - } else { - if ((ch & 0xc0) != 0x80) // Not a continuation, invalid - is_valid = false; - state -= 6; - codepoint |= (ch & 0x3f) << state; - if (state == 0) - push_back_u(codepoint); - } - } - // Write codepoint directly, possibly collating surrogate pairs - void push_back_u(unsigned int codepoint_) - { - if (state) // Only accept full codepoints in open state - is_valid = false; - if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair - if (surpair) // Two subsequent surrogate pair openers - fail - is_valid = false; - else - surpair = codepoint_; - } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair - if (surpair) { // Open surrogate pair, expect second half - // Compute code point from UTF-16 surrogate pair - append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); - surpair = 0; - } else // Second half doesn't follow a first half - fail - is_valid = false; - } else { - if (surpair) // First half of surrogate pair not followed by second - fail - is_valid = false; - else - append_codepoint(codepoint_); - } - } - // Check that we're in a state where the string can be ended - // No open sequences, no open surrogate pairs, etc - bool finalize() - { - if (state || surpair) - is_valid = false; - return is_valid; - } -private: - std::string &str; - bool is_valid; - // Current UTF-8 decoding state - unsigned int codepoint; - int state; // Top bit to be filled in for next UTF-8 byte, or 0 - - // Keep track of the following state to handle the following section of - // RFC4627: - // - // To escape an extended character that is not in the Basic Multilingual - // Plane, the character is represented as a twelve-character sequence, - // encoding the UTF-16 surrogate pair. So, for example, a string - // containing only the G clef character (U+1D11E) may be represented as - // "\uD834\uDD1E". - // - // Two subsequent \u.... may have to be replaced with one actual codepoint. - unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 - - void append_codepoint(unsigned int codepoint_) - { - if (codepoint_ <= 0x7f) - str.push_back((char)codepoint_); - else if (codepoint_ <= 0x7FF) { - str.push_back((char)(0xC0 | (codepoint_ >> 6))); - str.push_back((char)(0x80 | (codepoint_ & 0x3F))); - } else if (codepoint_ <= 0xFFFF) { - str.push_back((char)(0xE0 | (codepoint_ >> 12))); - str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); - str.push_back((char)(0x80 | (codepoint_ & 0x3F))); - } else if (codepoint_ <= 0x1FFFFF) { - str.push_back((char)(0xF0 | (codepoint_ >> 18))); - str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); - str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); - str.push_back((char)(0x80 | (codepoint_ & 0x3F))); - } - } -}; - -#endif diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp deleted file mode 100644 index cf27835991..0000000000 --- a/src/univalue/lib/univalue_write.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include "univalue.h" -#include "univalue_escapes.h" - -using namespace std; - -static string json_escape(const string& inS) -{ - string outS; - outS.reserve(inS.size() * 2); - - for (unsigned int i = 0; i < inS.size(); i++) { - unsigned char ch = inS[i]; - const char *escStr = escapes[ch]; - - if (escStr) - outS += escStr; - else - outS += ch; - } - - return outS; -} - -string UniValue::write(unsigned int prettyIndent, - unsigned int indentLevel) const -{ - string s; - s.reserve(1024); - - unsigned int modIndent = indentLevel; - if (modIndent == 0) - modIndent = 1; - - switch (typ) { - case VNULL: - s += "null"; - break; - case VOBJ: - writeObject(prettyIndent, modIndent, s); - break; - case VARR: - writeArray(prettyIndent, modIndent, s); - break; - case VSTR: - s += "\"" + json_escape(val) + "\""; - break; - case VNUM: - s += val; - break; - case VBOOL: - s += (val == "1" ? "true" : "false"); - break; - } - - return s; -} - -static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s) -{ - s.append(prettyIndent * indentLevel, ' '); -} - -void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const -{ - s += "["; - if (prettyIndent) - s += "\n"; - - for (unsigned int i = 0; i < values.size(); i++) { - if (prettyIndent) - indentStr(prettyIndent, indentLevel, s); - s += values[i].write(prettyIndent, indentLevel + 1); - if (i != (values.size() - 1)) { - s += ","; - } - if (prettyIndent) - s += "\n"; - } - - if (prettyIndent) - indentStr(prettyIndent, indentLevel - 1, s); - s += "]"; -} - -void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const -{ - s += "{"; - if (prettyIndent) - s += "\n"; - - for (unsigned int i = 0; i < keys.size(); i++) { - if (prettyIndent) - indentStr(prettyIndent, indentLevel, s); - s += "\"" + json_escape(keys[i]) + "\":"; - if (prettyIndent) - s += " "; - s += values.at(i).write(prettyIndent, indentLevel + 1); - if (i != (values.size() - 1)) - s += ","; - if (prettyIndent) - s += "\n"; - } - - if (prettyIndent) - indentStr(prettyIndent, indentLevel - 1, s); - s += "}"; -} - diff --git a/src/univalue/pc/libunivalue-uninstalled.pc.in b/src/univalue/pc/libunivalue-uninstalled.pc.in deleted file mode 100644 index b7f53e875e..0000000000 --- a/src/univalue/pc/libunivalue-uninstalled.pc.in +++ /dev/null @@ -1,9 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libunivalue -Description: libunivalue, C++ universal value object and JSON library -Version: @VERSION@ -Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la diff --git a/src/univalue/pc/libunivalue.pc.in b/src/univalue/pc/libunivalue.pc.in deleted file mode 100644 index 358a2d5f73..0000000000 --- a/src/univalue/pc/libunivalue.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libunivalue -Description: libunivalue, C++ universal value object and JSON library -Version: @VERSION@ -Libs: -L${libdir} -lunivalue -Cflags: -I${includedir} diff --git a/src/univalue/test/fail1.json b/src/univalue/test/fail1.json deleted file mode 100644 index 8feb01a6d0..0000000000 --- a/src/univalue/test/fail1.json +++ /dev/null @@ -1 +0,0 @@ -"This is a string that never ends, yes it goes on and on, my friends. diff --git a/src/univalue/test/fail10.json b/src/univalue/test/fail10.json deleted file mode 100644 index 5d8c0047bd..0000000000 --- a/src/univalue/test/fail10.json +++ /dev/null @@ -1 +0,0 @@ -{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/src/univalue/test/fail11.json b/src/univalue/test/fail11.json deleted file mode 100644 index 76eb95b458..0000000000 --- a/src/univalue/test/fail11.json +++ /dev/null @@ -1 +0,0 @@ -{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/src/univalue/test/fail12.json b/src/univalue/test/fail12.json deleted file mode 100644 index 77580a4522..0000000000 --- a/src/univalue/test/fail12.json +++ /dev/null @@ -1 +0,0 @@ -{"Illegal invocation": alert()} \ No newline at end of file diff --git a/src/univalue/test/fail13.json b/src/univalue/test/fail13.json deleted file mode 100644 index 379406b59b..0000000000 --- a/src/univalue/test/fail13.json +++ /dev/null @@ -1 +0,0 @@ -{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/src/univalue/test/fail14.json b/src/univalue/test/fail14.json deleted file mode 100644 index 0ed366b38a..0000000000 --- a/src/univalue/test/fail14.json +++ /dev/null @@ -1 +0,0 @@ -{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/src/univalue/test/fail15.json b/src/univalue/test/fail15.json deleted file mode 100644 index fc8376b605..0000000000 --- a/src/univalue/test/fail15.json +++ /dev/null @@ -1 +0,0 @@ -["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/src/univalue/test/fail16.json b/src/univalue/test/fail16.json deleted file mode 100644 index 3fe21d4b53..0000000000 --- a/src/univalue/test/fail16.json +++ /dev/null @@ -1 +0,0 @@ -[\naked] \ No newline at end of file diff --git a/src/univalue/test/fail17.json b/src/univalue/test/fail17.json deleted file mode 100644 index 62b9214aed..0000000000 --- a/src/univalue/test/fail17.json +++ /dev/null @@ -1 +0,0 @@ -["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/src/univalue/test/fail18.json b/src/univalue/test/fail18.json deleted file mode 100644 index edac92716f..0000000000 --- a/src/univalue/test/fail18.json +++ /dev/null @@ -1 +0,0 @@ -[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/src/univalue/test/fail19.json b/src/univalue/test/fail19.json deleted file mode 100644 index 3b9c46fa9a..0000000000 --- a/src/univalue/test/fail19.json +++ /dev/null @@ -1 +0,0 @@ -{"Missing colon" null} \ No newline at end of file diff --git a/src/univalue/test/fail2.json b/src/univalue/test/fail2.json deleted file mode 100644 index 6b7c11e5a5..0000000000 --- a/src/univalue/test/fail2.json +++ /dev/null @@ -1 +0,0 @@ -["Unclosed array" \ No newline at end of file diff --git a/src/univalue/test/fail20.json b/src/univalue/test/fail20.json deleted file mode 100644 index 27c1af3e72..0000000000 --- a/src/univalue/test/fail20.json +++ /dev/null @@ -1 +0,0 @@ -{"Double colon":: null} \ No newline at end of file diff --git a/src/univalue/test/fail21.json b/src/univalue/test/fail21.json deleted file mode 100644 index 62474573b2..0000000000 --- a/src/univalue/test/fail21.json +++ /dev/null @@ -1 +0,0 @@ -{"Comma instead of colon", null} \ No newline at end of file diff --git a/src/univalue/test/fail22.json b/src/univalue/test/fail22.json deleted file mode 100644 index a7752581bc..0000000000 --- a/src/univalue/test/fail22.json +++ /dev/null @@ -1 +0,0 @@ -["Colon instead of comma": false] \ No newline at end of file diff --git a/src/univalue/test/fail23.json b/src/univalue/test/fail23.json deleted file mode 100644 index 494add1ca1..0000000000 --- a/src/univalue/test/fail23.json +++ /dev/null @@ -1 +0,0 @@ -["Bad value", truth] \ No newline at end of file diff --git a/src/univalue/test/fail24.json b/src/univalue/test/fail24.json deleted file mode 100644 index caff239bfc..0000000000 --- a/src/univalue/test/fail24.json +++ /dev/null @@ -1 +0,0 @@ -['single quote'] \ No newline at end of file diff --git a/src/univalue/test/fail25.json b/src/univalue/test/fail25.json deleted file mode 100644 index 8b7ad23e01..0000000000 --- a/src/univalue/test/fail25.json +++ /dev/null @@ -1 +0,0 @@ -[" tab character in string "] \ No newline at end of file diff --git a/src/univalue/test/fail26.json b/src/univalue/test/fail26.json deleted file mode 100644 index 845d26a6a5..0000000000 --- a/src/univalue/test/fail26.json +++ /dev/null @@ -1 +0,0 @@ -["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/src/univalue/test/fail27.json b/src/univalue/test/fail27.json deleted file mode 100644 index 6b01a2ca4a..0000000000 --- a/src/univalue/test/fail27.json +++ /dev/null @@ -1,2 +0,0 @@ -["line -break"] \ No newline at end of file diff --git a/src/univalue/test/fail28.json b/src/univalue/test/fail28.json deleted file mode 100644 index 621a0101c6..0000000000 --- a/src/univalue/test/fail28.json +++ /dev/null @@ -1,2 +0,0 @@ -["line\ -break"] \ No newline at end of file diff --git a/src/univalue/test/fail29.json b/src/univalue/test/fail29.json deleted file mode 100644 index 47ec421bb6..0000000000 --- a/src/univalue/test/fail29.json +++ /dev/null @@ -1 +0,0 @@ -[0e] \ No newline at end of file diff --git a/src/univalue/test/fail3.json b/src/univalue/test/fail3.json deleted file mode 100644 index 168c81eb78..0000000000 --- a/src/univalue/test/fail3.json +++ /dev/null @@ -1 +0,0 @@ -{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/src/univalue/test/fail30.json b/src/univalue/test/fail30.json deleted file mode 100644 index 8ab0bc4b8b..0000000000 --- a/src/univalue/test/fail30.json +++ /dev/null @@ -1 +0,0 @@ -[0e+] \ No newline at end of file diff --git a/src/univalue/test/fail31.json b/src/univalue/test/fail31.json deleted file mode 100644 index 1cce602b51..0000000000 --- a/src/univalue/test/fail31.json +++ /dev/null @@ -1 +0,0 @@ -[0e+-1] \ No newline at end of file diff --git a/src/univalue/test/fail32.json b/src/univalue/test/fail32.json deleted file mode 100644 index 45cba7396f..0000000000 --- a/src/univalue/test/fail32.json +++ /dev/null @@ -1 +0,0 @@ -{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/src/univalue/test/fail33.json b/src/univalue/test/fail33.json deleted file mode 100644 index ca5eb19dc9..0000000000 --- a/src/univalue/test/fail33.json +++ /dev/null @@ -1 +0,0 @@ -["mismatch"} \ No newline at end of file diff --git a/src/univalue/test/fail34.json b/src/univalue/test/fail34.json deleted file mode 100644 index 3f8be17286..0000000000 --- a/src/univalue/test/fail34.json +++ /dev/null @@ -1 +0,0 @@ -{} garbage \ No newline at end of file diff --git a/src/univalue/test/fail35.json b/src/univalue/test/fail35.json deleted file mode 100644 index de30ca5c47..0000000000 --- a/src/univalue/test/fail35.json +++ /dev/null @@ -1 +0,0 @@ -[ true true true [] [] [] ] diff --git a/src/univalue/test/fail36.json b/src/univalue/test/fail36.json deleted file mode 100644 index f82eb8e1f0..0000000000 --- a/src/univalue/test/fail36.json +++ /dev/null @@ -1 +0,0 @@ -{"a":} diff --git a/src/univalue/test/fail37.json b/src/univalue/test/fail37.json deleted file mode 100644 index 3294dc3a42..0000000000 --- a/src/univalue/test/fail37.json +++ /dev/null @@ -1 +0,0 @@ -{"a":1 "b":2} diff --git a/src/univalue/test/fail38.json b/src/univalue/test/fail38.json deleted file mode 100644 index b245e2e46c..0000000000 --- a/src/univalue/test/fail38.json +++ /dev/null @@ -1 +0,0 @@ -["\ud834"] diff --git a/src/univalue/test/fail39.json b/src/univalue/test/fail39.json deleted file mode 100644 index 7c9e263f27..0000000000 --- a/src/univalue/test/fail39.json +++ /dev/null @@ -1 +0,0 @@ -["\udd61"] diff --git a/src/univalue/test/fail4.json b/src/univalue/test/fail4.json deleted file mode 100644 index 9de168bf34..0000000000 --- a/src/univalue/test/fail4.json +++ /dev/null @@ -1 +0,0 @@ -["extra comma",] \ No newline at end of file diff --git a/src/univalue/test/fail40.json b/src/univalue/test/fail40.json deleted file mode 100644 index 664dc9e245..0000000000 --- a/src/univalue/test/fail40.json +++ /dev/null @@ -1 +0,0 @@ -[""] \ No newline at end of file diff --git a/src/univalue/test/fail41.json b/src/univalue/test/fail41.json deleted file mode 100644 index 0de342a2b5..0000000000 --- a/src/univalue/test/fail41.json +++ /dev/null @@ -1 +0,0 @@ -[""] \ No newline at end of file diff --git a/src/univalue/test/fail42.json b/src/univalue/test/fail42.json deleted file mode 100644 index 9c7565adbddf645df5edfbdcd630c7a0f94aa2eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37 kcma!6N=i-3FG^L&E6q_zsw_!Wie*qrOe;w(LWpny0Pvs;RsaA1 diff --git a/src/univalue/test/fail44.json b/src/univalue/test/fail44.json deleted file mode 100644 index 80edceddf1..0000000000 --- a/src/univalue/test/fail44.json +++ /dev/null @@ -1 +0,0 @@ -"This file ends without a newline or close-quote. \ No newline at end of file diff --git a/src/univalue/test/fail5.json b/src/univalue/test/fail5.json deleted file mode 100644 index ddf3ce3d24..0000000000 --- a/src/univalue/test/fail5.json +++ /dev/null @@ -1 +0,0 @@ -["double extra comma",,] \ No newline at end of file diff --git a/src/univalue/test/fail6.json b/src/univalue/test/fail6.json deleted file mode 100644 index ed91580e1b..0000000000 --- a/src/univalue/test/fail6.json +++ /dev/null @@ -1 +0,0 @@ -[ , "<-- missing value"] \ No newline at end of file diff --git a/src/univalue/test/fail7.json b/src/univalue/test/fail7.json deleted file mode 100644 index 8a96af3e4e..0000000000 --- a/src/univalue/test/fail7.json +++ /dev/null @@ -1 +0,0 @@ -["Comma after the close"], \ No newline at end of file diff --git a/src/univalue/test/fail8.json b/src/univalue/test/fail8.json deleted file mode 100644 index b28479c6ec..0000000000 --- a/src/univalue/test/fail8.json +++ /dev/null @@ -1 +0,0 @@ -["Extra close"]] \ No newline at end of file diff --git a/src/univalue/test/fail9.json b/src/univalue/test/fail9.json deleted file mode 100644 index 5815574f36..0000000000 --- a/src/univalue/test/fail9.json +++ /dev/null @@ -1 +0,0 @@ -{"Extra comma": true,} \ No newline at end of file diff --git a/src/univalue/test/no_nul.cpp b/src/univalue/test/no_nul.cpp deleted file mode 100644 index 83d292200b..0000000000 --- a/src/univalue/test/no_nul.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "univalue.h" - -int main (int argc, char *argv[]) -{ - char buf[] = "___[1,2,3]___"; - UniValue val; - return val.read(buf + 3, 7) ? 0 : 1; -} diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp deleted file mode 100644 index 24f1f605b9..0000000000 --- a/src/univalue/test/object.cpp +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) 2014 BitPay Inc. -// Copyright (c) 2014-2016 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include - -#define BOOST_FIXTURE_TEST_SUITE(a, b) -#define BOOST_AUTO_TEST_CASE(funcName) void funcName() -#define BOOST_AUTO_TEST_SUITE_END() -#define BOOST_CHECK(expr) assert(expr) -#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) -#define BOOST_CHECK_THROW(stmt, excMatch) { \ - try { \ - (stmt); \ - } catch (excMatch & e) { \ - } catch (...) { \ - assert(0); \ - } \ - } -#define BOOST_CHECK_NO_THROW(stmt) { \ - try { \ - (stmt); \ - } catch (...) { \ - assert(0); \ - } \ - } - -BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(univalue_constructor) -{ - UniValue v1; - BOOST_CHECK(v1.isNull()); - - UniValue v2(UniValue::VSTR); - BOOST_CHECK(v2.isStr()); - - UniValue v3(UniValue::VSTR, "foo"); - BOOST_CHECK(v3.isStr()); - BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); - - UniValue numTest; - BOOST_CHECK(numTest.setNumStr("82")); - BOOST_CHECK(numTest.isNum()); - BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); - - uint64_t vu64 = 82; - UniValue v4(vu64); - BOOST_CHECK(v4.isNum()); - BOOST_CHECK_EQUAL(v4.getValStr(), "82"); - - int64_t vi64 = -82; - UniValue v5(vi64); - BOOST_CHECK(v5.isNum()); - BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); - - int vi = -688; - UniValue v6(vi); - BOOST_CHECK(v6.isNum()); - BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); - - double vd = -7.21; - UniValue v7(vd); - BOOST_CHECK(v7.isNum()); - BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); - - std::string vs("yawn"); - UniValue v8(vs); - BOOST_CHECK(v8.isStr()); - BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); - - const char *vcs = "zappa"; - UniValue v9(vcs); - BOOST_CHECK(v9.isStr()); - BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); -} - -BOOST_AUTO_TEST_CASE(univalue_typecheck) -{ - UniValue v1; - BOOST_CHECK(v1.setNumStr("1")); - BOOST_CHECK(v1.isNum()); - BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); - - UniValue v2; - BOOST_CHECK(v2.setBool(true)); - BOOST_CHECK_EQUAL(v2.get_bool(), true); - BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); - - UniValue v3; - BOOST_CHECK(v3.setNumStr("32482348723847471234")); - BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); - BOOST_CHECK(v3.setNumStr("1000")); - BOOST_CHECK_EQUAL(v3.get_int64(), 1000); - - UniValue v4; - BOOST_CHECK(v4.setNumStr("2147483648")); - BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); - BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); - BOOST_CHECK(v4.setNumStr("1000")); - BOOST_CHECK_EQUAL(v4.get_int(), 1000); - BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); - BOOST_CHECK_EQUAL(v4.get_real(), 1000); - BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); - BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); - BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); - BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); - - UniValue v5; - BOOST_CHECK(v5.read("[true, 10]")); - BOOST_CHECK_NO_THROW(v5.get_array()); - std::vector vals = v5.getValues(); - BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); - BOOST_CHECK_EQUAL(vals[0].get_bool(), true); - - BOOST_CHECK_EQUAL(vals[1].get_int(), 10); - BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); -} - -BOOST_AUTO_TEST_CASE(univalue_set) -{ - UniValue v(UniValue::VSTR, "foo"); - v.clear(); - BOOST_CHECK(v.isNull()); - BOOST_CHECK_EQUAL(v.getValStr(), ""); - - BOOST_CHECK(v.setObject()); - BOOST_CHECK(v.isObject()); - BOOST_CHECK_EQUAL(v.size(), 0); - BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); - BOOST_CHECK(v.empty()); - - BOOST_CHECK(v.setArray()); - BOOST_CHECK(v.isArray()); - BOOST_CHECK_EQUAL(v.size(), 0); - - BOOST_CHECK(v.setStr("zum")); - BOOST_CHECK(v.isStr()); - BOOST_CHECK_EQUAL(v.getValStr(), "zum"); - - BOOST_CHECK(v.setFloat(-1.01)); - BOOST_CHECK(v.isNum()); - BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); - - BOOST_CHECK(v.setInt((int)1023)); - BOOST_CHECK(v.isNum()); - BOOST_CHECK_EQUAL(v.getValStr(), "1023"); - - BOOST_CHECK(v.setInt((int64_t)-1023LL)); - BOOST_CHECK(v.isNum()); - BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); - - BOOST_CHECK(v.setInt((uint64_t)1023ULL)); - BOOST_CHECK(v.isNum()); - BOOST_CHECK_EQUAL(v.getValStr(), "1023"); - - BOOST_CHECK(v.setNumStr("-688")); - BOOST_CHECK(v.isNum()); - BOOST_CHECK_EQUAL(v.getValStr(), "-688"); - - BOOST_CHECK(v.setBool(false)); - BOOST_CHECK_EQUAL(v.isBool(), true); - BOOST_CHECK_EQUAL(v.isTrue(), false); - BOOST_CHECK_EQUAL(v.isFalse(), true); - BOOST_CHECK_EQUAL(v.getBool(), false); - - BOOST_CHECK(v.setBool(true)); - BOOST_CHECK_EQUAL(v.isBool(), true); - BOOST_CHECK_EQUAL(v.isTrue(), true); - BOOST_CHECK_EQUAL(v.isFalse(), false); - BOOST_CHECK_EQUAL(v.getBool(), true); - - BOOST_CHECK(!v.setNumStr("zombocom")); - - BOOST_CHECK(v.setNull()); - BOOST_CHECK(v.isNull()); -} - -BOOST_AUTO_TEST_CASE(univalue_array) -{ - UniValue arr(UniValue::VARR); - - UniValue v((int64_t)1023LL); - BOOST_CHECK(arr.push_back(v)); - - std::string vStr("zippy"); - BOOST_CHECK(arr.push_back(vStr)); - - const char *s = "pippy"; - BOOST_CHECK(arr.push_back(s)); - - std::vector vec; - v.setStr("boing"); - vec.push_back(v); - - v.setStr("going"); - vec.push_back(v); - - BOOST_CHECK(arr.push_backV(vec)); - - BOOST_CHECK_EQUAL(arr.empty(), false); - BOOST_CHECK_EQUAL(arr.size(), 5); - - BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); - BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); - BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); - BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); - BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); - - BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); - - arr.clear(); - BOOST_CHECK(arr.empty()); - BOOST_CHECK_EQUAL(arr.size(), 0); -} - -BOOST_AUTO_TEST_CASE(univalue_object) -{ - UniValue obj(UniValue::VOBJ); - std::string strKey, strVal; - UniValue v; - - strKey = "age"; - v.setInt(100); - BOOST_CHECK(obj.pushKV(strKey, v)); - - strKey = "first"; - strVal = "John"; - BOOST_CHECK(obj.pushKV(strKey, strVal)); - - strKey = "last"; - const char *cVal = "Smith"; - BOOST_CHECK(obj.pushKV(strKey, cVal)); - - strKey = "distance"; - BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); - - strKey = "time"; - BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); - - strKey = "calories"; - BOOST_CHECK(obj.pushKV(strKey, (int) 12)); - - strKey = "temperature"; - BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); - - UniValue obj2(UniValue::VOBJ); - BOOST_CHECK(obj2.pushKV("cat1", 9000)); - BOOST_CHECK(obj2.pushKV("cat2", 12345)); - - BOOST_CHECK(obj.pushKVs(obj2)); - - BOOST_CHECK_EQUAL(obj.empty(), false); - BOOST_CHECK_EQUAL(obj.size(), 9); - - BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); - BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); - BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); - BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); - BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); - BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); - BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); - BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); - BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); - - BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); - - BOOST_CHECK(obj.exists("age")); - BOOST_CHECK(obj.exists("first")); - BOOST_CHECK(obj.exists("last")); - BOOST_CHECK(obj.exists("distance")); - BOOST_CHECK(obj.exists("time")); - BOOST_CHECK(obj.exists("calories")); - BOOST_CHECK(obj.exists("temperature")); - BOOST_CHECK(obj.exists("cat1")); - BOOST_CHECK(obj.exists("cat2")); - - BOOST_CHECK(!obj.exists("nyuknyuknyuk")); - - std::map objTypes; - objTypes["age"] = UniValue::VNUM; - objTypes["first"] = UniValue::VSTR; - objTypes["last"] = UniValue::VSTR; - objTypes["distance"] = UniValue::VNUM; - objTypes["time"] = UniValue::VNUM; - objTypes["calories"] = UniValue::VNUM; - objTypes["temperature"] = UniValue::VNUM; - objTypes["cat1"] = UniValue::VNUM; - objTypes["cat2"] = UniValue::VNUM; - BOOST_CHECK(obj.checkObject(objTypes)); - - objTypes["cat2"] = UniValue::VSTR; - BOOST_CHECK(!obj.checkObject(objTypes)); - - obj.clear(); - BOOST_CHECK(obj.empty()); - BOOST_CHECK_EQUAL(obj.size(), 0); -} - -static const char *json1 = -"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; - -BOOST_AUTO_TEST_CASE(univalue_readwrite) -{ - UniValue v; - BOOST_CHECK(v.read(json1)); - - std::string strJson1(json1); - BOOST_CHECK(v.read(strJson1)); - - BOOST_CHECK(v.isArray()); - BOOST_CHECK_EQUAL(v.size(), 2); - - BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); - - UniValue obj = v[1]; - BOOST_CHECK(obj.isObject()); - BOOST_CHECK_EQUAL(obj.size(), 3); - - BOOST_CHECK(obj["key1"].isStr()); - std::string correctValue("str"); - correctValue.push_back('\0'); - BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); - BOOST_CHECK(obj["key2"].isNum()); - BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); - BOOST_CHECK(obj["key3"].isObject()); - - BOOST_CHECK_EQUAL(strJson1, v.write()); - - /* Check for (correctly reporting) a parsing error if the initial - JSON construct is followed by more stuff. Note that whitespace - is, of course, exempt. */ - - BOOST_CHECK(v.read(" {}\n ")); - BOOST_CHECK(v.isObject()); - BOOST_CHECK(v.read(" []\n ")); - BOOST_CHECK(v.isArray()); - - BOOST_CHECK(!v.read("@{}")); - BOOST_CHECK(!v.read("{} garbage")); - BOOST_CHECK(!v.read("[]{}")); - BOOST_CHECK(!v.read("{}[]")); - BOOST_CHECK(!v.read("{} 42")); -} - -BOOST_AUTO_TEST_SUITE_END() - -int main (int argc, char *argv[]) -{ - univalue_constructor(); - univalue_typecheck(); - univalue_set(); - univalue_array(); - univalue_object(); - univalue_readwrite(); - return 0; -} - diff --git a/src/univalue/test/pass1.json b/src/univalue/test/pass1.json deleted file mode 100644 index 70e2685436..0000000000 --- a/src/univalue/test/pass1.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - "JSON Test Pattern pass1", - {"object with 1 member":["array with 1 element"]}, - {}, - [], - -42, - true, - false, - null, - { - "integer": 1234567890, - "real": -9876.543210, - "e": 0.123456789e-12, - "E": 1.234567890E+34, - "": 23456789012E66, - "zero": 0, - "one": 1, - "space": " ", - "quote": "\"", - "backslash": "\\", - "controls": "\b\f\n\r\t", - "slash": "/ & \/", - "alpha": "abcdefghijklmnopqrstuvwyz", - "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", - "digit": "0123456789", - "0123456789": "digit", - "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", - "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", - "true": true, - "false": false, - "null": null, - "array":[ ], - "object":{ }, - "address": "50 St. James Street", - "url": "http://www.JSON.org/", - "comment": "// /* */": " ", - " s p a c e d " :[1,2 , 3 - -, - -4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], - "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", - "quotes": "" \u0022 %22 0x22 034 "", - "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" -: "A key can be any string" - }, - 0.5 ,98.6 -, -99.44 -, - -1066, -1e1, -0.1e1, -1e-1, -1e00,2e+00,2e-00 -,"rosebud"] \ No newline at end of file diff --git a/src/univalue/test/pass2.json b/src/univalue/test/pass2.json deleted file mode 100644 index d3c63c7ad8..0000000000 --- a/src/univalue/test/pass2.json +++ /dev/null @@ -1 +0,0 @@ -[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/src/univalue/test/pass3.json b/src/univalue/test/pass3.json deleted file mode 100644 index 4528d51f1a..0000000000 --- a/src/univalue/test/pass3.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "JSON Test Pattern pass3": { - "The outermost value": "must be an object or array.", - "In this test": "It is an object." - } -} diff --git a/src/univalue/test/round1.json b/src/univalue/test/round1.json deleted file mode 100644 index a711e7308b..0000000000 --- a/src/univalue/test/round1.json +++ /dev/null @@ -1 +0,0 @@ -["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"] diff --git a/src/univalue/test/round2.json b/src/univalue/test/round2.json deleted file mode 100644 index b766cccc68..0000000000 --- a/src/univalue/test/round2.json +++ /dev/null @@ -1 +0,0 @@ -["a§■𐎒𝅘𝅥𝅯"] diff --git a/src/univalue/test/round3.json b/src/univalue/test/round3.json deleted file mode 100644 index 7182dc2f9b..0000000000 --- a/src/univalue/test/round3.json +++ /dev/null @@ -1 +0,0 @@ -"abcdefghijklmnopqrstuvwxyz" diff --git a/src/univalue/test/round4.json b/src/univalue/test/round4.json deleted file mode 100644 index 7f8f011eb7..0000000000 --- a/src/univalue/test/round4.json +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/src/univalue/test/round5.json b/src/univalue/test/round5.json deleted file mode 100644 index 27ba77ddaf..0000000000 --- a/src/univalue/test/round5.json +++ /dev/null @@ -1 +0,0 @@ -true diff --git a/src/univalue/test/round6.json b/src/univalue/test/round6.json deleted file mode 100644 index c508d5366f..0000000000 --- a/src/univalue/test/round6.json +++ /dev/null @@ -1 +0,0 @@ -false diff --git a/src/univalue/test/round7.json b/src/univalue/test/round7.json deleted file mode 100644 index 19765bd501..0000000000 --- a/src/univalue/test/round7.json +++ /dev/null @@ -1 +0,0 @@ -null diff --git a/src/univalue/test/test_json.cpp b/src/univalue/test/test_json.cpp deleted file mode 100644 index 2943bae2b1..0000000000 --- a/src/univalue/test/test_json.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Test program that can be called by the JSON test suite at -// https://github.com/nst/JSONTestSuite. -// -// It reads JSON input from stdin and exits with code 0 if it can be parsed -// successfully. It also pretty prints the parsed JSON value to stdout. - -#include -#include -#include "univalue.h" - -using namespace std; - -int main (int argc, char *argv[]) -{ - UniValue val; - if (val.read(string(istreambuf_iterator(cin), - istreambuf_iterator()))) { - cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; - return 0; - } else { - cerr << "JSON Parse Error." << endl; - return 1; - } -} diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp deleted file mode 100644 index 2c37794a4b..0000000000 --- a/src/univalue/test/unitester.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include "univalue.h" - -#ifndef JSON_TEST_SRC -#error JSON_TEST_SRC must point to test source directory -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#endif - -using namespace std; -string srcdir(JSON_TEST_SRC); -static bool test_failed = false; - -#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } -#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } - -static std::string rtrim(std::string s) -{ - s.erase(s.find_last_not_of(" \n\r\t")+1); - return s; -} - -static void runtest(string filename, const string& jdata) -{ - string prefix = filename.substr(0, 4); - - bool wantPass = (prefix == "pass") || (prefix == "roun"); - bool wantFail = (prefix == "fail"); - bool wantRoundTrip = (prefix == "roun"); - assert(wantPass || wantFail); - - UniValue val; - bool testResult = val.read(jdata); - - if (wantPass) { - d_assert(testResult == true); - } else { - d_assert(testResult == false); - } - - if (wantRoundTrip) { - std::string odata = val.write(0, 0); - assert(odata == rtrim(jdata)); - } -} - -static void runtest_file(const char *filename_) -{ - string basename(filename_); - string filename = srcdir + "/" + basename; - FILE *f = fopen(filename.c_str(), "r"); - assert(f != NULL); - - string jdata; - - char buf[4096]; - while (!feof(f)) { - int bread = fread(buf, 1, sizeof(buf), f); - assert(!ferror(f)); - - string s(buf, bread); - jdata += s; - } - - assert(!ferror(f)); - fclose(f); - - runtest(basename, jdata); -} - -static const char *filenames[] = { - "fail10.json", - "fail11.json", - "fail12.json", - "fail13.json", - "fail14.json", - "fail15.json", - "fail16.json", - "fail17.json", - //"fail18.json", // investigate - "fail19.json", - "fail1.json", - "fail20.json", - "fail21.json", - "fail22.json", - "fail23.json", - "fail24.json", - "fail25.json", - "fail26.json", - "fail27.json", - "fail28.json", - "fail29.json", - "fail2.json", - "fail30.json", - "fail31.json", - "fail32.json", - "fail33.json", - "fail34.json", - "fail35.json", - "fail36.json", - "fail37.json", - "fail38.json", // invalid unicode: only first half of surrogate pair - "fail39.json", // invalid unicode: only second half of surrogate pair - "fail40.json", // invalid unicode: broken UTF-8 - "fail41.json", // invalid unicode: unfinished UTF-8 - "fail42.json", // valid json with garbage following a nul byte - "fail44.json", // unterminated string - "fail3.json", - "fail4.json", // extra comma - "fail5.json", - "fail6.json", - "fail7.json", - "fail8.json", - "fail9.json", // extra comma - "pass1.json", - "pass2.json", - "pass3.json", - "round1.json", // round-trip test - "round2.json", // unicode - "round3.json", // bare string - "round4.json", // bare number - "round5.json", // bare true - "round6.json", // bare false - "round7.json", // bare null -}; - -// Test \u handling -void unescape_unicode_test() -{ - UniValue val; - bool testResult; - // Escaped ASCII (quote) - testResult = val.read("[\"\\u0022\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\""); - // Escaped Basic Plane character, two-byte UTF-8 - testResult = val.read("[\"\\u0191\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xc6\x91"); - // Escaped Basic Plane character, three-byte UTF-8 - testResult = val.read("[\"\\u2191\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xe2\x86\x91"); - // Escaped Supplementary Plane character U+1d161 - testResult = val.read("[\"\\ud834\\udd61\"]"); - f_assert(testResult); - f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); -} - -int main (int argc, char *argv[]) -{ - for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { - runtest_file(filenames[fidx]); - } - - unescape_unicode_test(); - - return test_failed ? 1 : 0; -} - From 1f8ee6c961716f52f259c7a40a9a56669b2c8f7b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Nov 2020 11:50:39 -0500 Subject: [PATCH 0511/1888] Squashed 'src/univalue/' content from commit dac5296 git-subtree-dir: src/univalue git-subtree-split: dac529675973c5da1e32414e1274908836399d9b --- .gitignore | 32 +++ .travis.yml | 52 ++++ COPYING | 19 ++ Makefile.am | 115 ++++++++ README.md | 32 +++ TODO | 10 + autogen.sh | 9 + build-aux/m4/.gitignore | 1 + configure.ac | 69 +++++ gen/gen.cpp | 84 ++++++ include/univalue.h | 296 ++++++++++++++++++++ lib/.gitignore | 2 + lib/univalue.cpp | 359 ++++++++++++++++++++++++ lib/univalue_escapes.h | 262 ++++++++++++++++++ lib/univalue_read.cpp | 454 +++++++++++++++++++++++++++++++ lib/univalue_utffilter.h | 119 ++++++++ lib/univalue_write.cpp | 115 ++++++++ pc/libunivalue-uninstalled.pc.in | 9 + pc/libunivalue.pc.in | 10 + test/.gitignore | 8 + test/fail1.json | 1 + test/fail10.json | 1 + test/fail11.json | 1 + test/fail12.json | 1 + test/fail13.json | 1 + test/fail14.json | 1 + test/fail15.json | 1 + test/fail16.json | 1 + test/fail17.json | 1 + test/fail18.json | 1 + test/fail19.json | 1 + test/fail2.json | 1 + test/fail20.json | 1 + test/fail21.json | 1 + test/fail22.json | 1 + test/fail23.json | 1 + test/fail24.json | 1 + test/fail25.json | 1 + test/fail26.json | 1 + test/fail27.json | 2 + test/fail28.json | 2 + test/fail29.json | 1 + test/fail3.json | 1 + test/fail30.json | 1 + test/fail31.json | 1 + test/fail32.json | 1 + test/fail33.json | 1 + test/fail34.json | 1 + test/fail35.json | 1 + test/fail36.json | 1 + test/fail37.json | 1 + test/fail38.json | 1 + test/fail39.json | 1 + test/fail4.json | 1 + test/fail40.json | 1 + test/fail41.json | 1 + test/fail42.json | Bin 0 -> 37 bytes test/fail44.json | 1 + test/fail5.json | 1 + test/fail6.json | 1 + test/fail7.json | 1 + test/fail8.json | 1 + test/fail9.json | 1 + test/no_nul.cpp | 8 + test/object.cpp | 365 +++++++++++++++++++++++++ test/pass1.json | 58 ++++ test/pass2.json | 1 + test/pass3.json | 6 + test/round1.json | 1 + test/round2.json | 1 + test/round3.json | 1 + test/round4.json | 1 + test/round5.json | 1 + test/round6.json | 1 + test/round7.json | 1 + test/test_json.cpp | 24 ++ test/unitester.cpp | 170 ++++++++++++ 77 files changed, 2740 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 COPYING create mode 100644 Makefile.am create mode 100644 README.md create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 build-aux/m4/.gitignore create mode 100644 configure.ac create mode 100644 gen/gen.cpp create mode 100644 include/univalue.h create mode 100644 lib/.gitignore create mode 100644 lib/univalue.cpp create mode 100644 lib/univalue_escapes.h create mode 100644 lib/univalue_read.cpp create mode 100644 lib/univalue_utffilter.h create mode 100644 lib/univalue_write.cpp create mode 100644 pc/libunivalue-uninstalled.pc.in create mode 100644 pc/libunivalue.pc.in create mode 100644 test/.gitignore create mode 100644 test/fail1.json create mode 100644 test/fail10.json create mode 100644 test/fail11.json create mode 100644 test/fail12.json create mode 100644 test/fail13.json create mode 100644 test/fail14.json create mode 100644 test/fail15.json create mode 100644 test/fail16.json create mode 100644 test/fail17.json create mode 100644 test/fail18.json create mode 100644 test/fail19.json create mode 100644 test/fail2.json create mode 100644 test/fail20.json create mode 100644 test/fail21.json create mode 100644 test/fail22.json create mode 100644 test/fail23.json create mode 100644 test/fail24.json create mode 100644 test/fail25.json create mode 100644 test/fail26.json create mode 100644 test/fail27.json create mode 100644 test/fail28.json create mode 100644 test/fail29.json create mode 100644 test/fail3.json create mode 100644 test/fail30.json create mode 100644 test/fail31.json create mode 100644 test/fail32.json create mode 100644 test/fail33.json create mode 100644 test/fail34.json create mode 100644 test/fail35.json create mode 100644 test/fail36.json create mode 100644 test/fail37.json create mode 100644 test/fail38.json create mode 100644 test/fail39.json create mode 100644 test/fail4.json create mode 100644 test/fail40.json create mode 100644 test/fail41.json create mode 100644 test/fail42.json create mode 100644 test/fail44.json create mode 100644 test/fail5.json create mode 100644 test/fail6.json create mode 100644 test/fail7.json create mode 100644 test/fail8.json create mode 100644 test/fail9.json create mode 100644 test/no_nul.cpp create mode 100644 test/object.cpp create mode 100644 test/pass1.json create mode 100644 test/pass2.json create mode 100644 test/pass3.json create mode 100644 test/round1.json create mode 100644 test/round2.json create mode 100644 test/round3.json create mode 100644 test/round4.json create mode 100644 test/round5.json create mode 100644 test/round6.json create mode 100644 test/round7.json create mode 100644 test/test_json.cpp create mode 100644 test/unitester.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..19e42f814a --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.log +config.status +config.guess +config.sub +configure +depcomp +install-sh +missing +stamp-h1 +univalue-config.h* +test-driver +libtool +ltmain.sh +test-suite.log + +*.a +*.la +*.lo +*.logs +*.o +*.pc +*.trs + +.dirstamp +.libs diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..132743d349 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,52 @@ +language: cpp + +compiler: + - clang + - gcc + +os: + - linux + - osx + +sudo: false + +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=true + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + +cache: + apt: true + +addons: + apt: + packages: + - pkg-config + +before_script: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh + +script: + - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) + - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi + +matrix: + fast_finish: true + include: + - os: linux + compiler: gcc + env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false + addons: + apt: + packages: + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - binutils-mingw-w64-x86-64 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..1fb429f356 --- /dev/null +++ b/COPYING @@ -0,0 +1,19 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..287bb97fec --- /dev/null +++ b/Makefile.am @@ -0,0 +1,115 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 +.PHONY: gen +.INTERMEDIATE: $(GENBIN) + +include_HEADERS = include/univalue.h +noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h + +lib_LTLIBRARIES = libunivalue.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pc/libunivalue.pc + +libunivalue_la_SOURCES = \ + lib/univalue.cpp \ + lib/univalue_read.cpp \ + lib/univalue_write.cpp + +libunivalue_la_LDFLAGS = \ + -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ + -no-undefined +libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include + +TESTS = test/object test/unitester test/no_nul + +GENBIN = gen/gen$(BUILD_EXEEXT) +GEN_SRCS = gen/gen.cpp + +$(GENBIN): $(GEN_SRCS) + @echo Building $@ + $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< + +gen: lib/univalue_escapes.h $(GENBIN) + @echo Updating $< + $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h + +noinst_PROGRAMS = $(TESTS) test/test_json + +TEST_DATA_DIR=test + +test_unitester_SOURCES = test/unitester.cpp +test_unitester_LDADD = libunivalue.la +test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_test_json_SOURCES = test/test_json.cpp +test_test_json_LDADD = libunivalue.la +test_test_json_CXXFLAGS = -I$(top_srcdir)/include +test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_no_nul_SOURCES = test/no_nul.cpp +test_no_nul_LDADD = libunivalue.la +test_no_nul_CXXFLAGS = -I$(top_srcdir)/include +test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_object_SOURCES = test/object.cpp +test_object_LDADD = libunivalue.la +test_object_CXXFLAGS = -I$(top_srcdir)/include +test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = \ + $(TEST_DATA_DIR)/fail10.json \ + $(TEST_DATA_DIR)/fail11.json \ + $(TEST_DATA_DIR)/fail12.json \ + $(TEST_DATA_DIR)/fail13.json \ + $(TEST_DATA_DIR)/fail14.json \ + $(TEST_DATA_DIR)/fail15.json \ + $(TEST_DATA_DIR)/fail16.json \ + $(TEST_DATA_DIR)/fail17.json \ + $(TEST_DATA_DIR)/fail18.json \ + $(TEST_DATA_DIR)/fail19.json \ + $(TEST_DATA_DIR)/fail1.json \ + $(TEST_DATA_DIR)/fail20.json \ + $(TEST_DATA_DIR)/fail21.json \ + $(TEST_DATA_DIR)/fail22.json \ + $(TEST_DATA_DIR)/fail23.json \ + $(TEST_DATA_DIR)/fail24.json \ + $(TEST_DATA_DIR)/fail25.json \ + $(TEST_DATA_DIR)/fail26.json \ + $(TEST_DATA_DIR)/fail27.json \ + $(TEST_DATA_DIR)/fail28.json \ + $(TEST_DATA_DIR)/fail29.json \ + $(TEST_DATA_DIR)/fail2.json \ + $(TEST_DATA_DIR)/fail30.json \ + $(TEST_DATA_DIR)/fail31.json \ + $(TEST_DATA_DIR)/fail32.json \ + $(TEST_DATA_DIR)/fail33.json \ + $(TEST_DATA_DIR)/fail34.json \ + $(TEST_DATA_DIR)/fail35.json \ + $(TEST_DATA_DIR)/fail36.json \ + $(TEST_DATA_DIR)/fail37.json \ + $(TEST_DATA_DIR)/fail38.json \ + $(TEST_DATA_DIR)/fail39.json \ + $(TEST_DATA_DIR)/fail40.json \ + $(TEST_DATA_DIR)/fail41.json \ + $(TEST_DATA_DIR)/fail42.json \ + $(TEST_DATA_DIR)/fail44.json \ + $(TEST_DATA_DIR)/fail3.json \ + $(TEST_DATA_DIR)/fail4.json \ + $(TEST_DATA_DIR)/fail5.json \ + $(TEST_DATA_DIR)/fail6.json \ + $(TEST_DATA_DIR)/fail7.json \ + $(TEST_DATA_DIR)/fail8.json \ + $(TEST_DATA_DIR)/fail9.json \ + $(TEST_DATA_DIR)/pass1.json \ + $(TEST_DATA_DIR)/pass2.json \ + $(TEST_DATA_DIR)/pass3.json \ + $(TEST_DATA_DIR)/round1.json \ + $(TEST_DATA_DIR)/round2.json \ + $(TEST_DATA_DIR)/round3.json \ + $(TEST_DATA_DIR)/round4.json \ + $(TEST_DATA_DIR)/round5.json \ + $(TEST_DATA_DIR)/round6.json \ + $(TEST_DATA_DIR)/round7.json + +EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) diff --git a/README.md b/README.md new file mode 100644 index 0000000000..36aa786a4c --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ + +# UniValue + +## Summary + +A universal value class, with JSON encoding and decoding. + +UniValue is an abstract data type that may be a null, boolean, string, +number, array container, or a key/value dictionary container, nested to +an arbitrary depth. + +This class is aligned with the JSON standard, [RFC +7159](https://tools.ietf.org/html/rfc7159.html). + +## Installation + +This project is a standard GNU +[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) +project. Build and install instructions are available in the `INSTALL` +file provided with GNU autotools. + +``` +$ ./autogen.sh +$ ./configure +$ make +``` + +## Design + +UniValue provides a single dynamic RAII C++ object class, +and minimizes template use (contra json_spirit). + diff --git a/TODO b/TODO new file mode 100644 index 0000000000..5530048e92 --- /dev/null +++ b/TODO @@ -0,0 +1,10 @@ + +Rearrange tree for easier 'git subtree' style use + +Move towards C++11 etc. + +Namespace support - must come up with useful shorthand, avoiding +long Univalue::Univalue::Univalue usages forced upon library users. + +Improve test suite + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000000..4b38721faa --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +autoreconf --install --force diff --git a/build-aux/m4/.gitignore b/build-aux/m4/.gitignore new file mode 100644 index 0000000000..f063686524 --- /dev/null +++ b/build-aux/m4/.gitignore @@ -0,0 +1 @@ +/*.m4 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000000..8298332ac1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,69 @@ +m4_define([libunivalue_major_version], [1]) +m4_define([libunivalue_minor_version], [1]) +m4_define([libunivalue_micro_version], [3]) +m4_define([libunivalue_interface_age], [3]) +# If you need a modifier for the version number. +# Normally empty, but can be used to make "fixup" releases. +m4_define([libunivalue_extraversion], []) + +dnl libtool versioning from libunivalue +m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) +m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) +m4_define([libunivalue_revision], [libunivalue_interface_age]) +m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) +m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) + + +AC_INIT([univalue], [1.0.3], + [http://github.com/jgarzik/univalue/]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREREQ(2.60) +AC_CONFIG_SRCDIR([lib/univalue.cpp]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_HEADERS([univalue-config.h]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) + +LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version +LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version +LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version +LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age + +# ABI version +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +LIBUNIVALUE_CURRENT=libunivalue_current +LIBUNIVALUE_REVISION=libunivalue_revision +LIBUNIVALUE_AGE=libunivalue_age + +AC_SUBST(LIBUNIVALUE_CURRENT) +AC_SUBST(LIBUNIVALUE_REVISION) +AC_SUBST(LIBUNIVALUE_AGE) + +LT_INIT +LT_LANG([C++]) + +case $host in + *mingw*) + LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" + ;; +esac + +BUILD_EXEEXT= +case $build in + *mingw*) + BUILD_EXEEXT=".exe" + ;; +esac + +AC_CONFIG_FILES([ + Makefile + pc/libunivalue.pc + pc/libunivalue-uninstalled.pc]) + +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_OUTPUT + diff --git a/gen/gen.cpp b/gen/gen.cpp new file mode 100644 index 0000000000..17f361941d --- /dev/null +++ b/gen/gen.cpp @@ -0,0 +1,84 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// +// To re-create univalue_escapes.h: +// $ g++ -o gen gen.cpp +// $ ./gen > univalue_escapes.h +// + +#include +#include +#include "univalue.h" + +using namespace std; + +static bool initEscapes; +static std::string escapes[256]; + +static void initJsonEscape() +{ + // Escape all lower control characters (some get overridden with smaller sequences below) + for (int ch=0x00; ch<0x20; ++ch) { + char tmpbuf[20]; + snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); + escapes[ch] = std::string(tmpbuf); + } + + escapes[(int)'"'] = "\\\""; + escapes[(int)'\\'] = "\\\\"; + escapes[(int)'\b'] = "\\b"; + escapes[(int)'\f'] = "\\f"; + escapes[(int)'\n'] = "\\n"; + escapes[(int)'\r'] = "\\r"; + escapes[(int)'\t'] = "\\t"; + escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE + + initEscapes = true; +} + +static void outputEscape() +{ + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "static const char *escapes[256] = {\n"); + + for (unsigned int i = 0; i < 256; i++) { + if (escapes[i].empty()) { + printf("\tNULL,\n"); + } else { + printf("\t\""); + + unsigned int si; + for (si = 0; si < escapes[i].size(); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } + + printf("\",\n"); + } + } + + printf( "};\n" + "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); +} + +int main (int argc, char *argv[]) +{ + initJsonEscape(); + outputEscape(); + return 0; +} + diff --git a/include/univalue.h b/include/univalue.h new file mode 100644 index 0000000000..cc92cd2a9c --- /dev/null +++ b/include/univalue.h @@ -0,0 +1,296 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef __UNIVALUE_H__ +#define __UNIVALUE_H__ + +#include + +#include +#include +#include +#include + +#include // .get_int64() +#include // std::pair + +class UniValue { +public: + enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; + + UniValue() { typ = VNULL; } + UniValue(UniValue::VType initialType, const std::string& initialStr = "") { + typ = initialType; + val = initialStr; + } + UniValue(uint64_t val_) { + setInt(val_); + } + UniValue(int64_t val_) { + setInt(val_); + } + UniValue(bool val_) { + setBool(val_); + } + UniValue(int val_) { + setInt(val_); + } + UniValue(double val_) { + setFloat(val_); + } + UniValue(const std::string& val_) { + setStr(val_); + } + UniValue(const char *val_) { + std::string s(val_); + setStr(s); + } + ~UniValue() {} + + void clear(); + + bool setNull(); + bool setBool(bool val); + bool setNumStr(const std::string& val); + bool setInt(uint64_t val); + bool setInt(int64_t val); + bool setInt(int val_) { return setInt((int64_t)val_); } + bool setFloat(double val); + bool setStr(const std::string& val); + bool setArray(); + bool setObject(); + + enum VType getType() const { return typ; } + const std::string& getValStr() const { return val; } + bool empty() const { return (values.size() == 0); } + + size_t size() const { return values.size(); } + + bool getBool() const { return isTrue(); } + bool checkObject(const std::map& memberTypes); + const UniValue& operator[](const std::string& key) const; + const UniValue& operator[](size_t index) const; + bool exists(const std::string& key) const { size_t i; return findKey(key, i); } + + bool isNull() const { return (typ == VNULL); } + bool isTrue() const { return (typ == VBOOL) && (val == "1"); } + bool isFalse() const { return (typ == VBOOL) && (val != "1"); } + bool isBool() const { return (typ == VBOOL); } + bool isStr() const { return (typ == VSTR); } + bool isNum() const { return (typ == VNUM); } + bool isArray() const { return (typ == VARR); } + bool isObject() const { return (typ == VOBJ); } + + bool push_back(const UniValue& val); + bool push_back(const std::string& val_) { + UniValue tmpVal(VSTR, val_); + return push_back(tmpVal); + } + bool push_back(const char *val_) { + std::string s(val_); + return push_back(s); + } + bool push_back(uint64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_backV(const std::vector& vec); + + bool pushKV(const std::string& key, const UniValue& val); + bool pushKV(const std::string& key, const std::string& val_) { + UniValue tmpVal(VSTR, val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, const char *val_) { + std::string _val(val_); + return pushKV(key, _val); + } + bool pushKV(const std::string& key, int64_t val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, uint64_t val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, int val_) { + UniValue tmpVal((int64_t)val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, double val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKVs(const UniValue& obj); + + std::string write(unsigned int prettyIndent = 0, + unsigned int indentLevel = 0) const; + + bool read(const char *raw, size_t len); + bool read(const char *raw); + bool read(const std::string& rawStr) { + return read(rawStr.data(), rawStr.size()); + } + +private: + UniValue::VType typ; + std::string val; // numbers are stored as C++ strings + std::vector keys; + std::vector values; + + bool findKey(const std::string& key, size_t& retIdx) const; + void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; + void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; + +public: + // Strict type-specific getters, these throw std::runtime_error if the + // value is of unexpected type + const std::vector& getKeys() const; + const std::vector& getValues() const; + bool get_bool() const; + const std::string& get_str() const; + int get_int() const; + int64_t get_int64() const; + double get_real() const; + const UniValue& get_obj() const; + const UniValue& get_array() const; + + enum VType type() const { return getType(); } + bool push_back(std::pair pear) { + return pushKV(pear.first, pear.second); + } + friend const UniValue& find_value( const UniValue& obj, const std::string& name); +}; + +// +// The following were added for compatibility with json_spirit. +// Most duplicate other methods, and should be removed. +// +static inline std::pair Pair(const char *cKey, const char *cVal) +{ + std::string key(cKey); + UniValue uVal(cVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, std::string strVal) +{ + std::string key(cKey); + UniValue uVal(strVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, uint64_t u64Val) +{ + std::string key(cKey); + UniValue uVal(u64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int64_t i64Val) +{ + std::string key(cKey); + UniValue uVal(i64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, bool iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, double dVal) +{ + std::string key(cKey); + UniValue uVal(dVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, const UniValue& uVal) +{ + std::string key(cKey); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(std::string key, const UniValue& uVal) +{ + return std::make_pair(key, uVal); +} + +enum jtokentype { + JTOK_ERR = -1, + JTOK_NONE = 0, // eof + JTOK_OBJ_OPEN, + JTOK_OBJ_CLOSE, + JTOK_ARR_OPEN, + JTOK_ARR_CLOSE, + JTOK_COLON, + JTOK_COMMA, + JTOK_KW_NULL, + JTOK_KW_TRUE, + JTOK_KW_FALSE, + JTOK_NUMBER, + JTOK_STRING, +}; + +extern enum jtokentype getJsonToken(std::string& tokenVal, + unsigned int& consumed, const char *raw, const char *end); +extern const char *uvTypeName(UniValue::VType t); + +static inline bool jsonTokenIsValue(enum jtokentype jtt) +{ + switch (jtt) { + case JTOK_KW_NULL: + case JTOK_KW_TRUE: + case JTOK_KW_FALSE: + case JTOK_NUMBER: + case JTOK_STRING: + return true; + + default: + return false; + } + + // not reached +} + +static inline bool json_isspace(int ch) +{ + switch (ch) { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + return true; + + default: + return false; + } + + // not reached +} + +extern const UniValue NullUniValue; + +const UniValue& find_value( const UniValue& obj, const std::string& name); + +#endif // __UNIVALUE_H__ diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000000..ee7fc2851c --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,2 @@ +gen +.libs diff --git a/lib/univalue.cpp b/lib/univalue.cpp new file mode 100644 index 0000000000..b9491a967b --- /dev/null +++ b/lib/univalue.cpp @@ -0,0 +1,359 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "univalue.h" + +namespace +{ +static bool ParsePrechecks(const std::string& str) +{ + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int32_t)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); +} +} + +using namespace std; + +const UniValue NullUniValue; + +void UniValue::clear() +{ + typ = VNULL; + val.clear(); + keys.clear(); + values.clear(); +} + +bool UniValue::setNull() +{ + clear(); + return true; +} + +bool UniValue::setBool(bool val_) +{ + clear(); + typ = VBOOL; + if (val_) + val = "1"; + return true; +} + +static bool validNumStr(const string& s) +{ + string tokenVal; + unsigned int consumed; + enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size()); + return (tt == JTOK_NUMBER); +} + +bool UniValue::setNumStr(const string& val_) +{ + if (!validNumStr(val_)) + return false; + + clear(); + typ = VNUM; + val = val_; + return true; +} + +bool UniValue::setInt(uint64_t val_) +{ + ostringstream oss; + + oss << val_; + + return setNumStr(oss.str()); +} + +bool UniValue::setInt(int64_t val_) +{ + ostringstream oss; + + oss << val_; + + return setNumStr(oss.str()); +} + +bool UniValue::setFloat(double val_) +{ + ostringstream oss; + + oss << std::setprecision(16) << val_; + + bool ret = setNumStr(oss.str()); + typ = VNUM; + return ret; +} + +bool UniValue::setStr(const string& val_) +{ + clear(); + typ = VSTR; + val = val_; + return true; +} + +bool UniValue::setArray() +{ + clear(); + typ = VARR; + return true; +} + +bool UniValue::setObject() +{ + clear(); + typ = VOBJ; + return true; +} + +bool UniValue::push_back(const UniValue& val_) +{ + if (typ != VARR) + return false; + + values.push_back(val_); + return true; +} + +bool UniValue::push_backV(const std::vector& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), vec.begin(), vec.end()); + + return true; +} + +bool UniValue::pushKV(const std::string& key, const UniValue& val_) +{ + if (typ != VOBJ) + return false; + + keys.push_back(key); + values.push_back(val_); + return true; +} + +bool UniValue::pushKVs(const UniValue& obj) +{ + if (typ != VOBJ || obj.typ != VOBJ) + return false; + + for (unsigned int i = 0; i < obj.keys.size(); i++) { + keys.push_back(obj.keys[i]); + values.push_back(obj.values.at(i)); + } + + return true; +} + +bool UniValue::findKey(const std::string& key, size_t& retIdx) const +{ + for (size_t i = 0; i < keys.size(); i++) { + if (keys[i] == key) { + retIdx = i; + return true; + } + } + + return false; +} + +bool UniValue::checkObject(const std::map& t) +{ + for (std::map::const_iterator it = t.begin(); + it != t.end(); ++it) { + size_t idx = 0; + if (!findKey(it->first, idx)) + return false; + + if (values.at(idx).getType() != it->second) + return false; + } + + return true; +} + +const UniValue& UniValue::operator[](const std::string& key) const +{ + if (typ != VOBJ) + return NullUniValue; + + size_t index = 0; + if (!findKey(key, index)) + return NullUniValue; + + return values.at(index); +} + +const UniValue& UniValue::operator[](size_t index) const +{ + if (typ != VOBJ && typ != VARR) + return NullUniValue; + if (index >= values.size()) + return NullUniValue; + + return values.at(index); +} + +const char *uvTypeName(UniValue::VType t) +{ + switch (t) { + case UniValue::VNULL: return "null"; + case UniValue::VBOOL: return "bool"; + case UniValue::VOBJ: return "object"; + case UniValue::VARR: return "array"; + case UniValue::VSTR: return "string"; + case UniValue::VNUM: return "number"; + } + + // not reached + return NULL; +} + +const UniValue& find_value(const UniValue& obj, const std::string& name) +{ + for (unsigned int i = 0; i < obj.keys.size(); i++) + if (obj.keys[i] == name) + return obj.values.at(i); + + return NullUniValue; +} + +const std::vector& UniValue::getKeys() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return keys; +} + +const std::vector& UniValue::getValues() const +{ + if (typ != VOBJ && typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +bool UniValue::get_bool() const +{ + if (typ != VBOOL) + throw std::runtime_error("JSON value is not a boolean as expected"); + return getBool(); +} + +const std::string& UniValue::get_str() const +{ + if (typ != VSTR) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +int UniValue::get_int() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int32_t retval; + if (!ParseInt32(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +int64_t UniValue::get_int64() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int64_t retval; + if (!ParseInt64(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +double UniValue::get_real() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not a number as expected"); + double retval; + if (!ParseDouble(getValStr(), &retval)) + throw std::runtime_error("JSON double out of range"); + return retval; +} + +const UniValue& UniValue::get_obj() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return *this; +} + +const UniValue& UniValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/lib/univalue_escapes.h b/lib/univalue_escapes.h new file mode 100644 index 0000000000..74596aab6d --- /dev/null +++ b/lib/univalue_escapes.h @@ -0,0 +1,262 @@ +// Automatically generated file. Do not modify. +#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H +static const char *escapes[256] = { + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", + "\\b", + "\\t", + "\\n", + "\\u000b", + "\\f", + "\\r", + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", + NULL, + NULL, + "\\\"", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\\", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\u007f", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; +#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/lib/univalue_read.cpp b/lib/univalue_read.cpp new file mode 100644 index 0000000000..2bd83238b4 --- /dev/null +++ b/lib/univalue_read.cpp @@ -0,0 +1,454 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include "univalue.h" +#include "univalue_utffilter.h" + +using namespace std; + +static bool json_isdigit(int ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + +// convert hexadecimal string to unsigned integer +static const char *hatoui(const char *first, const char *last, + unsigned int& out) +{ + unsigned int result = 0; + for (; first != last; ++first) + { + int digit; + if (json_isdigit(*first)) + digit = *first - '0'; + + else if (*first >= 'a' && *first <= 'f') + digit = *first - 'a' + 10; + + else if (*first >= 'A' && *first <= 'F') + digit = *first - 'A' + 10; + + else + break; + + result = 16 * result + digit; + } + out = result; + + return first; +} + +enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, + const char *raw, const char *end) +{ + tokenVal.clear(); + consumed = 0; + + const char *rawStart = raw; + + while (raw < end && (json_isspace(*raw))) // skip whitespace + raw++; + + if (raw >= end) + return JTOK_NONE; + + switch (*raw) { + + case '{': + raw++; + consumed = (raw - rawStart); + return JTOK_OBJ_OPEN; + case '}': + raw++; + consumed = (raw - rawStart); + return JTOK_OBJ_CLOSE; + case '[': + raw++; + consumed = (raw - rawStart); + return JTOK_ARR_OPEN; + case ']': + raw++; + consumed = (raw - rawStart); + return JTOK_ARR_CLOSE; + + case ':': + raw++; + consumed = (raw - rawStart); + return JTOK_COLON; + case ',': + raw++; + consumed = (raw - rawStart); + return JTOK_COMMA; + + case 'n': + case 't': + case 'f': + if (!strncmp(raw, "null", 4)) { + raw += 4; + consumed = (raw - rawStart); + return JTOK_KW_NULL; + } else if (!strncmp(raw, "true", 4)) { + raw += 4; + consumed = (raw - rawStart); + return JTOK_KW_TRUE; + } else if (!strncmp(raw, "false", 5)) { + raw += 5; + consumed = (raw - rawStart); + return JTOK_KW_FALSE; + } else + return JTOK_ERR; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + // part 1: int + string numStr; + + const char *first = raw; + + const char *firstDigit = first; + if (!json_isdigit(*firstDigit)) + firstDigit++; + if ((*firstDigit == '0') && json_isdigit(firstDigit[1])) + return JTOK_ERR; + + numStr += *raw; // copy first char + raw++; + + if ((*first == '-') && (raw < end) && (!json_isdigit(*raw))) + return JTOK_ERR; + + while (raw < end && json_isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + + // part 2: frac + if (raw < end && *raw == '.') { + numStr += *raw; // copy . + raw++; + + if (raw >= end || !json_isdigit(*raw)) + return JTOK_ERR; + while (raw < end && json_isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + } + + // part 3: exp + if (raw < end && (*raw == 'e' || *raw == 'E')) { + numStr += *raw; // copy E + raw++; + + if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/- + numStr += *raw; + raw++; + } + + if (raw >= end || !json_isdigit(*raw)) + return JTOK_ERR; + while (raw < end && json_isdigit(*raw)) { // copy digits + numStr += *raw; + raw++; + } + } + + tokenVal = numStr; + consumed = (raw - rawStart); + return JTOK_NUMBER; + } + + case '"': { + raw++; // skip " + + string valStr; + JSONUTF8StringFilter writer(valStr); + + while (true) { + if (raw >= end || (unsigned char)*raw < 0x20) + return JTOK_ERR; + + else if (*raw == '\\') { + raw++; // skip backslash + + if (raw >= end) + return JTOK_ERR; + + switch (*raw) { + case '"': writer.push_back('\"'); break; + case '\\': writer.push_back('\\'); break; + case '/': writer.push_back('/'); break; + case 'b': writer.push_back('\b'); break; + case 'f': writer.push_back('\f'); break; + case 'n': writer.push_back('\n'); break; + case 'r': writer.push_back('\r'); break; + case 't': writer.push_back('\t'); break; + + case 'u': { + unsigned int codepoint; + if (raw + 1 + 4 >= end || + hatoui(raw + 1, raw + 1 + 4, codepoint) != + raw + 1 + 4) + return JTOK_ERR; + writer.push_back_u(codepoint); + raw += 4; + break; + } + default: + return JTOK_ERR; + + } + + raw++; // skip esc'd char + } + + else if (*raw == '"') { + raw++; // skip " + break; // stop scanning + } + + else { + writer.push_back(*raw); + raw++; + } + } + + if (!writer.finalize()) + return JTOK_ERR; + tokenVal = valStr; + consumed = (raw - rawStart); + return JTOK_STRING; + } + + default: + return JTOK_ERR; + } +} + +enum expect_bits { + EXP_OBJ_NAME = (1U << 0), + EXP_COLON = (1U << 1), + EXP_ARR_VALUE = (1U << 2), + EXP_VALUE = (1U << 3), + EXP_NOT_VALUE = (1U << 4), +}; + +#define expect(bit) (expectMask & (EXP_##bit)) +#define setExpect(bit) (expectMask |= EXP_##bit) +#define clearExpect(bit) (expectMask &= ~EXP_##bit) + +bool UniValue::read(const char *raw, size_t size) +{ + clear(); + + uint32_t expectMask = 0; + vector stack; + + string tokenVal; + unsigned int consumed; + enum jtokentype tok = JTOK_NONE; + enum jtokentype last_tok = JTOK_NONE; + const char* end = raw + size; + do { + last_tok = tok; + + tok = getJsonToken(tokenVal, consumed, raw, end); + if (tok == JTOK_NONE || tok == JTOK_ERR) + return false; + raw += consumed; + + bool isValueOpen = jsonTokenIsValue(tok) || + tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN; + + if (expect(VALUE)) { + if (!isValueOpen) + return false; + clearExpect(VALUE); + + } else if (expect(ARR_VALUE)) { + bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); + if (!isArrValue) + return false; + + clearExpect(ARR_VALUE); + + } else if (expect(OBJ_NAME)) { + bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); + if (!isObjName) + return false; + + } else if (expect(COLON)) { + if (tok != JTOK_COLON) + return false; + clearExpect(COLON); + + } else if (!expect(COLON) && (tok == JTOK_COLON)) { + return false; + } + + if (expect(NOT_VALUE)) { + if (isValueOpen) + return false; + clearExpect(NOT_VALUE); + } + + switch (tok) { + + case JTOK_OBJ_OPEN: + case JTOK_ARR_OPEN: { + VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR); + if (!stack.size()) { + if (utyp == VOBJ) + setObject(); + else + setArray(); + stack.push_back(this); + } else { + UniValue tmpVal(utyp); + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + UniValue *newTop = &(top->values.back()); + stack.push_back(newTop); + } + + if (utyp == VOBJ) + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); + break; + } + + case JTOK_OBJ_CLOSE: + case JTOK_ARR_CLOSE: { + if (!stack.size() || (last_tok == JTOK_COMMA)) + return false; + + VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); + UniValue *top = stack.back(); + if (utyp != top->getType()) + return false; + + stack.pop_back(); + clearExpect(OBJ_NAME); + setExpect(NOT_VALUE); + break; + } + + case JTOK_COLON: { + if (!stack.size()) + return false; + + UniValue *top = stack.back(); + if (top->getType() != VOBJ) + return false; + + setExpect(VALUE); + break; + } + + case JTOK_COMMA: { + if (!stack.size() || + (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) + return false; + + UniValue *top = stack.back(); + if (top->getType() == VOBJ) + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); + break; + } + + case JTOK_KW_NULL: + case JTOK_KW_TRUE: + case JTOK_KW_FALSE: { + UniValue tmpVal; + switch (tok) { + case JTOK_KW_NULL: + // do nothing more + break; + case JTOK_KW_TRUE: + tmpVal.setBool(true); + break; + case JTOK_KW_FALSE: + tmpVal.setBool(false); + break; + default: /* impossible */ break; + } + + if (!stack.size()) { + *this = tmpVal; + break; + } + + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + setExpect(NOT_VALUE); + break; + } + + case JTOK_NUMBER: { + UniValue tmpVal(VNUM, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + + setExpect(NOT_VALUE); + break; + } + + case JTOK_STRING: { + if (expect(OBJ_NAME)) { + UniValue *top = stack.back(); + top->keys.push_back(tokenVal); + clearExpect(OBJ_NAME); + setExpect(COLON); + } else { + UniValue tmpVal(VSTR, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); + top->values.push_back(tmpVal); + } + + setExpect(NOT_VALUE); + break; + } + + default: + return false; + } + } while (!stack.empty ()); + + /* Check that nothing follows the initial construct (parsed above). */ + tok = getJsonToken(tokenVal, consumed, raw, end); + if (tok != JTOK_NONE) + return false; + + return true; +} + +bool UniValue::read(const char *raw) { + return read(raw, strlen(raw)); +} diff --git a/lib/univalue_utffilter.h b/lib/univalue_utffilter.h new file mode 100644 index 0000000000..b4a9ddc0a3 --- /dev/null +++ b/lib/univalue_utffilter.h @@ -0,0 +1,119 @@ +// Copyright 2016 Wladimir J. van der Laan +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef UNIVALUE_UTFFILTER_H +#define UNIVALUE_UTFFILTER_H + +#include + +/** + * Filter that generates and validates UTF-8, as well as collates UTF-16 + * surrogate pairs as specified in RFC4627. + */ +class JSONUTF8StringFilter +{ +public: + JSONUTF8StringFilter(std::string &s): + str(s), is_valid(true), codepoint(0), state(0), surpair(0) + { + } + // Write single 8-bit char (may be part of UTF-8 sequence) + void push_back(unsigned char ch) + { + if (state == 0) { + if (ch < 0x80) // 7-bit ASCII, fast direct pass-through + str.push_back(ch); + else if (ch < 0xc0) // Mid-sequence character, invalid in this state + is_valid = false; + else if (ch < 0xe0) { // Start of 2-byte sequence + codepoint = (ch & 0x1f) << 6; + state = 6; + } else if (ch < 0xf0) { // Start of 3-byte sequence + codepoint = (ch & 0x0f) << 12; + state = 12; + } else if (ch < 0xf8) { // Start of 4-byte sequence + codepoint = (ch & 0x07) << 18; + state = 18; + } else // Reserved, invalid + is_valid = false; + } else { + if ((ch & 0xc0) != 0x80) // Not a continuation, invalid + is_valid = false; + state -= 6; + codepoint |= (ch & 0x3f) << state; + if (state == 0) + push_back_u(codepoint); + } + } + // Write codepoint directly, possibly collating surrogate pairs + void push_back_u(unsigned int codepoint_) + { + if (state) // Only accept full codepoints in open state + is_valid = false; + if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair + if (surpair) // Two subsequent surrogate pair openers - fail + is_valid = false; + else + surpair = codepoint_; + } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair + if (surpair) { // Open surrogate pair, expect second half + // Compute code point from UTF-16 surrogate pair + append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); + surpair = 0; + } else // Second half doesn't follow a first half - fail + is_valid = false; + } else { + if (surpair) // First half of surrogate pair not followed by second - fail + is_valid = false; + else + append_codepoint(codepoint_); + } + } + // Check that we're in a state where the string can be ended + // No open sequences, no open surrogate pairs, etc + bool finalize() + { + if (state || surpair) + is_valid = false; + return is_valid; + } +private: + std::string &str; + bool is_valid; + // Current UTF-8 decoding state + unsigned int codepoint; + int state; // Top bit to be filled in for next UTF-8 byte, or 0 + + // Keep track of the following state to handle the following section of + // RFC4627: + // + // To escape an extended character that is not in the Basic Multilingual + // Plane, the character is represented as a twelve-character sequence, + // encoding the UTF-16 surrogate pair. So, for example, a string + // containing only the G clef character (U+1D11E) may be represented as + // "\uD834\uDD1E". + // + // Two subsequent \u.... may have to be replaced with one actual codepoint. + unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 + + void append_codepoint(unsigned int codepoint_) + { + if (codepoint_ <= 0x7f) + str.push_back((char)codepoint_); + else if (codepoint_ <= 0x7FF) { + str.push_back((char)(0xC0 | (codepoint_ >> 6))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0xFFFF) { + str.push_back((char)(0xE0 | (codepoint_ >> 12))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0x1FFFFF) { + str.push_back((char)(0xF0 | (codepoint_ >> 18))); + str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } + } +}; + +#endif diff --git a/lib/univalue_write.cpp b/lib/univalue_write.cpp new file mode 100644 index 0000000000..cf27835991 --- /dev/null +++ b/lib/univalue_write.cpp @@ -0,0 +1,115 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include "univalue.h" +#include "univalue_escapes.h" + +using namespace std; + +static string json_escape(const string& inS) +{ + string outS; + outS.reserve(inS.size() * 2); + + for (unsigned int i = 0; i < inS.size(); i++) { + unsigned char ch = inS[i]; + const char *escStr = escapes[ch]; + + if (escStr) + outS += escStr; + else + outS += ch; + } + + return outS; +} + +string UniValue::write(unsigned int prettyIndent, + unsigned int indentLevel) const +{ + string s; + s.reserve(1024); + + unsigned int modIndent = indentLevel; + if (modIndent == 0) + modIndent = 1; + + switch (typ) { + case VNULL: + s += "null"; + break; + case VOBJ: + writeObject(prettyIndent, modIndent, s); + break; + case VARR: + writeArray(prettyIndent, modIndent, s); + break; + case VSTR: + s += "\"" + json_escape(val) + "\""; + break; + case VNUM: + s += val; + break; + case VBOOL: + s += (val == "1" ? "true" : "false"); + break; + } + + return s; +} + +static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s) +{ + s.append(prettyIndent * indentLevel, ' '); +} + +void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +{ + s += "["; + if (prettyIndent) + s += "\n"; + + for (unsigned int i = 0; i < values.size(); i++) { + if (prettyIndent) + indentStr(prettyIndent, indentLevel, s); + s += values[i].write(prettyIndent, indentLevel + 1); + if (i != (values.size() - 1)) { + s += ","; + } + if (prettyIndent) + s += "\n"; + } + + if (prettyIndent) + indentStr(prettyIndent, indentLevel - 1, s); + s += "]"; +} + +void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const +{ + s += "{"; + if (prettyIndent) + s += "\n"; + + for (unsigned int i = 0; i < keys.size(); i++) { + if (prettyIndent) + indentStr(prettyIndent, indentLevel, s); + s += "\"" + json_escape(keys[i]) + "\":"; + if (prettyIndent) + s += " "; + s += values.at(i).write(prettyIndent, indentLevel + 1); + if (i != (values.size() - 1)) + s += ","; + if (prettyIndent) + s += "\n"; + } + + if (prettyIndent) + indentStr(prettyIndent, indentLevel - 1, s); + s += "}"; +} + diff --git a/pc/libunivalue-uninstalled.pc.in b/pc/libunivalue-uninstalled.pc.in new file mode 100644 index 0000000000..b7f53e875e --- /dev/null +++ b/pc/libunivalue-uninstalled.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la diff --git a/pc/libunivalue.pc.in b/pc/libunivalue.pc.in new file mode 100644 index 0000000000..358a2d5f73 --- /dev/null +++ b/pc/libunivalue.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: -L${libdir} -lunivalue +Cflags: -I${includedir} diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000000..7b27cf0da2 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,8 @@ + +object +unitester +test_json +no_nul + +*.trs +*.log diff --git a/test/fail1.json b/test/fail1.json new file mode 100644 index 0000000000..8feb01a6d0 --- /dev/null +++ b/test/fail1.json @@ -0,0 +1 @@ +"This is a string that never ends, yes it goes on and on, my friends. diff --git a/test/fail10.json b/test/fail10.json new file mode 100644 index 0000000000..5d8c0047bd --- /dev/null +++ b/test/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/test/fail11.json b/test/fail11.json new file mode 100644 index 0000000000..76eb95b458 --- /dev/null +++ b/test/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/test/fail12.json b/test/fail12.json new file mode 100644 index 0000000000..77580a4522 --- /dev/null +++ b/test/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/test/fail13.json b/test/fail13.json new file mode 100644 index 0000000000..379406b59b --- /dev/null +++ b/test/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/test/fail14.json b/test/fail14.json new file mode 100644 index 0000000000..0ed366b38a --- /dev/null +++ b/test/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/test/fail15.json b/test/fail15.json new file mode 100644 index 0000000000..fc8376b605 --- /dev/null +++ b/test/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/test/fail16.json b/test/fail16.json new file mode 100644 index 0000000000..3fe21d4b53 --- /dev/null +++ b/test/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/test/fail17.json b/test/fail17.json new file mode 100644 index 0000000000..62b9214aed --- /dev/null +++ b/test/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/test/fail18.json b/test/fail18.json new file mode 100644 index 0000000000..edac92716f --- /dev/null +++ b/test/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/test/fail19.json b/test/fail19.json new file mode 100644 index 0000000000..3b9c46fa9a --- /dev/null +++ b/test/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/test/fail2.json b/test/fail2.json new file mode 100644 index 0000000000..6b7c11e5a5 --- /dev/null +++ b/test/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/test/fail20.json b/test/fail20.json new file mode 100644 index 0000000000..27c1af3e72 --- /dev/null +++ b/test/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/test/fail21.json b/test/fail21.json new file mode 100644 index 0000000000..62474573b2 --- /dev/null +++ b/test/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/test/fail22.json b/test/fail22.json new file mode 100644 index 0000000000..a7752581bc --- /dev/null +++ b/test/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/test/fail23.json b/test/fail23.json new file mode 100644 index 0000000000..494add1ca1 --- /dev/null +++ b/test/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/test/fail24.json b/test/fail24.json new file mode 100644 index 0000000000..caff239bfc --- /dev/null +++ b/test/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/test/fail25.json b/test/fail25.json new file mode 100644 index 0000000000..8b7ad23e01 --- /dev/null +++ b/test/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/test/fail26.json b/test/fail26.json new file mode 100644 index 0000000000..845d26a6a5 --- /dev/null +++ b/test/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/test/fail27.json b/test/fail27.json new file mode 100644 index 0000000000..6b01a2ca4a --- /dev/null +++ b/test/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/test/fail28.json b/test/fail28.json new file mode 100644 index 0000000000..621a0101c6 --- /dev/null +++ b/test/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/test/fail29.json b/test/fail29.json new file mode 100644 index 0000000000..47ec421bb6 --- /dev/null +++ b/test/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/test/fail3.json b/test/fail3.json new file mode 100644 index 0000000000..168c81eb78 --- /dev/null +++ b/test/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/test/fail30.json b/test/fail30.json new file mode 100644 index 0000000000..8ab0bc4b8b --- /dev/null +++ b/test/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/test/fail31.json b/test/fail31.json new file mode 100644 index 0000000000..1cce602b51 --- /dev/null +++ b/test/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/test/fail32.json b/test/fail32.json new file mode 100644 index 0000000000..45cba7396f --- /dev/null +++ b/test/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/test/fail33.json b/test/fail33.json new file mode 100644 index 0000000000..ca5eb19dc9 --- /dev/null +++ b/test/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/test/fail34.json b/test/fail34.json new file mode 100644 index 0000000000..3f8be17286 --- /dev/null +++ b/test/fail34.json @@ -0,0 +1 @@ +{} garbage \ No newline at end of file diff --git a/test/fail35.json b/test/fail35.json new file mode 100644 index 0000000000..de30ca5c47 --- /dev/null +++ b/test/fail35.json @@ -0,0 +1 @@ +[ true true true [] [] [] ] diff --git a/test/fail36.json b/test/fail36.json new file mode 100644 index 0000000000..f82eb8e1f0 --- /dev/null +++ b/test/fail36.json @@ -0,0 +1 @@ +{"a":} diff --git a/test/fail37.json b/test/fail37.json new file mode 100644 index 0000000000..3294dc3a42 --- /dev/null +++ b/test/fail37.json @@ -0,0 +1 @@ +{"a":1 "b":2} diff --git a/test/fail38.json b/test/fail38.json new file mode 100644 index 0000000000..b245e2e46c --- /dev/null +++ b/test/fail38.json @@ -0,0 +1 @@ +["\ud834"] diff --git a/test/fail39.json b/test/fail39.json new file mode 100644 index 0000000000..7c9e263f27 --- /dev/null +++ b/test/fail39.json @@ -0,0 +1 @@ +["\udd61"] diff --git a/test/fail4.json b/test/fail4.json new file mode 100644 index 0000000000..9de168bf34 --- /dev/null +++ b/test/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/test/fail40.json b/test/fail40.json new file mode 100644 index 0000000000..664dc9e245 --- /dev/null +++ b/test/fail40.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/test/fail41.json b/test/fail41.json new file mode 100644 index 0000000000..0de342a2b5 --- /dev/null +++ b/test/fail41.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/test/fail42.json b/test/fail42.json new file mode 100644 index 0000000000000000000000000000000000000000..9c7565adbddf645df5edfbdcd630c7a0f94aa2eb GIT binary patch literal 37 kcma!6N=i-3FG^L&E6q_zsw_!Wie*qrOe;w(LWpny0Pvs;RsaA1 literal 0 HcmV?d00001 diff --git a/test/fail44.json b/test/fail44.json new file mode 100644 index 0000000000..80edceddf1 --- /dev/null +++ b/test/fail44.json @@ -0,0 +1 @@ +"This file ends without a newline or close-quote. \ No newline at end of file diff --git a/test/fail5.json b/test/fail5.json new file mode 100644 index 0000000000..ddf3ce3d24 --- /dev/null +++ b/test/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/test/fail6.json b/test/fail6.json new file mode 100644 index 0000000000..ed91580e1b --- /dev/null +++ b/test/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/test/fail7.json b/test/fail7.json new file mode 100644 index 0000000000..8a96af3e4e --- /dev/null +++ b/test/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/test/fail8.json b/test/fail8.json new file mode 100644 index 0000000000..b28479c6ec --- /dev/null +++ b/test/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/test/fail9.json b/test/fail9.json new file mode 100644 index 0000000000..5815574f36 --- /dev/null +++ b/test/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/test/no_nul.cpp b/test/no_nul.cpp new file mode 100644 index 0000000000..83d292200b --- /dev/null +++ b/test/no_nul.cpp @@ -0,0 +1,8 @@ +#include "univalue.h" + +int main (int argc, char *argv[]) +{ + char buf[] = "___[1,2,3]___"; + UniValue val; + return val.read(buf + 3, 7) ? 0 : 1; +} diff --git a/test/object.cpp b/test/object.cpp new file mode 100644 index 0000000000..f1f2e63b3d --- /dev/null +++ b/test/object.cpp @@ -0,0 +1,365 @@ +// Copyright (c) 2014 BitPay Inc. +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_FIXTURE_TEST_SUITE(a, b) +#define BOOST_AUTO_TEST_CASE(funcName) void funcName() +#define BOOST_AUTO_TEST_SUITE_END() +#define BOOST_CHECK(expr) assert(expr) +#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) +#define BOOST_CHECK_THROW(stmt, excMatch) { \ + try { \ + (stmt); \ + } catch (excMatch & e) { \ + } catch (...) { \ + assert(0); \ + } \ + } +#define BOOST_CHECK_NO_THROW(stmt) { \ + try { \ + (stmt); \ + } catch (...) { \ + assert(0); \ + } \ + } + +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(univalue_constructor) +{ + UniValue v1; + BOOST_CHECK(v1.isNull()); + + UniValue v2(UniValue::VSTR); + BOOST_CHECK(v2.isStr()); + + UniValue v3(UniValue::VSTR, "foo"); + BOOST_CHECK(v3.isStr()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + UniValue numTest; + BOOST_CHECK(numTest.setNumStr("82")); + BOOST_CHECK(numTest.isNum()); + BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); + + uint64_t vu64 = 82; + UniValue v4(vu64); + BOOST_CHECK(v4.isNum()); + BOOST_CHECK_EQUAL(v4.getValStr(), "82"); + + int64_t vi64 = -82; + UniValue v5(vi64); + BOOST_CHECK(v5.isNum()); + BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); + + int vi = -688; + UniValue v6(vi); + BOOST_CHECK(v6.isNum()); + BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); + + double vd = -7.21; + UniValue v7(vd); + BOOST_CHECK(v7.isNum()); + BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); + + std::string vs("yawn"); + UniValue v8(vs); + BOOST_CHECK(v8.isStr()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + UniValue v9(vcs); + BOOST_CHECK(v9.isStr()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(univalue_typecheck) +{ + UniValue v1; + BOOST_CHECK(v1.setNumStr("1")); + BOOST_CHECK(v1.isNum()); + BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); + + UniValue v2; + BOOST_CHECK(v2.setBool(true)); + BOOST_CHECK_EQUAL(v2.get_bool(), true); + BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); + + UniValue v3; + BOOST_CHECK(v3.setNumStr("32482348723847471234")); + BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); + BOOST_CHECK(v3.setNumStr("1000")); + BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + + UniValue v4; + BOOST_CHECK(v4.setNumStr("2147483648")); + BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); + BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); + BOOST_CHECK(v4.setNumStr("1000")); + BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); + BOOST_CHECK_EQUAL(v4.get_real(), 1000); + BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); + BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); + + UniValue v5; + BOOST_CHECK(v5.read("[true, 10]")); + BOOST_CHECK_NO_THROW(v5.get_array()); + std::vector vals = v5.getValues(); + BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); + BOOST_CHECK_EQUAL(vals[0].get_bool(), true); + + BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(univalue_set) +{ + UniValue v(UniValue::VSTR, "foo"); + v.clear(); + BOOST_CHECK(v.isNull()); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setObject()); + BOOST_CHECK(v.isObject()); + BOOST_CHECK_EQUAL(v.size(), 0); + BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); + BOOST_CHECK(v.empty()); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + BOOST_CHECK(v.setStr("zum")); + BOOST_CHECK(v.isStr()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + + BOOST_CHECK(v.setFloat(-1.01)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); + + BOOST_CHECK(v.setInt((int)1023)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setInt((int64_t)-1023LL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); + + BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setNumStr("-688")); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-688"); + + BOOST_CHECK(v.setBool(false)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), false); + BOOST_CHECK_EQUAL(v.isFalse(), true); + BOOST_CHECK_EQUAL(v.getBool(), false); + + BOOST_CHECK(v.setBool(true)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), true); + BOOST_CHECK_EQUAL(v.isFalse(), false); + BOOST_CHECK_EQUAL(v.getBool(), true); + + BOOST_CHECK(!v.setNumStr("zombocom")); + + BOOST_CHECK(v.setNull()); + BOOST_CHECK(v.isNull()); +} + +BOOST_AUTO_TEST_CASE(univalue_array) +{ + UniValue arr(UniValue::VARR); + + UniValue v((int64_t)1023LL); + BOOST_CHECK(arr.push_back(v)); + + std::string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + std::vector vec; + v.setStr("boing"); + vec.push_back(v); + + v.setStr("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 5); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(univalue_object) +{ + UniValue obj(UniValue::VOBJ); + std::string strKey, strVal; + UniValue v; + + strKey = "age"; + v.setInt(100); + BOOST_CHECK(obj.pushKV(strKey, v)); + + strKey = "first"; + strVal = "John"; + BOOST_CHECK(obj.pushKV(strKey, strVal)); + + strKey = "last"; + const char *cVal = "Smith"; + BOOST_CHECK(obj.pushKV(strKey, cVal)); + + strKey = "distance"; + BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); + + strKey = "time"; + BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); + + strKey = "calories"; + BOOST_CHECK(obj.pushKV(strKey, (int) 12)); + + strKey = "temperature"; + BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); + + UniValue obj2(UniValue::VOBJ); + BOOST_CHECK(obj2.pushKV("cat1", 9000)); + BOOST_CHECK(obj2.pushKV("cat2", 12345)); + + BOOST_CHECK(obj.pushKVs(obj2)); + + BOOST_CHECK_EQUAL(obj.empty(), false); + BOOST_CHECK_EQUAL(obj.size(), 9); + + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); + BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); + BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); + BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); + BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); + BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); + BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); + BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); + BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); + + BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); + + BOOST_CHECK(obj.exists("age")); + BOOST_CHECK(obj.exists("first")); + BOOST_CHECK(obj.exists("last")); + BOOST_CHECK(obj.exists("distance")); + BOOST_CHECK(obj.exists("time")); + BOOST_CHECK(obj.exists("calories")); + BOOST_CHECK(obj.exists("temperature")); + BOOST_CHECK(obj.exists("cat1")); + BOOST_CHECK(obj.exists("cat2")); + + BOOST_CHECK(!obj.exists("nyuknyuknyuk")); + + std::map objTypes; + objTypes["age"] = UniValue::VNUM; + objTypes["first"] = UniValue::VSTR; + objTypes["last"] = UniValue::VSTR; + objTypes["distance"] = UniValue::VNUM; + objTypes["time"] = UniValue::VNUM; + objTypes["calories"] = UniValue::VNUM; + objTypes["temperature"] = UniValue::VNUM; + objTypes["cat1"] = UniValue::VNUM; + objTypes["cat2"] = UniValue::VNUM; + BOOST_CHECK(obj.checkObject(objTypes)); + + objTypes["cat2"] = UniValue::VSTR; + BOOST_CHECK(!obj.checkObject(objTypes)); + + obj.clear(); + BOOST_CHECK(obj.empty()); + BOOST_CHECK_EQUAL(obj.size(), 0); +} + +static const char *json1 = +"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; + +BOOST_AUTO_TEST_CASE(univalue_readwrite) +{ + UniValue v; + BOOST_CHECK(v.read(json1)); + + std::string strJson1(json1); + BOOST_CHECK(v.read(strJson1)); + + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 2); + + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); + + UniValue obj = v[1]; + BOOST_CHECK(obj.isObject()); + BOOST_CHECK_EQUAL(obj.size(), 3); + + BOOST_CHECK(obj["key1"].isStr()); + std::string correctValue("str"); + correctValue.push_back('\0'); + BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); + BOOST_CHECK(obj["key2"].isNum()); + BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); + BOOST_CHECK(obj["key3"].isObject()); + + BOOST_CHECK_EQUAL(strJson1, v.write()); + + /* Check for (correctly reporting) a parsing error if the initial + JSON construct is followed by more stuff. Note that whitespace + is, of course, exempt. */ + + BOOST_CHECK(v.read(" {}\n ")); + BOOST_CHECK(v.isObject()); + BOOST_CHECK(v.read(" []\n ")); + BOOST_CHECK(v.isArray()); + + BOOST_CHECK(!v.read("@{}")); + BOOST_CHECK(!v.read("{} garbage")); + BOOST_CHECK(!v.read("[]{}")); + BOOST_CHECK(!v.read("{}[]")); + BOOST_CHECK(!v.read("{} 42")); +} + +BOOST_AUTO_TEST_SUITE_END() + +int main (int argc, char *argv[]) +{ + univalue_constructor(); + univalue_typecheck(); + univalue_set(); + univalue_array(); + univalue_object(); + univalue_readwrite(); + return 0; +} + diff --git a/test/pass1.json b/test/pass1.json new file mode 100644 index 0000000000..70e2685436 --- /dev/null +++ b/test/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/test/pass2.json b/test/pass2.json new file mode 100644 index 0000000000..d3c63c7ad8 --- /dev/null +++ b/test/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/test/pass3.json b/test/pass3.json new file mode 100644 index 0000000000..4528d51f1a --- /dev/null +++ b/test/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/test/round1.json b/test/round1.json new file mode 100644 index 0000000000..a711e7308b --- /dev/null +++ b/test/round1.json @@ -0,0 +1 @@ +["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"] diff --git a/test/round2.json b/test/round2.json new file mode 100644 index 0000000000..b766cccc68 --- /dev/null +++ b/test/round2.json @@ -0,0 +1 @@ +["a§■𐎒𝅘𝅥𝅯"] diff --git a/test/round3.json b/test/round3.json new file mode 100644 index 0000000000..7182dc2f9b --- /dev/null +++ b/test/round3.json @@ -0,0 +1 @@ +"abcdefghijklmnopqrstuvwxyz" diff --git a/test/round4.json b/test/round4.json new file mode 100644 index 0000000000..7f8f011eb7 --- /dev/null +++ b/test/round4.json @@ -0,0 +1 @@ +7 diff --git a/test/round5.json b/test/round5.json new file mode 100644 index 0000000000..27ba77ddaf --- /dev/null +++ b/test/round5.json @@ -0,0 +1 @@ +true diff --git a/test/round6.json b/test/round6.json new file mode 100644 index 0000000000..c508d5366f --- /dev/null +++ b/test/round6.json @@ -0,0 +1 @@ +false diff --git a/test/round7.json b/test/round7.json new file mode 100644 index 0000000000..19765bd501 --- /dev/null +++ b/test/round7.json @@ -0,0 +1 @@ +null diff --git a/test/test_json.cpp b/test/test_json.cpp new file mode 100644 index 0000000000..2943bae2b1 --- /dev/null +++ b/test/test_json.cpp @@ -0,0 +1,24 @@ +// Test program that can be called by the JSON test suite at +// https://github.com/nst/JSONTestSuite. +// +// It reads JSON input from stdin and exits with code 0 if it can be parsed +// successfully. It also pretty prints the parsed JSON value to stdout. + +#include +#include +#include "univalue.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + UniValue val; + if (val.read(string(istreambuf_iterator(cin), + istreambuf_iterator()))) { + cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; + return 0; + } else { + cerr << "JSON Parse Error." << endl; + return 1; + } +} diff --git a/test/unitester.cpp b/test/unitester.cpp new file mode 100644 index 0000000000..2c37794a4b --- /dev/null +++ b/test/unitester.cpp @@ -0,0 +1,170 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include "univalue.h" + +#ifndef JSON_TEST_SRC +#error JSON_TEST_SRC must point to test source directory +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +using namespace std; +string srcdir(JSON_TEST_SRC); +static bool test_failed = false; + +#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } +#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } + +static std::string rtrim(std::string s) +{ + s.erase(s.find_last_not_of(" \n\r\t")+1); + return s; +} + +static void runtest(string filename, const string& jdata) +{ + string prefix = filename.substr(0, 4); + + bool wantPass = (prefix == "pass") || (prefix == "roun"); + bool wantFail = (prefix == "fail"); + bool wantRoundTrip = (prefix == "roun"); + assert(wantPass || wantFail); + + UniValue val; + bool testResult = val.read(jdata); + + if (wantPass) { + d_assert(testResult == true); + } else { + d_assert(testResult == false); + } + + if (wantRoundTrip) { + std::string odata = val.write(0, 0); + assert(odata == rtrim(jdata)); + } +} + +static void runtest_file(const char *filename_) +{ + string basename(filename_); + string filename = srcdir + "/" + basename; + FILE *f = fopen(filename.c_str(), "r"); + assert(f != NULL); + + string jdata; + + char buf[4096]; + while (!feof(f)) { + int bread = fread(buf, 1, sizeof(buf), f); + assert(!ferror(f)); + + string s(buf, bread); + jdata += s; + } + + assert(!ferror(f)); + fclose(f); + + runtest(basename, jdata); +} + +static const char *filenames[] = { + "fail10.json", + "fail11.json", + "fail12.json", + "fail13.json", + "fail14.json", + "fail15.json", + "fail16.json", + "fail17.json", + //"fail18.json", // investigate + "fail19.json", + "fail1.json", + "fail20.json", + "fail21.json", + "fail22.json", + "fail23.json", + "fail24.json", + "fail25.json", + "fail26.json", + "fail27.json", + "fail28.json", + "fail29.json", + "fail2.json", + "fail30.json", + "fail31.json", + "fail32.json", + "fail33.json", + "fail34.json", + "fail35.json", + "fail36.json", + "fail37.json", + "fail38.json", // invalid unicode: only first half of surrogate pair + "fail39.json", // invalid unicode: only second half of surrogate pair + "fail40.json", // invalid unicode: broken UTF-8 + "fail41.json", // invalid unicode: unfinished UTF-8 + "fail42.json", // valid json with garbage following a nul byte + "fail44.json", // unterminated string + "fail3.json", + "fail4.json", // extra comma + "fail5.json", + "fail6.json", + "fail7.json", + "fail8.json", + "fail9.json", // extra comma + "pass1.json", + "pass2.json", + "pass3.json", + "round1.json", // round-trip test + "round2.json", // unicode + "round3.json", // bare string + "round4.json", // bare number + "round5.json", // bare true + "round6.json", // bare false + "round7.json", // bare null +}; + +// Test \u handling +void unescape_unicode_test() +{ + UniValue val; + bool testResult; + // Escaped ASCII (quote) + testResult = val.read("[\"\\u0022\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\""); + // Escaped Basic Plane character, two-byte UTF-8 + testResult = val.read("[\"\\u0191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xc6\x91"); + // Escaped Basic Plane character, three-byte UTF-8 + testResult = val.read("[\"\\u2191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xe2\x86\x91"); + // Escaped Supplementary Plane character U+1d161 + testResult = val.read("[\"\\ud834\\udd61\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); +} + +int main (int argc, char *argv[]) +{ + for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { + runtest_file(filenames[fidx]); + } + + unescape_unicode_test(); + + return test_failed ? 1 : 0; +} + From a8a37ba8900d167ca45a112f45bedd608ff82b0e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Nov 2020 12:47:54 -0500 Subject: [PATCH 0512/1888] Remove leveldb path in prep for subtree init --- src/leveldb/.gitignore | 13 - src/leveldb/.travis.yml | 13 - src/leveldb/AUTHORS | 12 - src/leveldb/CONTRIBUTING.md | 36 - src/leveldb/LICENSE | 27 - src/leveldb/Makefile | 227 -- src/leveldb/NEWS | 17 - src/leveldb/README | 51 - src/leveldb/README.md | 138 -- src/leveldb/TODO | 14 - src/leveldb/WINDOWS.md | 39 - src/leveldb/build_detect_platform | 231 -- src/leveldb/db/autocompact_test.cc | 118 - src/leveldb/db/builder.cc | 88 - src/leveldb/db/builder.h | 34 - src/leveldb/db/c.cc | 595 ------ src/leveldb/db/c_test.c | 390 ---- src/leveldb/db/corruption_test.cc | 374 ---- src/leveldb/db/db_bench.cc | 978 --------- src/leveldb/db/db_impl.cc | 1513 ------------- src/leveldb/db/db_impl.h | 211 -- src/leveldb/db/db_iter.cc | 317 --- src/leveldb/db/db_iter.h | 28 - src/leveldb/db/db_test.cc | 2128 ------------------- src/leveldb/db/dbformat.cc | 140 -- src/leveldb/db/dbformat.h | 230 -- src/leveldb/db/dbformat_test.cc | 112 - src/leveldb/db/dumpfile.cc | 225 -- src/leveldb/db/fault_injection_test.cc | 554 ----- src/leveldb/db/filename.cc | 144 -- src/leveldb/db/filename.h | 85 - src/leveldb/db/filename_test.cc | 123 -- src/leveldb/db/leveldb_main.cc | 64 - src/leveldb/db/leveldbutil.cc | 65 - src/leveldb/db/log_format.h | 35 - src/leveldb/db/log_reader.cc | 266 --- src/leveldb/db/log_reader.h | 108 - src/leveldb/db/log_test.cc | 530 ----- src/leveldb/db/log_writer.cc | 103 - src/leveldb/db/log_writer.h | 48 - src/leveldb/db/memtable.cc | 145 -- src/leveldb/db/memtable.h | 91 - src/leveldb/db/recovery_test.cc | 324 --- src/leveldb/db/repair.cc | 461 ---- src/leveldb/db/skiplist.h | 384 ---- src/leveldb/db/skiplist_test.cc | 378 ---- src/leveldb/db/snapshot.h | 66 - src/leveldb/db/table_cache.cc | 127 -- src/leveldb/db/table_cache.h | 61 - src/leveldb/db/version_edit.cc | 266 --- src/leveldb/db/version_edit.h | 107 - src/leveldb/db/version_edit_test.cc | 46 - src/leveldb/db/version_set.cc | 1484 ------------- src/leveldb/db/version_set.h | 396 ---- src/leveldb/db/version_set_test.cc | 179 -- src/leveldb/db/write_batch.cc | 147 -- src/leveldb/db/write_batch_internal.h | 49 - src/leveldb/db/write_batch_test.cc | 120 -- src/leveldb/doc/bench/db_bench_sqlite3.cc | 718 ------- src/leveldb/doc/bench/db_bench_tree_db.cc | 528 ----- src/leveldb/doc/benchmark.html | 459 ---- src/leveldb/doc/doc.css | 89 - src/leveldb/doc/impl.html | 213 -- src/leveldb/doc/impl.md | 170 -- src/leveldb/doc/index.html | 549 ----- src/leveldb/doc/index.md | 523 ----- src/leveldb/doc/log_format.md | 75 - src/leveldb/doc/log_format.txt | 75 - src/leveldb/doc/table_format.md | 107 - src/leveldb/doc/table_format.txt | 104 - src/leveldb/helpers/memenv/memenv.cc | 385 ---- src/leveldb/helpers/memenv/memenv.h | 20 - src/leveldb/helpers/memenv/memenv_test.cc | 232 -- src/leveldb/include/leveldb/c.h | 290 --- src/leveldb/include/leveldb/cache.h | 99 - src/leveldb/include/leveldb/comparator.h | 63 - src/leveldb/include/leveldb/db.h | 161 -- src/leveldb/include/leveldb/dumpfile.h | 25 - src/leveldb/include/leveldb/env.h | 333 --- src/leveldb/include/leveldb/filter_policy.h | 70 - src/leveldb/include/leveldb/iterator.h | 100 - src/leveldb/include/leveldb/options.h | 195 -- src/leveldb/include/leveldb/slice.h | 109 - src/leveldb/include/leveldb/status.h | 106 - src/leveldb/include/leveldb/table.h | 85 - src/leveldb/include/leveldb/table_builder.h | 92 - src/leveldb/include/leveldb/write_batch.h | 64 - src/leveldb/issues/issue178_test.cc | 92 - src/leveldb/issues/issue200_test.cc | 59 - src/leveldb/port/README | 10 - src/leveldb/port/atomic_pointer.h | 223 -- src/leveldb/port/port.h | 21 - src/leveldb/port/port_example.h | 135 -- src/leveldb/port/port_posix.cc | 54 - src/leveldb/port/port_posix.h | 158 -- src/leveldb/port/port_posix_sse.cc | 110 - src/leveldb/port/port_win.cc | 147 -- src/leveldb/port/port_win.h | 174 -- src/leveldb/port/thread_annotations.h | 60 - src/leveldb/port/win/stdint.h | 24 - src/leveldb/table/block.cc | 268 --- src/leveldb/table/block.h | 44 - src/leveldb/table/block_builder.cc | 109 - src/leveldb/table/block_builder.h | 57 - src/leveldb/table/filter_block.cc | 111 - src/leveldb/table/filter_block.h | 68 - src/leveldb/table/filter_block_test.cc | 128 -- src/leveldb/table/format.cc | 145 -- src/leveldb/table/format.h | 108 - src/leveldb/table/iterator.cc | 67 - src/leveldb/table/iterator_wrapper.h | 63 - src/leveldb/table/merger.cc | 197 -- src/leveldb/table/merger.h | 26 - src/leveldb/table/table.cc | 285 --- src/leveldb/table/table_builder.cc | 270 --- src/leveldb/table/table_test.cc | 868 -------- src/leveldb/table/two_level_iterator.cc | 182 -- src/leveldb/table/two_level_iterator.h | 34 - src/leveldb/util/arena.cc | 68 - src/leveldb/util/arena.h | 68 - src/leveldb/util/arena_test.cc | 68 - src/leveldb/util/bloom.cc | 95 - src/leveldb/util/bloom_test.cc | 161 -- src/leveldb/util/cache.cc | 325 --- src/leveldb/util/cache_test.cc | 186 -- src/leveldb/util/coding.cc | 194 -- src/leveldb/util/coding.h | 104 - src/leveldb/util/coding_test.cc | 196 -- src/leveldb/util/comparator.cc | 81 - src/leveldb/util/crc32c.cc | 332 --- src/leveldb/util/crc32c.h | 45 - src/leveldb/util/crc32c_test.cc | 72 - src/leveldb/util/env.cc | 96 - src/leveldb/util/env_posix.cc | 608 ------ src/leveldb/util/env_posix_test.cc | 66 - src/leveldb/util/env_posix_test_helper.h | 28 - src/leveldb/util/env_test.cc | 104 - src/leveldb/util/env_win.cc | 1031 --------- src/leveldb/util/filter_policy.cc | 11 - src/leveldb/util/hash.cc | 52 - src/leveldb/util/hash.h | 19 - src/leveldb/util/hash_test.cc | 54 - src/leveldb/util/histogram.cc | 139 -- src/leveldb/util/histogram.h | 42 - src/leveldb/util/logging.cc | 72 - src/leveldb/util/logging.h | 43 - src/leveldb/util/mutexlock.h | 41 - src/leveldb/util/options.cc | 29 - src/leveldb/util/posix_logger.h | 98 - src/leveldb/util/random.h | 64 - src/leveldb/util/status.cc | 75 - src/leveldb/util/testharness.cc | 77 - src/leveldb/util/testharness.h | 138 -- src/leveldb/util/testutil.cc | 51 - src/leveldb/util/testutil.h | 53 - 155 files changed, 30577 deletions(-) delete mode 100644 src/leveldb/.gitignore delete mode 100644 src/leveldb/.travis.yml delete mode 100644 src/leveldb/AUTHORS delete mode 100644 src/leveldb/CONTRIBUTING.md delete mode 100644 src/leveldb/LICENSE delete mode 100644 src/leveldb/Makefile delete mode 100644 src/leveldb/NEWS delete mode 100644 src/leveldb/README delete mode 100644 src/leveldb/README.md delete mode 100644 src/leveldb/TODO delete mode 100644 src/leveldb/WINDOWS.md delete mode 100755 src/leveldb/build_detect_platform delete mode 100644 src/leveldb/db/autocompact_test.cc delete mode 100644 src/leveldb/db/builder.cc delete mode 100644 src/leveldb/db/builder.h delete mode 100644 src/leveldb/db/c.cc delete mode 100644 src/leveldb/db/c_test.c delete mode 100644 src/leveldb/db/corruption_test.cc delete mode 100644 src/leveldb/db/db_bench.cc delete mode 100644 src/leveldb/db/db_impl.cc delete mode 100644 src/leveldb/db/db_impl.h delete mode 100644 src/leveldb/db/db_iter.cc delete mode 100644 src/leveldb/db/db_iter.h delete mode 100644 src/leveldb/db/db_test.cc delete mode 100644 src/leveldb/db/dbformat.cc delete mode 100644 src/leveldb/db/dbformat.h delete mode 100644 src/leveldb/db/dbformat_test.cc delete mode 100644 src/leveldb/db/dumpfile.cc delete mode 100644 src/leveldb/db/fault_injection_test.cc delete mode 100644 src/leveldb/db/filename.cc delete mode 100644 src/leveldb/db/filename.h delete mode 100644 src/leveldb/db/filename_test.cc delete mode 100644 src/leveldb/db/leveldb_main.cc delete mode 100644 src/leveldb/db/leveldbutil.cc delete mode 100644 src/leveldb/db/log_format.h delete mode 100644 src/leveldb/db/log_reader.cc delete mode 100644 src/leveldb/db/log_reader.h delete mode 100644 src/leveldb/db/log_test.cc delete mode 100644 src/leveldb/db/log_writer.cc delete mode 100644 src/leveldb/db/log_writer.h delete mode 100644 src/leveldb/db/memtable.cc delete mode 100644 src/leveldb/db/memtable.h delete mode 100644 src/leveldb/db/recovery_test.cc delete mode 100644 src/leveldb/db/repair.cc delete mode 100644 src/leveldb/db/skiplist.h delete mode 100644 src/leveldb/db/skiplist_test.cc delete mode 100644 src/leveldb/db/snapshot.h delete mode 100644 src/leveldb/db/table_cache.cc delete mode 100644 src/leveldb/db/table_cache.h delete mode 100644 src/leveldb/db/version_edit.cc delete mode 100644 src/leveldb/db/version_edit.h delete mode 100644 src/leveldb/db/version_edit_test.cc delete mode 100644 src/leveldb/db/version_set.cc delete mode 100644 src/leveldb/db/version_set.h delete mode 100644 src/leveldb/db/version_set_test.cc delete mode 100644 src/leveldb/db/write_batch.cc delete mode 100644 src/leveldb/db/write_batch_internal.h delete mode 100644 src/leveldb/db/write_batch_test.cc delete mode 100644 src/leveldb/doc/bench/db_bench_sqlite3.cc delete mode 100644 src/leveldb/doc/bench/db_bench_tree_db.cc delete mode 100644 src/leveldb/doc/benchmark.html delete mode 100644 src/leveldb/doc/doc.css delete mode 100644 src/leveldb/doc/impl.html delete mode 100644 src/leveldb/doc/impl.md delete mode 100644 src/leveldb/doc/index.html delete mode 100644 src/leveldb/doc/index.md delete mode 100644 src/leveldb/doc/log_format.md delete mode 100644 src/leveldb/doc/log_format.txt delete mode 100644 src/leveldb/doc/table_format.md delete mode 100644 src/leveldb/doc/table_format.txt delete mode 100644 src/leveldb/helpers/memenv/memenv.cc delete mode 100644 src/leveldb/helpers/memenv/memenv.h delete mode 100644 src/leveldb/helpers/memenv/memenv_test.cc delete mode 100644 src/leveldb/include/leveldb/c.h delete mode 100644 src/leveldb/include/leveldb/cache.h delete mode 100644 src/leveldb/include/leveldb/comparator.h delete mode 100644 src/leveldb/include/leveldb/db.h delete mode 100644 src/leveldb/include/leveldb/dumpfile.h delete mode 100644 src/leveldb/include/leveldb/env.h delete mode 100644 src/leveldb/include/leveldb/filter_policy.h delete mode 100644 src/leveldb/include/leveldb/iterator.h delete mode 100644 src/leveldb/include/leveldb/options.h delete mode 100644 src/leveldb/include/leveldb/slice.h delete mode 100644 src/leveldb/include/leveldb/status.h delete mode 100644 src/leveldb/include/leveldb/table.h delete mode 100644 src/leveldb/include/leveldb/table_builder.h delete mode 100644 src/leveldb/include/leveldb/write_batch.h delete mode 100644 src/leveldb/issues/issue178_test.cc delete mode 100644 src/leveldb/issues/issue200_test.cc delete mode 100644 src/leveldb/port/README delete mode 100644 src/leveldb/port/atomic_pointer.h delete mode 100644 src/leveldb/port/port.h delete mode 100644 src/leveldb/port/port_example.h delete mode 100644 src/leveldb/port/port_posix.cc delete mode 100644 src/leveldb/port/port_posix.h delete mode 100644 src/leveldb/port/port_posix_sse.cc delete mode 100644 src/leveldb/port/port_win.cc delete mode 100644 src/leveldb/port/port_win.h delete mode 100644 src/leveldb/port/thread_annotations.h delete mode 100644 src/leveldb/port/win/stdint.h delete mode 100644 src/leveldb/table/block.cc delete mode 100644 src/leveldb/table/block.h delete mode 100644 src/leveldb/table/block_builder.cc delete mode 100644 src/leveldb/table/block_builder.h delete mode 100644 src/leveldb/table/filter_block.cc delete mode 100644 src/leveldb/table/filter_block.h delete mode 100644 src/leveldb/table/filter_block_test.cc delete mode 100644 src/leveldb/table/format.cc delete mode 100644 src/leveldb/table/format.h delete mode 100644 src/leveldb/table/iterator.cc delete mode 100644 src/leveldb/table/iterator_wrapper.h delete mode 100644 src/leveldb/table/merger.cc delete mode 100644 src/leveldb/table/merger.h delete mode 100644 src/leveldb/table/table.cc delete mode 100644 src/leveldb/table/table_builder.cc delete mode 100644 src/leveldb/table/table_test.cc delete mode 100644 src/leveldb/table/two_level_iterator.cc delete mode 100644 src/leveldb/table/two_level_iterator.h delete mode 100644 src/leveldb/util/arena.cc delete mode 100644 src/leveldb/util/arena.h delete mode 100644 src/leveldb/util/arena_test.cc delete mode 100644 src/leveldb/util/bloom.cc delete mode 100644 src/leveldb/util/bloom_test.cc delete mode 100644 src/leveldb/util/cache.cc delete mode 100644 src/leveldb/util/cache_test.cc delete mode 100644 src/leveldb/util/coding.cc delete mode 100644 src/leveldb/util/coding.h delete mode 100644 src/leveldb/util/coding_test.cc delete mode 100644 src/leveldb/util/comparator.cc delete mode 100644 src/leveldb/util/crc32c.cc delete mode 100644 src/leveldb/util/crc32c.h delete mode 100644 src/leveldb/util/crc32c_test.cc delete mode 100644 src/leveldb/util/env.cc delete mode 100644 src/leveldb/util/env_posix.cc delete mode 100644 src/leveldb/util/env_posix_test.cc delete mode 100644 src/leveldb/util/env_posix_test_helper.h delete mode 100644 src/leveldb/util/env_test.cc delete mode 100644 src/leveldb/util/env_win.cc delete mode 100644 src/leveldb/util/filter_policy.cc delete mode 100644 src/leveldb/util/hash.cc delete mode 100644 src/leveldb/util/hash.h delete mode 100644 src/leveldb/util/hash_test.cc delete mode 100644 src/leveldb/util/histogram.cc delete mode 100644 src/leveldb/util/histogram.h delete mode 100644 src/leveldb/util/logging.cc delete mode 100644 src/leveldb/util/logging.h delete mode 100644 src/leveldb/util/mutexlock.h delete mode 100644 src/leveldb/util/options.cc delete mode 100644 src/leveldb/util/posix_logger.h delete mode 100644 src/leveldb/util/random.h delete mode 100644 src/leveldb/util/status.cc delete mode 100644 src/leveldb/util/testharness.cc delete mode 100644 src/leveldb/util/testharness.h delete mode 100644 src/leveldb/util/testutil.cc delete mode 100644 src/leveldb/util/testutil.h diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore deleted file mode 100644 index 71d87a4eeb..0000000000 --- a/src/leveldb/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -build_config.mk -*.a -*.o -*.dylib* -*.so -*.so.* -*_test -db_bench -leveldbutil -Release -Debug -Benchmark -vs2010.* diff --git a/src/leveldb/.travis.yml b/src/leveldb/.travis.yml deleted file mode 100644 index f5bd74c454..0000000000 --- a/src/leveldb/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: cpp -compiler: -- clang -- gcc -os: -- linux -- osx -sudo: false -before_install: -- echo $LANG -- echo $LC_ALL -script: -- make -j 4 check diff --git a/src/leveldb/AUTHORS b/src/leveldb/AUTHORS deleted file mode 100644 index 2439d7a452..0000000000 --- a/src/leveldb/AUTHORS +++ /dev/null @@ -1,12 +0,0 @@ -# Names should be added to this file like so: -# Name or Organization - -Google Inc. - -# Initial version authors: -Jeffrey Dean -Sanjay Ghemawat - -# Partial list of contributors: -Kevin Regan -Johan Bilien diff --git a/src/leveldb/CONTRIBUTING.md b/src/leveldb/CONTRIBUTING.md deleted file mode 100644 index cd600ff46b..0000000000 --- a/src/leveldb/CONTRIBUTING.md +++ /dev/null @@ -1,36 +0,0 @@ -# Contributing - -We'd love to accept your code patches! However, before we can take them, we -have to jump a couple of legal hurdles. - -## Contributor License Agreements - -Please fill out either the individual or corporate Contributor License -Agreement as appropriate. - -* If you are an individual writing original source code and you're sure you -own the intellectual property, then sign an [individual CLA](https://developers.google.com/open-source/cla/individual). -* If you work for a company that wants to allow you to contribute your work, -then sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate). - -Follow either of the two links above to access the appropriate CLA and -instructions for how to sign and return it. - -## Submitting a Patch - -1. Sign the contributors license agreement above. -2. Decide which code you want to submit. A submission should be a set of changes -that addresses one issue in the [issue tracker](https://github.com/google/leveldb/issues). -Please don't mix more than one logical change per submission, because it makes -the history hard to follow. If you want to make a change -(e.g. add a sample or feature) that doesn't have a corresponding issue in the -issue tracker, please create one. -3. **Submitting**: When you are ready to submit, send us a Pull Request. Be -sure to include the issue number you fixed and the name you used to sign -the CLA. - -## Writing Code ## - -If your contribution contains code, please make sure that it follows -[the style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). -Otherwise we will have to ask you to make changes, and that's no fun for anyone. diff --git a/src/leveldb/LICENSE b/src/leveldb/LICENSE deleted file mode 100644 index 8e80208cd7..0000000000 --- a/src/leveldb/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2011 The LevelDB Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile deleted file mode 100644 index 2bd2cadcdd..0000000000 --- a/src/leveldb/Makefile +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright (c) 2011 The LevelDB Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. See the AUTHORS file for names of contributors. - -#----------------------------------------------- -# Uncomment exactly one of the lines labelled (A), (B), and (C) below -# to switch between compilation modes. - -# (A) Production use (optimized mode) -OPT ?= -O2 -DNDEBUG -# (B) Debug mode, w/ full line-level debugging symbols -# OPT ?= -g2 -# (C) Profiling mode: opt, but w/debugging symbols -# OPT ?= -O2 -g2 -DNDEBUG -#----------------------------------------------- - -# detect what platform we're building on -$(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \ - ./build_detect_platform build_config.mk ./) -# this file is generated by the previous line to set build flags and sources -include build_config.mk - -CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) -CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) - -LDFLAGS += $(PLATFORM_LDFLAGS) -LIBS += $(PLATFORM_LIBS) - -LIBOBJECTS = $(SOURCES:.cc=.o) -MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) - -TESTUTIL = ./util/testutil.o -TESTHARNESS = ./util/testharness.o $(TESTUTIL) - -# Note: iOS should probably be using libtool, not ar. -ifeq ($(PLATFORM), IOS) -AR=xcrun ar -endif - -TESTS = \ - arena_test \ - autocompact_test \ - bloom_test \ - c_test \ - cache_test \ - coding_test \ - corruption_test \ - crc32c_test \ - db_test \ - dbformat_test \ - env_test \ - filename_test \ - filter_block_test \ - hash_test \ - issue178_test \ - issue200_test \ - log_test \ - memenv_test \ - skiplist_test \ - table_test \ - version_edit_test \ - version_set_test \ - write_batch_test - -PROGRAMS = db_bench leveldbutil $(TESTS) -BENCHMARKS = db_bench_sqlite3 db_bench_tree_db - -LIBRARY = libleveldb.a -MEMENVLIBRARY = libmemenv.a - -default: all - -# Should we build shared libraries? -ifneq ($(PLATFORM_SHARED_EXT),) - -ifneq ($(PLATFORM_SHARED_VERSIONED),true) -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1) -SHARED3 = $(SHARED1) -SHARED = $(SHARED1) -else -# Update db.h if you change these. -SHARED_MAJOR = 1 -SHARED_MINOR = 18 -SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) -SHARED2 = $(SHARED1).$(SHARED_MAJOR) -SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) -SHARED = $(SHARED1) $(SHARED2) $(SHARED3) -$(SHARED1): $(SHARED3) - ln -fs $(SHARED3) $(SHARED1) -$(SHARED2): $(SHARED3) - ln -fs $(SHARED3) $(SHARED2) -endif - -$(SHARED3): - $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS) - -endif # PLATFORM_SHARED_EXT - -all: $(SHARED) $(LIBRARY) - -check: all $(PROGRAMS) $(TESTS) - for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done - -clean: - -rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk - -rm -rf ios-x86/* ios-arm/* - -$(LIBRARY): $(LIBOBJECTS) - rm -f $@ - $(AR) -rs $@ $(LIBOBJECTS) - -db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) - -db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) - -db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) - -leveldbutil: db/leveldb_main.o $(LIBOBJECTS) - $(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS) - -arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -autocompact_test: db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/autocompact_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -hash_test: util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -issue178_test: issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) issues/issue178_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -issue200_test: issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) issues/issue200_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) - -$(MEMENVLIBRARY) : $(MEMENVOBJECTS) - rm -f $@ - $(AR) -rs $@ $(MEMENVOBJECTS) - -memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) - $(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS) - -ifeq ($(PLATFORM), IOS) -# For iOS, create universal object files to be used on both the simulator and -# a device. -PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms -SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer -DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer -IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) -IOSARCH=-arch armv6 -arch armv7 -arch armv7s -arch arm64 - -.cc.o: - mkdir -p ios-x86/$(dir $@) - xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ - xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@ - -.c.o: - mkdir -p ios-x86/$(dir $@) - xcrun -sdk iphonesimulator $(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -arch x86_64 -c $< -o ios-x86/$@ - mkdir -p ios-arm/$(dir $@) - xcrun -sdk iphoneos $(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk $(IOSARCH) -c $< -o ios-arm/$@ - xcrun lipo ios-x86/$@ ios-arm/$@ -create -output $@ - -else -.cc.o: - $(CXX) $(CXXFLAGS) -c $< -o $@ - -.c.o: - $(CC) $(CFLAGS) -c $< -o $@ -endif diff --git a/src/leveldb/NEWS b/src/leveldb/NEWS deleted file mode 100644 index 3fd99242d7..0000000000 --- a/src/leveldb/NEWS +++ /dev/null @@ -1,17 +0,0 @@ -Release 1.2 2011-05-16 ----------------------- - -Fixes for larger databases (tested up to one billion 100-byte entries, -i.e., ~100GB). - -(1) Place hard limit on number of level-0 files. This fixes errors -of the form "too many open files". - -(2) Fixed memtable management. Before the fix, a heavy write burst -could cause unbounded memory usage. - -A fix for a logging bug where the reader would incorrectly complain -about corruption. - -Allow public access to WriteBatch contents so that users can easily -wrap a DB. diff --git a/src/leveldb/README b/src/leveldb/README deleted file mode 100644 index 3618adeeed..0000000000 --- a/src/leveldb/README +++ /dev/null @@ -1,51 +0,0 @@ -leveldb: A key-value store -Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) - -The code under this directory implements a system for maintaining a -persistent key/value store. - -See doc/index.html for more explanation. -See doc/impl.html for a brief overview of the implementation. - -The public interface is in include/*.h. Callers should not include or -rely on the details of any other header files in this package. Those -internal APIs may be changed without warning. - -Guide to header files: - -include/db.h - Main interface to the DB: Start here - -include/options.h - Control over the behavior of an entire database, and also - control over the behavior of individual reads and writes. - -include/comparator.h - Abstraction for user-specified comparison function. If you want - just bytewise comparison of keys, you can use the default comparator, - but clients can write their own comparator implementations if they - want custom ordering (e.g. to handle different character - encodings, etc.) - -include/iterator.h - Interface for iterating over data. You can get an iterator - from a DB object. - -include/write_batch.h - Interface for atomically applying multiple updates to a database. - -include/slice.h - A simple module for maintaining a pointer and a length into some - other byte array. - -include/status.h - Status is returned from many of the public interfaces and is used - to report success and various kinds of errors. - -include/env.h - Abstraction of the OS environment. A posix implementation of - this interface is in util/env_posix.cc - -include/table.h -include/table_builder.h - Lower-level modules that most clients probably won't use directly diff --git a/src/leveldb/README.md b/src/leveldb/README.md deleted file mode 100644 index 480affb5ca..0000000000 --- a/src/leveldb/README.md +++ /dev/null @@ -1,138 +0,0 @@ -**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.** - -Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) - -# Features - * Keys and values are arbitrary byte arrays. - * Data is stored sorted by key. - * Callers can provide a custom comparison function to override the sort order. - * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`. - * Multiple changes can be made in one atomic batch. - * Users can create a transient snapshot to get a consistent view of data. - * Forward and backward iteration is supported over the data. - * Data is automatically compressed using the [Snappy compression library](http://code.google.com/p/snappy). - * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions. - * [Detailed documentation](http://htmlpreview.github.io/?https://github.com/google/leveldb/blob/master/doc/index.html) about how to use the library is included with the source code. - - -# Limitations - * This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes. - * Only a single process (possibly multi-threaded) can access a particular database at a time. - * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library. - -# Performance - -Here is a performance report (with explanations) from the run of the -included db_bench program. The results are somewhat noisy, but should -be enough to get a ballpark performance estimate. - -## Setup - -We use a database with a million entries. Each entry has a 16 byte -key, and a 100 byte value. Values used by the benchmark compress to -about half their original size. - - LevelDB: version 1.1 - Date: Sun May 1 12:11:26 2011 - CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz - CPUCache: 4096 KB - Keys: 16 bytes each - Values: 100 bytes each (50 bytes after compression) - Entries: 1000000 - Raw Size: 110.6 MB (estimated) - File Size: 62.9 MB (estimated) - -## Write performance - -The "fill" benchmarks create a brand new database, in either -sequential, or random order. The "fillsync" benchmark flushes data -from the operating system to the disk after every operation; the other -write operations leave the data sitting in the operating system buffer -cache for a while. The "overwrite" benchmark does random writes that -update existing keys in the database. - - fillseq : 1.765 micros/op; 62.7 MB/s - fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops) - fillrandom : 2.460 micros/op; 45.0 MB/s - overwrite : 2.380 micros/op; 46.5 MB/s - -Each "op" above corresponds to a write of a single key/value pair. -I.e., a random write benchmark goes at approximately 400,000 writes per second. - -Each "fillsync" operation costs much less (0.3 millisecond) -than a disk seek (typically 10 milliseconds). We suspect that this is -because the hard disk itself is buffering the update in its memory and -responding before the data has been written to the platter. This may -or may not be safe based on whether or not the hard disk has enough -power to save its memory in the event of a power failure. - -## Read performance - -We list the performance of reading sequentially in both the forward -and reverse direction, and also the performance of a random lookup. -Note that the database created by the benchmark is quite small. -Therefore the report characterizes the performance of leveldb when the -working set fits in memory. The cost of reading a piece of data that -is not present in the operating system buffer cache will be dominated -by the one or two disk seeks needed to fetch the data from disk. -Write performance will be mostly unaffected by whether or not the -working set fits in memory. - - readrandom : 16.677 micros/op; (approximately 60,000 reads per second) - readseq : 0.476 micros/op; 232.3 MB/s - readreverse : 0.724 micros/op; 152.9 MB/s - -LevelDB compacts its underlying storage data in the background to -improve read performance. The results listed above were done -immediately after a lot of random writes. The results after -compactions (which are usually triggered automatically) are better. - - readrandom : 11.602 micros/op; (approximately 85,000 reads per second) - readseq : 0.423 micros/op; 261.8 MB/s - readreverse : 0.663 micros/op; 166.9 MB/s - -Some of the high cost of reads comes from repeated decompression of blocks -read from disk. If we supply enough cache to the leveldb so it can hold the -uncompressed blocks in memory, the read performance improves again: - - readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) - readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) - -## Repository contents - -See doc/index.html for more explanation. See doc/impl.html for a brief overview of the implementation. - -The public interface is in include/*.h. Callers should not include or -rely on the details of any other header files in this package. Those -internal APIs may be changed without warning. - -Guide to header files: - -* **include/db.h**: Main interface to the DB: Start here - -* **include/options.h**: Control over the behavior of an entire database, -and also control over the behavior of individual reads and writes. - -* **include/comparator.h**: Abstraction for user-specified comparison function. -If you want just bytewise comparison of keys, you can use the default -comparator, but clients can write their own comparator implementations if they -want custom ordering (e.g. to handle different character encodings, etc.) - -* **include/iterator.h**: Interface for iterating over data. You can get -an iterator from a DB object. - -* **include/write_batch.h**: Interface for atomically applying multiple -updates to a database. - -* **include/slice.h**: A simple module for maintaining a pointer and a -length into some other byte array. - -* **include/status.h**: Status is returned from many of the public interfaces -and is used to report success and various kinds of errors. - -* **include/env.h**: -Abstraction of the OS environment. A posix implementation of this interface is -in util/env_posix.cc - -* **include/table.h, include/table_builder.h**: Lower-level modules that most -clients probably won't use directly diff --git a/src/leveldb/TODO b/src/leveldb/TODO deleted file mode 100644 index e603c07137..0000000000 --- a/src/leveldb/TODO +++ /dev/null @@ -1,14 +0,0 @@ -ss -- Stats - -db -- Maybe implement DB::BulkDeleteForRange(start_key, end_key) - that would blow away files whose ranges are entirely contained - within [start_key..end_key]? For Chrome, deletion of obsolete - object stores, etc. can be done in the background anyway, so - probably not that important. -- There have been requests for MultiGet. - -After a range is completely deleted, what gets rid of the -corresponding files if we do no future changes to that range. Make -the conditions for triggering compactions fire in more situations? diff --git a/src/leveldb/WINDOWS.md b/src/leveldb/WINDOWS.md deleted file mode 100644 index 5b76c2448f..0000000000 --- a/src/leveldb/WINDOWS.md +++ /dev/null @@ -1,39 +0,0 @@ -# Building LevelDB On Windows - -## Prereqs - -Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b). - -Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz) - -1. Open the "Windows SDK 7.1 Command Prompt" : - Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt" -2. Change the directory to the leveldb project - -## Building the Static lib - -* 32 bit Version - - setenv /x86 - msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 - -* 64 bit Version - - setenv /x64 - msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 - - -## Building and Running the Benchmark app - -* 32 bit Version - - setenv /x86 - msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 - Benchmark\leveldb.exe - -* 64 bit Version - - setenv /x64 - msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 - x64\Benchmark\leveldb.exe - diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform deleted file mode 100755 index a1101c1bda..0000000000 --- a/src/leveldb/build_detect_platform +++ /dev/null @@ -1,231 +0,0 @@ -#!/bin/sh -# -# Detects OS we're compiling on and outputs a file specified by the first -# argument, which in turn gets read while processing Makefile. -# -# The output will set the following variables: -# CC C Compiler path -# CXX C++ Compiler path -# PLATFORM_LDFLAGS Linker flags -# PLATFORM_LIBS Libraries flags -# PLATFORM_SHARED_EXT Extension for shared libraries -# PLATFORM_SHARED_LDFLAGS Flags for building shared library -# This flag is embedded just before the name -# of the shared library without intervening spaces -# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library -# PLATFORM_CCFLAGS C compiler flags -# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: -# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned -# shared libraries, empty otherwise. -# -# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: -# -# -DLEVELDB_ATOMIC_PRESENT if is present -# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms -# -DSNAPPY if the Snappy library is present -# - -OUTPUT=$1 -PREFIX=$2 -if test -z "$OUTPUT" || test -z "$PREFIX"; then - echo "usage: $0 " >&2 - exit 1 -fi - -# Delete existing output, if it exists -rm -f $OUTPUT -touch $OUTPUT - -if test -z "$CC"; then - CC=cc -fi - -if test -z "$CXX"; then - CXX=g++ -fi - -if test -z "$TMPDIR"; then - TMPDIR=/tmp -fi - -# Detect OS -if test -z "$TARGET_OS"; then - TARGET_OS=`uname -s` -fi - -COMMON_FLAGS= -CROSS_COMPILE= -PLATFORM_CCFLAGS= -PLATFORM_CXXFLAGS= -PLATFORM_LDFLAGS= -PLATFORM_LIBS= -PLATFORM_SHARED_EXT="so" -PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," -PLATFORM_SHARED_CFLAGS="-fPIC" -PLATFORM_SHARED_VERSIONED=true - -MEMCMP_FLAG= -if [ "$CXX" = "g++" ]; then - # Use libc's memcmp instead of GCC's memcmp. This results in ~40% - # performance improvement on readrandom under gcc 4.4.3 on Linux/x86. - MEMCMP_FLAG="-fno-builtin-memcmp" -fi - -case "$TARGET_OS" in - CYGWIN_*) - PLATFORM=OS_LINUX - COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN" - PLATFORM_LDFLAGS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - Darwin) - PLATFORM=OS_MACOSX - COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" - PLATFORM_SHARED_EXT=dylib - [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` - PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" - PORT_FILE=port/port_posix.cc - ;; - Linux) - PLATFORM=OS_LINUX - COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - ;; - SunOS) - PLATFORM=OS_SOLARIS - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" - PLATFORM_LIBS="-lpthread -lrt" - PORT_FILE=port/port_posix.cc - ;; - FreeBSD) - PLATFORM=OS_FREEBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" - PLATFORM_LIBS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - GNU/kFreeBSD) - PLATFORM=OS_KFREEBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_KFREEBSD" - PLATFORM_LIBS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - NetBSD) - PLATFORM=OS_NETBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" - PLATFORM_LIBS="-lpthread -lgcc_s" - PORT_FILE=port/port_posix.cc - ;; - OpenBSD) - PLATFORM=OS_OPENBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - ;; - DragonFly) - PLATFORM=OS_DRAGONFLYBSD - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" - PLATFORM_LIBS="-lpthread" - PORT_FILE=port/port_posix.cc - ;; - OS_ANDROID_CROSSCOMPILE) - PLATFORM=OS_ANDROID - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" - PLATFORM_LDFLAGS="" # All pthread features are in the Android C library - PORT_FILE=port/port_posix.cc - CROSS_COMPILE=true - ;; - HP-UX) - PLATFORM=OS_HPUX - COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" - PLATFORM_LDFLAGS="-pthread" - PORT_FILE=port/port_posix.cc - # man ld: +h internal_name - PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," - ;; - IOS) - PLATFORM=IOS - COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" - [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` - PORT_FILE=port/port_posix.cc - PLATFORM_SHARED_EXT= - PLATFORM_SHARED_LDFLAGS= - PLATFORM_SHARED_CFLAGS= - PLATFORM_SHARED_VERSIONED= - ;; - OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) - PLATFORM=OS_WINDOWS - COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" - PLATFORM_SOURCES="util/env_win.cc" - PLATFORM_LIBS="-lshlwapi" - PORT_FILE=port/port_win.cc - CROSS_COMPILE=true - ;; - *) - echo "Unknown platform!" >&2 - exit 1 -esac - -# We want to make a list of all cc files within util, db, table, and helpers -# except for the test and benchmark files. By default, find will output a list -# of all files matching either rule, so we need to append -print to make the -# prune take effect. -DIRS="$PREFIX/db $PREFIX/util $PREFIX/table" - -set -f # temporarily disable globbing so that our patterns aren't expanded -PRUNE_TEST="-name *test*.cc -prune" -PRUNE_BENCH="-name *_bench.cc -prune" -PRUNE_TOOL="-name leveldb_main.cc -prune" -PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "` - -set +f # re-enable globbing - -# The sources consist of the portable files, plus the platform-specific port -# file. -echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT -echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT - -if [ "$CROSS_COMPILE" = "true" ]; then - # Cross-compiling; do not try any compilation tests. - true -else - CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$" - - # If -std=c++0x works, use as fallback for when memory barriers - # are not available. - $CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null < - int main() {} -EOF - if [ "$?" = 0 ]; then - COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_ATOMIC_PRESENT" - PLATFORM_CXXFLAGS="-std=c++0x" - else - COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" - fi - - # Test whether tcmalloc is available - $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -ltcmalloc 2>/dev/null </dev/null -fi - -PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" -PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS" - -echo "CC=$CC" >> $OUTPUT -echo "CXX=$CXX" >> $OUTPUT -echo "PLATFORM=$PLATFORM" >> $OUTPUT -echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT -echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT -echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT -echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT -echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT -echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT diff --git a/src/leveldb/db/autocompact_test.cc b/src/leveldb/db/autocompact_test.cc deleted file mode 100644 index d20a2362c3..0000000000 --- a/src/leveldb/db/autocompact_test.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2013 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" -#include "db/db_impl.h" -#include "leveldb/cache.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -class AutoCompactTest { - public: - std::string dbname_; - Cache* tiny_cache_; - Options options_; - DB* db_; - - AutoCompactTest() { - dbname_ = test::TmpDir() + "/autocompact_test"; - tiny_cache_ = NewLRUCache(100); - options_.block_cache = tiny_cache_; - DestroyDB(dbname_, options_); - options_.create_if_missing = true; - options_.compression = kNoCompression; - ASSERT_OK(DB::Open(options_, dbname_, &db_)); - } - - ~AutoCompactTest() { - delete db_; - DestroyDB(dbname_, Options()); - delete tiny_cache_; - } - - std::string Key(int i) { - char buf[100]; - snprintf(buf, sizeof(buf), "key%06d", i); - return std::string(buf); - } - - uint64_t Size(const Slice& start, const Slice& limit) { - Range r(start, limit); - uint64_t size; - db_->GetApproximateSizes(&r, 1, &size); - return size; - } - - void DoReads(int n); -}; - -static const int kValueSize = 200 * 1024; -static const int kTotalSize = 100 * 1024 * 1024; -static const int kCount = kTotalSize / kValueSize; - -// Read through the first n keys repeatedly and check that they get -// compacted (verified by checking the size of the key space). -void AutoCompactTest::DoReads(int n) { - std::string value(kValueSize, 'x'); - DBImpl* dbi = reinterpret_cast(db_); - - // Fill database - for (int i = 0; i < kCount; i++) { - ASSERT_OK(db_->Put(WriteOptions(), Key(i), value)); - } - ASSERT_OK(dbi->TEST_CompactMemTable()); - - // Delete everything - for (int i = 0; i < kCount; i++) { - ASSERT_OK(db_->Delete(WriteOptions(), Key(i))); - } - ASSERT_OK(dbi->TEST_CompactMemTable()); - - // Get initial measurement of the space we will be reading. - const int64_t initial_size = Size(Key(0), Key(n)); - const int64_t initial_other_size = Size(Key(n), Key(kCount)); - - // Read until size drops significantly. - std::string limit_key = Key(n); - for (int read = 0; true; read++) { - ASSERT_LT(read, 100) << "Taking too long to compact"; - Iterator* iter = db_->NewIterator(ReadOptions()); - for (iter->SeekToFirst(); - iter->Valid() && iter->key().ToString() < limit_key; - iter->Next()) { - // Drop data - } - delete iter; - // Wait a little bit to allow any triggered compactions to complete. - Env::Default()->SleepForMicroseconds(1000000); - uint64_t size = Size(Key(0), Key(n)); - fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", - read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0); - if (size <= initial_size/10) { - break; - } - } - - // Verify that the size of the key space not touched by the reads - // is pretty much unchanged. - const int64_t final_other_size = Size(Key(n), Key(kCount)); - ASSERT_LE(final_other_size, initial_other_size + 1048576); - ASSERT_GE(final_other_size, initial_other_size/5 - 1048576); -} - -TEST(AutoCompactTest, ReadAll) { - DoReads(kCount); -} - -TEST(AutoCompactTest, ReadHalf) { - DoReads(kCount/2); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/builder.cc b/src/leveldb/db/builder.cc deleted file mode 100644 index f419882197..0000000000 --- a/src/leveldb/db/builder.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/builder.h" - -#include "db/filename.h" -#include "db/dbformat.h" -#include "db/table_cache.h" -#include "db/version_edit.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" - -namespace leveldb { - -Status BuildTable(const std::string& dbname, - Env* env, - const Options& options, - TableCache* table_cache, - Iterator* iter, - FileMetaData* meta) { - Status s; - meta->file_size = 0; - iter->SeekToFirst(); - - std::string fname = TableFileName(dbname, meta->number); - if (iter->Valid()) { - WritableFile* file; - s = env->NewWritableFile(fname, &file); - if (!s.ok()) { - return s; - } - - TableBuilder* builder = new TableBuilder(options, file); - meta->smallest.DecodeFrom(iter->key()); - for (; iter->Valid(); iter->Next()) { - Slice key = iter->key(); - meta->largest.DecodeFrom(key); - builder->Add(key, iter->value()); - } - - // Finish and check for builder errors - if (s.ok()) { - s = builder->Finish(); - if (s.ok()) { - meta->file_size = builder->FileSize(); - assert(meta->file_size > 0); - } - } else { - builder->Abandon(); - } - delete builder; - - // Finish and check for file errors - if (s.ok()) { - s = file->Sync(); - } - if (s.ok()) { - s = file->Close(); - } - delete file; - file = NULL; - - if (s.ok()) { - // Verify that the table is usable - Iterator* it = table_cache->NewIterator(ReadOptions(), - meta->number, - meta->file_size); - s = it->status(); - delete it; - } - } - - // Check for input iterator errors - if (!iter->status().ok()) { - s = iter->status(); - } - - if (s.ok() && meta->file_size > 0) { - // Keep it - } else { - env->DeleteFile(fname); - } - return s; -} - -} // namespace leveldb diff --git a/src/leveldb/db/builder.h b/src/leveldb/db/builder.h deleted file mode 100644 index 62431fcf44..0000000000 --- a/src/leveldb/db/builder.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ -#define STORAGE_LEVELDB_DB_BUILDER_H_ - -#include "leveldb/status.h" - -namespace leveldb { - -struct Options; -struct FileMetaData; - -class Env; -class Iterator; -class TableCache; -class VersionEdit; - -// Build a Table file from the contents of *iter. The generated file -// will be named according to meta->number. On success, the rest of -// *meta will be filled with metadata about the generated table. -// If no data is present in *iter, meta->file_size will be set to -// zero, and no Table file will be produced. -extern Status BuildTable(const std::string& dbname, - Env* env, - const Options& options, - TableCache* table_cache, - Iterator* iter, - FileMetaData* meta); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc deleted file mode 100644 index 08ff0ad90a..0000000000 --- a/src/leveldb/db/c.cc +++ /dev/null @@ -1,595 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/c.h" - -#include -#include -#include "leveldb/cache.h" -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/iterator.h" -#include "leveldb/options.h" -#include "leveldb/status.h" -#include "leveldb/write_batch.h" - -using leveldb::Cache; -using leveldb::Comparator; -using leveldb::CompressionType; -using leveldb::DB; -using leveldb::Env; -using leveldb::FileLock; -using leveldb::FilterPolicy; -using leveldb::Iterator; -using leveldb::kMajorVersion; -using leveldb::kMinorVersion; -using leveldb::Logger; -using leveldb::NewBloomFilterPolicy; -using leveldb::NewLRUCache; -using leveldb::Options; -using leveldb::RandomAccessFile; -using leveldb::Range; -using leveldb::ReadOptions; -using leveldb::SequentialFile; -using leveldb::Slice; -using leveldb::Snapshot; -using leveldb::Status; -using leveldb::WritableFile; -using leveldb::WriteBatch; -using leveldb::WriteOptions; - -extern "C" { - -struct leveldb_t { DB* rep; }; -struct leveldb_iterator_t { Iterator* rep; }; -struct leveldb_writebatch_t { WriteBatch rep; }; -struct leveldb_snapshot_t { const Snapshot* rep; }; -struct leveldb_readoptions_t { ReadOptions rep; }; -struct leveldb_writeoptions_t { WriteOptions rep; }; -struct leveldb_options_t { Options rep; }; -struct leveldb_cache_t { Cache* rep; }; -struct leveldb_seqfile_t { SequentialFile* rep; }; -struct leveldb_randomfile_t { RandomAccessFile* rep; }; -struct leveldb_writablefile_t { WritableFile* rep; }; -struct leveldb_logger_t { Logger* rep; }; -struct leveldb_filelock_t { FileLock* rep; }; - -struct leveldb_comparator_t : public Comparator { - void* state_; - void (*destructor_)(void*); - int (*compare_)( - void*, - const char* a, size_t alen, - const char* b, size_t blen); - const char* (*name_)(void*); - - virtual ~leveldb_comparator_t() { - (*destructor_)(state_); - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); - } - - virtual const char* Name() const { - return (*name_)(state_); - } - - // No-ops since the C binding does not support key shortening methods. - virtual void FindShortestSeparator(std::string*, const Slice&) const { } - virtual void FindShortSuccessor(std::string* key) const { } -}; - -struct leveldb_filterpolicy_t : public FilterPolicy { - void* state_; - void (*destructor_)(void*); - const char* (*name_)(void*); - char* (*create_)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length); - unsigned char (*key_match_)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length); - - virtual ~leveldb_filterpolicy_t() { - (*destructor_)(state_); - } - - virtual const char* Name() const { - return (*name_)(state_); - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - std::vector key_pointers(n); - std::vector key_sizes(n); - for (int i = 0; i < n; i++) { - key_pointers[i] = keys[i].data(); - key_sizes[i] = keys[i].size(); - } - size_t len; - char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); - dst->append(filter, len); - free(filter); - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { - return (*key_match_)(state_, key.data(), key.size(), - filter.data(), filter.size()); - } -}; - -struct leveldb_env_t { - Env* rep; - bool is_default; -}; - -static bool SaveError(char** errptr, const Status& s) { - assert(errptr != NULL); - if (s.ok()) { - return false; - } else if (*errptr == NULL) { - *errptr = strdup(s.ToString().c_str()); - } else { - // TODO(sanjay): Merge with existing error? - free(*errptr); - *errptr = strdup(s.ToString().c_str()); - } - return true; -} - -static char* CopyString(const std::string& str) { - char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); - memcpy(result, str.data(), sizeof(char) * str.size()); - return result; -} - -leveldb_t* leveldb_open( - const leveldb_options_t* options, - const char* name, - char** errptr) { - DB* db; - if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { - return NULL; - } - leveldb_t* result = new leveldb_t; - result->rep = db; - return result; -} - -void leveldb_close(leveldb_t* db) { - delete db->rep; - delete db; -} - -void leveldb_put( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - const char* val, size_t vallen, - char** errptr) { - SaveError(errptr, - db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); -} - -void leveldb_delete( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - char** errptr) { - SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); -} - - -void leveldb_write( - leveldb_t* db, - const leveldb_writeoptions_t* options, - leveldb_writebatch_t* batch, - char** errptr) { - SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); -} - -char* leveldb_get( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, size_t keylen, - size_t* vallen, - char** errptr) { - char* result = NULL; - std::string tmp; - Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); - if (s.ok()) { - *vallen = tmp.size(); - result = CopyString(tmp); - } else { - *vallen = 0; - if (!s.IsNotFound()) { - SaveError(errptr, s); - } - } - return result; -} - -leveldb_iterator_t* leveldb_create_iterator( - leveldb_t* db, - const leveldb_readoptions_t* options) { - leveldb_iterator_t* result = new leveldb_iterator_t; - result->rep = db->rep->NewIterator(options->rep); - return result; -} - -const leveldb_snapshot_t* leveldb_create_snapshot( - leveldb_t* db) { - leveldb_snapshot_t* result = new leveldb_snapshot_t; - result->rep = db->rep->GetSnapshot(); - return result; -} - -void leveldb_release_snapshot( - leveldb_t* db, - const leveldb_snapshot_t* snapshot) { - db->rep->ReleaseSnapshot(snapshot->rep); - delete snapshot; -} - -char* leveldb_property_value( - leveldb_t* db, - const char* propname) { - std::string tmp; - if (db->rep->GetProperty(Slice(propname), &tmp)) { - // We use strdup() since we expect human readable output. - return strdup(tmp.c_str()); - } else { - return NULL; - } -} - -void leveldb_approximate_sizes( - leveldb_t* db, - int num_ranges, - const char* const* range_start_key, const size_t* range_start_key_len, - const char* const* range_limit_key, const size_t* range_limit_key_len, - uint64_t* sizes) { - Range* ranges = new Range[num_ranges]; - for (int i = 0; i < num_ranges; i++) { - ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); - ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); - } - db->rep->GetApproximateSizes(ranges, num_ranges, sizes); - delete[] ranges; -} - -void leveldb_compact_range( - leveldb_t* db, - const char* start_key, size_t start_key_len, - const char* limit_key, size_t limit_key_len) { - Slice a, b; - db->rep->CompactRange( - // Pass NULL Slice if corresponding "const char*" is NULL - (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), - (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); -} - -void leveldb_destroy_db( - const leveldb_options_t* options, - const char* name, - char** errptr) { - SaveError(errptr, DestroyDB(name, options->rep)); -} - -void leveldb_repair_db( - const leveldb_options_t* options, - const char* name, - char** errptr) { - SaveError(errptr, RepairDB(name, options->rep)); -} - -void leveldb_iter_destroy(leveldb_iterator_t* iter) { - delete iter->rep; - delete iter; -} - -unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { - return iter->rep->Valid(); -} - -void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { - iter->rep->SeekToFirst(); -} - -void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { - iter->rep->SeekToLast(); -} - -void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { - iter->rep->Seek(Slice(k, klen)); -} - -void leveldb_iter_next(leveldb_iterator_t* iter) { - iter->rep->Next(); -} - -void leveldb_iter_prev(leveldb_iterator_t* iter) { - iter->rep->Prev(); -} - -const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { - Slice s = iter->rep->key(); - *klen = s.size(); - return s.data(); -} - -const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { - Slice s = iter->rep->value(); - *vlen = s.size(); - return s.data(); -} - -void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { - SaveError(errptr, iter->rep->status()); -} - -leveldb_writebatch_t* leveldb_writebatch_create() { - return new leveldb_writebatch_t; -} - -void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { - delete b; -} - -void leveldb_writebatch_clear(leveldb_writebatch_t* b) { - b->rep.Clear(); -} - -void leveldb_writebatch_put( - leveldb_writebatch_t* b, - const char* key, size_t klen, - const char* val, size_t vlen) { - b->rep.Put(Slice(key, klen), Slice(val, vlen)); -} - -void leveldb_writebatch_delete( - leveldb_writebatch_t* b, - const char* key, size_t klen) { - b->rep.Delete(Slice(key, klen)); -} - -void leveldb_writebatch_iterate( - leveldb_writebatch_t* b, - void* state, - void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), - void (*deleted)(void*, const char* k, size_t klen)) { - class H : public WriteBatch::Handler { - public: - void* state_; - void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); - void (*deleted_)(void*, const char* k, size_t klen); - virtual void Put(const Slice& key, const Slice& value) { - (*put_)(state_, key.data(), key.size(), value.data(), value.size()); - } - virtual void Delete(const Slice& key) { - (*deleted_)(state_, key.data(), key.size()); - } - }; - H handler; - handler.state_ = state; - handler.put_ = put; - handler.deleted_ = deleted; - b->rep.Iterate(&handler); -} - -leveldb_options_t* leveldb_options_create() { - return new leveldb_options_t; -} - -void leveldb_options_destroy(leveldb_options_t* options) { - delete options; -} - -void leveldb_options_set_comparator( - leveldb_options_t* opt, - leveldb_comparator_t* cmp) { - opt->rep.comparator = cmp; -} - -void leveldb_options_set_filter_policy( - leveldb_options_t* opt, - leveldb_filterpolicy_t* policy) { - opt->rep.filter_policy = policy; -} - -void leveldb_options_set_create_if_missing( - leveldb_options_t* opt, unsigned char v) { - opt->rep.create_if_missing = v; -} - -void leveldb_options_set_error_if_exists( - leveldb_options_t* opt, unsigned char v) { - opt->rep.error_if_exists = v; -} - -void leveldb_options_set_paranoid_checks( - leveldb_options_t* opt, unsigned char v) { - opt->rep.paranoid_checks = v; -} - -void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { - opt->rep.env = (env ? env->rep : NULL); -} - -void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { - opt->rep.info_log = (l ? l->rep : NULL); -} - -void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { - opt->rep.write_buffer_size = s; -} - -void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { - opt->rep.max_open_files = n; -} - -void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { - opt->rep.block_cache = c->rep; -} - -void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { - opt->rep.block_size = s; -} - -void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { - opt->rep.block_restart_interval = n; -} - -void leveldb_options_set_compression(leveldb_options_t* opt, int t) { - opt->rep.compression = static_cast(t); -} - -leveldb_comparator_t* leveldb_comparator_create( - void* state, - void (*destructor)(void*), - int (*compare)( - void*, - const char* a, size_t alen, - const char* b, size_t blen), - const char* (*name)(void*)) { - leveldb_comparator_t* result = new leveldb_comparator_t; - result->state_ = state; - result->destructor_ = destructor; - result->compare_ = compare; - result->name_ = name; - return result; -} - -void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { - delete cmp; -} - -leveldb_filterpolicy_t* leveldb_filterpolicy_create( - void* state, - void (*destructor)(void*), - char* (*create_filter)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length), - unsigned char (*key_may_match)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length), - const char* (*name)(void*)) { - leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; - result->state_ = state; - result->destructor_ = destructor; - result->create_ = create_filter; - result->key_match_ = key_may_match; - result->name_ = name; - return result; -} - -void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { - delete filter; -} - -leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { - // Make a leveldb_filterpolicy_t, but override all of its methods so - // they delegate to a NewBloomFilterPolicy() instead of user - // supplied C functions. - struct Wrapper : public leveldb_filterpolicy_t { - const FilterPolicy* rep_; - ~Wrapper() { delete rep_; } - const char* Name() const { return rep_->Name(); } - void CreateFilter(const Slice* keys, int n, std::string* dst) const { - return rep_->CreateFilter(keys, n, dst); - } - bool KeyMayMatch(const Slice& key, const Slice& filter) const { - return rep_->KeyMayMatch(key, filter); - } - static void DoNothing(void*) { } - }; - Wrapper* wrapper = new Wrapper; - wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); - wrapper->state_ = NULL; - wrapper->destructor_ = &Wrapper::DoNothing; - return wrapper; -} - -leveldb_readoptions_t* leveldb_readoptions_create() { - return new leveldb_readoptions_t; -} - -void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { - delete opt; -} - -void leveldb_readoptions_set_verify_checksums( - leveldb_readoptions_t* opt, - unsigned char v) { - opt->rep.verify_checksums = v; -} - -void leveldb_readoptions_set_fill_cache( - leveldb_readoptions_t* opt, unsigned char v) { - opt->rep.fill_cache = v; -} - -void leveldb_readoptions_set_snapshot( - leveldb_readoptions_t* opt, - const leveldb_snapshot_t* snap) { - opt->rep.snapshot = (snap ? snap->rep : NULL); -} - -leveldb_writeoptions_t* leveldb_writeoptions_create() { - return new leveldb_writeoptions_t; -} - -void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { - delete opt; -} - -void leveldb_writeoptions_set_sync( - leveldb_writeoptions_t* opt, unsigned char v) { - opt->rep.sync = v; -} - -leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { - leveldb_cache_t* c = new leveldb_cache_t; - c->rep = NewLRUCache(capacity); - return c; -} - -void leveldb_cache_destroy(leveldb_cache_t* cache) { - delete cache->rep; - delete cache; -} - -leveldb_env_t* leveldb_create_default_env() { - leveldb_env_t* result = new leveldb_env_t; - result->rep = Env::Default(); - result->is_default = true; - return result; -} - -void leveldb_env_destroy(leveldb_env_t* env) { - if (!env->is_default) delete env->rep; - delete env; -} - -void leveldb_free(void* ptr) { - free(ptr); -} - -int leveldb_major_version() { - return kMajorVersion; -} - -int leveldb_minor_version() { - return kMinorVersion; -} - -} // end extern "C" diff --git a/src/leveldb/db/c_test.c b/src/leveldb/db/c_test.c deleted file mode 100644 index 7cd5ee0207..0000000000 --- a/src/leveldb/db/c_test.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. See the AUTHORS file for names of contributors. */ - -#include "leveldb/c.h" - -#include -#include -#include -#include -#include -#include - -const char* phase = ""; -static char dbname[200]; - -static void StartPhase(const char* name) { - fprintf(stderr, "=== Test %s\n", name); - phase = name; -} - -static const char* GetTempDir(void) { - const char* ret = getenv("TEST_TMPDIR"); - if (ret == NULL || ret[0] == '\0') - ret = "/tmp"; - return ret; -} - -#define CheckNoError(err) \ - if ((err) != NULL) { \ - fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ - abort(); \ - } - -#define CheckCondition(cond) \ - if (!(cond)) { \ - fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ - abort(); \ - } - -static void CheckEqual(const char* expected, const char* v, size_t n) { - if (expected == NULL && v == NULL) { - // ok - } else if (expected != NULL && v != NULL && n == strlen(expected) && - memcmp(expected, v, n) == 0) { - // ok - return; - } else { - fprintf(stderr, "%s: expected '%s', got '%s'\n", - phase, - (expected ? expected : "(null)"), - (v ? v : "(null")); - abort(); - } -} - -static void Free(char** ptr) { - if (*ptr) { - free(*ptr); - *ptr = NULL; - } -} - -static void CheckGet( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, - const char* expected) { - char* err = NULL; - size_t val_len; - char* val; - val = leveldb_get(db, options, key, strlen(key), &val_len, &err); - CheckNoError(err); - CheckEqual(expected, val, val_len); - Free(&val); -} - -static void CheckIter(leveldb_iterator_t* iter, - const char* key, const char* val) { - size_t len; - const char* str; - str = leveldb_iter_key(iter, &len); - CheckEqual(key, str, len); - str = leveldb_iter_value(iter, &len); - CheckEqual(val, str, len); -} - -// Callback from leveldb_writebatch_iterate() -static void CheckPut(void* ptr, - const char* k, size_t klen, - const char* v, size_t vlen) { - int* state = (int*) ptr; - CheckCondition(*state < 2); - switch (*state) { - case 0: - CheckEqual("bar", k, klen); - CheckEqual("b", v, vlen); - break; - case 1: - CheckEqual("box", k, klen); - CheckEqual("c", v, vlen); - break; - } - (*state)++; -} - -// Callback from leveldb_writebatch_iterate() -static void CheckDel(void* ptr, const char* k, size_t klen) { - int* state = (int*) ptr; - CheckCondition(*state == 2); - CheckEqual("bar", k, klen); - (*state)++; -} - -static void CmpDestroy(void* arg) { } - -static int CmpCompare(void* arg, const char* a, size_t alen, - const char* b, size_t blen) { - int n = (alen < blen) ? alen : blen; - int r = memcmp(a, b, n); - if (r == 0) { - if (alen < blen) r = -1; - else if (alen > blen) r = +1; - } - return r; -} - -static const char* CmpName(void* arg) { - return "foo"; -} - -// Custom filter policy -static unsigned char fake_filter_result = 1; -static void FilterDestroy(void* arg) { } -static const char* FilterName(void* arg) { - return "TestFilter"; -} -static char* FilterCreate( - void* arg, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length) { - *filter_length = 4; - char* result = malloc(4); - memcpy(result, "fake", 4); - return result; -} -unsigned char FilterKeyMatch( - void* arg, - const char* key, size_t length, - const char* filter, size_t filter_length) { - CheckCondition(filter_length == 4); - CheckCondition(memcmp(filter, "fake", 4) == 0); - return fake_filter_result; -} - -int main(int argc, char** argv) { - leveldb_t* db; - leveldb_comparator_t* cmp; - leveldb_cache_t* cache; - leveldb_env_t* env; - leveldb_options_t* options; - leveldb_readoptions_t* roptions; - leveldb_writeoptions_t* woptions; - char* err = NULL; - int run = -1; - - CheckCondition(leveldb_major_version() >= 1); - CheckCondition(leveldb_minor_version() >= 1); - - snprintf(dbname, sizeof(dbname), - "%s/leveldb_c_test-%d", - GetTempDir(), - ((int) geteuid())); - - StartPhase("create_objects"); - cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); - env = leveldb_create_default_env(); - cache = leveldb_cache_create_lru(100000); - - options = leveldb_options_create(); - leveldb_options_set_comparator(options, cmp); - leveldb_options_set_error_if_exists(options, 1); - leveldb_options_set_cache(options, cache); - leveldb_options_set_env(options, env); - leveldb_options_set_info_log(options, NULL); - leveldb_options_set_write_buffer_size(options, 100000); - leveldb_options_set_paranoid_checks(options, 1); - leveldb_options_set_max_open_files(options, 10); - leveldb_options_set_block_size(options, 1024); - leveldb_options_set_block_restart_interval(options, 8); - leveldb_options_set_compression(options, leveldb_no_compression); - - roptions = leveldb_readoptions_create(); - leveldb_readoptions_set_verify_checksums(roptions, 1); - leveldb_readoptions_set_fill_cache(roptions, 0); - - woptions = leveldb_writeoptions_create(); - leveldb_writeoptions_set_sync(woptions, 1); - - StartPhase("destroy"); - leveldb_destroy_db(options, dbname, &err); - Free(&err); - - StartPhase("open_error"); - db = leveldb_open(options, dbname, &err); - CheckCondition(err != NULL); - Free(&err); - - StartPhase("leveldb_free"); - db = leveldb_open(options, dbname, &err); - CheckCondition(err != NULL); - leveldb_free(err); - err = NULL; - - StartPhase("open"); - leveldb_options_set_create_if_missing(options, 1); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", NULL); - - StartPhase("put"); - leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("compactall"); - leveldb_compact_range(db, NULL, 0, NULL, 0); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("compactrange"); - leveldb_compact_range(db, "a", 1, "z", 1); - CheckGet(db, roptions, "foo", "hello"); - - StartPhase("writebatch"); - { - leveldb_writebatch_t* wb = leveldb_writebatch_create(); - leveldb_writebatch_put(wb, "foo", 3, "a", 1); - leveldb_writebatch_clear(wb); - leveldb_writebatch_put(wb, "bar", 3, "b", 1); - leveldb_writebatch_put(wb, "box", 3, "c", 1); - leveldb_writebatch_delete(wb, "bar", 3); - leveldb_write(db, woptions, wb, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", "hello"); - CheckGet(db, roptions, "bar", NULL); - CheckGet(db, roptions, "box", "c"); - int pos = 0; - leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); - CheckCondition(pos == 3); - leveldb_writebatch_destroy(wb); - } - - StartPhase("iter"); - { - leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); - CheckCondition(!leveldb_iter_valid(iter)); - leveldb_iter_seek_to_first(iter); - CheckCondition(leveldb_iter_valid(iter)); - CheckIter(iter, "box", "c"); - leveldb_iter_next(iter); - CheckIter(iter, "foo", "hello"); - leveldb_iter_prev(iter); - CheckIter(iter, "box", "c"); - leveldb_iter_prev(iter); - CheckCondition(!leveldb_iter_valid(iter)); - leveldb_iter_seek_to_last(iter); - CheckIter(iter, "foo", "hello"); - leveldb_iter_seek(iter, "b", 1); - CheckIter(iter, "box", "c"); - leveldb_iter_get_error(iter, &err); - CheckNoError(err); - leveldb_iter_destroy(iter); - } - - StartPhase("approximate_sizes"); - { - int i; - int n = 20000; - char keybuf[100]; - char valbuf[100]; - uint64_t sizes[2]; - const char* start[2] = { "a", "k00000000000000010000" }; - size_t start_len[2] = { 1, 21 }; - const char* limit[2] = { "k00000000000000010000", "z" }; - size_t limit_len[2] = { 21, 1 }; - leveldb_writeoptions_set_sync(woptions, 0); - for (i = 0; i < n; i++) { - snprintf(keybuf, sizeof(keybuf), "k%020d", i); - snprintf(valbuf, sizeof(valbuf), "v%020d", i); - leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), - &err); - CheckNoError(err); - } - leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); - CheckCondition(sizes[0] > 0); - CheckCondition(sizes[1] > 0); - } - - StartPhase("property"); - { - char* prop = leveldb_property_value(db, "nosuchprop"); - CheckCondition(prop == NULL); - prop = leveldb_property_value(db, "leveldb.stats"); - CheckCondition(prop != NULL); - Free(&prop); - } - - StartPhase("snapshot"); - { - const leveldb_snapshot_t* snap; - snap = leveldb_create_snapshot(db); - leveldb_delete(db, woptions, "foo", 3, &err); - CheckNoError(err); - leveldb_readoptions_set_snapshot(roptions, snap); - CheckGet(db, roptions, "foo", "hello"); - leveldb_readoptions_set_snapshot(roptions, NULL); - CheckGet(db, roptions, "foo", NULL); - leveldb_release_snapshot(db, snap); - } - - StartPhase("repair"); - { - leveldb_close(db); - leveldb_options_set_create_if_missing(options, 0); - leveldb_options_set_error_if_exists(options, 0); - leveldb_repair_db(options, dbname, &err); - CheckNoError(err); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - CheckGet(db, roptions, "foo", NULL); - CheckGet(db, roptions, "bar", NULL); - CheckGet(db, roptions, "box", "c"); - leveldb_options_set_create_if_missing(options, 1); - leveldb_options_set_error_if_exists(options, 1); - } - - StartPhase("filter"); - for (run = 0; run < 2; run++) { - // First run uses custom filter, second run uses bloom filter - CheckNoError(err); - leveldb_filterpolicy_t* policy; - if (run == 0) { - policy = leveldb_filterpolicy_create( - NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); - } else { - policy = leveldb_filterpolicy_create_bloom(10); - } - - // Create new database - leveldb_close(db); - leveldb_destroy_db(options, dbname, &err); - leveldb_options_set_filter_policy(options, policy); - db = leveldb_open(options, dbname, &err); - CheckNoError(err); - leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); - CheckNoError(err); - leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); - CheckNoError(err); - leveldb_compact_range(db, NULL, 0, NULL, 0); - - fake_filter_result = 1; - CheckGet(db, roptions, "foo", "foovalue"); - CheckGet(db, roptions, "bar", "barvalue"); - if (phase == 0) { - // Must not find value when custom filter returns false - fake_filter_result = 0; - CheckGet(db, roptions, "foo", NULL); - CheckGet(db, roptions, "bar", NULL); - fake_filter_result = 1; - - CheckGet(db, roptions, "foo", "foovalue"); - CheckGet(db, roptions, "bar", "barvalue"); - } - leveldb_options_set_filter_policy(options, NULL); - leveldb_filterpolicy_destroy(policy); - } - - StartPhase("cleanup"); - leveldb_close(db); - leveldb_options_destroy(options); - leveldb_readoptions_destroy(roptions); - leveldb_writeoptions_destroy(woptions); - leveldb_cache_destroy(cache); - leveldb_comparator_destroy(cmp); - leveldb_env_destroy(env); - - fprintf(stderr, "PASS\n"); - return 0; -} diff --git a/src/leveldb/db/corruption_test.cc b/src/leveldb/db/corruption_test.cc deleted file mode 100644 index 96afc68913..0000000000 --- a/src/leveldb/db/corruption_test.cc +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" - -#include -#include -#include -#include -#include "leveldb/cache.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "leveldb/write_batch.h" -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/log_format.h" -#include "db/version_set.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static const int kValueSize = 1000; - -class CorruptionTest { - public: - test::ErrorEnv env_; - std::string dbname_; - Cache* tiny_cache_; - Options options_; - DB* db_; - - CorruptionTest() { - tiny_cache_ = NewLRUCache(100); - options_.env = &env_; - options_.block_cache = tiny_cache_; - dbname_ = test::TmpDir() + "/db_test"; - DestroyDB(dbname_, options_); - - db_ = NULL; - options_.create_if_missing = true; - Reopen(); - options_.create_if_missing = false; - } - - ~CorruptionTest() { - delete db_; - DestroyDB(dbname_, Options()); - delete tiny_cache_; - } - - Status TryReopen() { - delete db_; - db_ = NULL; - return DB::Open(options_, dbname_, &db_); - } - - void Reopen() { - ASSERT_OK(TryReopen()); - } - - void RepairDB() { - delete db_; - db_ = NULL; - ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); - } - - void Build(int n) { - std::string key_space, value_space; - WriteBatch batch; - for (int i = 0; i < n; i++) { - //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); - Slice key = Key(i, &key_space); - batch.Clear(); - batch.Put(key, Value(i, &value_space)); - WriteOptions options; - // Corrupt() doesn't work without this sync on windows; stat reports 0 for - // the file size. - if (i == n - 1) { - options.sync = true; - } - ASSERT_OK(db_->Write(options, &batch)); - } - } - - void Check(int min_expected, int max_expected) { - int next_expected = 0; - int missed = 0; - int bad_keys = 0; - int bad_values = 0; - int correct = 0; - std::string value_space; - Iterator* iter = db_->NewIterator(ReadOptions()); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - uint64_t key; - Slice in(iter->key()); - if (in == "" || in == "~") { - // Ignore boundary keys. - continue; - } - if (!ConsumeDecimalNumber(&in, &key) || - !in.empty() || - key < next_expected) { - bad_keys++; - continue; - } - missed += (key - next_expected); - next_expected = key + 1; - if (iter->value() != Value(key, &value_space)) { - bad_values++; - } else { - correct++; - } - } - delete iter; - - fprintf(stderr, - "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", - min_expected, max_expected, correct, bad_keys, bad_values, missed); - ASSERT_LE(min_expected, correct); - ASSERT_GE(max_expected, correct); - } - - void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { - // Pick file to corrupt - std::vector filenames; - ASSERT_OK(env_.GetChildren(dbname_, &filenames)); - uint64_t number; - FileType type; - std::string fname; - int picked_number = -1; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && - type == filetype && - int(number) > picked_number) { // Pick latest file - fname = dbname_ + "/" + filenames[i]; - picked_number = number; - } - } - ASSERT_TRUE(!fname.empty()) << filetype; - - struct stat sbuf; - if (stat(fname.c_str(), &sbuf) != 0) { - const char* msg = strerror(errno); - ASSERT_TRUE(false) << fname << ": " << msg; - } - - if (offset < 0) { - // Relative to end of file; make it absolute - if (-offset > sbuf.st_size) { - offset = 0; - } else { - offset = sbuf.st_size + offset; - } - } - if (offset > sbuf.st_size) { - offset = sbuf.st_size; - } - if (offset + bytes_to_corrupt > sbuf.st_size) { - bytes_to_corrupt = sbuf.st_size - offset; - } - - // Do it - std::string contents; - Status s = ReadFileToString(Env::Default(), fname, &contents); - ASSERT_TRUE(s.ok()) << s.ToString(); - for (int i = 0; i < bytes_to_corrupt; i++) { - contents[i + offset] ^= 0x80; - } - s = WriteStringToFile(Env::Default(), contents, fname); - ASSERT_TRUE(s.ok()) << s.ToString(); - } - - int Property(const std::string& name) { - std::string property; - int result; - if (db_->GetProperty(name, &property) && - sscanf(property.c_str(), "%d", &result) == 1) { - return result; - } else { - return -1; - } - } - - // Return the ith key - Slice Key(int i, std::string* storage) { - char buf[100]; - snprintf(buf, sizeof(buf), "%016d", i); - storage->assign(buf, strlen(buf)); - return Slice(*storage); - } - - // Return the value to associate with the specified key - Slice Value(int k, std::string* storage) { - Random r(k); - return test::RandomString(&r, kValueSize, storage); - } -}; - -TEST(CorruptionTest, Recovery) { - Build(100); - Check(100, 100); - Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record - Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block - Reopen(); - - // The 64 records in the first two log blocks are completely lost. - Check(36, 36); -} - -TEST(CorruptionTest, RecoverWriteError) { - env_.writable_file_error_ = true; - Status s = TryReopen(); - ASSERT_TRUE(!s.ok()); -} - -TEST(CorruptionTest, NewFileErrorDuringWrite) { - // Do enough writing to force minor compaction - env_.writable_file_error_ = true; - const int num = 3 + (Options().write_buffer_size / kValueSize); - std::string value_storage; - Status s; - for (int i = 0; s.ok() && i < num; i++) { - WriteBatch batch; - batch.Put("a", Value(100, &value_storage)); - s = db_->Write(WriteOptions(), &batch); - } - ASSERT_TRUE(!s.ok()); - ASSERT_GE(env_.num_writable_file_errors_, 1); - env_.writable_file_error_ = false; - Reopen(); -} - -TEST(CorruptionTest, TableFile) { - Build(100); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - dbi->TEST_CompactRange(0, NULL, NULL); - dbi->TEST_CompactRange(1, NULL, NULL); - - Corrupt(kTableFile, 100, 1); - Check(90, 99); -} - -TEST(CorruptionTest, TableFileRepair) { - options_.block_size = 2 * kValueSize; // Limit scope of corruption - options_.paranoid_checks = true; - Reopen(); - Build(100); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - dbi->TEST_CompactRange(0, NULL, NULL); - dbi->TEST_CompactRange(1, NULL, NULL); - - Corrupt(kTableFile, 100, 1); - RepairDB(); - Reopen(); - Check(95, 99); -} - -TEST(CorruptionTest, TableFileIndexData) { - Build(10000); // Enough to build multiple Tables - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - - Corrupt(kTableFile, -2000, 500); - Reopen(); - Check(5000, 9999); -} - -TEST(CorruptionTest, MissingDescriptor) { - Build(1000); - RepairDB(); - Reopen(); - Check(1000, 1000); -} - -TEST(CorruptionTest, SequenceNumberRecovery) { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); - RepairDB(); - Reopen(); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v5", v); - // Write something. If sequence number was not recovered properly, - // it will be hidden by an earlier write. - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v6", v); - Reopen(); - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("v6", v); -} - -TEST(CorruptionTest, CorruptedDescriptor) { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - dbi->TEST_CompactRange(0, NULL, NULL); - - Corrupt(kDescriptorFile, 0, 1000); - Status s = TryReopen(); - ASSERT_TRUE(!s.ok()); - - RepairDB(); - Reopen(); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); - ASSERT_EQ("hello", v); -} - -TEST(CorruptionTest, CompactionInputError) { - Build(10); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); - - Corrupt(kTableFile, 100, 1); - Check(5, 9); - - // Force compactions by writing lots of values - Build(10000); - Check(10000, 10000); -} - -TEST(CorruptionTest, CompactionInputErrorParanoid) { - options_.paranoid_checks = true; - options_.write_buffer_size = 512 << 10; - Reopen(); - DBImpl* dbi = reinterpret_cast(db_); - - // Make multiple inputs so we need to compact. - for (int i = 0; i < 2; i++) { - Build(10); - dbi->TEST_CompactMemTable(); - Corrupt(kTableFile, 100, 1); - env_.SleepForMicroseconds(100000); - } - dbi->CompactRange(NULL, NULL); - - // Write must fail because of corrupted table - std::string tmp1, tmp2; - Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2)); - ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; -} - -TEST(CorruptionTest, UnrelatedKeys) { - Build(10); - DBImpl* dbi = reinterpret_cast(db_); - dbi->TEST_CompactMemTable(); - Corrupt(kTableFile, 100, 1); - - std::string tmp1, tmp2; - ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); - std::string v; - ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); - ASSERT_EQ(Value(1000, &tmp2).ToString(), v); - dbi->TEST_CompactMemTable(); - ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); - ASSERT_EQ(Value(1000, &tmp2).ToString(), v); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/db_bench.cc b/src/leveldb/db/db_bench.cc deleted file mode 100644 index 705a170aae..0000000000 --- a/src/leveldb/db/db_bench.cc +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "db/db_impl.h" -#include "db/version_set.h" -#include "leveldb/cache.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/write_batch.h" -#include "port/port.h" -#include "util/crc32c.h" -#include "util/histogram.h" -#include "util/mutexlock.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// fillseq -- write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillsync -- write N/100 values in random key order in sync mode -// fill100K -- write N/1000 100K values in random order in async mode -// deleteseq -- delete N keys in sequential order -// deleterandom -- delete N keys in random order -// readseq -- read N times sequentially -// readreverse -- read N times in reverse order -// readrandom -- read N times in random order -// readmissing -- read N missing keys in random order -// readhot -- read N times in random order from 1% section of DB -// seekrandom -- N random seeks -// crc32c -- repeated crc32c of 4K of data -// acquireload -- load N*1000 times -// Meta operations: -// compact -- Compact the entire DB -// stats -- Print DB stats -// sstables -- Print sstable info -// heapprofile -- Dump a heap profile (if supported by this port) -static const char* FLAGS_benchmarks = - "fillseq," - "fillsync," - "fillrandom," - "overwrite," - "readrandom," - "readrandom," // Extra run to allow previous compactions to quiesce - "readseq," - "readreverse," - "compact," - "readrandom," - "readseq," - "readreverse," - "fill100K," - "crc32c," - "snappycomp," - "snappyuncomp," - "acquireload," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Number of concurrent threads to run. -static int FLAGS_threads = 1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Number of bytes to buffer in memtable before compacting -// (initialized to default value by "main") -static int FLAGS_write_buffer_size = 0; - -// Number of bytes to use as a cache of uncompressed data. -// Negative means use default settings. -static int FLAGS_cache_size = -1; - -// Maximum number of files to keep open at the same time (use default if == 0) -static int FLAGS_open_files = 0; - -// Bloom filter bits per key. -// Negative means use default settings. -static int FLAGS_bloom_bits = -1; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -namespace leveldb { - -namespace { - -// Helper for quickly generating random data. -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(size_t len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - size_t start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - size_t limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -static void AppendWithSpace(std::string* str, Slice msg) { - if (msg.empty()) return; - if (!str->empty()) { - str->push_back(' '); - } - str->append(msg.data(), msg.size()); -} - -class Stats { - private: - double start_; - double finish_; - double seconds_; - int done_; - int next_report_; - int64_t bytes_; - double last_op_finish_; - Histogram hist_; - std::string message_; - - public: - Stats() { Start(); } - - void Start() { - next_report_ = 100; - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - bytes_ = 0; - seconds_ = 0; - start_ = Env::Default()->NowMicros(); - finish_ = start_; - message_.clear(); - } - - void Merge(const Stats& other) { - hist_.Merge(other.hist_); - done_ += other.done_; - bytes_ += other.bytes_; - seconds_ += other.seconds_; - if (other.start_ < start_) start_ = other.start_; - if (other.finish_ > finish_) finish_ = other.finish_; - - // Just keep the messages from one thread - if (message_.empty()) message_ = other.message_; - } - - void Stop() { - finish_ = Env::Default()->NowMicros(); - seconds_ = (finish_ - start_) * 1e-6; - } - - void AddMessage(Slice msg) { - AppendWithSpace(&message_, msg); - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros(); - double micros = now - last_op_finish_; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void AddBytes(int64_t n) { - bytes_ += n; - } - - void Report(const Slice& name) { - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - std::string extra; - if (bytes_ > 0) { - // Rate is computed on actual elapsed time, not the sum of per-thread - // elapsed times. - double elapsed = (finish_ - start_) * 1e-6; - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / elapsed); - extra = rate; - } - AppendWithSpace(&extra, message_); - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - seconds_ * 1e6 / done_, - (extra.empty() ? "" : " "), - extra.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } -}; - -// State shared by all concurrent executions of the same benchmark. -struct SharedState { - port::Mutex mu; - port::CondVar cv; - int total; - - // Each thread goes through the following states: - // (1) initializing - // (2) waiting for others to be initialized - // (3) running - // (4) done - - int num_initialized; - int num_done; - bool start; - - SharedState() : cv(&mu) { } -}; - -// Per-thread state for concurrent executions of the same benchmark. -struct ThreadState { - int tid; // 0..n-1 when running in n threads - Random rand; // Has different seeds for different threads - Stats stats; - SharedState* shared; - - ThreadState(int index) - : tid(index), - rand(1000 + index) { - } -}; - -} // namespace - -class Benchmark { - private: - Cache* cache_; - const FilterPolicy* filter_policy_; - DB* db_; - int num_; - int value_size_; - int entries_per_batch_; - WriteOptions write_options_; - int reads_; - int heap_counter_; - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", - FLAGS_value_size, - static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - fprintf(stdout, "FileSize: %.1f MB (estimated)\n", - (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - - // See if snappy is working by attempting to compress a compressible string - const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; - std::string compressed; - if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { - fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); - } else if (compressed.size() >= sizeof(text)) { - fprintf(stdout, "WARNING: Snappy compression is not effective\n"); - } - } - - void PrintEnvironment() { - fprintf(stderr, "LevelDB: version %d.%d\n", - kMajorVersion, kMinorVersion); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - public: - Benchmark() - : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), - filter_policy_(FLAGS_bloom_bits >= 0 - ? NewBloomFilterPolicy(FLAGS_bloom_bits) - : NULL), - db_(NULL), - num_(FLAGS_num), - value_size_(FLAGS_value_size), - entries_per_batch_(1), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - heap_counter_(0) { - std::vector files; - Env::Default()->GetChildren(FLAGS_db, &files); - for (size_t i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("heap-")) { - Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); - } - } - if (!FLAGS_use_existing_db) { - DestroyDB(FLAGS_db, Options()); - } - } - - ~Benchmark() { - delete db_; - delete cache_; - delete filter_policy_; - } - - void Run() { - PrintHeader(); - Open(); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - // Reset parameters that may be overridden below - num_ = FLAGS_num; - reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); - value_size_ = FLAGS_value_size; - entries_per_batch_ = 1; - write_options_ = WriteOptions(); - - void (Benchmark::*method)(ThreadState*) = NULL; - bool fresh_db = false; - int num_threads = FLAGS_threads; - - if (name == Slice("fillseq")) { - fresh_db = true; - method = &Benchmark::WriteSeq; - } else if (name == Slice("fillbatch")) { - fresh_db = true; - entries_per_batch_ = 1000; - method = &Benchmark::WriteSeq; - } else if (name == Slice("fillrandom")) { - fresh_db = true; - method = &Benchmark::WriteRandom; - } else if (name == Slice("overwrite")) { - fresh_db = false; - method = &Benchmark::WriteRandom; - } else if (name == Slice("fillsync")) { - fresh_db = true; - num_ /= 1000; - write_options_.sync = true; - method = &Benchmark::WriteRandom; - } else if (name == Slice("fill100K")) { - fresh_db = true; - num_ /= 1000; - value_size_ = 100 * 1000; - method = &Benchmark::WriteRandom; - } else if (name == Slice("readseq")) { - method = &Benchmark::ReadSequential; - } else if (name == Slice("readreverse")) { - method = &Benchmark::ReadReverse; - } else if (name == Slice("readrandom")) { - method = &Benchmark::ReadRandom; - } else if (name == Slice("readmissing")) { - method = &Benchmark::ReadMissing; - } else if (name == Slice("seekrandom")) { - method = &Benchmark::SeekRandom; - } else if (name == Slice("readhot")) { - method = &Benchmark::ReadHot; - } else if (name == Slice("readrandomsmall")) { - reads_ /= 1000; - method = &Benchmark::ReadRandom; - } else if (name == Slice("deleteseq")) { - method = &Benchmark::DeleteSeq; - } else if (name == Slice("deleterandom")) { - method = &Benchmark::DeleteRandom; - } else if (name == Slice("readwhilewriting")) { - num_threads++; // Add extra thread for writing - method = &Benchmark::ReadWhileWriting; - } else if (name == Slice("compact")) { - method = &Benchmark::Compact; - } else if (name == Slice("crc32c")) { - method = &Benchmark::Crc32c; - } else if (name == Slice("acquireload")) { - method = &Benchmark::AcquireLoad; - } else if (name == Slice("snappycomp")) { - method = &Benchmark::SnappyCompress; - } else if (name == Slice("snappyuncomp")) { - method = &Benchmark::SnappyUncompress; - } else if (name == Slice("heapprofile")) { - HeapProfile(); - } else if (name == Slice("stats")) { - PrintStats("leveldb.stats"); - } else if (name == Slice("sstables")) { - PrintStats("leveldb.sstables"); - } else { - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - - if (fresh_db) { - if (FLAGS_use_existing_db) { - fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", - name.ToString().c_str()); - method = NULL; - } else { - delete db_; - db_ = NULL; - DestroyDB(FLAGS_db, Options()); - Open(); - } - } - - if (method != NULL) { - RunBenchmark(num_threads, name, method); - } - } - } - - private: - struct ThreadArg { - Benchmark* bm; - SharedState* shared; - ThreadState* thread; - void (Benchmark::*method)(ThreadState*); - }; - - static void ThreadBody(void* v) { - ThreadArg* arg = reinterpret_cast(v); - SharedState* shared = arg->shared; - ThreadState* thread = arg->thread; - { - MutexLock l(&shared->mu); - shared->num_initialized++; - if (shared->num_initialized >= shared->total) { - shared->cv.SignalAll(); - } - while (!shared->start) { - shared->cv.Wait(); - } - } - - thread->stats.Start(); - (arg->bm->*(arg->method))(thread); - thread->stats.Stop(); - - { - MutexLock l(&shared->mu); - shared->num_done++; - if (shared->num_done >= shared->total) { - shared->cv.SignalAll(); - } - } - } - - void RunBenchmark(int n, Slice name, - void (Benchmark::*method)(ThreadState*)) { - SharedState shared; - shared.total = n; - shared.num_initialized = 0; - shared.num_done = 0; - shared.start = false; - - ThreadArg* arg = new ThreadArg[n]; - for (int i = 0; i < n; i++) { - arg[i].bm = this; - arg[i].method = method; - arg[i].shared = &shared; - arg[i].thread = new ThreadState(i); - arg[i].thread->shared = &shared; - Env::Default()->StartThread(ThreadBody, &arg[i]); - } - - shared.mu.Lock(); - while (shared.num_initialized < n) { - shared.cv.Wait(); - } - - shared.start = true; - shared.cv.SignalAll(); - while (shared.num_done < n) { - shared.cv.Wait(); - } - shared.mu.Unlock(); - - for (int i = 1; i < n; i++) { - arg[0].thread->stats.Merge(arg[i].thread->stats); - } - arg[0].thread->stats.Report(name); - - for (int i = 0; i < n; i++) { - delete arg[i].thread; - } - delete[] arg; - } - - void Crc32c(ThreadState* thread) { - // Checksum about 500MB of data total - const int size = 4096; - const char* label = "(4K per op)"; - std::string data(size, 'x'); - int64_t bytes = 0; - uint32_t crc = 0; - while (bytes < 500 * 1048576) { - crc = crc32c::Value(data.data(), size); - thread->stats.FinishedSingleOp(); - bytes += size; - } - // Print so result is not dead - fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); - - thread->stats.AddBytes(bytes); - thread->stats.AddMessage(label); - } - - void AcquireLoad(ThreadState* thread) { - int dummy; - port::AtomicPointer ap(&dummy); - int count = 0; - void *ptr = NULL; - thread->stats.AddMessage("(each op is 1000 loads)"); - while (count < 100000) { - for (int i = 0; i < 1000; i++) { - ptr = ap.Acquire_Load(); - } - count++; - thread->stats.FinishedSingleOp(); - } - if (ptr == NULL) exit(1); // Disable unused variable warning. - } - - void SnappyCompress(ThreadState* thread) { - RandomGenerator gen; - Slice input = gen.Generate(Options().block_size); - int64_t bytes = 0; - int64_t produced = 0; - bool ok = true; - std::string compressed; - while (ok && bytes < 1024 * 1048576) { // Compress 1G - ok = port::Snappy_Compress(input.data(), input.size(), &compressed); - produced += compressed.size(); - bytes += input.size(); - thread->stats.FinishedSingleOp(); - } - - if (!ok) { - thread->stats.AddMessage("(snappy failure)"); - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "(output: %.1f%%)", - (produced * 100.0) / bytes); - thread->stats.AddMessage(buf); - thread->stats.AddBytes(bytes); - } - } - - void SnappyUncompress(ThreadState* thread) { - RandomGenerator gen; - Slice input = gen.Generate(Options().block_size); - std::string compressed; - bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); - int64_t bytes = 0; - char* uncompressed = new char[input.size()]; - while (ok && bytes < 1024 * 1048576) { // Compress 1G - ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), - uncompressed); - bytes += input.size(); - thread->stats.FinishedSingleOp(); - } - delete[] uncompressed; - - if (!ok) { - thread->stats.AddMessage("(snappy failure)"); - } else { - thread->stats.AddBytes(bytes); - } - } - - void Open() { - assert(db_ == NULL); - Options options; - options.create_if_missing = !FLAGS_use_existing_db; - options.block_cache = cache_; - options.write_buffer_size = FLAGS_write_buffer_size; - options.max_open_files = FLAGS_open_files; - options.filter_policy = filter_policy_; - Status s = DB::Open(options, FLAGS_db, &db_); - if (!s.ok()) { - fprintf(stderr, "open error: %s\n", s.ToString().c_str()); - exit(1); - } - } - - void WriteSeq(ThreadState* thread) { - DoWrite(thread, true); - } - - void WriteRandom(ThreadState* thread) { - DoWrite(thread, false); - } - - void DoWrite(ThreadState* thread, bool seq) { - if (num_ != FLAGS_num) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_); - thread->stats.AddMessage(msg); - } - - RandomGenerator gen; - WriteBatch batch; - Status s; - int64_t bytes = 0; - for (int i = 0; i < num_; i += entries_per_batch_) { - batch.Clear(); - for (int j = 0; j < entries_per_batch_; j++) { - const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - batch.Put(key, gen.Generate(value_size_)); - bytes += value_size_ + strlen(key); - thread->stats.FinishedSingleOp(); - } - s = db_->Write(write_options_, &batch); - if (!s.ok()) { - fprintf(stderr, "put error: %s\n", s.ToString().c_str()); - exit(1); - } - } - thread->stats.AddBytes(bytes); - } - - void ReadSequential(ThreadState* thread) { - Iterator* iter = db_->NewIterator(ReadOptions()); - int i = 0; - int64_t bytes = 0; - for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { - bytes += iter->key().size() + iter->value().size(); - thread->stats.FinishedSingleOp(); - ++i; - } - delete iter; - thread->stats.AddBytes(bytes); - } - - void ReadReverse(ThreadState* thread) { - Iterator* iter = db_->NewIterator(ReadOptions()); - int i = 0; - int64_t bytes = 0; - for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { - bytes += iter->key().size() + iter->value().size(); - thread->stats.FinishedSingleOp(); - ++i; - } - delete iter; - thread->stats.AddBytes(bytes); - } - - void ReadRandom(ThreadState* thread) { - ReadOptions options; - std::string value; - int found = 0; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d", k); - if (db_->Get(options, key, &value).ok()) { - found++; - } - thread->stats.FinishedSingleOp(); - } - char msg[100]; - snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); - thread->stats.AddMessage(msg); - } - - void ReadMissing(ThreadState* thread) { - ReadOptions options; - std::string value; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d.", k); - db_->Get(options, key, &value); - thread->stats.FinishedSingleOp(); - } - } - - void ReadHot(ThreadState* thread) { - ReadOptions options; - std::string value; - const int range = (FLAGS_num + 99) / 100; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = thread->rand.Next() % range; - snprintf(key, sizeof(key), "%016d", k); - db_->Get(options, key, &value); - thread->stats.FinishedSingleOp(); - } - } - - void SeekRandom(ThreadState* thread) { - ReadOptions options; - int found = 0; - for (int i = 0; i < reads_; i++) { - Iterator* iter = db_->NewIterator(options); - char key[100]; - const int k = thread->rand.Next() % FLAGS_num; - snprintf(key, sizeof(key), "%016d", k); - iter->Seek(key); - if (iter->Valid() && iter->key() == key) found++; - delete iter; - thread->stats.FinishedSingleOp(); - } - char msg[100]; - snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); - thread->stats.AddMessage(msg); - } - - void DoDelete(ThreadState* thread, bool seq) { - RandomGenerator gen; - WriteBatch batch; - Status s; - for (int i = 0; i < num_; i += entries_per_batch_) { - batch.Clear(); - for (int j = 0; j < entries_per_batch_; j++) { - const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - batch.Delete(key); - thread->stats.FinishedSingleOp(); - } - s = db_->Write(write_options_, &batch); - if (!s.ok()) { - fprintf(stderr, "del error: %s\n", s.ToString().c_str()); - exit(1); - } - } - } - - void DeleteSeq(ThreadState* thread) { - DoDelete(thread, true); - } - - void DeleteRandom(ThreadState* thread) { - DoDelete(thread, false); - } - - void ReadWhileWriting(ThreadState* thread) { - if (thread->tid > 0) { - ReadRandom(thread); - } else { - // Special thread that keeps writing until other threads are done. - RandomGenerator gen; - while (true) { - { - MutexLock l(&thread->shared->mu); - if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { - // Other threads have finished - break; - } - } - - const int k = thread->rand.Next() % FLAGS_num; - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); - if (!s.ok()) { - fprintf(stderr, "put error: %s\n", s.ToString().c_str()); - exit(1); - } - } - - // Do not count any of the preceding work/delay in stats. - thread->stats.Start(); - } - } - - void Compact(ThreadState* thread) { - db_->CompactRange(NULL, NULL); - } - - void PrintStats(const char* key) { - std::string stats; - if (!db_->GetProperty(key, &stats)) { - stats = "(failed)"; - } - fprintf(stdout, "\n%s\n", stats.c_str()); - } - - static void WriteToFile(void* arg, const char* buf, int n) { - reinterpret_cast(arg)->Append(Slice(buf, n)); - } - - void HeapProfile() { - char fname[100]; - snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); - WritableFile* file; - Status s = Env::Default()->NewWritableFile(fname, &file); - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - return; - } - bool ok = port::GetHeapProfile(WriteToFile, file); - delete file; - if (!ok) { - fprintf(stderr, "heap profiling not supported\n"); - Env::Default()->DeleteFile(fname); - } - } -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; - FLAGS_open_files = leveldb::Options().max_open_files; - std::string default_db_path; - - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_use_existing_db = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { - FLAGS_threads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { - FLAGS_write_buffer_size = n; - } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { - FLAGS_cache_size = n; - } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { - FLAGS_bloom_bits = n; - } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { - FLAGS_open_files = n; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/db/db_impl.cc b/src/leveldb/db/db_impl.cc deleted file mode 100644 index 49b95953b4..0000000000 --- a/src/leveldb/db/db_impl.cc +++ /dev/null @@ -1,1513 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/db_impl.h" - -#include -#include -#include -#include -#include -#include -#include "db/builder.h" -#include "db/db_iter.h" -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "db/version_set.h" -#include "db/write_batch_internal.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/status.h" -#include "leveldb/table.h" -#include "leveldb/table_builder.h" -#include "port/port.h" -#include "table/block.h" -#include "table/merger.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" -#include "util/logging.h" -#include "util/mutexlock.h" - -namespace leveldb { - -const int kNumNonTableCacheFiles = 10; - -// Information kept for every waiting writer -struct DBImpl::Writer { - Status status; - WriteBatch* batch; - bool sync; - bool done; - port::CondVar cv; - - explicit Writer(port::Mutex* mu) : cv(mu) { } -}; - -struct DBImpl::CompactionState { - Compaction* const compaction; - - // Sequence numbers < smallest_snapshot are not significant since we - // will never have to service a snapshot below smallest_snapshot. - // Therefore if we have seen a sequence number S <= smallest_snapshot, - // we can drop all entries for the same key with sequence numbers < S. - SequenceNumber smallest_snapshot; - - // Files produced by compaction - struct Output { - uint64_t number; - uint64_t file_size; - InternalKey smallest, largest; - }; - std::vector outputs; - - // State kept for output being generated - WritableFile* outfile; - TableBuilder* builder; - - uint64_t total_bytes; - - Output* current_output() { return &outputs[outputs.size()-1]; } - - explicit CompactionState(Compaction* c) - : compaction(c), - outfile(NULL), - builder(NULL), - total_bytes(0) { - } -}; - -// Fix user-supplied options to be reasonable -template -static void ClipToRange(T* ptr, V minvalue, V maxvalue) { - if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; - if (static_cast(*ptr) < minvalue) *ptr = minvalue; -} -Options SanitizeOptions(const std::string& dbname, - const InternalKeyComparator* icmp, - const InternalFilterPolicy* ipolicy, - const Options& src) { - Options result = src; - result.comparator = icmp; - result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; - ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); - ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); - ClipToRange(&result.block_size, 1<<10, 4<<20); - if (result.info_log == NULL) { - // Open a log file in the same directory as the db - src.env->CreateDir(dbname); // In case it does not exist - src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); - Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); - if (!s.ok()) { - // No place suitable for logging - result.info_log = NULL; - } - } - if (result.block_cache == NULL) { - result.block_cache = NewLRUCache(8 << 20); - } - return result; -} - -DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) - : env_(raw_options.env), - internal_comparator_(raw_options.comparator), - internal_filter_policy_(raw_options.filter_policy), - options_(SanitizeOptions(dbname, &internal_comparator_, - &internal_filter_policy_, raw_options)), - owns_info_log_(options_.info_log != raw_options.info_log), - owns_cache_(options_.block_cache != raw_options.block_cache), - dbname_(dbname), - db_lock_(NULL), - shutting_down_(NULL), - bg_cv_(&mutex_), - mem_(new MemTable(internal_comparator_)), - imm_(NULL), - logfile_(NULL), - logfile_number_(0), - log_(NULL), - seed_(0), - tmp_batch_(new WriteBatch), - bg_compaction_scheduled_(false), - manual_compaction_(NULL) { - mem_->Ref(); - has_imm_.Release_Store(NULL); - - // Reserve ten files or so for other uses and give the rest to TableCache. - const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles; - table_cache_ = new TableCache(dbname_, &options_, table_cache_size); - - versions_ = new VersionSet(dbname_, &options_, table_cache_, - &internal_comparator_); -} - -DBImpl::~DBImpl() { - // Wait for background work to finish - mutex_.Lock(); - shutting_down_.Release_Store(this); // Any non-NULL value is ok - while (bg_compaction_scheduled_) { - bg_cv_.Wait(); - } - mutex_.Unlock(); - - if (db_lock_ != NULL) { - env_->UnlockFile(db_lock_); - } - - delete versions_; - if (mem_ != NULL) mem_->Unref(); - if (imm_ != NULL) imm_->Unref(); - delete tmp_batch_; - delete log_; - delete logfile_; - delete table_cache_; - - if (owns_info_log_) { - delete options_.info_log; - } - if (owns_cache_) { - delete options_.block_cache; - } -} - -Status DBImpl::NewDB() { - VersionEdit new_db; - new_db.SetComparatorName(user_comparator()->Name()); - new_db.SetLogNumber(0); - new_db.SetNextFile(2); - new_db.SetLastSequence(0); - - const std::string manifest = DescriptorFileName(dbname_, 1); - WritableFile* file; - Status s = env_->NewWritableFile(manifest, &file); - if (!s.ok()) { - return s; - } - { - log::Writer log(file); - std::string record; - new_db.EncodeTo(&record); - s = log.AddRecord(record); - if (s.ok()) { - s = file->Close(); - } - } - delete file; - if (s.ok()) { - // Make "CURRENT" file that points to the new manifest file. - s = SetCurrentFile(env_, dbname_, 1); - } else { - env_->DeleteFile(manifest); - } - return s; -} - -void DBImpl::MaybeIgnoreError(Status* s) const { - if (s->ok() || options_.paranoid_checks) { - // No change needed - } else { - Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); - *s = Status::OK(); - } -} - -void DBImpl::DeleteObsoleteFiles() { - if (!bg_error_.ok()) { - // After a background error, we don't know whether a new version may - // or may not have been committed, so we cannot safely garbage collect. - return; - } - - // Make a set of all of the live files - std::set live = pending_outputs_; - versions_->AddLiveFiles(&live); - - std::vector filenames; - env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - bool keep = true; - switch (type) { - case kLogFile: - keep = ((number >= versions_->LogNumber()) || - (number == versions_->PrevLogNumber())); - break; - case kDescriptorFile: - // Keep my manifest file, and any newer incarnations' - // (in case there is a race that allows other incarnations) - keep = (number >= versions_->ManifestFileNumber()); - break; - case kTableFile: - keep = (live.find(number) != live.end()); - break; - case kTempFile: - // Any temp files that are currently being written to must - // be recorded in pending_outputs_, which is inserted into "live" - keep = (live.find(number) != live.end()); - break; - case kCurrentFile: - case kDBLockFile: - case kInfoLogFile: - keep = true; - break; - } - - if (!keep) { - if (type == kTableFile) { - table_cache_->Evict(number); - } - Log(options_.info_log, "Delete type=%d #%lld\n", - int(type), - static_cast(number)); - env_->DeleteFile(dbname_ + "/" + filenames[i]); - } - } - } -} - -Status DBImpl::Recover(VersionEdit* edit) { - mutex_.AssertHeld(); - - // Ignore error from CreateDir since the creation of the DB is - // committed only when the descriptor is created, and this directory - // may already exist from a previous failed creation attempt. - env_->CreateDir(dbname_); - assert(db_lock_ == NULL); - Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); - if (!s.ok()) { - return s; - } - - if (!env_->FileExists(CurrentFileName(dbname_))) { - if (options_.create_if_missing) { - s = NewDB(); - if (!s.ok()) { - return s; - } - } else { - return Status::InvalidArgument( - dbname_, "does not exist (create_if_missing is false)"); - } - } else { - if (options_.error_if_exists) { - return Status::InvalidArgument( - dbname_, "exists (error_if_exists is true)"); - } - } - - s = versions_->Recover(); - if (s.ok()) { - SequenceNumber max_sequence(0); - - // Recover from all newer log files than the ones named in the - // descriptor (new log files may have been added by the previous - // incarnation without registering them in the descriptor). - // - // Note that PrevLogNumber() is no longer used, but we pay - // attention to it in case we are recovering a database - // produced by an older version of leveldb. - const uint64_t min_log = versions_->LogNumber(); - const uint64_t prev_log = versions_->PrevLogNumber(); - std::vector filenames; - s = env_->GetChildren(dbname_, &filenames); - if (!s.ok()) { - return s; - } - std::set expected; - versions_->AddLiveFiles(&expected); - uint64_t number; - FileType type; - std::vector logs; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - expected.erase(number); - if (type == kLogFile && ((number >= min_log) || (number == prev_log))) - logs.push_back(number); - } - } - if (!expected.empty()) { - char buf[50]; - snprintf(buf, sizeof(buf), "%d missing files; e.g.", - static_cast(expected.size())); - return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); - } - - // Recover in the order in which the logs were generated - std::sort(logs.begin(), logs.end()); - for (size_t i = 0; i < logs.size(); i++) { - s = RecoverLogFile(logs[i], edit, &max_sequence); - - // The previous incarnation may not have written any MANIFEST - // records after allocating this log number. So we manually - // update the file number allocation counter in VersionSet. - versions_->MarkFileNumberUsed(logs[i]); - } - - if (s.ok()) { - if (versions_->LastSequence() < max_sequence) { - versions_->SetLastSequence(max_sequence); - } - } - } - - return s; -} - -Status DBImpl::RecoverLogFile(uint64_t log_number, - VersionEdit* edit, - SequenceNumber* max_sequence) { - struct LogReporter : public log::Reader::Reporter { - Env* env; - Logger* info_log; - const char* fname; - Status* status; // NULL if options_.paranoid_checks==false - virtual void Corruption(size_t bytes, const Status& s) { - Log(info_log, "%s%s: dropping %d bytes; %s", - (this->status == NULL ? "(ignoring error) " : ""), - fname, static_cast(bytes), s.ToString().c_str()); - if (this->status != NULL && this->status->ok()) *this->status = s; - } - }; - - mutex_.AssertHeld(); - - // Open the log file - std::string fname = LogFileName(dbname_, log_number); - SequentialFile* file; - Status status = env_->NewSequentialFile(fname, &file); - if (!status.ok()) { - MaybeIgnoreError(&status); - return status; - } - - // Create the log reader. - LogReporter reporter; - reporter.env = env_; - reporter.info_log = options_.info_log; - reporter.fname = fname.c_str(); - reporter.status = (options_.paranoid_checks ? &status : NULL); - // We intentionally make log::Reader do checksumming even if - // paranoid_checks==false so that corruptions cause entire commits - // to be skipped instead of propagating bad information (like overly - // large sequence numbers). - log::Reader reader(file, &reporter, true/*checksum*/, - 0/*initial_offset*/); - Log(options_.info_log, "Recovering log #%llu", - (unsigned long long) log_number); - - // Read all the records and add to a memtable - std::string scratch; - Slice record; - WriteBatch batch; - MemTable* mem = NULL; - while (reader.ReadRecord(&record, &scratch) && - status.ok()) { - if (record.size() < 12) { - reporter.Corruption( - record.size(), Status::Corruption("log record too small")); - continue; - } - WriteBatchInternal::SetContents(&batch, record); - - if (mem == NULL) { - mem = new MemTable(internal_comparator_); - mem->Ref(); - } - status = WriteBatchInternal::InsertInto(&batch, mem); - MaybeIgnoreError(&status); - if (!status.ok()) { - break; - } - const SequenceNumber last_seq = - WriteBatchInternal::Sequence(&batch) + - WriteBatchInternal::Count(&batch) - 1; - if (last_seq > *max_sequence) { - *max_sequence = last_seq; - } - - if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { - status = WriteLevel0Table(mem, edit, NULL); - if (!status.ok()) { - // Reflect errors immediately so that conditions like full - // file-systems cause the DB::Open() to fail. - break; - } - mem->Unref(); - mem = NULL; - } - } - - if (status.ok() && mem != NULL) { - status = WriteLevel0Table(mem, edit, NULL); - // Reflect errors immediately so that conditions like full - // file-systems cause the DB::Open() to fail. - } - - if (mem != NULL) mem->Unref(); - delete file; - return status; -} - -Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, - Version* base) { - mutex_.AssertHeld(); - const uint64_t start_micros = env_->NowMicros(); - FileMetaData meta; - meta.number = versions_->NewFileNumber(); - pending_outputs_.insert(meta.number); - Iterator* iter = mem->NewIterator(); - Log(options_.info_log, "Level-0 table #%llu: started", - (unsigned long long) meta.number); - - Status s; - { - mutex_.Unlock(); - s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); - mutex_.Lock(); - } - - Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", - (unsigned long long) meta.number, - (unsigned long long) meta.file_size, - s.ToString().c_str()); - delete iter; - pending_outputs_.erase(meta.number); - - - // Note that if file_size is zero, the file has been deleted and - // should not be added to the manifest. - int level = 0; - if (s.ok() && meta.file_size > 0) { - const Slice min_user_key = meta.smallest.user_key(); - const Slice max_user_key = meta.largest.user_key(); - if (base != NULL) { - level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); - } - edit->AddFile(level, meta.number, meta.file_size, - meta.smallest, meta.largest); - } - - CompactionStats stats; - stats.micros = env_->NowMicros() - start_micros; - stats.bytes_written = meta.file_size; - stats_[level].Add(stats); - return s; -} - -void DBImpl::CompactMemTable() { - mutex_.AssertHeld(); - assert(imm_ != NULL); - - // Save the contents of the memtable as a new Table - VersionEdit edit; - Version* base = versions_->current(); - base->Ref(); - Status s = WriteLevel0Table(imm_, &edit, base); - base->Unref(); - - if (s.ok() && shutting_down_.Acquire_Load()) { - s = Status::IOError("Deleting DB during memtable compaction"); - } - - // Replace immutable memtable with the generated Table - if (s.ok()) { - edit.SetPrevLogNumber(0); - edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed - s = versions_->LogAndApply(&edit, &mutex_); - } - - if (s.ok()) { - // Commit to the new state - imm_->Unref(); - imm_ = NULL; - has_imm_.Release_Store(NULL); - DeleteObsoleteFiles(); - } else { - RecordBackgroundError(s); - } -} - -void DBImpl::CompactRange(const Slice* begin, const Slice* end) { - int max_level_with_files = 1; - { - MutexLock l(&mutex_); - Version* base = versions_->current(); - for (int level = 1; level < config::kNumLevels; level++) { - if (base->OverlapInLevel(level, begin, end)) { - max_level_with_files = level; - } - } - } - TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap - for (int level = 0; level < max_level_with_files; level++) { - TEST_CompactRange(level, begin, end); - } -} - -void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { - assert(level >= 0); - assert(level + 1 < config::kNumLevels); - - InternalKey begin_storage, end_storage; - - ManualCompaction manual; - manual.level = level; - manual.done = false; - if (begin == NULL) { - manual.begin = NULL; - } else { - begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); - manual.begin = &begin_storage; - } - if (end == NULL) { - manual.end = NULL; - } else { - end_storage = InternalKey(*end, 0, static_cast(0)); - manual.end = &end_storage; - } - - MutexLock l(&mutex_); - while (!manual.done && !shutting_down_.Acquire_Load() && bg_error_.ok()) { - if (manual_compaction_ == NULL) { // Idle - manual_compaction_ = &manual; - MaybeScheduleCompaction(); - } else { // Running either my compaction or another compaction. - bg_cv_.Wait(); - } - } - if (manual_compaction_ == &manual) { - // Cancel my manual compaction since we aborted early for some reason. - manual_compaction_ = NULL; - } -} - -Status DBImpl::TEST_CompactMemTable() { - // NULL batch means just wait for earlier writes to be done - Status s = Write(WriteOptions(), NULL); - if (s.ok()) { - // Wait until the compaction completes - MutexLock l(&mutex_); - while (imm_ != NULL && bg_error_.ok()) { - bg_cv_.Wait(); - } - if (imm_ != NULL) { - s = bg_error_; - } - } - return s; -} - -void DBImpl::RecordBackgroundError(const Status& s) { - mutex_.AssertHeld(); - if (bg_error_.ok()) { - bg_error_ = s; - bg_cv_.SignalAll(); - } -} - -void DBImpl::MaybeScheduleCompaction() { - mutex_.AssertHeld(); - if (bg_compaction_scheduled_) { - // Already scheduled - } else if (shutting_down_.Acquire_Load()) { - // DB is being deleted; no more background compactions - } else if (!bg_error_.ok()) { - // Already got an error; no more changes - } else if (imm_ == NULL && - manual_compaction_ == NULL && - !versions_->NeedsCompaction()) { - // No work to be done - } else { - bg_compaction_scheduled_ = true; - env_->Schedule(&DBImpl::BGWork, this); - } -} - -void DBImpl::BGWork(void* db) { - reinterpret_cast(db)->BackgroundCall(); -} - -void DBImpl::BackgroundCall() { - MutexLock l(&mutex_); - assert(bg_compaction_scheduled_); - if (shutting_down_.Acquire_Load()) { - // No more background work when shutting down. - } else if (!bg_error_.ok()) { - // No more background work after a background error. - } else { - BackgroundCompaction(); - } - - bg_compaction_scheduled_ = false; - - // Previous compaction may have produced too many files in a level, - // so reschedule another compaction if needed. - MaybeScheduleCompaction(); - bg_cv_.SignalAll(); -} - -void DBImpl::BackgroundCompaction() { - mutex_.AssertHeld(); - - if (imm_ != NULL) { - CompactMemTable(); - return; - } - - Compaction* c; - bool is_manual = (manual_compaction_ != NULL); - InternalKey manual_end; - if (is_manual) { - ManualCompaction* m = manual_compaction_; - c = versions_->CompactRange(m->level, m->begin, m->end); - m->done = (c == NULL); - if (c != NULL) { - manual_end = c->input(0, c->num_input_files(0) - 1)->largest; - } - Log(options_.info_log, - "Manual compaction at level-%d from %s .. %s; will stop at %s\n", - m->level, - (m->begin ? m->begin->DebugString().c_str() : "(begin)"), - (m->end ? m->end->DebugString().c_str() : "(end)"), - (m->done ? "(end)" : manual_end.DebugString().c_str())); - } else { - c = versions_->PickCompaction(); - } - - Status status; - if (c == NULL) { - // Nothing to do - } else if (!is_manual && c->IsTrivialMove()) { - // Move file to next level - assert(c->num_input_files(0) == 1); - FileMetaData* f = c->input(0, 0); - c->edit()->DeleteFile(c->level(), f->number); - c->edit()->AddFile(c->level() + 1, f->number, f->file_size, - f->smallest, f->largest); - status = versions_->LogAndApply(c->edit(), &mutex_); - if (!status.ok()) { - RecordBackgroundError(status); - } - VersionSet::LevelSummaryStorage tmp; - Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", - static_cast(f->number), - c->level() + 1, - static_cast(f->file_size), - status.ToString().c_str(), - versions_->LevelSummary(&tmp)); - } else { - CompactionState* compact = new CompactionState(c); - status = DoCompactionWork(compact); - if (!status.ok()) { - RecordBackgroundError(status); - } - CleanupCompaction(compact); - c->ReleaseInputs(); - DeleteObsoleteFiles(); - } - delete c; - - if (status.ok()) { - // Done - } else if (shutting_down_.Acquire_Load()) { - // Ignore compaction errors found during shutting down - } else { - Log(options_.info_log, - "Compaction error: %s", status.ToString().c_str()); - } - - if (is_manual) { - ManualCompaction* m = manual_compaction_; - if (!status.ok()) { - m->done = true; - } - if (!m->done) { - // We only compacted part of the requested range. Update *m - // to the range that is left to be compacted. - m->tmp_storage = manual_end; - m->begin = &m->tmp_storage; - } - manual_compaction_ = NULL; - } -} - -void DBImpl::CleanupCompaction(CompactionState* compact) { - mutex_.AssertHeld(); - if (compact->builder != NULL) { - // May happen if we get a shutdown call in the middle of compaction - compact->builder->Abandon(); - delete compact->builder; - } else { - assert(compact->outfile == NULL); - } - delete compact->outfile; - for (size_t i = 0; i < compact->outputs.size(); i++) { - const CompactionState::Output& out = compact->outputs[i]; - pending_outputs_.erase(out.number); - } - delete compact; -} - -Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { - assert(compact != NULL); - assert(compact->builder == NULL); - uint64_t file_number; - { - mutex_.Lock(); - file_number = versions_->NewFileNumber(); - pending_outputs_.insert(file_number); - CompactionState::Output out; - out.number = file_number; - out.smallest.Clear(); - out.largest.Clear(); - compact->outputs.push_back(out); - mutex_.Unlock(); - } - - // Make the output file - std::string fname = TableFileName(dbname_, file_number); - Status s = env_->NewWritableFile(fname, &compact->outfile); - if (s.ok()) { - compact->builder = new TableBuilder(options_, compact->outfile); - } - return s; -} - -Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, - Iterator* input) { - assert(compact != NULL); - assert(compact->outfile != NULL); - assert(compact->builder != NULL); - - const uint64_t output_number = compact->current_output()->number; - assert(output_number != 0); - - // Check for iterator errors - Status s = input->status(); - const uint64_t current_entries = compact->builder->NumEntries(); - if (s.ok()) { - s = compact->builder->Finish(); - } else { - compact->builder->Abandon(); - } - const uint64_t current_bytes = compact->builder->FileSize(); - compact->current_output()->file_size = current_bytes; - compact->total_bytes += current_bytes; - delete compact->builder; - compact->builder = NULL; - - // Finish and check for file errors - if (s.ok()) { - s = compact->outfile->Sync(); - } - if (s.ok()) { - s = compact->outfile->Close(); - } - delete compact->outfile; - compact->outfile = NULL; - - if (s.ok() && current_entries > 0) { - // Verify that the table is usable - Iterator* iter = table_cache_->NewIterator(ReadOptions(), - output_number, - current_bytes); - s = iter->status(); - delete iter; - if (s.ok()) { - Log(options_.info_log, - "Generated table #%llu: %lld keys, %lld bytes", - (unsigned long long) output_number, - (unsigned long long) current_entries, - (unsigned long long) current_bytes); - } - } - return s; -} - - -Status DBImpl::InstallCompactionResults(CompactionState* compact) { - mutex_.AssertHeld(); - Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", - compact->compaction->num_input_files(0), - compact->compaction->level(), - compact->compaction->num_input_files(1), - compact->compaction->level() + 1, - static_cast(compact->total_bytes)); - - // Add compaction outputs - compact->compaction->AddInputDeletions(compact->compaction->edit()); - const int level = compact->compaction->level(); - for (size_t i = 0; i < compact->outputs.size(); i++) { - const CompactionState::Output& out = compact->outputs[i]; - compact->compaction->edit()->AddFile( - level + 1, - out.number, out.file_size, out.smallest, out.largest); - } - return versions_->LogAndApply(compact->compaction->edit(), &mutex_); -} - -Status DBImpl::DoCompactionWork(CompactionState* compact) { - const uint64_t start_micros = env_->NowMicros(); - int64_t imm_micros = 0; // Micros spent doing imm_ compactions - - Log(options_.info_log, "Compacting %d@%d + %d@%d files", - compact->compaction->num_input_files(0), - compact->compaction->level(), - compact->compaction->num_input_files(1), - compact->compaction->level() + 1); - - assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); - assert(compact->builder == NULL); - assert(compact->outfile == NULL); - if (snapshots_.empty()) { - compact->smallest_snapshot = versions_->LastSequence(); - } else { - compact->smallest_snapshot = snapshots_.oldest()->number_; - } - - // Release mutex while we're actually doing the compaction work - mutex_.Unlock(); - - Iterator* input = versions_->MakeInputIterator(compact->compaction); - input->SeekToFirst(); - Status status; - ParsedInternalKey ikey; - std::string current_user_key; - bool has_current_user_key = false; - SequenceNumber last_sequence_for_key = kMaxSequenceNumber; - for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { - // Prioritize immutable compaction work - if (has_imm_.NoBarrier_Load() != NULL) { - const uint64_t imm_start = env_->NowMicros(); - mutex_.Lock(); - if (imm_ != NULL) { - CompactMemTable(); - bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary - } - mutex_.Unlock(); - imm_micros += (env_->NowMicros() - imm_start); - } - - Slice key = input->key(); - if (compact->compaction->ShouldStopBefore(key) && - compact->builder != NULL) { - status = FinishCompactionOutputFile(compact, input); - if (!status.ok()) { - break; - } - } - - // Handle key/value, add to state, etc. - bool drop = false; - if (!ParseInternalKey(key, &ikey)) { - // Do not hide error keys - current_user_key.clear(); - has_current_user_key = false; - last_sequence_for_key = kMaxSequenceNumber; - } else { - if (!has_current_user_key || - user_comparator()->Compare(ikey.user_key, - Slice(current_user_key)) != 0) { - // First occurrence of this user key - current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); - has_current_user_key = true; - last_sequence_for_key = kMaxSequenceNumber; - } - - if (last_sequence_for_key <= compact->smallest_snapshot) { - // Hidden by an newer entry for same user key - drop = true; // (A) - } else if (ikey.type == kTypeDeletion && - ikey.sequence <= compact->smallest_snapshot && - compact->compaction->IsBaseLevelForKey(ikey.user_key)) { - // For this user key: - // (1) there is no data in higher levels - // (2) data in lower levels will have larger sequence numbers - // (3) data in layers that are being compacted here and have - // smaller sequence numbers will be dropped in the next - // few iterations of this loop (by rule (A) above). - // Therefore this deletion marker is obsolete and can be dropped. - drop = true; - } - - last_sequence_for_key = ikey.sequence; - } -#if 0 - Log(options_.info_log, - " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " - "%d smallest_snapshot: %d", - ikey.user_key.ToString().c_str(), - (int)ikey.sequence, ikey.type, kTypeValue, drop, - compact->compaction->IsBaseLevelForKey(ikey.user_key), - (int)last_sequence_for_key, (int)compact->smallest_snapshot); -#endif - - if (!drop) { - // Open output file if necessary - if (compact->builder == NULL) { - status = OpenCompactionOutputFile(compact); - if (!status.ok()) { - break; - } - } - if (compact->builder->NumEntries() == 0) { - compact->current_output()->smallest.DecodeFrom(key); - } - compact->current_output()->largest.DecodeFrom(key); - compact->builder->Add(key, input->value()); - - // Close output file if it is big enough - if (compact->builder->FileSize() >= - compact->compaction->MaxOutputFileSize()) { - status = FinishCompactionOutputFile(compact, input); - if (!status.ok()) { - break; - } - } - } - - input->Next(); - } - - if (status.ok() && shutting_down_.Acquire_Load()) { - status = Status::IOError("Deleting DB during compaction"); - } - if (status.ok() && compact->builder != NULL) { - status = FinishCompactionOutputFile(compact, input); - } - if (status.ok()) { - status = input->status(); - } - delete input; - input = NULL; - - CompactionStats stats; - stats.micros = env_->NowMicros() - start_micros - imm_micros; - for (int which = 0; which < 2; which++) { - for (int i = 0; i < compact->compaction->num_input_files(which); i++) { - stats.bytes_read += compact->compaction->input(which, i)->file_size; - } - } - for (size_t i = 0; i < compact->outputs.size(); i++) { - stats.bytes_written += compact->outputs[i].file_size; - } - - mutex_.Lock(); - stats_[compact->compaction->level() + 1].Add(stats); - - if (status.ok()) { - status = InstallCompactionResults(compact); - } - if (!status.ok()) { - RecordBackgroundError(status); - } - VersionSet::LevelSummaryStorage tmp; - Log(options_.info_log, - "compacted to: %s", versions_->LevelSummary(&tmp)); - return status; -} - -namespace { -struct IterState { - port::Mutex* mu; - Version* version; - MemTable* mem; - MemTable* imm; -}; - -static void CleanupIteratorState(void* arg1, void* arg2) { - IterState* state = reinterpret_cast(arg1); - state->mu->Lock(); - state->mem->Unref(); - if (state->imm != NULL) state->imm->Unref(); - state->version->Unref(); - state->mu->Unlock(); - delete state; -} -} // namespace - -Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, - SequenceNumber* latest_snapshot, - uint32_t* seed) { - IterState* cleanup = new IterState; - mutex_.Lock(); - *latest_snapshot = versions_->LastSequence(); - - // Collect together all needed child iterators - std::vector list; - list.push_back(mem_->NewIterator()); - mem_->Ref(); - if (imm_ != NULL) { - list.push_back(imm_->NewIterator()); - imm_->Ref(); - } - versions_->current()->AddIterators(options, &list); - Iterator* internal_iter = - NewMergingIterator(&internal_comparator_, &list[0], list.size()); - versions_->current()->Ref(); - - cleanup->mu = &mutex_; - cleanup->mem = mem_; - cleanup->imm = imm_; - cleanup->version = versions_->current(); - internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); - - *seed = ++seed_; - mutex_.Unlock(); - return internal_iter; -} - -Iterator* DBImpl::TEST_NewInternalIterator() { - SequenceNumber ignored; - uint32_t ignored_seed; - return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); -} - -int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { - MutexLock l(&mutex_); - return versions_->MaxNextLevelOverlappingBytes(); -} - -Status DBImpl::Get(const ReadOptions& options, - const Slice& key, - std::string* value) { - Status s; - MutexLock l(&mutex_); - SequenceNumber snapshot; - if (options.snapshot != NULL) { - snapshot = reinterpret_cast(options.snapshot)->number_; - } else { - snapshot = versions_->LastSequence(); - } - - MemTable* mem = mem_; - MemTable* imm = imm_; - Version* current = versions_->current(); - mem->Ref(); - if (imm != NULL) imm->Ref(); - current->Ref(); - - bool have_stat_update = false; - Version::GetStats stats; - - // Unlock while reading from files and memtables - { - mutex_.Unlock(); - // First look in the memtable, then in the immutable memtable (if any). - LookupKey lkey(key, snapshot); - if (mem->Get(lkey, value, &s)) { - // Done - } else if (imm != NULL && imm->Get(lkey, value, &s)) { - // Done - } else { - s = current->Get(options, lkey, value, &stats); - have_stat_update = true; - } - mutex_.Lock(); - } - - if (have_stat_update && current->UpdateStats(stats)) { - MaybeScheduleCompaction(); - } - mem->Unref(); - if (imm != NULL) imm->Unref(); - current->Unref(); - return s; -} - -Iterator* DBImpl::NewIterator(const ReadOptions& options) { - SequenceNumber latest_snapshot; - uint32_t seed; - Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); - return NewDBIterator( - this, user_comparator(), iter, - (options.snapshot != NULL - ? reinterpret_cast(options.snapshot)->number_ - : latest_snapshot), - seed); -} - -void DBImpl::RecordReadSample(Slice key) { - MutexLock l(&mutex_); - if (versions_->current()->RecordReadSample(key)) { - MaybeScheduleCompaction(); - } -} - -const Snapshot* DBImpl::GetSnapshot() { - MutexLock l(&mutex_); - return snapshots_.New(versions_->LastSequence()); -} - -void DBImpl::ReleaseSnapshot(const Snapshot* s) { - MutexLock l(&mutex_); - snapshots_.Delete(reinterpret_cast(s)); -} - -// Convenience methods -Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { - return DB::Put(o, key, val); -} - -Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { - return DB::Delete(options, key); -} - -Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { - Writer w(&mutex_); - w.batch = my_batch; - w.sync = options.sync; - w.done = false; - - MutexLock l(&mutex_); - writers_.push_back(&w); - while (!w.done && &w != writers_.front()) { - w.cv.Wait(); - } - if (w.done) { - return w.status; - } - - // May temporarily unlock and wait. - Status status = MakeRoomForWrite(my_batch == NULL); - uint64_t last_sequence = versions_->LastSequence(); - Writer* last_writer = &w; - if (status.ok() && my_batch != NULL) { // NULL batch is for compactions - WriteBatch* updates = BuildBatchGroup(&last_writer); - WriteBatchInternal::SetSequence(updates, last_sequence + 1); - last_sequence += WriteBatchInternal::Count(updates); - - // Add to log and apply to memtable. We can release the lock - // during this phase since &w is currently responsible for logging - // and protects against concurrent loggers and concurrent writes - // into mem_. - { - mutex_.Unlock(); - status = log_->AddRecord(WriteBatchInternal::Contents(updates)); - bool sync_error = false; - if (status.ok() && options.sync) { - status = logfile_->Sync(); - if (!status.ok()) { - sync_error = true; - } - } - if (status.ok()) { - status = WriteBatchInternal::InsertInto(updates, mem_); - } - mutex_.Lock(); - if (sync_error) { - // The state of the log file is indeterminate: the log record we - // just added may or may not show up when the DB is re-opened. - // So we force the DB into a mode where all future writes fail. - RecordBackgroundError(status); - } - } - if (updates == tmp_batch_) tmp_batch_->Clear(); - - versions_->SetLastSequence(last_sequence); - } - - while (true) { - Writer* ready = writers_.front(); - writers_.pop_front(); - if (ready != &w) { - ready->status = status; - ready->done = true; - ready->cv.Signal(); - } - if (ready == last_writer) break; - } - - // Notify new head of write queue - if (!writers_.empty()) { - writers_.front()->cv.Signal(); - } - - return status; -} - -// REQUIRES: Writer list must be non-empty -// REQUIRES: First writer must have a non-NULL batch -WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { - assert(!writers_.empty()); - Writer* first = writers_.front(); - WriteBatch* result = first->batch; - assert(result != NULL); - - size_t size = WriteBatchInternal::ByteSize(first->batch); - - // Allow the group to grow up to a maximum size, but if the - // original write is small, limit the growth so we do not slow - // down the small write too much. - size_t max_size = 1 << 20; - if (size <= (128<<10)) { - max_size = size + (128<<10); - } - - *last_writer = first; - std::deque::iterator iter = writers_.begin(); - ++iter; // Advance past "first" - for (; iter != writers_.end(); ++iter) { - Writer* w = *iter; - if (w->sync && !first->sync) { - // Do not include a sync write into a batch handled by a non-sync write. - break; - } - - if (w->batch != NULL) { - size += WriteBatchInternal::ByteSize(w->batch); - if (size > max_size) { - // Do not make batch too big - break; - } - - // Append to *result - if (result == first->batch) { - // Switch to temporary batch instead of disturbing caller's batch - result = tmp_batch_; - assert(WriteBatchInternal::Count(result) == 0); - WriteBatchInternal::Append(result, first->batch); - } - WriteBatchInternal::Append(result, w->batch); - } - *last_writer = w; - } - return result; -} - -// REQUIRES: mutex_ is held -// REQUIRES: this thread is currently at the front of the writer queue -Status DBImpl::MakeRoomForWrite(bool force) { - mutex_.AssertHeld(); - assert(!writers_.empty()); - bool allow_delay = !force; - Status s; - while (true) { - if (!bg_error_.ok()) { - // Yield previous error - s = bg_error_; - break; - } else if ( - allow_delay && - versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { - // We are getting close to hitting a hard limit on the number of - // L0 files. Rather than delaying a single write by several - // seconds when we hit the hard limit, start delaying each - // individual write by 1ms to reduce latency variance. Also, - // this delay hands over some CPU to the compaction thread in - // case it is sharing the same core as the writer. - mutex_.Unlock(); - env_->SleepForMicroseconds(1000); - allow_delay = false; // Do not delay a single write more than once - mutex_.Lock(); - } else if (!force && - (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { - // There is room in current memtable - break; - } else if (imm_ != NULL) { - // We have filled up the current memtable, but the previous - // one is still being compacted, so we wait. - Log(options_.info_log, "Current memtable full; waiting...\n"); - bg_cv_.Wait(); - } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { - // There are too many level-0 files. - Log(options_.info_log, "Too many L0 files; waiting...\n"); - bg_cv_.Wait(); - } else { - // Attempt to switch to a new memtable and trigger compaction of old - assert(versions_->PrevLogNumber() == 0); - uint64_t new_log_number = versions_->NewFileNumber(); - WritableFile* lfile = NULL; - s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); - if (!s.ok()) { - // Avoid chewing through file number space in a tight loop. - versions_->ReuseFileNumber(new_log_number); - break; - } - delete log_; - delete logfile_; - logfile_ = lfile; - logfile_number_ = new_log_number; - log_ = new log::Writer(lfile); - imm_ = mem_; - has_imm_.Release_Store(imm_); - mem_ = new MemTable(internal_comparator_); - mem_->Ref(); - force = false; // Do not force another compaction if have room - MaybeScheduleCompaction(); - } - } - return s; -} - -bool DBImpl::GetProperty(const Slice& property, std::string* value) { - value->clear(); - - MutexLock l(&mutex_); - Slice in = property; - Slice prefix("leveldb."); - if (!in.starts_with(prefix)) return false; - in.remove_prefix(prefix.size()); - - if (in.starts_with("num-files-at-level")) { - in.remove_prefix(strlen("num-files-at-level")); - uint64_t level; - bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); - if (!ok || level >= config::kNumLevels) { - return false; - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "%d", - versions_->NumLevelFiles(static_cast(level))); - *value = buf; - return true; - } - } else if (in == "stats") { - char buf[200]; - snprintf(buf, sizeof(buf), - " Compactions\n" - "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" - "--------------------------------------------------\n" - ); - value->append(buf); - for (int level = 0; level < config::kNumLevels; level++) { - int files = versions_->NumLevelFiles(level); - if (stats_[level].micros > 0 || files > 0) { - snprintf( - buf, sizeof(buf), - "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", - level, - files, - versions_->NumLevelBytes(level) / 1048576.0, - stats_[level].micros / 1e6, - stats_[level].bytes_read / 1048576.0, - stats_[level].bytes_written / 1048576.0); - value->append(buf); - } - } - return true; - } else if (in == "sstables") { - *value = versions_->current()->DebugString(); - return true; - } - - return false; -} - -void DBImpl::GetApproximateSizes( - const Range* range, int n, - uint64_t* sizes) { - // TODO(opt): better implementation - Version* v; - { - MutexLock l(&mutex_); - versions_->current()->Ref(); - v = versions_->current(); - } - - for (int i = 0; i < n; i++) { - // Convert user_key into a corresponding internal key. - InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); - InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); - uint64_t start = versions_->ApproximateOffsetOf(v, k1); - uint64_t limit = versions_->ApproximateOffsetOf(v, k2); - sizes[i] = (limit >= start ? limit - start : 0); - } - - { - MutexLock l(&mutex_); - v->Unref(); - } -} - -// Default implementations of convenience methods that subclasses of DB -// can call if they wish -Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { - WriteBatch batch; - batch.Put(key, value); - return Write(opt, &batch); -} - -Status DB::Delete(const WriteOptions& opt, const Slice& key) { - WriteBatch batch; - batch.Delete(key); - return Write(opt, &batch); -} - -DB::~DB() { } - -Status DB::Open(const Options& options, const std::string& dbname, - DB** dbptr) { - *dbptr = NULL; - - DBImpl* impl = new DBImpl(options, dbname); - impl->mutex_.Lock(); - VersionEdit edit; - Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists - if (s.ok()) { - uint64_t new_log_number = impl->versions_->NewFileNumber(); - WritableFile* lfile; - s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), - &lfile); - if (s.ok()) { - edit.SetLogNumber(new_log_number); - impl->logfile_ = lfile; - impl->logfile_number_ = new_log_number; - impl->log_ = new log::Writer(lfile); - s = impl->versions_->LogAndApply(&edit, &impl->mutex_); - } - if (s.ok()) { - impl->DeleteObsoleteFiles(); - impl->MaybeScheduleCompaction(); - } - } - impl->mutex_.Unlock(); - if (s.ok()) { - *dbptr = impl; - } else { - delete impl; - } - return s; -} - -Snapshot::~Snapshot() { -} - -Status DestroyDB(const std::string& dbname, const Options& options) { - Env* env = options.env; - std::vector filenames; - // Ignore error in case directory does not exist - env->GetChildren(dbname, &filenames); - if (filenames.empty()) { - return Status::OK(); - } - - FileLock* lock; - const std::string lockname = LockFileName(dbname); - Status result = env->LockFile(lockname, &lock); - if (result.ok()) { - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && - type != kDBLockFile) { // Lock file will be deleted at end - Status del = env->DeleteFile(dbname + "/" + filenames[i]); - if (result.ok() && !del.ok()) { - result = del; - } - } - } - env->UnlockFile(lock); // Ignore error since state is already gone - env->DeleteFile(lockname); - env->DeleteDir(dbname); // Ignore error in case dir contains other files - } - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/db/db_impl.h b/src/leveldb/db/db_impl.h deleted file mode 100644 index cfc998164a..0000000000 --- a/src/leveldb/db/db_impl.h +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ -#define STORAGE_LEVELDB_DB_DB_IMPL_H_ - -#include -#include -#include "db/dbformat.h" -#include "db/log_writer.h" -#include "db/snapshot.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -class MemTable; -class TableCache; -class Version; -class VersionEdit; -class VersionSet; - -class DBImpl : public DB { - public: - DBImpl(const Options& options, const std::string& dbname); - virtual ~DBImpl(); - - // Implementations of the DB interface - virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); - virtual Status Delete(const WriteOptions&, const Slice& key); - virtual Status Write(const WriteOptions& options, WriteBatch* updates); - virtual Status Get(const ReadOptions& options, - const Slice& key, - std::string* value); - virtual Iterator* NewIterator(const ReadOptions&); - virtual const Snapshot* GetSnapshot(); - virtual void ReleaseSnapshot(const Snapshot* snapshot); - virtual bool GetProperty(const Slice& property, std::string* value); - virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); - virtual void CompactRange(const Slice* begin, const Slice* end); - - // Extra methods (for testing) that are not in the public DB interface - - // Compact any files in the named level that overlap [*begin,*end] - void TEST_CompactRange(int level, const Slice* begin, const Slice* end); - - // Force current memtable contents to be compacted. - Status TEST_CompactMemTable(); - - // Return an internal iterator over the current state of the database. - // The keys of this iterator are internal keys (see format.h). - // The returned iterator should be deleted when no longer needed. - Iterator* TEST_NewInternalIterator(); - - // Return the maximum overlapping data (in bytes) at next level for any - // file at a level >= 1. - int64_t TEST_MaxNextLevelOverlappingBytes(); - - // Record a sample of bytes read at the specified internal key. - // Samples are taken approximately once every config::kReadBytesPeriod - // bytes. - void RecordReadSample(Slice key); - - private: - friend class DB; - struct CompactionState; - struct Writer; - - Iterator* NewInternalIterator(const ReadOptions&, - SequenceNumber* latest_snapshot, - uint32_t* seed); - - Status NewDB(); - - // Recover the descriptor from persistent storage. May do a significant - // amount of work to recover recently logged updates. Any changes to - // be made to the descriptor are added to *edit. - Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - void MaybeIgnoreError(Status* s) const; - - // Delete any unneeded files and stale in-memory entries. - void DeleteObsoleteFiles(); - - // Compact the in-memory write buffer to disk. Switches to a new - // log-file/memtable and writes a new descriptor iff successful. - // Errors are recorded in bg_error_. - void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status RecoverLogFile(uint64_t log_number, - VersionEdit* edit, - SequenceNumber* max_sequence) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status MakeRoomForWrite(bool force /* compact even if there is room? */) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - WriteBatch* BuildBatchGroup(Writer** last_writer); - - void RecordBackgroundError(const Status& s); - - void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - static void BGWork(void* db); - void BackgroundCall(); - void BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void CleanupCompaction(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Status DoCompactionWork(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - Status OpenCompactionOutputFile(CompactionState* compact); - Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); - Status InstallCompactionResults(CompactionState* compact) - EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Constant after construction - Env* const env_; - const InternalKeyComparator internal_comparator_; - const InternalFilterPolicy internal_filter_policy_; - const Options options_; // options_.comparator == &internal_comparator_ - bool owns_info_log_; - bool owns_cache_; - const std::string dbname_; - - // table_cache_ provides its own synchronization - TableCache* table_cache_; - - // Lock over the persistent DB state. Non-NULL iff successfully acquired. - FileLock* db_lock_; - - // State below is protected by mutex_ - port::Mutex mutex_; - port::AtomicPointer shutting_down_; - port::CondVar bg_cv_; // Signalled when background work finishes - MemTable* mem_; - MemTable* imm_; // Memtable being compacted - port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ - WritableFile* logfile_; - uint64_t logfile_number_; - log::Writer* log_; - uint32_t seed_; // For sampling. - - // Queue of writers. - std::deque writers_; - WriteBatch* tmp_batch_; - - SnapshotList snapshots_; - - // Set of table files to protect from deletion because they are - // part of ongoing compactions. - std::set pending_outputs_; - - // Has a background compaction been scheduled or is running? - bool bg_compaction_scheduled_; - - // Information for a manual compaction - struct ManualCompaction { - int level; - bool done; - const InternalKey* begin; // NULL means beginning of key range - const InternalKey* end; // NULL means end of key range - InternalKey tmp_storage; // Used to keep track of compaction progress - }; - ManualCompaction* manual_compaction_; - - VersionSet* versions_; - - // Have we encountered a background error in paranoid mode? - Status bg_error_; - - // Per level compaction stats. stats_[level] stores the stats for - // compactions that produced data for the specified "level". - struct CompactionStats { - int64_t micros; - int64_t bytes_read; - int64_t bytes_written; - - CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } - - void Add(const CompactionStats& c) { - this->micros += c.micros; - this->bytes_read += c.bytes_read; - this->bytes_written += c.bytes_written; - } - }; - CompactionStats stats_[config::kNumLevels]; - - // No copying allowed - DBImpl(const DBImpl&); - void operator=(const DBImpl&); - - const Comparator* user_comparator() const { - return internal_comparator_.user_comparator(); - } -}; - -// Sanitize db options. The caller should delete result.info_log if -// it is not equal to src.info_log. -extern Options SanitizeOptions(const std::string& db, - const InternalKeyComparator* icmp, - const InternalFilterPolicy* ipolicy, - const Options& src); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/src/leveldb/db/db_iter.cc b/src/leveldb/db/db_iter.cc deleted file mode 100644 index 3b2035e9e3..0000000000 --- a/src/leveldb/db/db_iter.cc +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/db_iter.h" - -#include "db/filename.h" -#include "db/db_impl.h" -#include "db/dbformat.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/random.h" - -namespace leveldb { - -#if 0 -static void DumpInternalIter(Iterator* iter) { - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ParsedInternalKey k; - if (!ParseInternalKey(iter->key(), &k)) { - fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); - } else { - fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); - } - } -} -#endif - -namespace { - -// Memtables and sstables that make the DB representation contain -// (userkey,seq,type) => uservalue entries. DBIter -// combines multiple entries for the same userkey found in the DB -// representation into a single entry while accounting for sequence -// numbers, deletion markers, overwrites, etc. -class DBIter: public Iterator { - public: - // Which direction is the iterator currently moving? - // (1) When moving forward, the internal iterator is positioned at - // the exact entry that yields this->key(), this->value() - // (2) When moving backwards, the internal iterator is positioned - // just before all entries whose user key == this->key(). - enum Direction { - kForward, - kReverse - }; - - DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, - uint32_t seed) - : db_(db), - user_comparator_(cmp), - iter_(iter), - sequence_(s), - direction_(kForward), - valid_(false), - rnd_(seed), - bytes_counter_(RandomPeriod()) { - } - virtual ~DBIter() { - delete iter_; - } - virtual bool Valid() const { return valid_; } - virtual Slice key() const { - assert(valid_); - return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; - } - virtual Slice value() const { - assert(valid_); - return (direction_ == kForward) ? iter_->value() : saved_value_; - } - virtual Status status() const { - if (status_.ok()) { - return iter_->status(); - } else { - return status_; - } - } - - virtual void Next(); - virtual void Prev(); - virtual void Seek(const Slice& target); - virtual void SeekToFirst(); - virtual void SeekToLast(); - - private: - void FindNextUserEntry(bool skipping, std::string* skip); - void FindPrevUserEntry(); - bool ParseKey(ParsedInternalKey* key); - - inline void SaveKey(const Slice& k, std::string* dst) { - dst->assign(k.data(), k.size()); - } - - inline void ClearSavedValue() { - if (saved_value_.capacity() > 1048576) { - std::string empty; - swap(empty, saved_value_); - } else { - saved_value_.clear(); - } - } - - // Pick next gap with average value of config::kReadBytesPeriod. - ssize_t RandomPeriod() { - return rnd_.Uniform(2*config::kReadBytesPeriod); - } - - DBImpl* db_; - const Comparator* const user_comparator_; - Iterator* const iter_; - SequenceNumber const sequence_; - - Status status_; - std::string saved_key_; // == current key when direction_==kReverse - std::string saved_value_; // == current raw value when direction_==kReverse - Direction direction_; - bool valid_; - - Random rnd_; - ssize_t bytes_counter_; - - // No copying allowed - DBIter(const DBIter&); - void operator=(const DBIter&); -}; - -inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { - Slice k = iter_->key(); - ssize_t n = k.size() + iter_->value().size(); - bytes_counter_ -= n; - while (bytes_counter_ < 0) { - bytes_counter_ += RandomPeriod(); - db_->RecordReadSample(k); - } - if (!ParseInternalKey(k, ikey)) { - status_ = Status::Corruption("corrupted internal key in DBIter"); - return false; - } else { - return true; - } -} - -void DBIter::Next() { - assert(valid_); - - if (direction_ == kReverse) { // Switch directions? - direction_ = kForward; - // iter_ is pointing just before the entries for this->key(), - // so advance into the range of entries for this->key() and then - // use the normal skipping code below. - if (!iter_->Valid()) { - iter_->SeekToFirst(); - } else { - iter_->Next(); - } - if (!iter_->Valid()) { - valid_ = false; - saved_key_.clear(); - return; - } - // saved_key_ already contains the key to skip past. - } else { - // Store in saved_key_ the current key so we skip it below. - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); - } - - FindNextUserEntry(true, &saved_key_); -} - -void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { - // Loop until we hit an acceptable entry to yield - assert(iter_->Valid()); - assert(direction_ == kForward); - do { - ParsedInternalKey ikey; - if (ParseKey(&ikey) && ikey.sequence <= sequence_) { - switch (ikey.type) { - case kTypeDeletion: - // Arrange to skip all upcoming entries for this key since - // they are hidden by this deletion. - SaveKey(ikey.user_key, skip); - skipping = true; - break; - case kTypeValue: - if (skipping && - user_comparator_->Compare(ikey.user_key, *skip) <= 0) { - // Entry hidden - } else { - valid_ = true; - saved_key_.clear(); - return; - } - break; - } - } - iter_->Next(); - } while (iter_->Valid()); - saved_key_.clear(); - valid_ = false; -} - -void DBIter::Prev() { - assert(valid_); - - if (direction_ == kForward) { // Switch directions? - // iter_ is pointing at the current entry. Scan backwards until - // the key changes so we can use the normal reverse scanning code. - assert(iter_->Valid()); // Otherwise valid_ would have been false - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); - while (true) { - iter_->Prev(); - if (!iter_->Valid()) { - valid_ = false; - saved_key_.clear(); - ClearSavedValue(); - return; - } - if (user_comparator_->Compare(ExtractUserKey(iter_->key()), - saved_key_) < 0) { - break; - } - } - direction_ = kReverse; - } - - FindPrevUserEntry(); -} - -void DBIter::FindPrevUserEntry() { - assert(direction_ == kReverse); - - ValueType value_type = kTypeDeletion; - if (iter_->Valid()) { - do { - ParsedInternalKey ikey; - if (ParseKey(&ikey) && ikey.sequence <= sequence_) { - if ((value_type != kTypeDeletion) && - user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { - // We encountered a non-deleted value in entries for previous keys, - break; - } - value_type = ikey.type; - if (value_type == kTypeDeletion) { - saved_key_.clear(); - ClearSavedValue(); - } else { - Slice raw_value = iter_->value(); - if (saved_value_.capacity() > raw_value.size() + 1048576) { - std::string empty; - swap(empty, saved_value_); - } - SaveKey(ExtractUserKey(iter_->key()), &saved_key_); - saved_value_.assign(raw_value.data(), raw_value.size()); - } - } - iter_->Prev(); - } while (iter_->Valid()); - } - - if (value_type == kTypeDeletion) { - // End - valid_ = false; - saved_key_.clear(); - ClearSavedValue(); - direction_ = kForward; - } else { - valid_ = true; - } -} - -void DBIter::Seek(const Slice& target) { - direction_ = kForward; - ClearSavedValue(); - saved_key_.clear(); - AppendInternalKey( - &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); - iter_->Seek(saved_key_); - if (iter_->Valid()) { - FindNextUserEntry(false, &saved_key_ /* temporary storage */); - } else { - valid_ = false; - } -} - -void DBIter::SeekToFirst() { - direction_ = kForward; - ClearSavedValue(); - iter_->SeekToFirst(); - if (iter_->Valid()) { - FindNextUserEntry(false, &saved_key_ /* temporary storage */); - } else { - valid_ = false; - } -} - -void DBIter::SeekToLast() { - direction_ = kReverse; - ClearSavedValue(); - iter_->SeekToLast(); - FindPrevUserEntry(); -} - -} // anonymous namespace - -Iterator* NewDBIterator( - DBImpl* db, - const Comparator* user_key_comparator, - Iterator* internal_iter, - SequenceNumber sequence, - uint32_t seed) { - return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); -} - -} // namespace leveldb diff --git a/src/leveldb/db/db_iter.h b/src/leveldb/db/db_iter.h deleted file mode 100644 index 04927e937b..0000000000 --- a/src/leveldb/db/db_iter.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ -#define STORAGE_LEVELDB_DB_DB_ITER_H_ - -#include -#include "leveldb/db.h" -#include "db/dbformat.h" - -namespace leveldb { - -class DBImpl; - -// Return a new iterator that converts internal keys (yielded by -// "*internal_iter") that were live at the specified "sequence" number -// into appropriate user keys. -extern Iterator* NewDBIterator( - DBImpl* db, - const Comparator* user_key_comparator, - Iterator* internal_iter, - SequenceNumber sequence, - uint32_t seed); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/src/leveldb/db/db_test.cc b/src/leveldb/db/db_test.cc deleted file mode 100644 index 0fed9137d5..0000000000 --- a/src/leveldb/db/db_test.cc +++ /dev/null @@ -1,2128 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" -#include "leveldb/filter_policy.h" -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/version_set.h" -#include "db/write_batch_internal.h" -#include "leveldb/cache.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "util/hash.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static std::string RandomString(Random* rnd, int len) { - std::string r; - test::RandomString(rnd, len, &r); - return r; -} - -namespace { -class AtomicCounter { - private: - port::Mutex mu_; - int count_; - public: - AtomicCounter() : count_(0) { } - void Increment() { - IncrementBy(1); - } - void IncrementBy(int count) { - MutexLock l(&mu_); - count_ += count; - } - int Read() { - MutexLock l(&mu_); - return count_; - } - void Reset() { - MutexLock l(&mu_); - count_ = 0; - } -}; - -void DelayMilliseconds(int millis) { - Env::Default()->SleepForMicroseconds(millis * 1000); -} -} - -// Special Env used to delay background operations -class SpecialEnv : public EnvWrapper { - public: - // sstable/log Sync() calls are blocked while this pointer is non-NULL. - port::AtomicPointer delay_data_sync_; - - // sstable/log Sync() calls return an error. - port::AtomicPointer data_sync_error_; - - // Simulate no-space errors while this pointer is non-NULL. - port::AtomicPointer no_space_; - - // Simulate non-writable file system while this pointer is non-NULL - port::AtomicPointer non_writable_; - - // Force sync of manifest files to fail while this pointer is non-NULL - port::AtomicPointer manifest_sync_error_; - - // Force write to manifest files to fail while this pointer is non-NULL - port::AtomicPointer manifest_write_error_; - - bool count_random_reads_; - AtomicCounter random_read_counter_; - - explicit SpecialEnv(Env* base) : EnvWrapper(base) { - delay_data_sync_.Release_Store(NULL); - data_sync_error_.Release_Store(NULL); - no_space_.Release_Store(NULL); - non_writable_.Release_Store(NULL); - count_random_reads_ = false; - manifest_sync_error_.Release_Store(NULL); - manifest_write_error_.Release_Store(NULL); - } - - Status NewWritableFile(const std::string& f, WritableFile** r) { - class DataFile : public WritableFile { - private: - SpecialEnv* env_; - WritableFile* base_; - - public: - DataFile(SpecialEnv* env, WritableFile* base) - : env_(env), - base_(base) { - } - ~DataFile() { delete base_; } - Status Append(const Slice& data) { - if (env_->no_space_.Acquire_Load() != NULL) { - // Drop writes on the floor - return Status::OK(); - } else { - return base_->Append(data); - } - } - Status Close() { return base_->Close(); } - Status Flush() { return base_->Flush(); } - Status Sync() { - if (env_->data_sync_error_.Acquire_Load() != NULL) { - return Status::IOError("simulated data sync error"); - } - while (env_->delay_data_sync_.Acquire_Load() != NULL) { - DelayMilliseconds(100); - } - return base_->Sync(); - } - }; - class ManifestFile : public WritableFile { - private: - SpecialEnv* env_; - WritableFile* base_; - public: - ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } - ~ManifestFile() { delete base_; } - Status Append(const Slice& data) { - if (env_->manifest_write_error_.Acquire_Load() != NULL) { - return Status::IOError("simulated writer error"); - } else { - return base_->Append(data); - } - } - Status Close() { return base_->Close(); } - Status Flush() { return base_->Flush(); } - Status Sync() { - if (env_->manifest_sync_error_.Acquire_Load() != NULL) { - return Status::IOError("simulated sync error"); - } else { - return base_->Sync(); - } - } - }; - - if (non_writable_.Acquire_Load() != NULL) { - return Status::IOError("simulated write error"); - } - - Status s = target()->NewWritableFile(f, r); - if (s.ok()) { - if (strstr(f.c_str(), ".ldb") != NULL || - strstr(f.c_str(), ".log") != NULL) { - *r = new DataFile(this, *r); - } else if (strstr(f.c_str(), "MANIFEST") != NULL) { - *r = new ManifestFile(this, *r); - } - } - return s; - } - - Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { - class CountingFile : public RandomAccessFile { - private: - RandomAccessFile* target_; - AtomicCounter* counter_; - public: - CountingFile(RandomAccessFile* target, AtomicCounter* counter) - : target_(target), counter_(counter) { - } - virtual ~CountingFile() { delete target_; } - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - counter_->Increment(); - return target_->Read(offset, n, result, scratch); - } - }; - - Status s = target()->NewRandomAccessFile(f, r); - if (s.ok() && count_random_reads_) { - *r = new CountingFile(*r, &random_read_counter_); - } - return s; - } -}; - -class DBTest { - private: - const FilterPolicy* filter_policy_; - - // Sequence of option configurations to try - enum OptionConfig { - kDefault, - kFilter, - kUncompressed, - kEnd - }; - int option_config_; - - public: - std::string dbname_; - SpecialEnv* env_; - DB* db_; - - Options last_options_; - - DBTest() : option_config_(kDefault), - env_(new SpecialEnv(Env::Default())) { - filter_policy_ = NewBloomFilterPolicy(10); - dbname_ = test::TmpDir() + "/db_test"; - DestroyDB(dbname_, Options()); - db_ = NULL; - Reopen(); - } - - ~DBTest() { - delete db_; - DestroyDB(dbname_, Options()); - delete env_; - delete filter_policy_; - } - - // Switch to a fresh database with the next option configuration to - // test. Return false if there are no more configurations to test. - bool ChangeOptions() { - option_config_++; - if (option_config_ >= kEnd) { - return false; - } else { - DestroyAndReopen(); - return true; - } - } - - // Return the current option configuration. - Options CurrentOptions() { - Options options; - switch (option_config_) { - case kFilter: - options.filter_policy = filter_policy_; - break; - case kUncompressed: - options.compression = kNoCompression; - break; - default: - break; - } - return options; - } - - DBImpl* dbfull() { - return reinterpret_cast(db_); - } - - void Reopen(Options* options = NULL) { - ASSERT_OK(TryReopen(options)); - } - - void Close() { - delete db_; - db_ = NULL; - } - - void DestroyAndReopen(Options* options = NULL) { - delete db_; - db_ = NULL; - DestroyDB(dbname_, Options()); - ASSERT_OK(TryReopen(options)); - } - - Status TryReopen(Options* options) { - delete db_; - db_ = NULL; - Options opts; - if (options != NULL) { - opts = *options; - } else { - opts = CurrentOptions(); - opts.create_if_missing = true; - } - last_options_ = opts; - - return DB::Open(opts, dbname_, &db_); - } - - Status Put(const std::string& k, const std::string& v) { - return db_->Put(WriteOptions(), k, v); - } - - Status Delete(const std::string& k) { - return db_->Delete(WriteOptions(), k); - } - - std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { - ReadOptions options; - options.snapshot = snapshot; - std::string result; - Status s = db_->Get(options, k, &result); - if (s.IsNotFound()) { - result = "NOT_FOUND"; - } else if (!s.ok()) { - result = s.ToString(); - } - return result; - } - - // Return a string that contains all key,value pairs in order, - // formatted like "(k1->v1)(k2->v2)". - std::string Contents() { - std::vector forward; - std::string result; - Iterator* iter = db_->NewIterator(ReadOptions()); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - std::string s = IterStatus(iter); - result.push_back('('); - result.append(s); - result.push_back(')'); - forward.push_back(s); - } - - // Check reverse iteration results are the reverse of forward results - size_t matched = 0; - for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { - ASSERT_LT(matched, forward.size()); - ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); - matched++; - } - ASSERT_EQ(matched, forward.size()); - - delete iter; - return result; - } - - std::string AllEntriesFor(const Slice& user_key) { - Iterator* iter = dbfull()->TEST_NewInternalIterator(); - InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); - iter->Seek(target.Encode()); - std::string result; - if (!iter->status().ok()) { - result = iter->status().ToString(); - } else { - result = "[ "; - bool first = true; - while (iter->Valid()) { - ParsedInternalKey ikey; - if (!ParseInternalKey(iter->key(), &ikey)) { - result += "CORRUPTED"; - } else { - if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { - break; - } - if (!first) { - result += ", "; - } - first = false; - switch (ikey.type) { - case kTypeValue: - result += iter->value().ToString(); - break; - case kTypeDeletion: - result += "DEL"; - break; - } - } - iter->Next(); - } - if (!first) { - result += " "; - } - result += "]"; - } - delete iter; - return result; - } - - int NumTableFilesAtLevel(int level) { - std::string property; - ASSERT_TRUE( - db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), - &property)); - return atoi(property.c_str()); - } - - int TotalTableFiles() { - int result = 0; - for (int level = 0; level < config::kNumLevels; level++) { - result += NumTableFilesAtLevel(level); - } - return result; - } - - // Return spread of files per level - std::string FilesPerLevel() { - std::string result; - int last_non_zero_offset = 0; - for (int level = 0; level < config::kNumLevels; level++) { - int f = NumTableFilesAtLevel(level); - char buf[100]; - snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); - result += buf; - if (f > 0) { - last_non_zero_offset = result.size(); - } - } - result.resize(last_non_zero_offset); - return result; - } - - int CountFiles() { - std::vector files; - env_->GetChildren(dbname_, &files); - return static_cast(files.size()); - } - - uint64_t Size(const Slice& start, const Slice& limit) { - Range r(start, limit); - uint64_t size; - db_->GetApproximateSizes(&r, 1, &size); - return size; - } - - void Compact(const Slice& start, const Slice& limit) { - db_->CompactRange(&start, &limit); - } - - // Do n memtable compactions, each of which produces an sstable - // covering the range [small,large]. - void MakeTables(int n, const std::string& small, const std::string& large) { - for (int i = 0; i < n; i++) { - Put(small, "begin"); - Put(large, "end"); - dbfull()->TEST_CompactMemTable(); - } - } - - // Prevent pushing of new sstables into deeper levels by adding - // tables that cover a specified range to all levels. - void FillLevels(const std::string& smallest, const std::string& largest) { - MakeTables(config::kNumLevels, smallest, largest); - } - - void DumpFileCounts(const char* label) { - fprintf(stderr, "---\n%s:\n", label); - fprintf(stderr, "maxoverlap: %lld\n", - static_cast( - dbfull()->TEST_MaxNextLevelOverlappingBytes())); - for (int level = 0; level < config::kNumLevels; level++) { - int num = NumTableFilesAtLevel(level); - if (num > 0) { - fprintf(stderr, " level %3d : %d files\n", level, num); - } - } - } - - std::string DumpSSTableList() { - std::string property; - db_->GetProperty("leveldb.sstables", &property); - return property; - } - - std::string IterStatus(Iterator* iter) { - std::string result; - if (iter->Valid()) { - result = iter->key().ToString() + "->" + iter->value().ToString(); - } else { - result = "(invalid)"; - } - return result; - } - - bool DeleteAnSSTFile() { - std::vector filenames; - ASSERT_OK(env_->GetChildren(dbname_, &filenames)); - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { - ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); - return true; - } - } - return false; - } - - // Returns number of files renamed. - int RenameLDBToSST() { - std::vector filenames; - ASSERT_OK(env_->GetChildren(dbname_, &filenames)); - uint64_t number; - FileType type; - int files_renamed = 0; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { - const std::string from = TableFileName(dbname_, number); - const std::string to = SSTTableFileName(dbname_, number); - ASSERT_OK(env_->RenameFile(from, to)); - files_renamed++; - } - } - return files_renamed; - } -}; - -TEST(DBTest, Empty) { - do { - ASSERT_TRUE(db_ != NULL); - ASSERT_EQ("NOT_FOUND", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, ReadWrite) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(Put("bar", "v2")); - ASSERT_OK(Put("foo", "v3")); - ASSERT_EQ("v3", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - } while (ChangeOptions()); -} - -TEST(DBTest, PutDeleteGet) { - do { - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); - ASSERT_EQ("v2", Get("foo")); - ASSERT_OK(db_->Delete(WriteOptions(), "foo")); - ASSERT_EQ("NOT_FOUND", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetFromImmutableLayer) { - do { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 100000; // Small write buffer - Reopen(&options); - - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - - env_->delay_data_sync_.Release_Store(env_); // Block sync calls - Put("k1", std::string(100000, 'x')); // Fill memtable - Put("k2", std::string(100000, 'y')); // Trigger compaction - ASSERT_EQ("v1", Get("foo")); - env_->delay_data_sync_.Release_Store(NULL); // Release sync calls - } while (ChangeOptions()); -} - -TEST(DBTest, GetFromVersions) { - do { - ASSERT_OK(Put("foo", "v1")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v1", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetSnapshot) { - do { - // Try with both a short key and a long key - for (int i = 0; i < 2; i++) { - std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); - ASSERT_OK(Put(key, "v1")); - const Snapshot* s1 = db_->GetSnapshot(); - ASSERT_OK(Put(key, "v2")); - ASSERT_EQ("v2", Get(key)); - ASSERT_EQ("v1", Get(key, s1)); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get(key)); - ASSERT_EQ("v1", Get(key, s1)); - db_->ReleaseSnapshot(s1); - } - } while (ChangeOptions()); -} - -TEST(DBTest, GetLevel0Ordering) { - do { - // Check that we process level-0 files in correct order. The code - // below generates two level-0 files where the earlier one comes - // before the later one in the level-0 file list since the earlier - // one has a smaller "smallest" key. - ASSERT_OK(Put("bar", "b")); - ASSERT_OK(Put("foo", "v1")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Put("foo", "v2")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetOrderedByLevels) { - do { - ASSERT_OK(Put("foo", "v1")); - Compact("a", "z"); - ASSERT_EQ("v1", Get("foo")); - ASSERT_OK(Put("foo", "v2")); - ASSERT_EQ("v2", Get("foo")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("v2", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetPicksCorrectFile) { - do { - // Arrange to have multiple files in a non-level-0 level. - ASSERT_OK(Put("a", "va")); - Compact("a", "b"); - ASSERT_OK(Put("x", "vx")); - Compact("x", "y"); - ASSERT_OK(Put("f", "vf")); - Compact("f", "g"); - ASSERT_EQ("va", Get("a")); - ASSERT_EQ("vf", Get("f")); - ASSERT_EQ("vx", Get("x")); - } while (ChangeOptions()); -} - -TEST(DBTest, GetEncountersEmptyLevel) { - do { - // Arrange for the following to happen: - // * sstable A in level 0 - // * nothing in level 1 - // * sstable B in level 2 - // Then do enough Get() calls to arrange for an automatic compaction - // of sstable A. A bug would cause the compaction to be marked as - // occurring at level 1 (instead of the correct level 0). - - // Step 1: First place sstables in levels 0 and 2 - int compaction_count = 0; - while (NumTableFilesAtLevel(0) == 0 || - NumTableFilesAtLevel(2) == 0) { - ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; - compaction_count++; - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - } - - // Step 2: clear level 1 if necessary. - dbfull()->TEST_CompactRange(1, NULL, NULL); - ASSERT_EQ(NumTableFilesAtLevel(0), 1); - ASSERT_EQ(NumTableFilesAtLevel(1), 0); - ASSERT_EQ(NumTableFilesAtLevel(2), 1); - - // Step 3: read a bunch of times - for (int i = 0; i < 1000; i++) { - ASSERT_EQ("NOT_FOUND", Get("missing")); - } - - // Step 4: Wait for compaction to finish - DelayMilliseconds(1000); - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - } while (ChangeOptions()); -} - -TEST(DBTest, IterEmpty) { - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("foo"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterSingle) { - ASSERT_OK(Put("a", "va")); - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek(""); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("a"); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek("b"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterMulti) { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", "vb")); - ASSERT_OK(Put("c", "vc")); - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->Seek(""); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Seek("a"); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Seek("ax"); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Seek("b"); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Seek("z"); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - // Switch from reverse to forward - iter->SeekToLast(); - iter->Prev(); - iter->Prev(); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - - // Switch from forward to reverse - iter->SeekToFirst(); - iter->Next(); - iter->Next(); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - - // Make sure iter stays at snapshot - ASSERT_OK(Put("a", "va2")); - ASSERT_OK(Put("a2", "va3")); - ASSERT_OK(Put("b", "vb2")); - ASSERT_OK(Put("c", "vc2")); - ASSERT_OK(Delete("b")); - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->vb"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterSmallAndLargeMix) { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", std::string(100000, 'b'))); - ASSERT_OK(Put("c", "vc")); - ASSERT_OK(Put("d", std::string(100000, 'd'))); - ASSERT_OK(Put("e", std::string(100000, 'e'))); - - Iterator* iter = db_->NewIterator(ReadOptions()); - - iter->SeekToFirst(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); - iter->Next(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - iter->SeekToLast(); - ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "(invalid)"); - - delete iter; -} - -TEST(DBTest, IterMultiWithDelete) { - do { - ASSERT_OK(Put("a", "va")); - ASSERT_OK(Put("b", "vb")); - ASSERT_OK(Put("c", "vc")); - ASSERT_OK(Delete("b")); - ASSERT_EQ("NOT_FOUND", Get("b")); - - Iterator* iter = db_->NewIterator(ReadOptions()); - iter->Seek("c"); - ASSERT_EQ(IterStatus(iter), "c->vc"); - iter->Prev(); - ASSERT_EQ(IterStatus(iter), "a->va"); - delete iter; - } while (ChangeOptions()); -} - -TEST(DBTest, Recover) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_OK(Put("baz", "v5")); - - Reopen(); - ASSERT_EQ("v1", Get("foo")); - - ASSERT_EQ("v1", Get("foo")); - ASSERT_EQ("v5", Get("baz")); - ASSERT_OK(Put("bar", "v2")); - ASSERT_OK(Put("foo", "v3")); - - Reopen(); - ASSERT_EQ("v3", Get("foo")); - ASSERT_OK(Put("foo", "v4")); - ASSERT_EQ("v4", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - ASSERT_EQ("v5", Get("baz")); - } while (ChangeOptions()); -} - -TEST(DBTest, RecoveryWithEmptyLog) { - do { - ASSERT_OK(Put("foo", "v1")); - ASSERT_OK(Put("foo", "v2")); - Reopen(); - Reopen(); - ASSERT_OK(Put("foo", "v3")); - Reopen(); - ASSERT_EQ("v3", Get("foo")); - } while (ChangeOptions()); -} - -// Check that writes done during a memtable compaction are recovered -// if the database is shutdown during the memtable compaction. -TEST(DBTest, RecoverDuringMemtableCompaction) { - do { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 1000000; - Reopen(&options); - - // Trigger a long memtable compaction and reopen the database during it - ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file - ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable - ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction - ASSERT_OK(Put("bar", "v2")); // Goes to new log file - - Reopen(&options); - ASSERT_EQ("v1", Get("foo")); - ASSERT_EQ("v2", Get("bar")); - ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); - ASSERT_EQ(std::string(1000, 'y'), Get("big2")); - } while (ChangeOptions()); -} - -static std::string Key(int i) { - char buf[100]; - snprintf(buf, sizeof(buf), "key%06d", i); - return std::string(buf); -} - -TEST(DBTest, MinorCompactionsHappen) { - Options options = CurrentOptions(); - options.write_buffer_size = 10000; - Reopen(&options); - - const int N = 500; - - int starting_num_tables = TotalTableFiles(); - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); - } - int ending_num_tables = TotalTableFiles(); - ASSERT_GT(ending_num_tables, starting_num_tables); - - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); - } - - Reopen(); - - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); - } -} - -TEST(DBTest, RecoverWithLargeLog) { - { - Options options = CurrentOptions(); - Reopen(&options); - ASSERT_OK(Put("big1", std::string(200000, '1'))); - ASSERT_OK(Put("big2", std::string(200000, '2'))); - ASSERT_OK(Put("small3", std::string(10, '3'))); - ASSERT_OK(Put("small4", std::string(10, '4'))); - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - } - - // Make sure that if we re-open with a small write buffer size that - // we flush table files in the middle of a large log file. - Options options = CurrentOptions(); - options.write_buffer_size = 100000; - Reopen(&options); - ASSERT_EQ(NumTableFilesAtLevel(0), 3); - ASSERT_EQ(std::string(200000, '1'), Get("big1")); - ASSERT_EQ(std::string(200000, '2'), Get("big2")); - ASSERT_EQ(std::string(10, '3'), Get("small3")); - ASSERT_EQ(std::string(10, '4'), Get("small4")); - ASSERT_GT(NumTableFilesAtLevel(0), 1); -} - -TEST(DBTest, CompactionsGenerateMultipleFiles) { - Options options = CurrentOptions(); - options.write_buffer_size = 100000000; // Large write buffer - Reopen(&options); - - Random rnd(301); - - // Write 8MB (80 values, each 100K) - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - std::vector values; - for (int i = 0; i < 80; i++) { - values.push_back(RandomString(&rnd, 100000)); - ASSERT_OK(Put(Key(i), values[i])); - } - - // Reopening moves updates to level-0 - Reopen(&options); - dbfull()->TEST_CompactRange(0, NULL, NULL); - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GT(NumTableFilesAtLevel(1), 1); - for (int i = 0; i < 80; i++) { - ASSERT_EQ(Get(Key(i)), values[i]); - } -} - -TEST(DBTest, RepeatedWritesToSameKey) { - Options options = CurrentOptions(); - options.env = env_; - options.write_buffer_size = 100000; // Small write buffer - Reopen(&options); - - // We must have at most one file per level except for level-0, - // which may have up to kL0_StopWritesTrigger files. - const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; - - Random rnd(301); - std::string value = RandomString(&rnd, 2 * options.write_buffer_size); - for (int i = 0; i < 5 * kMaxFiles; i++) { - Put("key", value); - ASSERT_LE(TotalTableFiles(), kMaxFiles); - fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); - } -} - -TEST(DBTest, SparseMerge) { - Options options = CurrentOptions(); - options.compression = kNoCompression; - Reopen(&options); - - FillLevels("A", "Z"); - - // Suppose there is: - // small amount of data with prefix A - // large amount of data with prefix B - // small amount of data with prefix C - // and that recent updates have made small changes to all three prefixes. - // Check that we do not do a compaction that merges all of B in one shot. - const std::string value(1000, 'x'); - Put("A", "va"); - // Write approximately 100MB of "B" values - for (int i = 0; i < 100000; i++) { - char key[100]; - snprintf(key, sizeof(key), "B%010d", i); - Put(key, value); - } - Put("C", "vc"); - dbfull()->TEST_CompactMemTable(); - dbfull()->TEST_CompactRange(0, NULL, NULL); - - // Make sparse update - Put("A", "va2"); - Put("B100", "bvalue2"); - Put("C", "vc2"); - dbfull()->TEST_CompactMemTable(); - - // Compactions should not cause us to create a situation where - // a file overlaps too much data at the next level. - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); - dbfull()->TEST_CompactRange(0, NULL, NULL); - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); - dbfull()->TEST_CompactRange(1, NULL, NULL); - ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); -} - -static bool Between(uint64_t val, uint64_t low, uint64_t high) { - bool result = (val >= low) && (val <= high); - if (!result) { - fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", - (unsigned long long)(val), - (unsigned long long)(low), - (unsigned long long)(high)); - } - return result; -} - -TEST(DBTest, ApproximateSizes) { - do { - Options options = CurrentOptions(); - options.write_buffer_size = 100000000; // Large write buffer - options.compression = kNoCompression; - DestroyAndReopen(); - - ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); - Reopen(&options); - ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); - - // Write 8MB (80 values, each 100K) - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - const int N = 80; - static const int S1 = 100000; - static const int S2 = 105000; // Allow some expansion from metadata - Random rnd(301); - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); - } - - // 0 because GetApproximateSizes() does not account for memtable space - ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); - - // Check sizes across recovery by reopening a few times - for (int run = 0; run < 3; run++) { - Reopen(&options); - - for (int compact_start = 0; compact_start < N; compact_start += 10) { - for (int i = 0; i < N; i += 10) { - ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); - ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); - ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); - } - ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); - ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); - - std::string cstart_str = Key(compact_start); - std::string cend_str = Key(compact_start + 9); - Slice cstart = cstart_str; - Slice cend = cend_str; - dbfull()->TEST_CompactRange(0, &cstart, &cend); - } - - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GT(NumTableFilesAtLevel(1), 0); - } - } while (ChangeOptions()); -} - -TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { - do { - Options options = CurrentOptions(); - options.compression = kNoCompression; - Reopen(); - - Random rnd(301); - std::string big1 = RandomString(&rnd, 100000); - ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(2), big1)); - ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(4), big1)); - ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); - ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); - ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); - - // Check sizes across recovery by reopening a few times - for (int run = 0; run < 3; run++) { - Reopen(&options); - - ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); - ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); - ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); - ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); - ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); - ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); - ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); - ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); - ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); - - ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); - - dbfull()->TEST_CompactRange(0, NULL, NULL); - } - } while (ChangeOptions()); -} - -TEST(DBTest, IteratorPinsRef) { - Put("foo", "hello"); - - // Get iterator that will yield the current contents of the DB. - Iterator* iter = db_->NewIterator(ReadOptions()); - - // Write to force compactions - Put("foo", "newvalue1"); - for (int i = 0; i < 100; i++) { - ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values - } - Put("foo", "newvalue2"); - - iter->SeekToFirst(); - ASSERT_TRUE(iter->Valid()); - ASSERT_EQ("foo", iter->key().ToString()); - ASSERT_EQ("hello", iter->value().ToString()); - iter->Next(); - ASSERT_TRUE(!iter->Valid()); - delete iter; -} - -TEST(DBTest, Snapshot) { - do { - Put("foo", "v1"); - const Snapshot* s1 = db_->GetSnapshot(); - Put("foo", "v2"); - const Snapshot* s2 = db_->GetSnapshot(); - Put("foo", "v3"); - const Snapshot* s3 = db_->GetSnapshot(); - - Put("foo", "v4"); - ASSERT_EQ("v1", Get("foo", s1)); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v3", Get("foo", s3)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s3); - ASSERT_EQ("v1", Get("foo", s1)); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s1); - ASSERT_EQ("v2", Get("foo", s2)); - ASSERT_EQ("v4", Get("foo")); - - db_->ReleaseSnapshot(s2); - ASSERT_EQ("v4", Get("foo")); - } while (ChangeOptions()); -} - -TEST(DBTest, HiddenValuesAreRemoved) { - do { - Random rnd(301); - FillLevels("a", "z"); - - std::string big = RandomString(&rnd, 50000); - Put("foo", big); - Put("pastfoo", "v"); - const Snapshot* snapshot = db_->GetSnapshot(); - Put("foo", "tiny"); - Put("pastfoo2", "v2"); // Advance sequence number one more - - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - ASSERT_GT(NumTableFilesAtLevel(0), 0); - - ASSERT_EQ(big, Get("foo", snapshot)); - ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); - db_->ReleaseSnapshot(snapshot); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); - Slice x("x"); - dbfull()->TEST_CompactRange(0, NULL, &x); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); - ASSERT_EQ(NumTableFilesAtLevel(0), 0); - ASSERT_GE(NumTableFilesAtLevel(1), 1); - dbfull()->TEST_CompactRange(1, NULL, &x); - ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); - - ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); - } while (ChangeOptions()); -} - -TEST(DBTest, DeletionMarkers1) { - Put("foo", "v1"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level - - // Place a table at level last-1 to prevent merging with preceding mutation - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ(NumTableFilesAtLevel(last), 1); - ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); - - Delete("foo"); - Put("foo", "v2"); - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); - Slice z("z"); - dbfull()->TEST_CompactRange(last-2, NULL, &z); - // DEL eliminated, but v1 remains because we aren't compacting that level - // (DEL can be eliminated because v2 hides v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); - dbfull()->TEST_CompactRange(last-1, NULL, NULL); - // Merging last-1 w/ last, so we are the base level for "foo", so - // DEL is removed. (as is v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); -} - -TEST(DBTest, DeletionMarkers2) { - Put("foo", "v1"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level - - // Place a table at level last-1 to prevent merging with preceding mutation - Put("a", "begin"); - Put("z", "end"); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ(NumTableFilesAtLevel(last), 1); - ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); - - Delete("foo"); - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - dbfull()->TEST_CompactRange(last-2, NULL, NULL); - // DEL kept: "last" file overlaps - ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); - dbfull()->TEST_CompactRange(last-1, NULL, NULL); - // Merging last-1 w/ last, so we are the base level for "foo", so - // DEL is removed. (as is v1). - ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); -} - -TEST(DBTest, OverlapInLevel0) { - do { - ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; - - // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. - ASSERT_OK(Put("100", "v100")); - ASSERT_OK(Put("999", "v999")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Delete("100")); - ASSERT_OK(Delete("999")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("0,1,1", FilesPerLevel()); - - // Make files spanning the following ranges in level-0: - // files[0] 200 .. 900 - // files[1] 300 .. 500 - // Note that files are sorted by smallest key. - ASSERT_OK(Put("300", "v300")); - ASSERT_OK(Put("500", "v500")); - dbfull()->TEST_CompactMemTable(); - ASSERT_OK(Put("200", "v200")); - ASSERT_OK(Put("600", "v600")); - ASSERT_OK(Put("900", "v900")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("2,1,1", FilesPerLevel()); - - // Compact away the placeholder files we created initially - dbfull()->TEST_CompactRange(1, NULL, NULL); - dbfull()->TEST_CompactRange(2, NULL, NULL); - ASSERT_EQ("2", FilesPerLevel()); - - // Do a memtable compaction. Before bug-fix, the compaction would - // not detect the overlap with level-0 files and would incorrectly place - // the deletion in a deeper level. - ASSERT_OK(Delete("600")); - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("3", FilesPerLevel()); - ASSERT_EQ("NOT_FOUND", Get("600")); - } while (ChangeOptions()); -} - -TEST(DBTest, L0_CompactionBug_Issue44_a) { - Reopen(); - ASSERT_OK(Put("b", "v")); - Reopen(); - ASSERT_OK(Delete("b")); - ASSERT_OK(Delete("a")); - Reopen(); - ASSERT_OK(Delete("a")); - Reopen(); - ASSERT_OK(Put("a", "v")); - Reopen(); - Reopen(); - ASSERT_EQ("(a->v)", Contents()); - DelayMilliseconds(1000); // Wait for compaction to finish - ASSERT_EQ("(a->v)", Contents()); -} - -TEST(DBTest, L0_CompactionBug_Issue44_b) { - Reopen(); - Put("",""); - Reopen(); - Delete("e"); - Put("",""); - Reopen(); - Put("c", "cv"); - Reopen(); - Put("",""); - Reopen(); - Put("",""); - DelayMilliseconds(1000); // Wait for compaction to finish - Reopen(); - Put("d","dv"); - Reopen(); - Put("",""); - Reopen(); - Delete("d"); - Delete("b"); - Reopen(); - ASSERT_EQ("(->)(c->cv)", Contents()); - DelayMilliseconds(1000); // Wait for compaction to finish - ASSERT_EQ("(->)(c->cv)", Contents()); -} - -TEST(DBTest, ComparatorCheck) { - class NewComparator : public Comparator { - public: - virtual const char* Name() const { return "leveldb.NewComparator"; } - virtual int Compare(const Slice& a, const Slice& b) const { - return BytewiseComparator()->Compare(a, b); - } - virtual void FindShortestSeparator(std::string* s, const Slice& l) const { - BytewiseComparator()->FindShortestSeparator(s, l); - } - virtual void FindShortSuccessor(std::string* key) const { - BytewiseComparator()->FindShortSuccessor(key); - } - }; - NewComparator cmp; - Options new_options = CurrentOptions(); - new_options.comparator = &cmp; - Status s = TryReopen(&new_options); - ASSERT_TRUE(!s.ok()); - ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) - << s.ToString(); -} - -TEST(DBTest, CustomComparator) { - class NumberComparator : public Comparator { - public: - virtual const char* Name() const { return "test.NumberComparator"; } - virtual int Compare(const Slice& a, const Slice& b) const { - return ToNumber(a) - ToNumber(b); - } - virtual void FindShortestSeparator(std::string* s, const Slice& l) const { - ToNumber(*s); // Check format - ToNumber(l); // Check format - } - virtual void FindShortSuccessor(std::string* key) const { - ToNumber(*key); // Check format - } - private: - static int ToNumber(const Slice& x) { - // Check that there are no extra characters. - ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') - << EscapeString(x); - int val; - char ignored; - ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) - << EscapeString(x); - return val; - } - }; - NumberComparator cmp; - Options new_options = CurrentOptions(); - new_options.create_if_missing = true; - new_options.comparator = &cmp; - new_options.filter_policy = NULL; // Cannot use bloom filters - new_options.write_buffer_size = 1000; // Compact more often - DestroyAndReopen(&new_options); - ASSERT_OK(Put("[10]", "ten")); - ASSERT_OK(Put("[0x14]", "twenty")); - for (int i = 0; i < 2; i++) { - ASSERT_EQ("ten", Get("[10]")); - ASSERT_EQ("ten", Get("[0xa]")); - ASSERT_EQ("twenty", Get("[20]")); - ASSERT_EQ("twenty", Get("[0x14]")); - ASSERT_EQ("NOT_FOUND", Get("[15]")); - ASSERT_EQ("NOT_FOUND", Get("[0xf]")); - Compact("[0]", "[9999]"); - } - - for (int run = 0; run < 2; run++) { - for (int i = 0; i < 1000; i++) { - char buf[100]; - snprintf(buf, sizeof(buf), "[%d]", i*10); - ASSERT_OK(Put(buf, buf)); - } - Compact("[0]", "[1000000]"); - } -} - -TEST(DBTest, ManualCompaction) { - ASSERT_EQ(config::kMaxMemCompactLevel, 2) - << "Need to update this test to match kMaxMemCompactLevel"; - - MakeTables(3, "p", "q"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range falls before files - Compact("", "c"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range falls after files - Compact("r", "z"); - ASSERT_EQ("1,1,1", FilesPerLevel()); - - // Compaction range overlaps files - Compact("p1", "p9"); - ASSERT_EQ("0,0,1", FilesPerLevel()); - - // Populate a different range - MakeTables(3, "c", "e"); - ASSERT_EQ("1,1,2", FilesPerLevel()); - - // Compact just the new range - Compact("b", "f"); - ASSERT_EQ("0,0,2", FilesPerLevel()); - - // Compact all - MakeTables(1, "a", "z"); - ASSERT_EQ("0,1,2", FilesPerLevel()); - db_->CompactRange(NULL, NULL); - ASSERT_EQ("0,0,1", FilesPerLevel()); -} - -TEST(DBTest, DBOpen_Options) { - std::string dbname = test::TmpDir() + "/db_options_test"; - DestroyDB(dbname, Options()); - - // Does not exist, and create_if_missing == false: error - DB* db = NULL; - Options opts; - opts.create_if_missing = false; - Status s = DB::Open(opts, dbname, &db); - ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); - ASSERT_TRUE(db == NULL); - - // Does not exist, and create_if_missing == true: OK - opts.create_if_missing = true; - s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; - - // Does exist, and error_if_exists == true: error - opts.create_if_missing = false; - opts.error_if_exists = true; - s = DB::Open(opts, dbname, &db); - ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); - ASSERT_TRUE(db == NULL); - - // Does exist, and error_if_exists == false: OK - opts.create_if_missing = true; - opts.error_if_exists = false; - s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; -} - -TEST(DBTest, Locking) { - DB* db2 = NULL; - Status s = DB::Open(CurrentOptions(), dbname_, &db2); - ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; -} - -// Check that number of files does not grow when we are out of space -TEST(DBTest, NoSpace) { - Options options = CurrentOptions(); - options.env = env_; - Reopen(&options); - - ASSERT_OK(Put("foo", "v1")); - ASSERT_EQ("v1", Get("foo")); - Compact("a", "z"); - const int num_files = CountFiles(); - env_->no_space_.Release_Store(env_); // Force out-of-space errors - for (int i = 0; i < 10; i++) { - for (int level = 0; level < config::kNumLevels-1; level++) { - dbfull()->TEST_CompactRange(level, NULL, NULL); - } - } - env_->no_space_.Release_Store(NULL); - ASSERT_LT(CountFiles(), num_files + 3); -} - -TEST(DBTest, NonWritableFileSystem) { - Options options = CurrentOptions(); - options.write_buffer_size = 1000; - options.env = env_; - Reopen(&options); - ASSERT_OK(Put("foo", "v1")); - env_->non_writable_.Release_Store(env_); // Force errors for new files - std::string big(100000, 'x'); - int errors = 0; - for (int i = 0; i < 20; i++) { - fprintf(stderr, "iter %d; errors %d\n", i, errors); - if (!Put("foo", big).ok()) { - errors++; - DelayMilliseconds(100); - } - } - ASSERT_GT(errors, 0); - env_->non_writable_.Release_Store(NULL); -} - -TEST(DBTest, WriteSyncError) { - // Check that log sync errors cause the DB to disallow future writes. - - // (a) Cause log sync calls to fail - Options options = CurrentOptions(); - options.env = env_; - Reopen(&options); - env_->data_sync_error_.Release_Store(env_); - - // (b) Normal write should succeed - WriteOptions w; - ASSERT_OK(db_->Put(w, "k1", "v1")); - ASSERT_EQ("v1", Get("k1")); - - // (c) Do a sync write; should fail - w.sync = true; - ASSERT_TRUE(!db_->Put(w, "k2", "v2").ok()); - ASSERT_EQ("v1", Get("k1")); - ASSERT_EQ("NOT_FOUND", Get("k2")); - - // (d) make sync behave normally - env_->data_sync_error_.Release_Store(NULL); - - // (e) Do a non-sync write; should fail - w.sync = false; - ASSERT_TRUE(!db_->Put(w, "k3", "v3").ok()); - ASSERT_EQ("v1", Get("k1")); - ASSERT_EQ("NOT_FOUND", Get("k2")); - ASSERT_EQ("NOT_FOUND", Get("k3")); -} - -TEST(DBTest, ManifestWriteError) { - // Test for the following problem: - // (a) Compaction produces file F - // (b) Log record containing F is written to MANIFEST file, but Sync() fails - // (c) GC deletes F - // (d) After reopening DB, reads fail since deleted F is named in log record - - // We iterate twice. In the second iteration, everything is the - // same except the log record never makes it to the MANIFEST file. - for (int iter = 0; iter < 2; iter++) { - port::AtomicPointer* error_type = (iter == 0) - ? &env_->manifest_sync_error_ - : &env_->manifest_write_error_; - - // Insert foo=>bar mapping - Options options = CurrentOptions(); - options.env = env_; - options.create_if_missing = true; - options.error_if_exists = false; - DestroyAndReopen(&options); - ASSERT_OK(Put("foo", "bar")); - ASSERT_EQ("bar", Get("foo")); - - // Memtable compaction (will succeed) - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("bar", Get("foo")); - const int last = config::kMaxMemCompactLevel; - ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level - - // Merging compaction (will fail) - error_type->Release_Store(env_); - dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail - ASSERT_EQ("bar", Get("foo")); - - // Recovery: should not lose data - error_type->Release_Store(NULL); - Reopen(&options); - ASSERT_EQ("bar", Get("foo")); - } -} - -TEST(DBTest, MissingSSTFile) { - ASSERT_OK(Put("foo", "bar")); - ASSERT_EQ("bar", Get("foo")); - - // Dump the memtable to disk. - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("bar", Get("foo")); - - Close(); - ASSERT_TRUE(DeleteAnSSTFile()); - Options options = CurrentOptions(); - options.paranoid_checks = true; - Status s = TryReopen(&options); - ASSERT_TRUE(!s.ok()); - ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) - << s.ToString(); -} - -TEST(DBTest, StillReadSST) { - ASSERT_OK(Put("foo", "bar")); - ASSERT_EQ("bar", Get("foo")); - - // Dump the memtable to disk. - dbfull()->TEST_CompactMemTable(); - ASSERT_EQ("bar", Get("foo")); - Close(); - ASSERT_GT(RenameLDBToSST(), 0); - Options options = CurrentOptions(); - options.paranoid_checks = true; - Status s = TryReopen(&options); - ASSERT_TRUE(s.ok()); - ASSERT_EQ("bar", Get("foo")); -} - -TEST(DBTest, FilesDeletedAfterCompaction) { - ASSERT_OK(Put("foo", "v2")); - Compact("a", "z"); - const int num_files = CountFiles(); - for (int i = 0; i < 10; i++) { - ASSERT_OK(Put("foo", "v2")); - Compact("a", "z"); - } - ASSERT_EQ(CountFiles(), num_files); -} - -TEST(DBTest, BloomFilter) { - env_->count_random_reads_ = true; - Options options = CurrentOptions(); - options.env = env_; - options.block_cache = NewLRUCache(0); // Prevent cache hits - options.filter_policy = NewBloomFilterPolicy(10); - Reopen(&options); - - // Populate multiple layers - const int N = 10000; - for (int i = 0; i < N; i++) { - ASSERT_OK(Put(Key(i), Key(i))); - } - Compact("a", "z"); - for (int i = 0; i < N; i += 100) { - ASSERT_OK(Put(Key(i), Key(i))); - } - dbfull()->TEST_CompactMemTable(); - - // Prevent auto compactions triggered by seeks - env_->delay_data_sync_.Release_Store(env_); - - // Lookup present keys. Should rarely read from small sstable. - env_->random_read_counter_.Reset(); - for (int i = 0; i < N; i++) { - ASSERT_EQ(Key(i), Get(Key(i))); - } - int reads = env_->random_read_counter_.Read(); - fprintf(stderr, "%d present => %d reads\n", N, reads); - ASSERT_GE(reads, N); - ASSERT_LE(reads, N + 2*N/100); - - // Lookup present keys. Should rarely read from either sstable. - env_->random_read_counter_.Reset(); - for (int i = 0; i < N; i++) { - ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); - } - reads = env_->random_read_counter_.Read(); - fprintf(stderr, "%d missing => %d reads\n", N, reads); - ASSERT_LE(reads, 3*N/100); - - env_->delay_data_sync_.Release_Store(NULL); - Close(); - delete options.block_cache; - delete options.filter_policy; -} - -// Multi-threaded test: -namespace { - -static const int kNumThreads = 4; -static const int kTestSeconds = 10; -static const int kNumKeys = 1000; - -struct MTState { - DBTest* test; - port::AtomicPointer stop; - port::AtomicPointer counter[kNumThreads]; - port::AtomicPointer thread_done[kNumThreads]; -}; - -struct MTThread { - MTState* state; - int id; -}; - -static void MTThreadBody(void* arg) { - MTThread* t = reinterpret_cast(arg); - int id = t->id; - DB* db = t->state->test->db_; - uintptr_t counter = 0; - fprintf(stderr, "... starting thread %d\n", id); - Random rnd(1000 + id); - std::string value; - char valbuf[1500]; - while (t->state->stop.Acquire_Load() == NULL) { - t->state->counter[id].Release_Store(reinterpret_cast(counter)); - - int key = rnd.Uniform(kNumKeys); - char keybuf[20]; - snprintf(keybuf, sizeof(keybuf), "%016d", key); - - if (rnd.OneIn(2)) { - // Write values of the form . - // We add some padding for force compactions. - snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", - key, id, static_cast(counter)); - ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); - } else { - // Read a value and verify that it matches the pattern written above. - Status s = db->Get(ReadOptions(), Slice(keybuf), &value); - if (s.IsNotFound()) { - // Key has not yet been written - } else { - // Check that the writer thread counter is >= the counter in the value - ASSERT_OK(s); - int k, w, c; - ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; - ASSERT_EQ(k, key); - ASSERT_GE(w, 0); - ASSERT_LT(w, kNumThreads); - ASSERT_LE(static_cast(c), reinterpret_cast( - t->state->counter[w].Acquire_Load())); - } - } - counter++; - } - t->state->thread_done[id].Release_Store(t); - fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); -} - -} // namespace - -TEST(DBTest, MultiThreaded) { - do { - // Initialize state - MTState mt; - mt.test = this; - mt.stop.Release_Store(0); - for (int id = 0; id < kNumThreads; id++) { - mt.counter[id].Release_Store(0); - mt.thread_done[id].Release_Store(0); - } - - // Start threads - MTThread thread[kNumThreads]; - for (int id = 0; id < kNumThreads; id++) { - thread[id].state = &mt; - thread[id].id = id; - env_->StartThread(MTThreadBody, &thread[id]); - } - - // Let them run for a while - DelayMilliseconds(kTestSeconds * 1000); - - // Stop the threads and wait for them to finish - mt.stop.Release_Store(&mt); - for (int id = 0; id < kNumThreads; id++) { - while (mt.thread_done[id].Acquire_Load() == NULL) { - DelayMilliseconds(100); - } - } - } while (ChangeOptions()); -} - -namespace { -typedef std::map KVMap; -} - -class ModelDB: public DB { - public: - class ModelSnapshot : public Snapshot { - public: - KVMap map_; - }; - - explicit ModelDB(const Options& options): options_(options) { } - ~ModelDB() { } - virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { - return DB::Put(o, k, v); - } - virtual Status Delete(const WriteOptions& o, const Slice& key) { - return DB::Delete(o, key); - } - virtual Status Get(const ReadOptions& options, - const Slice& key, std::string* value) { - assert(false); // Not implemented - return Status::NotFound(key); - } - virtual Iterator* NewIterator(const ReadOptions& options) { - if (options.snapshot == NULL) { - KVMap* saved = new KVMap; - *saved = map_; - return new ModelIter(saved, true); - } else { - const KVMap* snapshot_state = - &(reinterpret_cast(options.snapshot)->map_); - return new ModelIter(snapshot_state, false); - } - } - virtual const Snapshot* GetSnapshot() { - ModelSnapshot* snapshot = new ModelSnapshot; - snapshot->map_ = map_; - return snapshot; - } - - virtual void ReleaseSnapshot(const Snapshot* snapshot) { - delete reinterpret_cast(snapshot); - } - virtual Status Write(const WriteOptions& options, WriteBatch* batch) { - class Handler : public WriteBatch::Handler { - public: - KVMap* map_; - virtual void Put(const Slice& key, const Slice& value) { - (*map_)[key.ToString()] = value.ToString(); - } - virtual void Delete(const Slice& key) { - map_->erase(key.ToString()); - } - }; - Handler handler; - handler.map_ = &map_; - return batch->Iterate(&handler); - } - - virtual bool GetProperty(const Slice& property, std::string* value) { - return false; - } - virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { - for (int i = 0; i < n; i++) { - sizes[i] = 0; - } - } - virtual void CompactRange(const Slice* start, const Slice* end) { - } - - private: - class ModelIter: public Iterator { - public: - ModelIter(const KVMap* map, bool owned) - : map_(map), owned_(owned), iter_(map_->end()) { - } - ~ModelIter() { - if (owned_) delete map_; - } - virtual bool Valid() const { return iter_ != map_->end(); } - virtual void SeekToFirst() { iter_ = map_->begin(); } - virtual void SeekToLast() { - if (map_->empty()) { - iter_ = map_->end(); - } else { - iter_ = map_->find(map_->rbegin()->first); - } - } - virtual void Seek(const Slice& k) { - iter_ = map_->lower_bound(k.ToString()); - } - virtual void Next() { ++iter_; } - virtual void Prev() { --iter_; } - virtual Slice key() const { return iter_->first; } - virtual Slice value() const { return iter_->second; } - virtual Status status() const { return Status::OK(); } - private: - const KVMap* const map_; - const bool owned_; // Do we own map_ - KVMap::const_iterator iter_; - }; - const Options options_; - KVMap map_; -}; - -static std::string RandomKey(Random* rnd) { - int len = (rnd->OneIn(3) - ? 1 // Short sometimes to encourage collisions - : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); - return test::RandomKey(rnd, len); -} - -static bool CompareIterators(int step, - DB* model, - DB* db, - const Snapshot* model_snap, - const Snapshot* db_snap) { - ReadOptions options; - options.snapshot = model_snap; - Iterator* miter = model->NewIterator(options); - options.snapshot = db_snap; - Iterator* dbiter = db->NewIterator(options); - bool ok = true; - int count = 0; - for (miter->SeekToFirst(), dbiter->SeekToFirst(); - ok && miter->Valid() && dbiter->Valid(); - miter->Next(), dbiter->Next()) { - count++; - if (miter->key().compare(dbiter->key()) != 0) { - fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", - step, - EscapeString(miter->key()).c_str(), - EscapeString(dbiter->key()).c_str()); - ok = false; - break; - } - - if (miter->value().compare(dbiter->value()) != 0) { - fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", - step, - EscapeString(miter->key()).c_str(), - EscapeString(miter->value()).c_str(), - EscapeString(miter->value()).c_str()); - ok = false; - } - } - - if (ok) { - if (miter->Valid() != dbiter->Valid()) { - fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", - step, miter->Valid(), dbiter->Valid()); - ok = false; - } - } - fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); - delete miter; - delete dbiter; - return ok; -} - -TEST(DBTest, Randomized) { - Random rnd(test::RandomSeed()); - do { - ModelDB model(CurrentOptions()); - const int N = 10000; - const Snapshot* model_snap = NULL; - const Snapshot* db_snap = NULL; - std::string k, v; - for (int step = 0; step < N; step++) { - if (step % 100 == 0) { - fprintf(stderr, "Step %d of %d\n", step, N); - } - // TODO(sanjay): Test Get() works - int p = rnd.Uniform(100); - if (p < 45) { // Put - k = RandomKey(&rnd); - v = RandomString(&rnd, - rnd.OneIn(20) - ? 100 + rnd.Uniform(100) - : rnd.Uniform(8)); - ASSERT_OK(model.Put(WriteOptions(), k, v)); - ASSERT_OK(db_->Put(WriteOptions(), k, v)); - - } else if (p < 90) { // Delete - k = RandomKey(&rnd); - ASSERT_OK(model.Delete(WriteOptions(), k)); - ASSERT_OK(db_->Delete(WriteOptions(), k)); - - - } else { // Multi-element batch - WriteBatch b; - const int num = rnd.Uniform(8); - for (int i = 0; i < num; i++) { - if (i == 0 || !rnd.OneIn(10)) { - k = RandomKey(&rnd); - } else { - // Periodically re-use the same key from the previous iter, so - // we have multiple entries in the write batch for the same key - } - if (rnd.OneIn(2)) { - v = RandomString(&rnd, rnd.Uniform(10)); - b.Put(k, v); - } else { - b.Delete(k); - } - } - ASSERT_OK(model.Write(WriteOptions(), &b)); - ASSERT_OK(db_->Write(WriteOptions(), &b)); - } - - if ((step % 100) == 0) { - ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); - ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); - // Save a snapshot from each DB this time that we'll use next - // time we compare things, to make sure the current state is - // preserved with the snapshot - if (model_snap != NULL) model.ReleaseSnapshot(model_snap); - if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); - - Reopen(); - ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); - - model_snap = model.GetSnapshot(); - db_snap = db_->GetSnapshot(); - } - } - if (model_snap != NULL) model.ReleaseSnapshot(model_snap); - if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); - } while (ChangeOptions()); -} - -std::string MakeKey(unsigned int num) { - char buf[30]; - snprintf(buf, sizeof(buf), "%016u", num); - return std::string(buf); -} - -void BM_LogAndApply(int iters, int num_base_files) { - std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; - DestroyDB(dbname, Options()); - - DB* db = NULL; - Options opts; - opts.create_if_missing = true; - Status s = DB::Open(opts, dbname, &db); - ASSERT_OK(s); - ASSERT_TRUE(db != NULL); - - delete db; - db = NULL; - - Env* env = Env::Default(); - - port::Mutex mu; - MutexLock l(&mu); - - InternalKeyComparator cmp(BytewiseComparator()); - Options options; - VersionSet vset(dbname, &options, NULL, &cmp); - ASSERT_OK(vset.Recover()); - VersionEdit vbase; - uint64_t fnum = 1; - for (int i = 0; i < num_base_files; i++) { - InternalKey start(MakeKey(2*fnum), 1, kTypeValue); - InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); - vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); - } - ASSERT_OK(vset.LogAndApply(&vbase, &mu)); - - uint64_t start_micros = env->NowMicros(); - - for (int i = 0; i < iters; i++) { - VersionEdit vedit; - vedit.DeleteFile(2, fnum); - InternalKey start(MakeKey(2*fnum), 1, kTypeValue); - InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); - vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); - vset.LogAndApply(&vedit, &mu); - } - uint64_t stop_micros = env->NowMicros(); - unsigned int us = stop_micros - start_micros; - char buf[16]; - snprintf(buf, sizeof(buf), "%d", num_base_files); - fprintf(stderr, - "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", - buf, iters, us, ((float)us) / iters); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - if (argc > 1 && std::string(argv[1]) == "--benchmark") { - leveldb::BM_LogAndApply(1000, 1); - leveldb::BM_LogAndApply(1000, 100); - leveldb::BM_LogAndApply(1000, 10000); - leveldb::BM_LogAndApply(100, 100000); - return 0; - } - - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/dbformat.cc b/src/leveldb/db/dbformat.cc deleted file mode 100644 index 20a7ca4462..0000000000 --- a/src/leveldb/db/dbformat.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "db/dbformat.h" -#include "port/port.h" -#include "util/coding.h" - -namespace leveldb { - -static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { - assert(seq <= kMaxSequenceNumber); - assert(t <= kValueTypeForSeek); - return (seq << 8) | t; -} - -void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { - result->append(key.user_key.data(), key.user_key.size()); - PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); -} - -std::string ParsedInternalKey::DebugString() const { - char buf[50]; - snprintf(buf, sizeof(buf), "' @ %llu : %d", - (unsigned long long) sequence, - int(type)); - std::string result = "'"; - result += EscapeString(user_key.ToString()); - result += buf; - return result; -} - -std::string InternalKey::DebugString() const { - std::string result; - ParsedInternalKey parsed; - if (ParseInternalKey(rep_, &parsed)) { - result = parsed.DebugString(); - } else { - result = "(bad)"; - result.append(EscapeString(rep_)); - } - return result; -} - -const char* InternalKeyComparator::Name() const { - return "leveldb.InternalKeyComparator"; -} - -int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { - // Order by: - // increasing user key (according to user-supplied comparator) - // decreasing sequence number - // decreasing type (though sequence# should be enough to disambiguate) - int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); - if (r == 0) { - const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); - const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); - if (anum > bnum) { - r = -1; - } else if (anum < bnum) { - r = +1; - } - } - return r; -} - -void InternalKeyComparator::FindShortestSeparator( - std::string* start, - const Slice& limit) const { - // Attempt to shorten the user portion of the key - Slice user_start = ExtractUserKey(*start); - Slice user_limit = ExtractUserKey(limit); - std::string tmp(user_start.data(), user_start.size()); - user_comparator_->FindShortestSeparator(&tmp, user_limit); - if (tmp.size() < user_start.size() && - user_comparator_->Compare(user_start, tmp) < 0) { - // User key has become shorter physically, but larger logically. - // Tack on the earliest possible number to the shortened user key. - PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); - assert(this->Compare(*start, tmp) < 0); - assert(this->Compare(tmp, limit) < 0); - start->swap(tmp); - } -} - -void InternalKeyComparator::FindShortSuccessor(std::string* key) const { - Slice user_key = ExtractUserKey(*key); - std::string tmp(user_key.data(), user_key.size()); - user_comparator_->FindShortSuccessor(&tmp); - if (tmp.size() < user_key.size() && - user_comparator_->Compare(user_key, tmp) < 0) { - // User key has become shorter physically, but larger logically. - // Tack on the earliest possible number to the shortened user key. - PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); - assert(this->Compare(*key, tmp) < 0); - key->swap(tmp); - } -} - -const char* InternalFilterPolicy::Name() const { - return user_policy_->Name(); -} - -void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, - std::string* dst) const { - // We rely on the fact that the code in table.cc does not mind us - // adjusting keys[]. - Slice* mkey = const_cast(keys); - for (int i = 0; i < n; i++) { - mkey[i] = ExtractUserKey(keys[i]); - // TODO(sanjay): Suppress dups? - } - user_policy_->CreateFilter(keys, n, dst); -} - -bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { - return user_policy_->KeyMayMatch(ExtractUserKey(key), f); -} - -LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { - size_t usize = user_key.size(); - size_t needed = usize + 13; // A conservative estimate - char* dst; - if (needed <= sizeof(space_)) { - dst = space_; - } else { - dst = new char[needed]; - } - start_ = dst; - dst = EncodeVarint32(dst, usize + 8); - kstart_ = dst; - memcpy(dst, user_key.data(), usize); - dst += usize; - EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); - dst += 8; - end_ = dst; -} - -} // namespace leveldb diff --git a/src/leveldb/db/dbformat.h b/src/leveldb/db/dbformat.h deleted file mode 100644 index ea897b13c0..0000000000 --- a/src/leveldb/db/dbformat.h +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_ -#define STORAGE_LEVELDB_DB_DBFORMAT_H_ - -#include -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/filter_policy.h" -#include "leveldb/slice.h" -#include "leveldb/table_builder.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -// Grouping of constants. We may want to make some of these -// parameters set via options. -namespace config { -static const int kNumLevels = 7; - -// Level-0 compaction is started when we hit this many files. -static const int kL0_CompactionTrigger = 4; - -// Soft limit on number of level-0 files. We slow down writes at this point. -static const int kL0_SlowdownWritesTrigger = 8; - -// Maximum number of level-0 files. We stop writes at this point. -static const int kL0_StopWritesTrigger = 12; - -// Maximum level to which a new compacted memtable is pushed if it -// does not create overlap. We try to push to level 2 to avoid the -// relatively expensive level 0=>1 compactions and to avoid some -// expensive manifest file operations. We do not push all the way to -// the largest level since that can generate a lot of wasted disk -// space if the same key space is being repeatedly overwritten. -static const int kMaxMemCompactLevel = 2; - -// Approximate gap in bytes between samples of data read during iteration. -static const int kReadBytesPeriod = 1048576; - -} // namespace config - -class InternalKey; - -// Value types encoded as the last component of internal keys. -// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk -// data structures. -enum ValueType { - kTypeDeletion = 0x0, - kTypeValue = 0x1 -}; -// kValueTypeForSeek defines the ValueType that should be passed when -// constructing a ParsedInternalKey object for seeking to a particular -// sequence number (since we sort sequence numbers in decreasing order -// and the value type is embedded as the low 8 bits in the sequence -// number in internal keys, we need to use the highest-numbered -// ValueType, not the lowest). -static const ValueType kValueTypeForSeek = kTypeValue; - -typedef uint64_t SequenceNumber; - -// We leave eight bits empty at the bottom so a type and sequence# -// can be packed together into 64-bits. -static const SequenceNumber kMaxSequenceNumber = - ((0x1ull << 56) - 1); - -struct ParsedInternalKey { - Slice user_key; - SequenceNumber sequence; - ValueType type; - - ParsedInternalKey() { } // Intentionally left uninitialized (for speed) - ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) - : user_key(u), sequence(seq), type(t) { } - std::string DebugString() const; -}; - -// Return the length of the encoding of "key". -inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { - return key.user_key.size() + 8; -} - -// Append the serialization of "key" to *result. -extern void AppendInternalKey(std::string* result, - const ParsedInternalKey& key); - -// Attempt to parse an internal key from "internal_key". On success, -// stores the parsed data in "*result", and returns true. -// -// On error, returns false, leaves "*result" in an undefined state. -extern bool ParseInternalKey(const Slice& internal_key, - ParsedInternalKey* result); - -// Returns the user key portion of an internal key. -inline Slice ExtractUserKey(const Slice& internal_key) { - assert(internal_key.size() >= 8); - return Slice(internal_key.data(), internal_key.size() - 8); -} - -inline ValueType ExtractValueType(const Slice& internal_key) { - assert(internal_key.size() >= 8); - const size_t n = internal_key.size(); - uint64_t num = DecodeFixed64(internal_key.data() + n - 8); - unsigned char c = num & 0xff; - return static_cast(c); -} - -// A comparator for internal keys that uses a specified comparator for -// the user key portion and breaks ties by decreasing sequence number. -class InternalKeyComparator : public Comparator { - private: - const Comparator* user_comparator_; - public: - explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } - virtual const char* Name() const; - virtual int Compare(const Slice& a, const Slice& b) const; - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const; - virtual void FindShortSuccessor(std::string* key) const; - - const Comparator* user_comparator() const { return user_comparator_; } - - int Compare(const InternalKey& a, const InternalKey& b) const; -}; - -// Filter policy wrapper that converts from internal keys to user keys -class InternalFilterPolicy : public FilterPolicy { - private: - const FilterPolicy* const user_policy_; - public: - explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } - virtual const char* Name() const; - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; -}; - -// Modules in this directory should keep internal keys wrapped inside -// the following class instead of plain strings so that we do not -// incorrectly use string comparisons instead of an InternalKeyComparator. -class InternalKey { - private: - std::string rep_; - public: - InternalKey() { } // Leave rep_ as empty to indicate it is invalid - InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { - AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); - } - - void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } - Slice Encode() const { - assert(!rep_.empty()); - return rep_; - } - - Slice user_key() const { return ExtractUserKey(rep_); } - - void SetFrom(const ParsedInternalKey& p) { - rep_.clear(); - AppendInternalKey(&rep_, p); - } - - void Clear() { rep_.clear(); } - - std::string DebugString() const; -}; - -inline int InternalKeyComparator::Compare( - const InternalKey& a, const InternalKey& b) const { - return Compare(a.Encode(), b.Encode()); -} - -inline bool ParseInternalKey(const Slice& internal_key, - ParsedInternalKey* result) { - const size_t n = internal_key.size(); - if (n < 8) return false; - uint64_t num = DecodeFixed64(internal_key.data() + n - 8); - unsigned char c = num & 0xff; - result->sequence = num >> 8; - result->type = static_cast(c); - result->user_key = Slice(internal_key.data(), n - 8); - return (c <= static_cast(kTypeValue)); -} - -// A helper class useful for DBImpl::Get() -class LookupKey { - public: - // Initialize *this for looking up user_key at a snapshot with - // the specified sequence number. - LookupKey(const Slice& user_key, SequenceNumber sequence); - - ~LookupKey(); - - // Return a key suitable for lookup in a MemTable. - Slice memtable_key() const { return Slice(start_, end_ - start_); } - - // Return an internal key (suitable for passing to an internal iterator) - Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } - - // Return the user key - Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } - - private: - // We construct a char array of the form: - // klength varint32 <-- start_ - // userkey char[klength] <-- kstart_ - // tag uint64 - // <-- end_ - // The array is a suitable MemTable key. - // The suffix starting with "userkey" can be used as an InternalKey. - const char* start_; - const char* kstart_; - const char* end_; - char space_[200]; // Avoid allocation for short keys - - // No copying allowed - LookupKey(const LookupKey&); - void operator=(const LookupKey&); -}; - -inline LookupKey::~LookupKey() { - if (start_ != space_) delete[] start_; -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_DBFORMAT_H_ diff --git a/src/leveldb/db/dbformat_test.cc b/src/leveldb/db/dbformat_test.cc deleted file mode 100644 index 5d82f5d313..0000000000 --- a/src/leveldb/db/dbformat_test.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/dbformat.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -static std::string IKey(const std::string& user_key, - uint64_t seq, - ValueType vt) { - std::string encoded; - AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); - return encoded; -} - -static std::string Shorten(const std::string& s, const std::string& l) { - std::string result = s; - InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); - return result; -} - -static std::string ShortSuccessor(const std::string& s) { - std::string result = s; - InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); - return result; -} - -static void TestKey(const std::string& key, - uint64_t seq, - ValueType vt) { - std::string encoded = IKey(key, seq, vt); - - Slice in(encoded); - ParsedInternalKey decoded("", 0, kTypeValue); - - ASSERT_TRUE(ParseInternalKey(in, &decoded)); - ASSERT_EQ(key, decoded.user_key.ToString()); - ASSERT_EQ(seq, decoded.sequence); - ASSERT_EQ(vt, decoded.type); - - ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); -} - -class FormatTest { }; - -TEST(FormatTest, InternalKey_EncodeDecode) { - const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; - const uint64_t seq[] = { - 1, 2, 3, - (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, - (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, - (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 - }; - for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { - for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { - TestKey(keys[k], seq[s], kTypeValue); - TestKey("hello", 1, kTypeDeletion); - } - } -} - -TEST(FormatTest, InternalKeyShortSeparator) { - // When user keys are same - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 99, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 101, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 100, kTypeValue))); - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foo", 100, kTypeDeletion))); - - // When user keys are misordered - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("bar", 99, kTypeValue))); - - // When user keys are different, but correctly ordered - ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), - Shorten(IKey("foo", 100, kTypeValue), - IKey("hello", 200, kTypeValue))); - - // When start user key is prefix of limit user key - ASSERT_EQ(IKey("foo", 100, kTypeValue), - Shorten(IKey("foo", 100, kTypeValue), - IKey("foobar", 200, kTypeValue))); - - // When limit user key is prefix of start user key - ASSERT_EQ(IKey("foobar", 100, kTypeValue), - Shorten(IKey("foobar", 100, kTypeValue), - IKey("foo", 200, kTypeValue))); -} - -TEST(FormatTest, InternalKeyShortestSuccessor) { - ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), - ShortSuccessor(IKey("foo", 100, kTypeValue))); - ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), - ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/dumpfile.cc b/src/leveldb/db/dumpfile.cc deleted file mode 100644 index 61c47c2ff9..0000000000 --- a/src/leveldb/db/dumpfile.cc +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/version_edit.h" -#include "db/write_batch_internal.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "leveldb/options.h" -#include "leveldb/status.h" -#include "leveldb/table.h" -#include "leveldb/write_batch.h" -#include "util/logging.h" - -namespace leveldb { - -namespace { - -bool GuessType(const std::string& fname, FileType* type) { - size_t pos = fname.rfind('/'); - std::string basename; - if (pos == std::string::npos) { - basename = fname; - } else { - basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); - } - uint64_t ignored; - return ParseFileName(basename, &ignored, type); -} - -// Notified when log reader encounters corruption. -class CorruptionReporter : public log::Reader::Reporter { - public: - WritableFile* dst_; - virtual void Corruption(size_t bytes, const Status& status) { - std::string r = "corruption: "; - AppendNumberTo(&r, bytes); - r += " bytes; "; - r += status.ToString(); - r.push_back('\n'); - dst_->Append(r); - } -}; - -// Print contents of a log file. (*func)() is called on every record. -Status PrintLogContents(Env* env, const std::string& fname, - void (*func)(uint64_t, Slice, WritableFile*), - WritableFile* dst) { - SequentialFile* file; - Status s = env->NewSequentialFile(fname, &file); - if (!s.ok()) { - return s; - } - CorruptionReporter reporter; - reporter.dst_ = dst; - log::Reader reader(file, &reporter, true, 0); - Slice record; - std::string scratch; - while (reader.ReadRecord(&record, &scratch)) { - (*func)(reader.LastRecordOffset(), record, dst); - } - delete file; - return Status::OK(); -} - -// Called on every item found in a WriteBatch. -class WriteBatchItemPrinter : public WriteBatch::Handler { - public: - WritableFile* dst_; - virtual void Put(const Slice& key, const Slice& value) { - std::string r = " put '"; - AppendEscapedStringTo(&r, key); - r += "' '"; - AppendEscapedStringTo(&r, value); - r += "'\n"; - dst_->Append(r); - } - virtual void Delete(const Slice& key) { - std::string r = " del '"; - AppendEscapedStringTo(&r, key); - r += "'\n"; - dst_->Append(r); - } -}; - - -// Called on every log record (each one of which is a WriteBatch) -// found in a kLogFile. -static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) { - std::string r = "--- offset "; - AppendNumberTo(&r, pos); - r += "; "; - if (record.size() < 12) { - r += "log record length "; - AppendNumberTo(&r, record.size()); - r += " is too small\n"; - dst->Append(r); - return; - } - WriteBatch batch; - WriteBatchInternal::SetContents(&batch, record); - r += "sequence "; - AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch)); - r.push_back('\n'); - dst->Append(r); - WriteBatchItemPrinter batch_item_printer; - batch_item_printer.dst_ = dst; - Status s = batch.Iterate(&batch_item_printer); - if (!s.ok()) { - dst->Append(" error: " + s.ToString() + "\n"); - } -} - -Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) { - return PrintLogContents(env, fname, WriteBatchPrinter, dst); -} - -// Called on every log record (each one of which is a WriteBatch) -// found in a kDescriptorFile. -static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) { - std::string r = "--- offset "; - AppendNumberTo(&r, pos); - r += "; "; - VersionEdit edit; - Status s = edit.DecodeFrom(record); - if (!s.ok()) { - r += s.ToString(); - r.push_back('\n'); - } else { - r += edit.DebugString(); - } - dst->Append(r); -} - -Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) { - return PrintLogContents(env, fname, VersionEditPrinter, dst); -} - -Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) { - uint64_t file_size; - RandomAccessFile* file = NULL; - Table* table = NULL; - Status s = env->GetFileSize(fname, &file_size); - if (s.ok()) { - s = env->NewRandomAccessFile(fname, &file); - } - if (s.ok()) { - // We use the default comparator, which may or may not match the - // comparator used in this database. However this should not cause - // problems since we only use Table operations that do not require - // any comparisons. In particular, we do not call Seek or Prev. - s = Table::Open(Options(), file, file_size, &table); - } - if (!s.ok()) { - delete table; - delete file; - return s; - } - - ReadOptions ro; - ro.fill_cache = false; - Iterator* iter = table->NewIterator(ro); - std::string r; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - r.clear(); - ParsedInternalKey key; - if (!ParseInternalKey(iter->key(), &key)) { - r = "badkey '"; - AppendEscapedStringTo(&r, iter->key()); - r += "' => '"; - AppendEscapedStringTo(&r, iter->value()); - r += "'\n"; - dst->Append(r); - } else { - r = "'"; - AppendEscapedStringTo(&r, key.user_key); - r += "' @ "; - AppendNumberTo(&r, key.sequence); - r += " : "; - if (key.type == kTypeDeletion) { - r += "del"; - } else if (key.type == kTypeValue) { - r += "val"; - } else { - AppendNumberTo(&r, key.type); - } - r += " => '"; - AppendEscapedStringTo(&r, iter->value()); - r += "'\n"; - dst->Append(r); - } - } - s = iter->status(); - if (!s.ok()) { - dst->Append("iterator error: " + s.ToString() + "\n"); - } - - delete iter; - delete table; - delete file; - return Status::OK(); -} - -} // namespace - -Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) { - FileType ftype; - if (!GuessType(fname, &ftype)) { - return Status::InvalidArgument(fname + ": unknown file type"); - } - switch (ftype) { - case kLogFile: return DumpLog(env, fname, dst); - case kDescriptorFile: return DumpDescriptor(env, fname, dst); - case kTableFile: return DumpTable(env, fname, dst); - default: - break; - } - return Status::InvalidArgument(fname + ": not a dump-able file type"); -} - -} // namespace leveldb diff --git a/src/leveldb/db/fault_injection_test.cc b/src/leveldb/db/fault_injection_test.cc deleted file mode 100644 index 875dfe81ee..0000000000 --- a/src/leveldb/db/fault_injection_test.cc +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright 2014 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// This test uses a custom Env to keep track of the state of a filesystem as of -// the last "sync". It then checks for data loss errors by purposely dropping -// file data (or entire files) not protected by a "sync". - -#include "leveldb/db.h" - -#include -#include -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/log_format.h" -#include "db/version_set.h" -#include "leveldb/cache.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "leveldb/write_batch.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static const int kValueSize = 1000; -static const int kMaxNumValues = 2000; -static const size_t kNumIterations = 3; - -class FaultInjectionTestEnv; - -namespace { - -// Assume a filename, and not a directory name like "/foo/bar/" -static std::string GetDirName(const std::string filename) { - size_t found = filename.find_last_of("/\\"); - if (found == std::string::npos) { - return ""; - } else { - return filename.substr(0, found); - } -} - -Status SyncDir(const std::string& dir) { - // As this is a test it isn't required to *actually* sync this directory. - return Status::OK(); -} - -// A basic file truncation function suitable for this test. -Status Truncate(const std::string& filename, uint64_t length) { - leveldb::Env* env = leveldb::Env::Default(); - - SequentialFile* orig_file; - Status s = env->NewSequentialFile(filename, &orig_file); - if (!s.ok()) - return s; - - char* scratch = new char[length]; - leveldb::Slice result; - s = orig_file->Read(length, &result, scratch); - delete orig_file; - if (s.ok()) { - std::string tmp_name = GetDirName(filename) + "/truncate.tmp"; - WritableFile* tmp_file; - s = env->NewWritableFile(tmp_name, &tmp_file); - if (s.ok()) { - s = tmp_file->Append(result); - delete tmp_file; - if (s.ok()) { - s = env->RenameFile(tmp_name, filename); - } else { - env->DeleteFile(tmp_name); - } - } - } - - delete[] scratch; - - return s; -} - -struct FileState { - std::string filename_; - ssize_t pos_; - ssize_t pos_at_last_sync_; - ssize_t pos_at_last_flush_; - - FileState(const std::string& filename) - : filename_(filename), - pos_(-1), - pos_at_last_sync_(-1), - pos_at_last_flush_(-1) { } - - FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {} - - bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; } - - Status DropUnsyncedData() const; -}; - -} // anonymous namespace - -// A wrapper around WritableFile which informs another Env whenever this file -// is written to or sync'ed. -class TestWritableFile : public WritableFile { - public: - TestWritableFile(const FileState& state, - WritableFile* f, - FaultInjectionTestEnv* env); - virtual ~TestWritableFile(); - virtual Status Append(const Slice& data); - virtual Status Close(); - virtual Status Flush(); - virtual Status Sync(); - - private: - FileState state_; - WritableFile* target_; - bool writable_file_opened_; - FaultInjectionTestEnv* env_; - - Status SyncParent(); -}; - -class FaultInjectionTestEnv : public EnvWrapper { - public: - FaultInjectionTestEnv() : EnvWrapper(Env::Default()), filesystem_active_(true) {} - virtual ~FaultInjectionTestEnv() { } - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result); - virtual Status NewAppendableFile(const std::string& fname, - WritableFile** result); - virtual Status DeleteFile(const std::string& f); - virtual Status RenameFile(const std::string& s, const std::string& t); - - void WritableFileClosed(const FileState& state); - Status DropUnsyncedFileData(); - Status DeleteFilesCreatedAfterLastDirSync(); - void DirWasSynced(); - bool IsFileCreatedSinceLastDirSync(const std::string& filename); - void ResetState(); - void UntrackFile(const std::string& f); - // Setting the filesystem to inactive is the test equivalent to simulating a - // system reset. Setting to inactive will freeze our saved filesystem state so - // that it will stop being recorded. It can then be reset back to the state at - // the time of the reset. - bool IsFilesystemActive() const { return filesystem_active_; } - void SetFilesystemActive(bool active) { filesystem_active_ = active; } - - private: - port::Mutex mutex_; - std::map db_file_state_; - std::set new_files_since_last_dir_sync_; - bool filesystem_active_; // Record flushes, syncs, writes -}; - -TestWritableFile::TestWritableFile(const FileState& state, - WritableFile* f, - FaultInjectionTestEnv* env) - : state_(state), - target_(f), - writable_file_opened_(true), - env_(env) { - assert(f != NULL); -} - -TestWritableFile::~TestWritableFile() { - if (writable_file_opened_) { - Close(); - } - delete target_; -} - -Status TestWritableFile::Append(const Slice& data) { - Status s = target_->Append(data); - if (s.ok() && env_->IsFilesystemActive()) { - state_.pos_ += data.size(); - } - return s; -} - -Status TestWritableFile::Close() { - writable_file_opened_ = false; - Status s = target_->Close(); - if (s.ok()) { - env_->WritableFileClosed(state_); - } - return s; -} - -Status TestWritableFile::Flush() { - Status s = target_->Flush(); - if (s.ok() && env_->IsFilesystemActive()) { - state_.pos_at_last_flush_ = state_.pos_; - } - return s; -} - -Status TestWritableFile::SyncParent() { - Status s = SyncDir(GetDirName(state_.filename_)); - if (s.ok()) { - env_->DirWasSynced(); - } - return s; -} - -Status TestWritableFile::Sync() { - if (!env_->IsFilesystemActive()) { - return Status::OK(); - } - // Ensure new files referred to by the manifest are in the filesystem. - Status s = target_->Sync(); - if (s.ok()) { - state_.pos_at_last_sync_ = state_.pos_; - } - if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) { - Status ps = SyncParent(); - if (s.ok() && !ps.ok()) { - s = ps; - } - } - return s; -} - -Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname, - WritableFile** result) { - WritableFile* actual_writable_file; - Status s = target()->NewWritableFile(fname, &actual_writable_file); - if (s.ok()) { - FileState state(fname); - state.pos_ = 0; - *result = new TestWritableFile(state, actual_writable_file, this); - // NewWritableFile doesn't append to files, so if the same file is - // opened again then it will be truncated - so forget our saved - // state. - UntrackFile(fname); - MutexLock l(&mutex_); - new_files_since_last_dir_sync_.insert(fname); - } - return s; -} - -Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname, - WritableFile** result) { - WritableFile* actual_writable_file; - Status s = target()->NewAppendableFile(fname, &actual_writable_file); - if (s.ok()) { - FileState state(fname); - state.pos_ = 0; - { - MutexLock l(&mutex_); - if (db_file_state_.count(fname) == 0) { - new_files_since_last_dir_sync_.insert(fname); - } else { - state = db_file_state_[fname]; - } - } - *result = new TestWritableFile(state, actual_writable_file, this); - } - return s; -} - -Status FaultInjectionTestEnv::DropUnsyncedFileData() { - Status s; - MutexLock l(&mutex_); - for (std::map::const_iterator it = - db_file_state_.begin(); - s.ok() && it != db_file_state_.end(); ++it) { - const FileState& state = it->second; - if (!state.IsFullySynced()) { - s = state.DropUnsyncedData(); - } - } - return s; -} - -void FaultInjectionTestEnv::DirWasSynced() { - MutexLock l(&mutex_); - new_files_since_last_dir_sync_.clear(); -} - -bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync( - const std::string& filename) { - MutexLock l(&mutex_); - return new_files_since_last_dir_sync_.find(filename) != - new_files_since_last_dir_sync_.end(); -} - -void FaultInjectionTestEnv::UntrackFile(const std::string& f) { - MutexLock l(&mutex_); - db_file_state_.erase(f); - new_files_since_last_dir_sync_.erase(f); -} - -Status FaultInjectionTestEnv::DeleteFile(const std::string& f) { - Status s = EnvWrapper::DeleteFile(f); - ASSERT_OK(s); - if (s.ok()) { - UntrackFile(f); - } - return s; -} - -Status FaultInjectionTestEnv::RenameFile(const std::string& s, - const std::string& t) { - Status ret = EnvWrapper::RenameFile(s, t); - - if (ret.ok()) { - MutexLock l(&mutex_); - if (db_file_state_.find(s) != db_file_state_.end()) { - db_file_state_[t] = db_file_state_[s]; - db_file_state_.erase(s); - } - - if (new_files_since_last_dir_sync_.erase(s) != 0) { - assert(new_files_since_last_dir_sync_.find(t) == - new_files_since_last_dir_sync_.end()); - new_files_since_last_dir_sync_.insert(t); - } - } - - return ret; -} - -void FaultInjectionTestEnv::ResetState() { - // Since we are not destroying the database, the existing files - // should keep their recorded synced/flushed state. Therefore - // we do not reset db_file_state_ and new_files_since_last_dir_sync_. - MutexLock l(&mutex_); - SetFilesystemActive(true); -} - -Status FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() { - // Because DeleteFile access this container make a copy to avoid deadlock - mutex_.Lock(); - std::set new_files(new_files_since_last_dir_sync_.begin(), - new_files_since_last_dir_sync_.end()); - mutex_.Unlock(); - Status s; - std::set::const_iterator it; - for (it = new_files.begin(); s.ok() && it != new_files.end(); ++it) { - s = DeleteFile(*it); - } - return s; -} - -void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) { - MutexLock l(&mutex_); - db_file_state_[state.filename_] = state; -} - -Status FileState::DropUnsyncedData() const { - ssize_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_; - return Truncate(filename_, sync_pos); -} - -class FaultInjectionTest { - public: - enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR }; - enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES }; - - FaultInjectionTestEnv* env_; - std::string dbname_; - Cache* tiny_cache_; - Options options_; - DB* db_; - - FaultInjectionTest() - : env_(new FaultInjectionTestEnv), - tiny_cache_(NewLRUCache(100)), - db_(NULL) { - dbname_ = test::TmpDir() + "/fault_test"; - DestroyDB(dbname_, Options()); // Destroy any db from earlier run - options_.reuse_logs = true; - options_.env = env_; - options_.paranoid_checks = true; - options_.block_cache = tiny_cache_; - options_.create_if_missing = true; - } - - ~FaultInjectionTest() { - CloseDB(); - DestroyDB(dbname_, Options()); - delete tiny_cache_; - delete env_; - } - - void ReuseLogs(bool reuse) { - options_.reuse_logs = reuse; - } - - void Build(int start_idx, int num_vals) { - std::string key_space, value_space; - WriteBatch batch; - for (int i = start_idx; i < start_idx + num_vals; i++) { - Slice key = Key(i, &key_space); - batch.Clear(); - batch.Put(key, Value(i, &value_space)); - WriteOptions options; - ASSERT_OK(db_->Write(options, &batch)); - } - } - - Status ReadValue(int i, std::string* val) const { - std::string key_space, value_space; - Slice key = Key(i, &key_space); - Value(i, &value_space); - ReadOptions options; - return db_->Get(options, key, val); - } - - Status Verify(int start_idx, int num_vals, - ExpectedVerifResult expected) const { - std::string val; - std::string value_space; - Status s; - for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) { - Value(i, &value_space); - s = ReadValue(i, &val); - if (expected == VAL_EXPECT_NO_ERROR) { - if (s.ok()) { - ASSERT_EQ(value_space, val); - } - } else if (s.ok()) { - fprintf(stderr, "Expected an error at %d, but was OK\n", i); - s = Status::IOError(dbname_, "Expected value error:"); - } else { - s = Status::OK(); // An expected error - } - } - return s; - } - - // Return the ith key - Slice Key(int i, std::string* storage) const { - char buf[100]; - snprintf(buf, sizeof(buf), "%016d", i); - storage->assign(buf, strlen(buf)); - return Slice(*storage); - } - - // Return the value to associate with the specified key - Slice Value(int k, std::string* storage) const { - Random r(k); - return test::RandomString(&r, kValueSize, storage); - } - - Status OpenDB() { - delete db_; - db_ = NULL; - env_->ResetState(); - return DB::Open(options_, dbname_, &db_); - } - - void CloseDB() { - delete db_; - db_ = NULL; - } - - void DeleteAllData() { - Iterator* iter = db_->NewIterator(ReadOptions()); - WriteOptions options; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ASSERT_OK(db_->Delete(WriteOptions(), iter->key())); - } - - delete iter; - } - - void ResetDBState(ResetMethod reset_method) { - switch (reset_method) { - case RESET_DROP_UNSYNCED_DATA: - ASSERT_OK(env_->DropUnsyncedFileData()); - break; - case RESET_DELETE_UNSYNCED_FILES: - ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync()); - break; - default: - assert(false); - } - } - - void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) { - DeleteAllData(); - Build(0, num_pre_sync); - db_->CompactRange(NULL, NULL); - Build(num_pre_sync, num_post_sync); - } - - void PartialCompactTestReopenWithFault(ResetMethod reset_method, - int num_pre_sync, - int num_post_sync) { - env_->SetFilesystemActive(false); - CloseDB(); - ResetDBState(reset_method); - ASSERT_OK(OpenDB()); - ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR)); - ASSERT_OK(Verify(num_pre_sync, num_post_sync, FaultInjectionTest::VAL_EXPECT_ERROR)); - } - - void NoWriteTestPreFault() { - } - - void NoWriteTestReopenWithFault(ResetMethod reset_method) { - CloseDB(); - ResetDBState(reset_method); - ASSERT_OK(OpenDB()); - } - - void DoTest() { - Random rnd(0); - ASSERT_OK(OpenDB()); - for (size_t idx = 0; idx < kNumIterations; idx++) { - int num_pre_sync = rnd.Uniform(kMaxNumValues); - int num_post_sync = rnd.Uniform(kMaxNumValues); - - PartialCompactTestPreFault(num_pre_sync, num_post_sync); - PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA, - num_pre_sync, - num_post_sync); - - NoWriteTestPreFault(); - NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA); - - PartialCompactTestPreFault(num_pre_sync, num_post_sync); - // No new files created so we expect all values since no files will be - // dropped. - PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES, - num_pre_sync + num_post_sync, - 0); - - NoWriteTestPreFault(); - NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES); - } - } -}; - -TEST(FaultInjectionTest, FaultTestNoLogReuse) { - ReuseLogs(false); - DoTest(); -} - -TEST(FaultInjectionTest, FaultTestWithLogReuse) { - ReuseLogs(true); - DoTest(); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/filename.cc b/src/leveldb/db/filename.cc deleted file mode 100644 index da32946d99..0000000000 --- a/src/leveldb/db/filename.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "db/filename.h" -#include "db/dbformat.h" -#include "leveldb/env.h" -#include "util/logging.h" - -namespace leveldb { - -// A utility routine: write "data" to the named file and Sync() it. -extern Status WriteStringToFileSync(Env* env, const Slice& data, - const std::string& fname); - -static std::string MakeFileName(const std::string& name, uint64_t number, - const char* suffix) { - char buf[100]; - snprintf(buf, sizeof(buf), "/%06llu.%s", - static_cast(number), - suffix); - return name + buf; -} - -std::string LogFileName(const std::string& name, uint64_t number) { - assert(number > 0); - return MakeFileName(name, number, "log"); -} - -std::string TableFileName(const std::string& name, uint64_t number) { - assert(number > 0); - return MakeFileName(name, number, "ldb"); -} - -std::string SSTTableFileName(const std::string& name, uint64_t number) { - assert(number > 0); - return MakeFileName(name, number, "sst"); -} - -std::string DescriptorFileName(const std::string& dbname, uint64_t number) { - assert(number > 0); - char buf[100]; - snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", - static_cast(number)); - return dbname + buf; -} - -std::string CurrentFileName(const std::string& dbname) { - return dbname + "/CURRENT"; -} - -std::string LockFileName(const std::string& dbname) { - return dbname + "/LOCK"; -} - -std::string TempFileName(const std::string& dbname, uint64_t number) { - assert(number > 0); - return MakeFileName(dbname, number, "dbtmp"); -} - -std::string InfoLogFileName(const std::string& dbname) { - return dbname + "/LOG"; -} - -// Return the name of the old info log file for "dbname". -std::string OldInfoLogFileName(const std::string& dbname) { - return dbname + "/LOG.old"; -} - - -// Owned filenames have the form: -// dbname/CURRENT -// dbname/LOCK -// dbname/LOG -// dbname/LOG.old -// dbname/MANIFEST-[0-9]+ -// dbname/[0-9]+.(log|sst|ldb) -bool ParseFileName(const std::string& fname, - uint64_t* number, - FileType* type) { - Slice rest(fname); - if (rest == "CURRENT") { - *number = 0; - *type = kCurrentFile; - } else if (rest == "LOCK") { - *number = 0; - *type = kDBLockFile; - } else if (rest == "LOG" || rest == "LOG.old") { - *number = 0; - *type = kInfoLogFile; - } else if (rest.starts_with("MANIFEST-")) { - rest.remove_prefix(strlen("MANIFEST-")); - uint64_t num; - if (!ConsumeDecimalNumber(&rest, &num)) { - return false; - } - if (!rest.empty()) { - return false; - } - *type = kDescriptorFile; - *number = num; - } else { - // Avoid strtoull() to keep filename format independent of the - // current locale - uint64_t num; - if (!ConsumeDecimalNumber(&rest, &num)) { - return false; - } - Slice suffix = rest; - if (suffix == Slice(".log")) { - *type = kLogFile; - } else if (suffix == Slice(".sst") || suffix == Slice(".ldb")) { - *type = kTableFile; - } else if (suffix == Slice(".dbtmp")) { - *type = kTempFile; - } else { - return false; - } - *number = num; - } - return true; -} - -Status SetCurrentFile(Env* env, const std::string& dbname, - uint64_t descriptor_number) { - // Remove leading "dbname/" and add newline to manifest file name - std::string manifest = DescriptorFileName(dbname, descriptor_number); - Slice contents = manifest; - assert(contents.starts_with(dbname + "/")); - contents.remove_prefix(dbname.size() + 1); - std::string tmp = TempFileName(dbname, descriptor_number); - Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); - if (s.ok()) { - s = env->RenameFile(tmp, CurrentFileName(dbname)); - } - if (!s.ok()) { - env->DeleteFile(tmp); - } - return s; -} - -} // namespace leveldb diff --git a/src/leveldb/db/filename.h b/src/leveldb/db/filename.h deleted file mode 100644 index 87a752605d..0000000000 --- a/src/leveldb/db/filename.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// File names used by DB code - -#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ -#define STORAGE_LEVELDB_DB_FILENAME_H_ - -#include -#include -#include "leveldb/slice.h" -#include "leveldb/status.h" -#include "port/port.h" - -namespace leveldb { - -class Env; - -enum FileType { - kLogFile, - kDBLockFile, - kTableFile, - kDescriptorFile, - kCurrentFile, - kTempFile, - kInfoLogFile // Either the current one, or an old one -}; - -// Return the name of the log file with the specified number -// in the db named by "dbname". The result will be prefixed with -// "dbname". -extern std::string LogFileName(const std::string& dbname, uint64_t number); - -// Return the name of the sstable with the specified number -// in the db named by "dbname". The result will be prefixed with -// "dbname". -extern std::string TableFileName(const std::string& dbname, uint64_t number); - -// Return the legacy file name for an sstable with the specified number -// in the db named by "dbname". The result will be prefixed with -// "dbname". -extern std::string SSTTableFileName(const std::string& dbname, uint64_t number); - -// Return the name of the descriptor file for the db named by -// "dbname" and the specified incarnation number. The result will be -// prefixed with "dbname". -extern std::string DescriptorFileName(const std::string& dbname, - uint64_t number); - -// Return the name of the current file. This file contains the name -// of the current manifest file. The result will be prefixed with -// "dbname". -extern std::string CurrentFileName(const std::string& dbname); - -// Return the name of the lock file for the db named by -// "dbname". The result will be prefixed with "dbname". -extern std::string LockFileName(const std::string& dbname); - -// Return the name of a temporary file owned by the db named "dbname". -// The result will be prefixed with "dbname". -extern std::string TempFileName(const std::string& dbname, uint64_t number); - -// Return the name of the info log file for "dbname". -extern std::string InfoLogFileName(const std::string& dbname); - -// Return the name of the old info log file for "dbname". -extern std::string OldInfoLogFileName(const std::string& dbname); - -// If filename is a leveldb file, store the type of the file in *type. -// The number encoded in the filename is stored in *number. If the -// filename was successfully parsed, returns true. Else return false. -extern bool ParseFileName(const std::string& filename, - uint64_t* number, - FileType* type); - -// Make the CURRENT file point to the descriptor file with the -// specified number. -extern Status SetCurrentFile(Env* env, const std::string& dbname, - uint64_t descriptor_number); - - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/src/leveldb/db/filename_test.cc b/src/leveldb/db/filename_test.cc deleted file mode 100644 index a32556deaf..0000000000 --- a/src/leveldb/db/filename_test.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/filename.h" - -#include "db/dbformat.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -class FileNameTest { }; - -TEST(FileNameTest, Parse) { - Slice db; - FileType type; - uint64_t number; - - // Successful parses - static struct { - const char* fname; - uint64_t number; - FileType type; - } cases[] = { - { "100.log", 100, kLogFile }, - { "0.log", 0, kLogFile }, - { "0.sst", 0, kTableFile }, - { "0.ldb", 0, kTableFile }, - { "CURRENT", 0, kCurrentFile }, - { "LOCK", 0, kDBLockFile }, - { "MANIFEST-2", 2, kDescriptorFile }, - { "MANIFEST-7", 7, kDescriptorFile }, - { "LOG", 0, kInfoLogFile }, - { "LOG.old", 0, kInfoLogFile }, - { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, - }; - for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { - std::string f = cases[i].fname; - ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; - ASSERT_EQ(cases[i].type, type) << f; - ASSERT_EQ(cases[i].number, number) << f; - } - - // Errors - static const char* errors[] = { - "", - "foo", - "foo-dx-100.log", - ".log", - "", - "manifest", - "CURREN", - "CURRENTX", - "MANIFES", - "MANIFEST", - "MANIFEST-", - "XMANIFEST-3", - "MANIFEST-3x", - "LOC", - "LOCKx", - "LO", - "LOGx", - "18446744073709551616.log", - "184467440737095516150.log", - "100", - "100.", - "100.lop" - }; - for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { - std::string f = errors[i]; - ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; - } -} - -TEST(FileNameTest, Construction) { - uint64_t number; - FileType type; - std::string fname; - - fname = CurrentFileName("foo"); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(0, number); - ASSERT_EQ(kCurrentFile, type); - - fname = LockFileName("foo"); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(0, number); - ASSERT_EQ(kDBLockFile, type); - - fname = LogFileName("foo", 192); - ASSERT_EQ("foo/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(192, number); - ASSERT_EQ(kLogFile, type); - - fname = TableFileName("bar", 200); - ASSERT_EQ("bar/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(200, number); - ASSERT_EQ(kTableFile, type); - - fname = DescriptorFileName("bar", 100); - ASSERT_EQ("bar/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(100, number); - ASSERT_EQ(kDescriptorFile, type); - - fname = TempFileName("tmp", 999); - ASSERT_EQ("tmp/", std::string(fname.data(), 4)); - ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); - ASSERT_EQ(999, number); - ASSERT_EQ(kTempFile, type); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/leveldb_main.cc b/src/leveldb/db/leveldb_main.cc deleted file mode 100644 index 9f4b7dd70c..0000000000 --- a/src/leveldb/db/leveldb_main.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "leveldb/dumpfile.h" -#include "leveldb/env.h" -#include "leveldb/status.h" - -namespace leveldb { -namespace { - -class StdoutPrinter : public WritableFile { - public: - virtual Status Append(const Slice& data) { - fwrite(data.data(), 1, data.size(), stdout); - return Status::OK(); - } - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } -}; - -bool HandleDumpCommand(Env* env, char** files, int num) { - StdoutPrinter printer; - bool ok = true; - for (int i = 0; i < num; i++) { - Status s = DumpFile(env, files[i], &printer); - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - ok = false; - } - } - return ok; -} - -} // namespace -} // namespace leveldb - -static void Usage() { - fprintf( - stderr, - "Usage: leveldbutil command...\n" - " dump files... -- dump contents of specified files\n" - ); -} - -int main(int argc, char** argv) { - leveldb::Env* env = leveldb::Env::Default(); - bool ok = true; - if (argc < 2) { - Usage(); - ok = false; - } else { - std::string command = argv[1]; - if (command == "dump") { - ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); - } else { - Usage(); - ok = false; - } - } - return (ok ? 0 : 1); -} diff --git a/src/leveldb/db/leveldbutil.cc b/src/leveldb/db/leveldbutil.cc deleted file mode 100644 index d06d64d640..0000000000 --- a/src/leveldb/db/leveldbutil.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "leveldb/dumpfile.h" -#include "leveldb/env.h" -#include "leveldb/status.h" - -namespace leveldb { -namespace { - -class StdoutPrinter : public WritableFile { - public: - virtual Status Append(const Slice& data) { - fwrite(data.data(), 1, data.size(), stdout); - return Status::OK(); - } - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - virtual std::string GetName() const { return "[stdout]"; } -}; - -bool HandleDumpCommand(Env* env, char** files, int num) { - StdoutPrinter printer; - bool ok = true; - for (int i = 0; i < num; i++) { - Status s = DumpFile(env, files[i], &printer); - if (!s.ok()) { - fprintf(stderr, "%s\n", s.ToString().c_str()); - ok = false; - } - } - return ok; -} - -} // namespace -} // namespace leveldb - -static void Usage() { - fprintf( - stderr, - "Usage: leveldbutil command...\n" - " dump files... -- dump contents of specified files\n" - ); -} - -int main(int argc, char** argv) { - leveldb::Env* env = leveldb::Env::Default(); - bool ok = true; - if (argc < 2) { - Usage(); - ok = false; - } else { - std::string command = argv[1]; - if (command == "dump") { - ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); - } else { - Usage(); - ok = false; - } - } - return (ok ? 0 : 1); -} diff --git a/src/leveldb/db/log_format.h b/src/leveldb/db/log_format.h deleted file mode 100644 index a8c06efe18..0000000000 --- a/src/leveldb/db/log_format.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Log format information shared by reader and writer. -// See ../doc/log_format.txt for more detail. - -#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ -#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ - -namespace leveldb { -namespace log { - -enum RecordType { - // Zero is reserved for preallocated files - kZeroType = 0, - - kFullType = 1, - - // For fragments - kFirstType = 2, - kMiddleType = 3, - kLastType = 4 -}; -static const int kMaxRecordType = kLastType; - -static const int kBlockSize = 32768; - -// Header is checksum (4 bytes), length (2 bytes), type (1 byte). -static const int kHeaderSize = 4 + 2 + 1; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/src/leveldb/db/log_reader.cc b/src/leveldb/db/log_reader.cc deleted file mode 100644 index e44b66c85b..0000000000 --- a/src/leveldb/db/log_reader.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_reader.h" - -#include -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { -namespace log { - -Reader::Reporter::~Reporter() { -} - -Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, - uint64_t initial_offset) - : file_(file), - reporter_(reporter), - checksum_(checksum), - backing_store_(new char[kBlockSize]), - buffer_(), - eof_(false), - last_record_offset_(0), - end_of_buffer_offset_(0), - initial_offset_(initial_offset) { -} - -Reader::~Reader() { - delete[] backing_store_; -} - -bool Reader::SkipToInitialBlock() { - size_t offset_in_block = initial_offset_ % kBlockSize; - uint64_t block_start_location = initial_offset_ - offset_in_block; - - // Don't search a block if we'd be in the trailer - if (offset_in_block > kBlockSize - 6) { - offset_in_block = 0; - block_start_location += kBlockSize; - } - - end_of_buffer_offset_ = block_start_location; - - // Skip to start of first block that can contain the initial record - if (block_start_location > 0) { - Status skip_status = file_->Skip(block_start_location); - if (!skip_status.ok()) { - ReportDrop(block_start_location, skip_status); - return false; - } - } - - return true; -} - -bool Reader::ReadRecord(Slice* record, std::string* scratch) { - if (last_record_offset_ < initial_offset_) { - if (!SkipToInitialBlock()) { - return false; - } - } - - scratch->clear(); - record->clear(); - bool in_fragmented_record = false; - // Record offset of the logical record that we're reading - // 0 is a dummy value to make compilers happy - uint64_t prospective_record_offset = 0; - - Slice fragment; - while (true) { - uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size(); - const unsigned int record_type = ReadPhysicalRecord(&fragment); - switch (record_type) { - case kFullType: - if (in_fragmented_record) { - // Handle bug in earlier versions of log::Writer where - // it could emit an empty kFirstType record at the tail end - // of a block followed by a kFullType or kFirstType record - // at the beginning of the next block. - if (scratch->empty()) { - in_fragmented_record = false; - } else { - ReportCorruption(scratch->size(), "partial record without end(1)"); - } - } - prospective_record_offset = physical_record_offset; - scratch->clear(); - *record = fragment; - last_record_offset_ = prospective_record_offset; - return true; - - case kFirstType: - if (in_fragmented_record) { - // Handle bug in earlier versions of log::Writer where - // it could emit an empty kFirstType record at the tail end - // of a block followed by a kFullType or kFirstType record - // at the beginning of the next block. - if (scratch->empty()) { - in_fragmented_record = false; - } else { - ReportCorruption(scratch->size(), "partial record without end(2)"); - } - } - prospective_record_offset = physical_record_offset; - scratch->assign(fragment.data(), fragment.size()); - in_fragmented_record = true; - break; - - case kMiddleType: - if (!in_fragmented_record) { - ReportCorruption(fragment.size(), - "missing start of fragmented record(1)"); - } else { - scratch->append(fragment.data(), fragment.size()); - } - break; - - case kLastType: - if (!in_fragmented_record) { - ReportCorruption(fragment.size(), - "missing start of fragmented record(2)"); - } else { - scratch->append(fragment.data(), fragment.size()); - *record = Slice(*scratch); - last_record_offset_ = prospective_record_offset; - return true; - } - break; - - case kEof: - if (in_fragmented_record) { - // This can be caused by the writer dying immediately after - // writing a physical record but before completing the next; don't - // treat it as a corruption, just ignore the entire logical record. - scratch->clear(); - } - return false; - - case kBadRecord: - if (in_fragmented_record) { - ReportCorruption(scratch->size(), "error in middle of record"); - in_fragmented_record = false; - scratch->clear(); - } - break; - - default: { - char buf[40]; - snprintf(buf, sizeof(buf), "unknown record type %u", record_type); - ReportCorruption( - (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), - buf); - in_fragmented_record = false; - scratch->clear(); - break; - } - } - } - return false; -} - -uint64_t Reader::LastRecordOffset() { - return last_record_offset_; -} - -void Reader::ReportCorruption(uint64_t bytes, const char* reason) { - ReportDrop(bytes, Status::Corruption(reason)); -} - -void Reader::ReportDrop(uint64_t bytes, const Status& reason) { - if (reporter_ != NULL && - end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { - reporter_->Corruption(static_cast(bytes), reason); - } -} - -unsigned int Reader::ReadPhysicalRecord(Slice* result) { - while (true) { - if (buffer_.size() < kHeaderSize) { - if (!eof_) { - // Last read was a full read, so this is a trailer to skip - buffer_.clear(); - Status status = file_->Read(kBlockSize, &buffer_, backing_store_); - end_of_buffer_offset_ += buffer_.size(); - if (!status.ok()) { - buffer_.clear(); - ReportDrop(kBlockSize, status); - eof_ = true; - return kEof; - } else if (buffer_.size() < kBlockSize) { - eof_ = true; - } - continue; - } else { - // Note that if buffer_ is non-empty, we have a truncated header at the - // end of the file, which can be caused by the writer crashing in the - // middle of writing the header. Instead of considering this an error, - // just report EOF. - buffer_.clear(); - return kEof; - } - } - - // Parse the header - const char* header = buffer_.data(); - const uint32_t a = static_cast(header[4]) & 0xff; - const uint32_t b = static_cast(header[5]) & 0xff; - const unsigned int type = header[6]; - const uint32_t length = a | (b << 8); - if (kHeaderSize + length > buffer_.size()) { - size_t drop_size = buffer_.size(); - buffer_.clear(); - if (!eof_) { - ReportCorruption(drop_size, "bad record length"); - return kBadRecord; - } - // If the end of the file has been reached without reading |length| bytes - // of payload, assume the writer died in the middle of writing the record. - // Don't report a corruption. - return kEof; - } - - if (type == kZeroType && length == 0) { - // Skip zero length record without reporting any drops since - // such records are produced by the mmap based writing code in - // env_posix.cc that preallocates file regions. - buffer_.clear(); - return kBadRecord; - } - - // Check crc - if (checksum_) { - uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); - uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); - if (actual_crc != expected_crc) { - // Drop the rest of the buffer since "length" itself may have - // been corrupted and if we trust it, we could find some - // fragment of a real log record that just happens to look - // like a valid log record. - size_t drop_size = buffer_.size(); - buffer_.clear(); - ReportCorruption(drop_size, "checksum mismatch"); - return kBadRecord; - } - } - - buffer_.remove_prefix(kHeaderSize + length); - - // Skip physical record that started before initial_offset_ - if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < - initial_offset_) { - result->clear(); - return kBadRecord; - } - - *result = Slice(header + kHeaderSize, length); - return type; - } -} - -} // namespace log -} // namespace leveldb diff --git a/src/leveldb/db/log_reader.h b/src/leveldb/db/log_reader.h deleted file mode 100644 index 6aff791716..0000000000 --- a/src/leveldb/db/log_reader.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ -#define STORAGE_LEVELDB_DB_LOG_READER_H_ - -#include - -#include "db/log_format.h" -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class SequentialFile; - -namespace log { - -class Reader { - public: - // Interface for reporting errors. - class Reporter { - public: - virtual ~Reporter(); - - // Some corruption was detected. "size" is the approximate number - // of bytes dropped due to the corruption. - virtual void Corruption(size_t bytes, const Status& status) = 0; - }; - - // Create a reader that will return log records from "*file". - // "*file" must remain live while this Reader is in use. - // - // If "reporter" is non-NULL, it is notified whenever some data is - // dropped due to a detected corruption. "*reporter" must remain - // live while this Reader is in use. - // - // If "checksum" is true, verify checksums if available. - // - // The Reader will start reading at the first record located at physical - // position >= initial_offset within the file. - Reader(SequentialFile* file, Reporter* reporter, bool checksum, - uint64_t initial_offset); - - ~Reader(); - - // Read the next record into *record. Returns true if read - // successfully, false if we hit end of the input. May use - // "*scratch" as temporary storage. The contents filled in *record - // will only be valid until the next mutating operation on this - // reader or the next mutation to *scratch. - bool ReadRecord(Slice* record, std::string* scratch); - - // Returns the physical offset of the last record returned by ReadRecord. - // - // Undefined before the first call to ReadRecord. - uint64_t LastRecordOffset(); - - private: - SequentialFile* const file_; - Reporter* const reporter_; - bool const checksum_; - char* const backing_store_; - Slice buffer_; - bool eof_; // Last Read() indicated EOF by returning < kBlockSize - - // Offset of the last record returned by ReadRecord. - uint64_t last_record_offset_; - // Offset of the first location past the end of buffer_. - uint64_t end_of_buffer_offset_; - - // Offset at which to start looking for the first record to return - uint64_t const initial_offset_; - - // Extend record types with the following special values - enum { - kEof = kMaxRecordType + 1, - // Returned whenever we find an invalid physical record. - // Currently there are three situations in which this happens: - // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) - // * The record is a 0-length record (No drop is reported) - // * The record is below constructor's initial_offset (No drop is reported) - kBadRecord = kMaxRecordType + 2 - }; - - // Skips all blocks that are completely before "initial_offset_". - // - // Returns true on success. Handles reporting. - bool SkipToInitialBlock(); - - // Return type, or one of the preceding special values - unsigned int ReadPhysicalRecord(Slice* result); - - // Reports dropped bytes to the reporter. - // buffer_ must be updated to remove the dropped bytes prior to invocation. - void ReportCorruption(uint64_t bytes, const char* reason); - void ReportDrop(uint64_t bytes, const Status& reason); - - // No copying allowed - Reader(const Reader&); - void operator=(const Reader&); -}; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/src/leveldb/db/log_test.cc b/src/leveldb/db/log_test.cc deleted file mode 100644 index dcf0562652..0000000000 --- a/src/leveldb/db/log_test.cc +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { -namespace log { - -// Construct a string of the specified length made out of the supplied -// partial string. -static std::string BigString(const std::string& partial_string, size_t n) { - std::string result; - while (result.size() < n) { - result.append(partial_string); - } - result.resize(n); - return result; -} - -// Construct a string from a number -static std::string NumberString(int n) { - char buf[50]; - snprintf(buf, sizeof(buf), "%d.", n); - return std::string(buf); -} - -// Return a skewed potentially long string -static std::string RandomSkewedString(int i, Random* rnd) { - return BigString(NumberString(i), rnd->Skewed(17)); -} - -class LogTest { - private: - class StringDest : public WritableFile { - public: - std::string contents_; - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - virtual Status Append(const Slice& slice) { - contents_.append(slice.data(), slice.size()); - return Status::OK(); - } - }; - - class StringSource : public SequentialFile { - public: - Slice contents_; - bool force_error_; - bool returned_partial_; - StringSource() : force_error_(false), returned_partial_(false) { } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; - - if (force_error_) { - force_error_ = false; - returned_partial_ = true; - return Status::Corruption("read error"); - } - - if (contents_.size() < n) { - n = contents_.size(); - returned_partial_ = true; - } - *result = Slice(contents_.data(), n); - contents_.remove_prefix(n); - return Status::OK(); - } - - virtual Status Skip(uint64_t n) { - if (n > contents_.size()) { - contents_.clear(); - return Status::NotFound("in-memory file skipepd past end"); - } - - contents_.remove_prefix(n); - - return Status::OK(); - } - }; - - class ReportCollector : public Reader::Reporter { - public: - size_t dropped_bytes_; - std::string message_; - - ReportCollector() : dropped_bytes_(0) { } - virtual void Corruption(size_t bytes, const Status& status) { - dropped_bytes_ += bytes; - message_.append(status.ToString()); - } - }; - - StringDest dest_; - StringSource source_; - ReportCollector report_; - bool reading_; - Writer writer_; - Reader reader_; - - // Record metadata for testing initial offset functionality - static size_t initial_offset_record_sizes_[]; - static uint64_t initial_offset_last_record_offsets_[]; - - public: - LogTest() : reading_(false), - writer_(&dest_), - reader_(&source_, &report_, true/*checksum*/, - 0/*initial_offset*/) { - } - - void Write(const std::string& msg) { - ASSERT_TRUE(!reading_) << "Write() after starting to read"; - writer_.AddRecord(Slice(msg)); - } - - size_t WrittenBytes() const { - return dest_.contents_.size(); - } - - std::string Read() { - if (!reading_) { - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - } - std::string scratch; - Slice record; - if (reader_.ReadRecord(&record, &scratch)) { - return record.ToString(); - } else { - return "EOF"; - } - } - - void IncrementByte(int offset, int delta) { - dest_.contents_[offset] += delta; - } - - void SetByte(int offset, char new_byte) { - dest_.contents_[offset] = new_byte; - } - - void ShrinkSize(int bytes) { - dest_.contents_.resize(dest_.contents_.size() - bytes); - } - - void FixChecksum(int header_offset, int len) { - // Compute crc of type/len/data - uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); - crc = crc32c::Mask(crc); - EncodeFixed32(&dest_.contents_[header_offset], crc); - } - - void ForceError() { - source_.force_error_ = true; - } - - size_t DroppedBytes() const { - return report_.dropped_bytes_; - } - - std::string ReportMessage() const { - return report_.message_; - } - - // Returns OK iff recorded error message contains "msg" - std::string MatchError(const std::string& msg) const { - if (report_.message_.find(msg) == std::string::npos) { - return report_.message_; - } else { - return "OK"; - } - } - - void WriteInitialOffsetLog() { - for (int i = 0; i < 4; i++) { - std::string record(initial_offset_record_sizes_[i], - static_cast('a' + i)); - Write(record); - } - } - - void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { - WriteInitialOffsetLog(); - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, - WrittenBytes() + offset_past_end); - Slice record; - std::string scratch; - ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); - delete offset_reader; - } - - void CheckInitialOffsetRecord(uint64_t initial_offset, - int expected_record_offset) { - WriteInitialOffsetLog(); - reading_ = true; - source_.contents_ = Slice(dest_.contents_); - Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, - initial_offset); - Slice record; - std::string scratch; - ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); - ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], - record.size()); - ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], - offset_reader->LastRecordOffset()); - ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); - delete offset_reader; - } - -}; - -size_t LogTest::initial_offset_record_sizes_[] = - {10000, // Two sizable records in first block - 10000, - 2 * log::kBlockSize - 1000, // Span three blocks - 1}; - -uint64_t LogTest::initial_offset_last_record_offsets_[] = - {0, - kHeaderSize + 10000, - 2 * (kHeaderSize + 10000), - 2 * (kHeaderSize + 10000) + - (2 * log::kBlockSize - 1000) + 3 * kHeaderSize}; - - -TEST(LogTest, Empty) { - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, ReadWrite) { - Write("foo"); - Write("bar"); - Write(""); - Write("xxxx"); - ASSERT_EQ("foo", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("xxxx", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ("EOF", Read()); // Make sure reads at eof work -} - -TEST(LogTest, ManyBlocks) { - for (int i = 0; i < 100000; i++) { - Write(NumberString(i)); - } - for (int i = 0; i < 100000; i++) { - ASSERT_EQ(NumberString(i), Read()); - } - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, Fragmentation) { - Write("small"); - Write(BigString("medium", 50000)); - Write(BigString("large", 100000)); - ASSERT_EQ("small", Read()); - ASSERT_EQ(BigString("medium", 50000), Read()); - ASSERT_EQ(BigString("large", 100000), Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, MarginalTrailer) { - // Make a trailer that is exactly the same length as an empty record. - const int n = kBlockSize - 2*kHeaderSize; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); - Write(""); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, MarginalTrailer2) { - // Make a trailer that is exactly the same length as an empty record. - const int n = kBlockSize - 2*kHeaderSize; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(0, DroppedBytes()); - ASSERT_EQ("", ReportMessage()); -} - -TEST(LogTest, ShortTrailer) { - const int n = kBlockSize - 2*kHeaderSize + 4; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); - Write(""); - Write("bar"); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("", Read()); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, AlignedEof) { - const int n = kBlockSize - 2*kHeaderSize + 4; - Write(BigString("foo", n)); - ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); - ASSERT_EQ(BigString("foo", n), Read()); - ASSERT_EQ("EOF", Read()); -} - -TEST(LogTest, RandomRead) { - const int N = 500; - Random write_rnd(301); - for (int i = 0; i < N; i++) { - Write(RandomSkewedString(i, &write_rnd)); - } - Random read_rnd(301); - for (int i = 0; i < N; i++) { - ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); - } - ASSERT_EQ("EOF", Read()); -} - -// Tests of all the error paths in log_reader.cc follow: - -TEST(LogTest, ReadError) { - Write("foo"); - ForceError(); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(kBlockSize, DroppedBytes()); - ASSERT_EQ("OK", MatchError("read error")); -} - -TEST(LogTest, BadRecordType) { - Write("foo"); - // Type is stored in header[6] - IncrementByte(6, 100); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("unknown record type")); -} - -TEST(LogTest, TruncatedTrailingRecordIsIgnored) { - Write("foo"); - ShrinkSize(4); // Drop all payload as well as a header byte - ASSERT_EQ("EOF", Read()); - // Truncated last record is ignored, not treated as an error. - ASSERT_EQ(0, DroppedBytes()); - ASSERT_EQ("", ReportMessage()); -} - -TEST(LogTest, BadLength) { - const int kPayloadSize = kBlockSize - kHeaderSize; - Write(BigString("bar", kPayloadSize)); - Write("foo"); - // Least significant size byte is stored in header[4]. - IncrementByte(4, 1); - ASSERT_EQ("foo", Read()); - ASSERT_EQ(kBlockSize, DroppedBytes()); - ASSERT_EQ("OK", MatchError("bad record length")); -} - -TEST(LogTest, BadLengthAtEndIsIgnored) { - Write("foo"); - ShrinkSize(1); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(0, DroppedBytes()); - ASSERT_EQ("", ReportMessage()); -} - -TEST(LogTest, ChecksumMismatch) { - Write("foo"); - IncrementByte(0, 10); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(10, DroppedBytes()); - ASSERT_EQ("OK", MatchError("checksum mismatch")); -} - -TEST(LogTest, UnexpectedMiddleType) { - Write("foo"); - SetByte(6, kMiddleType); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("missing start")); -} - -TEST(LogTest, UnexpectedLastType) { - Write("foo"); - SetByte(6, kLastType); - FixChecksum(0, 3); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("missing start")); -} - -TEST(LogTest, UnexpectedFullType) { - Write("foo"); - Write("bar"); - SetByte(6, kFirstType); - FixChecksum(0, 3); - ASSERT_EQ("bar", Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("partial record without end")); -} - -TEST(LogTest, UnexpectedFirstType) { - Write("foo"); - Write(BigString("bar", 100000)); - SetByte(6, kFirstType); - FixChecksum(0, 3); - ASSERT_EQ(BigString("bar", 100000), Read()); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ(3, DroppedBytes()); - ASSERT_EQ("OK", MatchError("partial record without end")); -} - -TEST(LogTest, MissingLastIsIgnored) { - Write(BigString("bar", kBlockSize)); - // Remove the LAST block, including header. - ShrinkSize(14); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ("", ReportMessage()); - ASSERT_EQ(0, DroppedBytes()); -} - -TEST(LogTest, PartialLastIsIgnored) { - Write(BigString("bar", kBlockSize)); - // Cause a bad record length in the LAST block. - ShrinkSize(1); - ASSERT_EQ("EOF", Read()); - ASSERT_EQ("", ReportMessage()); - ASSERT_EQ(0, DroppedBytes()); -} - -TEST(LogTest, ErrorJoinsRecords) { - // Consider two fragmented records: - // first(R1) last(R1) first(R2) last(R2) - // where the middle two fragments disappear. We do not want - // first(R1),last(R2) to get joined and returned as a valid record. - - // Write records that span two blocks - Write(BigString("foo", kBlockSize)); - Write(BigString("bar", kBlockSize)); - Write("correct"); - - // Wipe the middle block - for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { - SetByte(offset, 'x'); - } - - ASSERT_EQ("correct", Read()); - ASSERT_EQ("EOF", Read()); - const size_t dropped = DroppedBytes(); - ASSERT_LE(dropped, 2*kBlockSize + 100); - ASSERT_GE(dropped, 2*kBlockSize); -} - -TEST(LogTest, ReadStart) { - CheckInitialOffsetRecord(0, 0); -} - -TEST(LogTest, ReadSecondOneOff) { - CheckInitialOffsetRecord(1, 1); -} - -TEST(LogTest, ReadSecondTenThousand) { - CheckInitialOffsetRecord(10000, 1); -} - -TEST(LogTest, ReadSecondStart) { - CheckInitialOffsetRecord(10007, 1); -} - -TEST(LogTest, ReadThirdOneOff) { - CheckInitialOffsetRecord(10008, 2); -} - -TEST(LogTest, ReadThirdStart) { - CheckInitialOffsetRecord(20014, 2); -} - -TEST(LogTest, ReadFourthOneOff) { - CheckInitialOffsetRecord(20015, 3); -} - -TEST(LogTest, ReadFourthFirstBlockTrailer) { - CheckInitialOffsetRecord(log::kBlockSize - 4, 3); -} - -TEST(LogTest, ReadFourthMiddleBlock) { - CheckInitialOffsetRecord(log::kBlockSize + 1, 3); -} - -TEST(LogTest, ReadFourthLastBlock) { - CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); -} - -TEST(LogTest, ReadFourthStart) { - CheckInitialOffsetRecord( - 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, - 3); -} - -TEST(LogTest, ReadEnd) { - CheckOffsetPastEndReturnsNoRecords(0); -} - -TEST(LogTest, ReadPastEnd) { - CheckOffsetPastEndReturnsNoRecords(5); -} - -} // namespace log -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/log_writer.cc b/src/leveldb/db/log_writer.cc deleted file mode 100644 index 2da99ac088..0000000000 --- a/src/leveldb/db/log_writer.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/log_writer.h" - -#include -#include "leveldb/env.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { -namespace log { - -Writer::Writer(WritableFile* dest) - : dest_(dest), - block_offset_(0) { - for (int i = 0; i <= kMaxRecordType; i++) { - char t = static_cast(i); - type_crc_[i] = crc32c::Value(&t, 1); - } -} - -Writer::~Writer() { -} - -Status Writer::AddRecord(const Slice& slice) { - const char* ptr = slice.data(); - size_t left = slice.size(); - - // Fragment the record if necessary and emit it. Note that if slice - // is empty, we still want to iterate once to emit a single - // zero-length record - Status s; - bool begin = true; - do { - const int leftover = kBlockSize - block_offset_; - assert(leftover >= 0); - if (leftover < kHeaderSize) { - // Switch to a new block - if (leftover > 0) { - // Fill the trailer (literal below relies on kHeaderSize being 7) - assert(kHeaderSize == 7); - dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); - } - block_offset_ = 0; - } - - // Invariant: we never leave < kHeaderSize bytes in a block. - assert(kBlockSize - block_offset_ - kHeaderSize >= 0); - - const size_t avail = kBlockSize - block_offset_ - kHeaderSize; - const size_t fragment_length = (left < avail) ? left : avail; - - RecordType type; - const bool end = (left == fragment_length); - if (begin && end) { - type = kFullType; - } else if (begin) { - type = kFirstType; - } else if (end) { - type = kLastType; - } else { - type = kMiddleType; - } - - s = EmitPhysicalRecord(type, ptr, fragment_length); - ptr += fragment_length; - left -= fragment_length; - begin = false; - } while (s.ok() && left > 0); - return s; -} - -Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { - assert(n <= 0xffff); // Must fit in two bytes - assert(block_offset_ + kHeaderSize + n <= kBlockSize); - - // Format the header - char buf[kHeaderSize]; - buf[4] = static_cast(n & 0xff); - buf[5] = static_cast(n >> 8); - buf[6] = static_cast(t); - - // Compute the crc of the record type and the payload. - uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); - crc = crc32c::Mask(crc); // Adjust for storage - EncodeFixed32(buf, crc); - - // Write the header and the payload - Status s = dest_->Append(Slice(buf, kHeaderSize)); - if (s.ok()) { - s = dest_->Append(Slice(ptr, n)); - if (s.ok()) { - s = dest_->Flush(); - } - } - block_offset_ += kHeaderSize + n; - return s; -} - -} // namespace log -} // namespace leveldb diff --git a/src/leveldb/db/log_writer.h b/src/leveldb/db/log_writer.h deleted file mode 100644 index a3a954d967..0000000000 --- a/src/leveldb/db/log_writer.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ -#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ - -#include -#include "db/log_format.h" -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class WritableFile; - -namespace log { - -class Writer { - public: - // Create a writer that will append data to "*dest". - // "*dest" must be initially empty. - // "*dest" must remain live while this Writer is in use. - explicit Writer(WritableFile* dest); - ~Writer(); - - Status AddRecord(const Slice& slice); - - private: - WritableFile* dest_; - int block_offset_; // Current offset in block - - // crc32c values for all supported record types. These are - // pre-computed to reduce the overhead of computing the crc of the - // record type stored in the header. - uint32_t type_crc_[kMaxRecordType + 1]; - - Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); - - // No copying allowed - Writer(const Writer&); - void operator=(const Writer&); -}; - -} // namespace log -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc deleted file mode 100644 index 31ad995d12..0000000000 --- a/src/leveldb/db/memtable.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/memtable.h" -#include "db/dbformat.h" -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "util/coding.h" - -namespace leveldb { - -static Slice GetLengthPrefixedSlice(const char* data) { - uint32_t len; - const char* p = data; - p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted - return Slice(p, len); -} - -MemTable::MemTable(const InternalKeyComparator& cmp) - : comparator_(cmp), - refs_(0), - table_(comparator_, &arena_) { -} - -MemTable::~MemTable() { - assert(refs_ == 0); -} - -size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } - -int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) - const { - // Internal keys are encoded as length-prefixed strings. - Slice a = GetLengthPrefixedSlice(aptr); - Slice b = GetLengthPrefixedSlice(bptr); - return comparator.Compare(a, b); -} - -// Encode a suitable internal key target for "target" and return it. -// Uses *scratch as scratch space, and the returned pointer will point -// into this scratch space. -static const char* EncodeKey(std::string* scratch, const Slice& target) { - scratch->clear(); - PutVarint32(scratch, target.size()); - scratch->append(target.data(), target.size()); - return scratch->data(); -} - -class MemTableIterator: public Iterator { - public: - explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } - - virtual bool Valid() const { return iter_.Valid(); } - virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } - virtual void SeekToFirst() { iter_.SeekToFirst(); } - virtual void SeekToLast() { iter_.SeekToLast(); } - virtual void Next() { iter_.Next(); } - virtual void Prev() { iter_.Prev(); } - virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } - virtual Slice value() const { - Slice key_slice = GetLengthPrefixedSlice(iter_.key()); - return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); - } - - virtual Status status() const { return Status::OK(); } - - private: - MemTable::Table::Iterator iter_; - std::string tmp_; // For passing to EncodeKey - - // No copying allowed - MemTableIterator(const MemTableIterator&); - void operator=(const MemTableIterator&); -}; - -Iterator* MemTable::NewIterator() { - return new MemTableIterator(&table_); -} - -void MemTable::Add(SequenceNumber s, ValueType type, - const Slice& key, - const Slice& value) { - // Format of an entry is concatenation of: - // key_size : varint32 of internal_key.size() - // key bytes : char[internal_key.size()] - // value_size : varint32 of value.size() - // value bytes : char[value.size()] - size_t key_size = key.size(); - size_t val_size = value.size(); - size_t internal_key_size = key_size + 8; - const size_t encoded_len = - VarintLength(internal_key_size) + internal_key_size + - VarintLength(val_size) + val_size; - char* buf = arena_.Allocate(encoded_len); - char* p = EncodeVarint32(buf, internal_key_size); - memcpy(p, key.data(), key_size); - p += key_size; - EncodeFixed64(p, (s << 8) | type); - p += 8; - p = EncodeVarint32(p, val_size); - memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == (long)encoded_len); - table_.Insert(buf); -} - -bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { - Slice memkey = key.memtable_key(); - Table::Iterator iter(&table_); - iter.Seek(memkey.data()); - if (iter.Valid()) { - // entry format is: - // klength varint32 - // userkey char[klength] - // tag uint64 - // vlength varint32 - // value char[vlength] - // Check that it belongs to same user key. We do not check the - // sequence number since the Seek() call above should have skipped - // all entries with overly large sequence numbers. - const char* entry = iter.key(); - uint32_t key_length; - const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); - if (comparator_.comparator.user_comparator()->Compare( - Slice(key_ptr, key_length - 8), - key.user_key()) == 0) { - // Correct user key - const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); - switch (static_cast(tag & 0xff)) { - case kTypeValue: { - Slice v = GetLengthPrefixedSlice(key_ptr + key_length); - value->assign(v.data(), v.size()); - return true; - } - case kTypeDeletion: - *s = Status::NotFound(Slice()); - return true; - } - } - } - return false; -} - -} // namespace leveldb diff --git a/src/leveldb/db/memtable.h b/src/leveldb/db/memtable.h deleted file mode 100644 index 92e90bb099..0000000000 --- a/src/leveldb/db/memtable.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ -#define STORAGE_LEVELDB_DB_MEMTABLE_H_ - -#include -#include "leveldb/db.h" -#include "db/dbformat.h" -#include "db/skiplist.h" -#include "util/arena.h" - -namespace leveldb { - -class InternalKeyComparator; -class Mutex; -class MemTableIterator; - -class MemTable { - public: - // MemTables are reference counted. The initial reference count - // is zero and the caller must call Ref() at least once. - explicit MemTable(const InternalKeyComparator& comparator); - - // Increase reference count. - void Ref() { ++refs_; } - - // Drop reference count. Delete if no more references exist. - void Unref() { - --refs_; - assert(refs_ >= 0); - if (refs_ <= 0) { - delete this; - } - } - - // Returns an estimate of the number of bytes of data in use by this - // data structure. - // - // REQUIRES: external synchronization to prevent simultaneous - // operations on the same MemTable. - size_t ApproximateMemoryUsage(); - - // Return an iterator that yields the contents of the memtable. - // - // The caller must ensure that the underlying MemTable remains live - // while the returned iterator is live. The keys returned by this - // iterator are internal keys encoded by AppendInternalKey in the - // db/format.{h,cc} module. - Iterator* NewIterator(); - - // Add an entry into memtable that maps key to value at the - // specified sequence number and with the specified type. - // Typically value will be empty if type==kTypeDeletion. - void Add(SequenceNumber seq, ValueType type, - const Slice& key, - const Slice& value); - - // If memtable contains a value for key, store it in *value and return true. - // If memtable contains a deletion for key, store a NotFound() error - // in *status and return true. - // Else, return false. - bool Get(const LookupKey& key, std::string* value, Status* s); - - private: - ~MemTable(); // Private since only Unref() should be used to delete it - - struct KeyComparator { - const InternalKeyComparator comparator; - explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } - int operator()(const char* a, const char* b) const; - }; - friend class MemTableIterator; - friend class MemTableBackwardIterator; - - typedef SkipList Table; - - KeyComparator comparator_; - int refs_; - Arena arena_; - Table table_; - - // No copying allowed - MemTable(const MemTable&); - void operator=(const MemTable&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/src/leveldb/db/recovery_test.cc b/src/leveldb/db/recovery_test.cc deleted file mode 100644 index 9596f4288a..0000000000 --- a/src/leveldb/db/recovery_test.cc +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (c) 2014 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/db_impl.h" -#include "db/filename.h" -#include "db/version_set.h" -#include "db/write_batch_internal.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/write_batch.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -class RecoveryTest { - public: - RecoveryTest() : env_(Env::Default()), db_(NULL) { - dbname_ = test::TmpDir() + "/recovery_test"; - DestroyDB(dbname_, Options()); - Open(); - } - - ~RecoveryTest() { - Close(); - DestroyDB(dbname_, Options()); - } - - DBImpl* dbfull() const { return reinterpret_cast(db_); } - Env* env() const { return env_; } - - bool CanAppend() { - WritableFile* tmp; - Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp); - delete tmp; - if (s.IsNotSupportedError()) { - return false; - } else { - return true; - } - } - - void Close() { - delete db_; - db_ = NULL; - } - - void Open(Options* options = NULL) { - Close(); - Options opts; - if (options != NULL) { - opts = *options; - } else { - opts.reuse_logs = true; // TODO(sanjay): test both ways - opts.create_if_missing = true; - } - if (opts.env == NULL) { - opts.env = env_; - } - ASSERT_OK(DB::Open(opts, dbname_, &db_)); - ASSERT_EQ(1, NumLogs()); - } - - Status Put(const std::string& k, const std::string& v) { - return db_->Put(WriteOptions(), k, v); - } - - std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { - std::string result; - Status s = db_->Get(ReadOptions(), k, &result); - if (s.IsNotFound()) { - result = "NOT_FOUND"; - } else if (!s.ok()) { - result = s.ToString(); - } - return result; - } - - std::string ManifestFileName() { - std::string current; - ASSERT_OK(ReadFileToString(env_, CurrentFileName(dbname_), ¤t)); - size_t len = current.size(); - if (len > 0 && current[len-1] == '\n') { - current.resize(len - 1); - } - return dbname_ + "/" + current; - } - - std::string LogName(uint64_t number) { - return LogFileName(dbname_, number); - } - - size_t DeleteLogFiles() { - std::vector logs = GetFiles(kLogFile); - for (size_t i = 0; i < logs.size(); i++) { - ASSERT_OK(env_->DeleteFile(LogName(logs[i]))) << LogName(logs[i]); - } - return logs.size(); - } - - uint64_t FirstLogFile() { - return GetFiles(kLogFile)[0]; - } - - std::vector GetFiles(FileType t) { - std::vector filenames; - ASSERT_OK(env_->GetChildren(dbname_, &filenames)); - std::vector result; - for (size_t i = 0; i < filenames.size(); i++) { - uint64_t number; - FileType type; - if (ParseFileName(filenames[i], &number, &type) && type == t) { - result.push_back(number); - } - } - return result; - } - - int NumLogs() { - return GetFiles(kLogFile).size(); - } - - int NumTables() { - return GetFiles(kTableFile).size(); - } - - uint64_t FileSize(const std::string& fname) { - uint64_t result; - ASSERT_OK(env_->GetFileSize(fname, &result)) << fname; - return result; - } - - void CompactMemTable() { - dbfull()->TEST_CompactMemTable(); - } - - // Directly construct a log file that sets key to val. - void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) { - std::string fname = LogFileName(dbname_, lognum); - WritableFile* file; - ASSERT_OK(env_->NewWritableFile(fname, &file)); - log::Writer writer(file); - WriteBatch batch; - batch.Put(key, val); - WriteBatchInternal::SetSequence(&batch, seq); - ASSERT_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch))); - ASSERT_OK(file->Flush()); - delete file; - } - - private: - std::string dbname_; - Env* env_; - DB* db_; -}; - -TEST(RecoveryTest, ManifestReused) { - if (!CanAppend()) { - fprintf(stderr, "skipping test because env does not support appending\n"); - return; - } - ASSERT_OK(Put("foo", "bar")); - Close(); - std::string old_manifest = ManifestFileName(); - Open(); - ASSERT_EQ(old_manifest, ManifestFileName()); - ASSERT_EQ("bar", Get("foo")); - Open(); - ASSERT_EQ(old_manifest, ManifestFileName()); - ASSERT_EQ("bar", Get("foo")); -} - -TEST(RecoveryTest, LargeManifestCompacted) { - if (!CanAppend()) { - fprintf(stderr, "skipping test because env does not support appending\n"); - return; - } - ASSERT_OK(Put("foo", "bar")); - Close(); - std::string old_manifest = ManifestFileName(); - - // Pad with zeroes to make manifest file very big. - { - uint64_t len = FileSize(old_manifest); - WritableFile* file; - ASSERT_OK(env()->NewAppendableFile(old_manifest, &file)); - std::string zeroes(3*1048576 - static_cast(len), 0); - ASSERT_OK(file->Append(zeroes)); - ASSERT_OK(file->Flush()); - delete file; - } - - Open(); - std::string new_manifest = ManifestFileName(); - ASSERT_NE(old_manifest, new_manifest); - ASSERT_GT(10000, FileSize(new_manifest)); - ASSERT_EQ("bar", Get("foo")); - - Open(); - ASSERT_EQ(new_manifest, ManifestFileName()); - ASSERT_EQ("bar", Get("foo")); -} - -TEST(RecoveryTest, NoLogFiles) { - ASSERT_OK(Put("foo", "bar")); - ASSERT_EQ(1, DeleteLogFiles()); - Open(); - ASSERT_EQ("NOT_FOUND", Get("foo")); - Open(); - ASSERT_EQ("NOT_FOUND", Get("foo")); -} - -TEST(RecoveryTest, LogFileReuse) { - if (!CanAppend()) { - fprintf(stderr, "skipping test because env does not support appending\n"); - return; - } - for (int i = 0; i < 2; i++) { - ASSERT_OK(Put("foo", "bar")); - if (i == 0) { - // Compact to ensure current log is empty - CompactMemTable(); - } - Close(); - ASSERT_EQ(1, NumLogs()); - uint64_t number = FirstLogFile(); - if (i == 0) { - ASSERT_EQ(0, FileSize(LogName(number))); - } else { - ASSERT_LT(0, FileSize(LogName(number))); - } - Open(); - ASSERT_EQ(1, NumLogs()); - ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; - ASSERT_EQ("bar", Get("foo")); - Open(); - ASSERT_EQ(1, NumLogs()); - ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; - ASSERT_EQ("bar", Get("foo")); - } -} - -TEST(RecoveryTest, MultipleMemTables) { - // Make a large log. - const int kNum = 1000; - for (int i = 0; i < kNum; i++) { - char buf[100]; - snprintf(buf, sizeof(buf), "%050d", i); - ASSERT_OK(Put(buf, buf)); - } - ASSERT_EQ(0, NumTables()); - Close(); - ASSERT_EQ(0, NumTables()); - ASSERT_EQ(1, NumLogs()); - uint64_t old_log_file = FirstLogFile(); - - // Force creation of multiple memtables by reducing the write buffer size. - Options opt; - opt.reuse_logs = true; - opt.write_buffer_size = (kNum*100) / 2; - Open(&opt); - ASSERT_LE(2, NumTables()); - ASSERT_EQ(1, NumLogs()); - ASSERT_NE(old_log_file, FirstLogFile()) << "must not reuse log"; - for (int i = 0; i < kNum; i++) { - char buf[100]; - snprintf(buf, sizeof(buf), "%050d", i); - ASSERT_EQ(buf, Get(buf)); - } -} - -TEST(RecoveryTest, MultipleLogFiles) { - ASSERT_OK(Put("foo", "bar")); - Close(); - ASSERT_EQ(1, NumLogs()); - - // Make a bunch of uncompacted log files. - uint64_t old_log = FirstLogFile(); - MakeLogFile(old_log+1, 1000, "hello", "world"); - MakeLogFile(old_log+2, 1001, "hi", "there"); - MakeLogFile(old_log+3, 1002, "foo", "bar2"); - - // Recover and check that all log files were processed. - Open(); - ASSERT_LE(1, NumTables()); - ASSERT_EQ(1, NumLogs()); - uint64_t new_log = FirstLogFile(); - ASSERT_LE(old_log+3, new_log); - ASSERT_EQ("bar2", Get("foo")); - ASSERT_EQ("world", Get("hello")); - ASSERT_EQ("there", Get("hi")); - - // Test that previous recovery produced recoverable state. - Open(); - ASSERT_LE(1, NumTables()); - ASSERT_EQ(1, NumLogs()); - if (CanAppend()) { - ASSERT_EQ(new_log, FirstLogFile()); - } - ASSERT_EQ("bar2", Get("foo")); - ASSERT_EQ("world", Get("hello")); - ASSERT_EQ("there", Get("hi")); - - // Check that introducing an older log file does not cause it to be re-read. - Close(); - MakeLogFile(old_log+1, 2000, "hello", "stale write"); - Open(); - ASSERT_LE(1, NumTables()); - ASSERT_EQ(1, NumLogs()); - if (CanAppend()) { - ASSERT_EQ(new_log, FirstLogFile()); - } - ASSERT_EQ("bar2", Get("foo")); - ASSERT_EQ("world", Get("hello")); - ASSERT_EQ("there", Get("hi")); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/repair.cc b/src/leveldb/db/repair.cc deleted file mode 100644 index 4cd4bb047f..0000000000 --- a/src/leveldb/db/repair.cc +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// We recover the contents of the descriptor from the other files we find. -// (1) Any log files are first converted to tables -// (2) We scan every table to compute -// (a) smallest/largest for the table -// (b) largest sequence number in the table -// (3) We generate descriptor contents: -// - log number is set to zero -// - next-file-number is set to 1 + largest file number we found -// - last-sequence-number is set to largest sequence# found across -// all tables (see 2c) -// - compaction pointers are cleared -// - every table file is added at level 0 -// -// Possible optimization 1: -// (a) Compute total size and use to pick appropriate max-level M -// (b) Sort tables by largest sequence# in the table -// (c) For each table: if it overlaps earlier table, place in level-0, -// else place in level-M. -// Possible optimization 2: -// Store per-table metadata (smallest, largest, largest-seq#, ...) -// in the table's meta section to speed up ScanTable. - -#include "db/builder.h" -#include "db/db_impl.h" -#include "db/dbformat.h" -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "db/version_edit.h" -#include "db/write_batch_internal.h" -#include "leveldb/comparator.h" -#include "leveldb/db.h" -#include "leveldb/env.h" - -namespace leveldb { - -namespace { - -class Repairer { - public: - Repairer(const std::string& dbname, const Options& options) - : dbname_(dbname), - env_(options.env), - icmp_(options.comparator), - ipolicy_(options.filter_policy), - options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), - owns_info_log_(options_.info_log != options.info_log), - owns_cache_(options_.block_cache != options.block_cache), - next_file_number_(1) { - // TableCache can be small since we expect each table to be opened once. - table_cache_ = new TableCache(dbname_, &options_, 10); - } - - ~Repairer() { - delete table_cache_; - if (owns_info_log_) { - delete options_.info_log; - } - if (owns_cache_) { - delete options_.block_cache; - } - } - - Status Run() { - Status status = FindFiles(); - if (status.ok()) { - ConvertLogFilesToTables(); - ExtractMetaData(); - status = WriteDescriptor(); - } - if (status.ok()) { - unsigned long long bytes = 0; - for (size_t i = 0; i < tables_.size(); i++) { - bytes += tables_[i].meta.file_size; - } - Log(options_.info_log, - "**** Repaired leveldb %s; " - "recovered %d files; %llu bytes. " - "Some data may have been lost. " - "****", - dbname_.c_str(), - static_cast(tables_.size()), - bytes); - } - return status; - } - - private: - struct TableInfo { - FileMetaData meta; - SequenceNumber max_sequence; - }; - - std::string const dbname_; - Env* const env_; - InternalKeyComparator const icmp_; - InternalFilterPolicy const ipolicy_; - Options const options_; - bool owns_info_log_; - bool owns_cache_; - TableCache* table_cache_; - VersionEdit edit_; - - std::vector manifests_; - std::vector table_numbers_; - std::vector logs_; - std::vector tables_; - uint64_t next_file_number_; - - Status FindFiles() { - std::vector filenames; - Status status = env_->GetChildren(dbname_, &filenames); - if (!status.ok()) { - return status; - } - if (filenames.empty()) { - return Status::IOError(dbname_, "repair found no files"); - } - - uint64_t number; - FileType type; - for (size_t i = 0; i < filenames.size(); i++) { - if (ParseFileName(filenames[i], &number, &type)) { - if (type == kDescriptorFile) { - manifests_.push_back(filenames[i]); - } else { - if (number + 1 > next_file_number_) { - next_file_number_ = number + 1; - } - if (type == kLogFile) { - logs_.push_back(number); - } else if (type == kTableFile) { - table_numbers_.push_back(number); - } else { - // Ignore other files - } - } - } - } - return status; - } - - void ConvertLogFilesToTables() { - for (size_t i = 0; i < logs_.size(); i++) { - std::string logname = LogFileName(dbname_, logs_[i]); - Status status = ConvertLogToTable(logs_[i]); - if (!status.ok()) { - Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", - (unsigned long long) logs_[i], - status.ToString().c_str()); - } - ArchiveFile(logname); - } - } - - Status ConvertLogToTable(uint64_t log) { - struct LogReporter : public log::Reader::Reporter { - Env* env; - Logger* info_log; - uint64_t lognum; - virtual void Corruption(size_t bytes, const Status& s) { - // We print error messages for corruption, but continue repairing. - Log(info_log, "Log #%llu: dropping %d bytes; %s", - (unsigned long long) lognum, - static_cast(bytes), - s.ToString().c_str()); - } - }; - - // Open the log file - std::string logname = LogFileName(dbname_, log); - SequentialFile* lfile; - Status status = env_->NewSequentialFile(logname, &lfile); - if (!status.ok()) { - return status; - } - - // Create the log reader. - LogReporter reporter; - reporter.env = env_; - reporter.info_log = options_.info_log; - reporter.lognum = log; - // We intentionally make log::Reader do checksumming so that - // corruptions cause entire commits to be skipped instead of - // propagating bad information (like overly large sequence - // numbers). - log::Reader reader(lfile, &reporter, false/*do not checksum*/, - 0/*initial_offset*/); - - // Read all the records and add to a memtable - std::string scratch; - Slice record; - WriteBatch batch; - MemTable* mem = new MemTable(icmp_); - mem->Ref(); - int counter = 0; - while (reader.ReadRecord(&record, &scratch)) { - if (record.size() < 12) { - reporter.Corruption( - record.size(), Status::Corruption("log record too small")); - continue; - } - WriteBatchInternal::SetContents(&batch, record); - status = WriteBatchInternal::InsertInto(&batch, mem); - if (status.ok()) { - counter += WriteBatchInternal::Count(&batch); - } else { - Log(options_.info_log, "Log #%llu: ignoring %s", - (unsigned long long) log, - status.ToString().c_str()); - status = Status::OK(); // Keep going with rest of file - } - } - delete lfile; - - // Do not record a version edit for this conversion to a Table - // since ExtractMetaData() will also generate edits. - FileMetaData meta; - meta.number = next_file_number_++; - Iterator* iter = mem->NewIterator(); - status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); - delete iter; - mem->Unref(); - mem = NULL; - if (status.ok()) { - if (meta.file_size > 0) { - table_numbers_.push_back(meta.number); - } - } - Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", - (unsigned long long) log, - counter, - (unsigned long long) meta.number, - status.ToString().c_str()); - return status; - } - - void ExtractMetaData() { - for (size_t i = 0; i < table_numbers_.size(); i++) { - ScanTable(table_numbers_[i]); - } - } - - Iterator* NewTableIterator(const FileMetaData& meta) { - // Same as compaction iterators: if paranoid_checks are on, turn - // on checksum verification. - ReadOptions r; - r.verify_checksums = options_.paranoid_checks; - return table_cache_->NewIterator(r, meta.number, meta.file_size); - } - - void ScanTable(uint64_t number) { - TableInfo t; - t.meta.number = number; - std::string fname = TableFileName(dbname_, number); - Status status = env_->GetFileSize(fname, &t.meta.file_size); - if (!status.ok()) { - // Try alternate file name. - fname = SSTTableFileName(dbname_, number); - Status s2 = env_->GetFileSize(fname, &t.meta.file_size); - if (s2.ok()) { - status = Status::OK(); - } - } - if (!status.ok()) { - ArchiveFile(TableFileName(dbname_, number)); - ArchiveFile(SSTTableFileName(dbname_, number)); - Log(options_.info_log, "Table #%llu: dropped: %s", - (unsigned long long) t.meta.number, - status.ToString().c_str()); - return; - } - - // Extract metadata by scanning through table. - int counter = 0; - Iterator* iter = NewTableIterator(t.meta); - bool empty = true; - ParsedInternalKey parsed; - t.max_sequence = 0; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - Slice key = iter->key(); - if (!ParseInternalKey(key, &parsed)) { - Log(options_.info_log, "Table #%llu: unparsable key %s", - (unsigned long long) t.meta.number, - EscapeString(key).c_str()); - continue; - } - - counter++; - if (empty) { - empty = false; - t.meta.smallest.DecodeFrom(key); - } - t.meta.largest.DecodeFrom(key); - if (parsed.sequence > t.max_sequence) { - t.max_sequence = parsed.sequence; - } - } - if (!iter->status().ok()) { - status = iter->status(); - } - delete iter; - Log(options_.info_log, "Table #%llu: %d entries %s", - (unsigned long long) t.meta.number, - counter, - status.ToString().c_str()); - - if (status.ok()) { - tables_.push_back(t); - } else { - RepairTable(fname, t); // RepairTable archives input file. - } - } - - void RepairTable(const std::string& src, TableInfo t) { - // We will copy src contents to a new table and then rename the - // new table over the source. - - // Create builder. - std::string copy = TableFileName(dbname_, next_file_number_++); - WritableFile* file; - Status s = env_->NewWritableFile(copy, &file); - if (!s.ok()) { - return; - } - TableBuilder* builder = new TableBuilder(options_, file); - - // Copy data. - Iterator* iter = NewTableIterator(t.meta); - int counter = 0; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - builder->Add(iter->key(), iter->value()); - counter++; - } - delete iter; - - ArchiveFile(src); - if (counter == 0) { - builder->Abandon(); // Nothing to save - } else { - s = builder->Finish(); - if (s.ok()) { - t.meta.file_size = builder->FileSize(); - } - } - delete builder; - builder = NULL; - - if (s.ok()) { - s = file->Close(); - } - delete file; - file = NULL; - - if (counter > 0 && s.ok()) { - std::string orig = TableFileName(dbname_, t.meta.number); - s = env_->RenameFile(copy, orig); - if (s.ok()) { - Log(options_.info_log, "Table #%llu: %d entries repaired", - (unsigned long long) t.meta.number, counter); - tables_.push_back(t); - } - } - if (!s.ok()) { - env_->DeleteFile(copy); - } - } - - Status WriteDescriptor() { - std::string tmp = TempFileName(dbname_, 1); - WritableFile* file; - Status status = env_->NewWritableFile(tmp, &file); - if (!status.ok()) { - return status; - } - - SequenceNumber max_sequence = 0; - for (size_t i = 0; i < tables_.size(); i++) { - if (max_sequence < tables_[i].max_sequence) { - max_sequence = tables_[i].max_sequence; - } - } - - edit_.SetComparatorName(icmp_.user_comparator()->Name()); - edit_.SetLogNumber(0); - edit_.SetNextFile(next_file_number_); - edit_.SetLastSequence(max_sequence); - - for (size_t i = 0; i < tables_.size(); i++) { - // TODO(opt): separate out into multiple levels - const TableInfo& t = tables_[i]; - edit_.AddFile(0, t.meta.number, t.meta.file_size, - t.meta.smallest, t.meta.largest); - } - - //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); - { - log::Writer log(file); - std::string record; - edit_.EncodeTo(&record); - status = log.AddRecord(record); - } - if (status.ok()) { - status = file->Close(); - } - delete file; - file = NULL; - - if (!status.ok()) { - env_->DeleteFile(tmp); - } else { - // Discard older manifests - for (size_t i = 0; i < manifests_.size(); i++) { - ArchiveFile(dbname_ + "/" + manifests_[i]); - } - - // Install new manifest - status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); - if (status.ok()) { - status = SetCurrentFile(env_, dbname_, 1); - } else { - env_->DeleteFile(tmp); - } - } - return status; - } - - void ArchiveFile(const std::string& fname) { - // Move into another directory. E.g., for - // dir/foo - // rename to - // dir/lost/foo - const char* slash = strrchr(fname.c_str(), '/'); - std::string new_dir; - if (slash != NULL) { - new_dir.assign(fname.data(), slash - fname.data()); - } - new_dir.append("/lost"); - env_->CreateDir(new_dir); // Ignore error - std::string new_file = new_dir; - new_file.append("/"); - new_file.append((slash == NULL) ? fname.c_str() : slash + 1); - Status s = env_->RenameFile(fname, new_file); - Log(options_.info_log, "Archiving %s: %s\n", - fname.c_str(), s.ToString().c_str()); - } -}; -} // namespace - -Status RepairDB(const std::string& dbname, const Options& options) { - Repairer repairer(dbname, options); - return repairer.Run(); -} - -} // namespace leveldb diff --git a/src/leveldb/db/skiplist.h b/src/leveldb/db/skiplist.h deleted file mode 100644 index ed8b092203..0000000000 --- a/src/leveldb/db/skiplist.h +++ /dev/null @@ -1,384 +0,0 @@ -#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ -#define STORAGE_LEVELDB_DB_SKIPLIST_H_ - -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Thread safety -// ------------- -// -// Writes require external synchronization, most likely a mutex. -// Reads require a guarantee that the SkipList will not be destroyed -// while the read is in progress. Apart from that, reads progress -// without any internal locking or synchronization. -// -// Invariants: -// -// (1) Allocated nodes are never deleted until the SkipList is -// destroyed. This is trivially guaranteed by the code since we -// never delete any skip list nodes. -// -// (2) The contents of a Node except for the next/prev pointers are -// immutable after the Node has been linked into the SkipList. -// Only Insert() modifies the list, and it is careful to initialize -// a node and use release-stores to publish the nodes in one or -// more lists. -// -// ... prev vs. next pointer ordering ... - -#include -#include -#include "port/port.h" -#include "util/arena.h" -#include "util/random.h" - -namespace leveldb { - -class Arena; - -template -class SkipList { - private: - struct Node; - - public: - // Create a new SkipList object that will use "cmp" for comparing keys, - // and will allocate memory using "*arena". Objects allocated in the arena - // must remain allocated for the lifetime of the skiplist object. - explicit SkipList(Comparator cmp, Arena* arena); - - // Insert key into the list. - // REQUIRES: nothing that compares equal to key is currently in the list. - void Insert(const Key& key); - - // Returns true iff an entry that compares equal to key is in the list. - bool Contains(const Key& key) const; - - // Iteration over the contents of a skip list - class Iterator { - public: - // Initialize an iterator over the specified list. - // The returned iterator is not valid. - explicit Iterator(const SkipList* list); - - // Returns true iff the iterator is positioned at a valid node. - bool Valid() const; - - // Returns the key at the current position. - // REQUIRES: Valid() - const Key& key() const; - - // Advances to the next position. - // REQUIRES: Valid() - void Next(); - - // Advances to the previous position. - // REQUIRES: Valid() - void Prev(); - - // Advance to the first entry with a key >= target - void Seek(const Key& target); - - // Position at the first entry in list. - // Final state of iterator is Valid() iff list is not empty. - void SeekToFirst(); - - // Position at the last entry in list. - // Final state of iterator is Valid() iff list is not empty. - void SeekToLast(); - - private: - const SkipList* list_; - Node* node_; - // Intentionally copyable - }; - - private: - enum { kMaxHeight = 12 }; - - // Immutable after construction - Comparator const compare_; - Arena* const arena_; // Arena used for allocations of nodes - - Node* const head_; - - // Modified only by Insert(). Read racily by readers, but stale - // values are ok. - port::AtomicPointer max_height_; // Height of the entire list - - inline int GetMaxHeight() const { - return static_cast( - reinterpret_cast(max_height_.NoBarrier_Load())); - } - - // Read/written only by Insert(). - Random rnd_; - - Node* NewNode(const Key& key, int height); - int RandomHeight(); - bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } - - // Return true if key is greater than the data stored in "n" - bool KeyIsAfterNode(const Key& key, Node* n) const; - - // Return the earliest node that comes at or after key. - // Return NULL if there is no such node. - // - // If prev is non-NULL, fills prev[level] with pointer to previous - // node at "level" for every level in [0..max_height_-1]. - Node* FindGreaterOrEqual(const Key& key, Node** prev) const; - - // Return the latest node with a key < key. - // Return head_ if there is no such node. - Node* FindLessThan(const Key& key) const; - - // Return the last node in the list. - // Return head_ if list is empty. - Node* FindLast() const; - - // No copying allowed - SkipList(const SkipList&); - void operator=(const SkipList&); -}; - -// Implementation details follow -template -struct SkipList::Node { - explicit Node(const Key& k) : key(k) { } - - Key const key; - - // Accessors/mutators for links. Wrapped in methods so we can - // add the appropriate barriers as necessary. - Node* Next(int n) { - assert(n >= 0); - // Use an 'acquire load' so that we observe a fully initialized - // version of the returned Node. - return reinterpret_cast(next_[n].Acquire_Load()); - } - void SetNext(int n, Node* x) { - assert(n >= 0); - // Use a 'release store' so that anybody who reads through this - // pointer observes a fully initialized version of the inserted node. - next_[n].Release_Store(x); - } - - // No-barrier variants that can be safely used in a few locations. - Node* NoBarrier_Next(int n) { - assert(n >= 0); - return reinterpret_cast(next_[n].NoBarrier_Load()); - } - void NoBarrier_SetNext(int n, Node* x) { - assert(n >= 0); - next_[n].NoBarrier_Store(x); - } - - private: - // Array of length equal to the node height. next_[0] is lowest level link. - port::AtomicPointer next_[1]; -}; - -template -typename SkipList::Node* -SkipList::NewNode(const Key& key, int height) { - char* mem = arena_->AllocateAligned( - sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); - return new (mem) Node(key); -} - -template -inline SkipList::Iterator::Iterator(const SkipList* list) { - list_ = list; - node_ = NULL; -} - -template -inline bool SkipList::Iterator::Valid() const { - return node_ != NULL; -} - -template -inline const Key& SkipList::Iterator::key() const { - assert(Valid()); - return node_->key; -} - -template -inline void SkipList::Iterator::Next() { - assert(Valid()); - node_ = node_->Next(0); -} - -template -inline void SkipList::Iterator::Prev() { - // Instead of using explicit "prev" links, we just search for the - // last node that falls before key. - assert(Valid()); - node_ = list_->FindLessThan(node_->key); - if (node_ == list_->head_) { - node_ = NULL; - } -} - -template -inline void SkipList::Iterator::Seek(const Key& target) { - node_ = list_->FindGreaterOrEqual(target, NULL); -} - -template -inline void SkipList::Iterator::SeekToFirst() { - node_ = list_->head_->Next(0); -} - -template -inline void SkipList::Iterator::SeekToLast() { - node_ = list_->FindLast(); - if (node_ == list_->head_) { - node_ = NULL; - } -} - -template -int SkipList::RandomHeight() { - // Increase height with probability 1 in kBranching - static const unsigned int kBranching = 4; - int height = 1; - while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { - height++; - } - assert(height > 0); - assert(height <= kMaxHeight); - return height; -} - -template -bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { - // NULL n is considered infinite - return (n != NULL) && (compare_(n->key, key) < 0); -} - -template -typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) - const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - Node* next = x->Next(level); - if (KeyIsAfterNode(key, next)) { - // Keep searching in this list - x = next; - } else { - if (prev != NULL) prev[level] = x; - if (level == 0) { - return next; - } else { - // Switch to next list - level--; - } - } - } -} - -template -typename SkipList::Node* -SkipList::FindLessThan(const Key& key) const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - assert(x == head_ || compare_(x->key, key) < 0); - Node* next = x->Next(level); - if (next == NULL || compare_(next->key, key) >= 0) { - if (level == 0) { - return x; - } else { - // Switch to next list - level--; - } - } else { - x = next; - } - } -} - -template -typename SkipList::Node* SkipList::FindLast() - const { - Node* x = head_; - int level = GetMaxHeight() - 1; - while (true) { - Node* next = x->Next(level); - if (next == NULL) { - if (level == 0) { - return x; - } else { - // Switch to next list - level--; - } - } else { - x = next; - } - } -} - -template -SkipList::SkipList(Comparator cmp, Arena* arena) - : compare_(cmp), - arena_(arena), - head_(NewNode(0 /* any key will do */, kMaxHeight)), - max_height_(reinterpret_cast(1)), - rnd_(0xdeadbeef) { - for (int i = 0; i < kMaxHeight; i++) { - head_->SetNext(i, NULL); - } -} - -template -void SkipList::Insert(const Key& key) { - // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() - // here since Insert() is externally synchronized. - Node* prev[kMaxHeight]; - Node* x = FindGreaterOrEqual(key, prev); - - // Our data structure does not allow duplicate insertion - assert(x == NULL || !Equal(key, x->key)); - - int height = RandomHeight(); - if (height > GetMaxHeight()) { - for (int i = GetMaxHeight(); i < height; i++) { - prev[i] = head_; - } - //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); - - // It is ok to mutate max_height_ without any synchronization - // with concurrent readers. A concurrent reader that observes - // the new value of max_height_ will see either the old value of - // new level pointers from head_ (NULL), or a new value set in - // the loop below. In the former case the reader will - // immediately drop to the next level since NULL sorts after all - // keys. In the latter case the reader will use the new node. - max_height_.NoBarrier_Store(reinterpret_cast(height)); - } - - x = NewNode(key, height); - for (int i = 0; i < height; i++) { - // NoBarrier_SetNext() suffices since we will add a barrier when - // we publish a pointer to "x" in prev[i]. - x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); - prev[i]->SetNext(i, x); - } -} - -template -bool SkipList::Contains(const Key& key) const { - Node* x = FindGreaterOrEqual(key, NULL); - if (x != NULL && Equal(key, x->key)) { - return true; - } else { - return false; - } -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_ diff --git a/src/leveldb/db/skiplist_test.cc b/src/leveldb/db/skiplist_test.cc deleted file mode 100644 index c78f4b4fb1..0000000000 --- a/src/leveldb/db/skiplist_test.cc +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/skiplist.h" -#include -#include "leveldb/env.h" -#include "util/arena.h" -#include "util/hash.h" -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { - -typedef uint64_t Key; - -struct Comparator { - int operator()(const Key& a, const Key& b) const { - if (a < b) { - return -1; - } else if (a > b) { - return +1; - } else { - return 0; - } - } -}; - -class SkipTest { }; - -TEST(SkipTest, Empty) { - Arena arena; - Comparator cmp; - SkipList list(cmp, &arena); - ASSERT_TRUE(!list.Contains(10)); - - SkipList::Iterator iter(&list); - ASSERT_TRUE(!iter.Valid()); - iter.SeekToFirst(); - ASSERT_TRUE(!iter.Valid()); - iter.Seek(100); - ASSERT_TRUE(!iter.Valid()); - iter.SeekToLast(); - ASSERT_TRUE(!iter.Valid()); -} - -TEST(SkipTest, InsertAndLookup) { - const int N = 2000; - const int R = 5000; - Random rnd(1000); - std::set keys; - Arena arena; - Comparator cmp; - SkipList list(cmp, &arena); - for (int i = 0; i < N; i++) { - Key key = rnd.Next() % R; - if (keys.insert(key).second) { - list.Insert(key); - } - } - - for (int i = 0; i < R; i++) { - if (list.Contains(i)) { - ASSERT_EQ(keys.count(i), 1); - } else { - ASSERT_EQ(keys.count(i), 0); - } - } - - // Simple iterator tests - { - SkipList::Iterator iter(&list); - ASSERT_TRUE(!iter.Valid()); - - iter.Seek(0); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.begin()), iter.key()); - - iter.SeekToFirst(); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.begin()), iter.key()); - - iter.SeekToLast(); - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*(keys.rbegin()), iter.key()); - } - - // Forward iteration test - for (int i = 0; i < R; i++) { - SkipList::Iterator iter(&list); - iter.Seek(i); - - // Compare against model iterator - std::set::iterator model_iter = keys.lower_bound(i); - for (int j = 0; j < 3; j++) { - if (model_iter == keys.end()) { - ASSERT_TRUE(!iter.Valid()); - break; - } else { - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*model_iter, iter.key()); - ++model_iter; - iter.Next(); - } - } - } - - // Backward iteration test - { - SkipList::Iterator iter(&list); - iter.SeekToLast(); - - // Compare against model iterator - for (std::set::reverse_iterator model_iter = keys.rbegin(); - model_iter != keys.rend(); - ++model_iter) { - ASSERT_TRUE(iter.Valid()); - ASSERT_EQ(*model_iter, iter.key()); - iter.Prev(); - } - ASSERT_TRUE(!iter.Valid()); - } -} - -// We want to make sure that with a single writer and multiple -// concurrent readers (with no synchronization other than when a -// reader's iterator is created), the reader always observes all the -// data that was present in the skip list when the iterator was -// constructor. Because insertions are happening concurrently, we may -// also observe new values that were inserted since the iterator was -// constructed, but we should never miss any values that were present -// at iterator construction time. -// -// We generate multi-part keys: -// -// where: -// key is in range [0..K-1] -// gen is a generation number for key -// hash is hash(key,gen) -// -// The insertion code picks a random key, sets gen to be 1 + the last -// generation number inserted for that key, and sets hash to Hash(key,gen). -// -// At the beginning of a read, we snapshot the last inserted -// generation number for each key. We then iterate, including random -// calls to Next() and Seek(). For every key we encounter, we -// check that it is either expected given the initial snapshot or has -// been concurrently added since the iterator started. -class ConcurrentTest { - private: - static const uint32_t K = 4; - - static uint64_t key(Key key) { return (key >> 40); } - static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } - static uint64_t hash(Key key) { return key & 0xff; } - - static uint64_t HashNumbers(uint64_t k, uint64_t g) { - uint64_t data[2] = { k, g }; - return Hash(reinterpret_cast(data), sizeof(data), 0); - } - - static Key MakeKey(uint64_t k, uint64_t g) { - assert(sizeof(Key) == sizeof(uint64_t)); - assert(k <= K); // We sometimes pass K to seek to the end of the skiplist - assert(g <= 0xffffffffu); - return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); - } - - static bool IsValidKey(Key k) { - return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); - } - - static Key RandomTarget(Random* rnd) { - switch (rnd->Next() % 10) { - case 0: - // Seek to beginning - return MakeKey(0, 0); - case 1: - // Seek to end - return MakeKey(K, 0); - default: - // Seek to middle - return MakeKey(rnd->Next() % K, 0); - } - } - - // Per-key generation - struct State { - port::AtomicPointer generation[K]; - void Set(int k, intptr_t v) { - generation[k].Release_Store(reinterpret_cast(v)); - } - intptr_t Get(int k) { - return reinterpret_cast(generation[k].Acquire_Load()); - } - - State() { - for (int k = 0; k < K; k++) { - Set(k, 0); - } - } - }; - - // Current state of the test - State current_; - - Arena arena_; - - // SkipList is not protected by mu_. We just use a single writer - // thread to modify it. - SkipList list_; - - public: - ConcurrentTest() : list_(Comparator(), &arena_) { } - - // REQUIRES: External synchronization - void WriteStep(Random* rnd) { - const uint32_t k = rnd->Next() % K; - const intptr_t g = current_.Get(k) + 1; - const Key key = MakeKey(k, g); - list_.Insert(key); - current_.Set(k, g); - } - - void ReadStep(Random* rnd) { - // Remember the initial committed state of the skiplist. - State initial_state; - for (int k = 0; k < K; k++) { - initial_state.Set(k, current_.Get(k)); - } - - Key pos = RandomTarget(rnd); - SkipList::Iterator iter(&list_); - iter.Seek(pos); - while (true) { - Key current; - if (!iter.Valid()) { - current = MakeKey(K, 0); - } else { - current = iter.key(); - ASSERT_TRUE(IsValidKey(current)) << current; - } - ASSERT_LE(pos, current) << "should not go backwards"; - - // Verify that everything in [pos,current) was not present in - // initial_state. - while (pos < current) { - ASSERT_LT(key(pos), K) << pos; - - // Note that generation 0 is never inserted, so it is ok if - // <*,0,*> is missing. - ASSERT_TRUE((gen(pos) == 0) || - (gen(pos) > initial_state.Get(key(pos))) - ) << "key: " << key(pos) - << "; gen: " << gen(pos) - << "; initgen: " - << initial_state.Get(key(pos)); - - // Advance to next key in the valid key space - if (key(pos) < key(current)) { - pos = MakeKey(key(pos) + 1, 0); - } else { - pos = MakeKey(key(pos), gen(pos) + 1); - } - } - - if (!iter.Valid()) { - break; - } - - if (rnd->Next() % 2) { - iter.Next(); - pos = MakeKey(key(pos), gen(pos) + 1); - } else { - Key new_target = RandomTarget(rnd); - if (new_target > pos) { - pos = new_target; - iter.Seek(new_target); - } - } - } - } -}; -const uint32_t ConcurrentTest::K; - -// Simple test that does single-threaded testing of the ConcurrentTest -// scaffolding. -TEST(SkipTest, ConcurrentWithoutThreads) { - ConcurrentTest test; - Random rnd(test::RandomSeed()); - for (int i = 0; i < 10000; i++) { - test.ReadStep(&rnd); - test.WriteStep(&rnd); - } -} - -class TestState { - public: - ConcurrentTest t_; - int seed_; - port::AtomicPointer quit_flag_; - - enum ReaderState { - STARTING, - RUNNING, - DONE - }; - - explicit TestState(int s) - : seed_(s), - quit_flag_(NULL), - state_(STARTING), - state_cv_(&mu_) {} - - void Wait(ReaderState s) { - mu_.Lock(); - while (state_ != s) { - state_cv_.Wait(); - } - mu_.Unlock(); - } - - void Change(ReaderState s) { - mu_.Lock(); - state_ = s; - state_cv_.Signal(); - mu_.Unlock(); - } - - private: - port::Mutex mu_; - ReaderState state_; - port::CondVar state_cv_; -}; - -static void ConcurrentReader(void* arg) { - TestState* state = reinterpret_cast(arg); - Random rnd(state->seed_); - int64_t reads = 0; - state->Change(TestState::RUNNING); - while (!state->quit_flag_.Acquire_Load()) { - state->t_.ReadStep(&rnd); - ++reads; - } - state->Change(TestState::DONE); -} - -static void RunConcurrent(int run) { - const int seed = test::RandomSeed() + (run * 100); - Random rnd(seed); - const int N = 1000; - const int kSize = 1000; - for (int i = 0; i < N; i++) { - if ((i % 100) == 0) { - fprintf(stderr, "Run %d of %d\n", i, N); - } - TestState state(seed + 1); - Env::Default()->Schedule(ConcurrentReader, &state); - state.Wait(TestState::RUNNING); - for (int i = 0; i < kSize; i++) { - state.t_.WriteStep(&rnd); - } - state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do - state.Wait(TestState::DONE); - } -} - -TEST(SkipTest, Concurrent1) { RunConcurrent(1); } -TEST(SkipTest, Concurrent2) { RunConcurrent(2); } -TEST(SkipTest, Concurrent3) { RunConcurrent(3); } -TEST(SkipTest, Concurrent4) { RunConcurrent(4); } -TEST(SkipTest, Concurrent5) { RunConcurrent(5); } - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/snapshot.h b/src/leveldb/db/snapshot.h deleted file mode 100644 index e7f8fd2c37..0000000000 --- a/src/leveldb/db/snapshot.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ -#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ - -#include "leveldb/db.h" - -namespace leveldb { - -class SnapshotList; - -// Snapshots are kept in a doubly-linked list in the DB. -// Each SnapshotImpl corresponds to a particular sequence number. -class SnapshotImpl : public Snapshot { - public: - SequenceNumber number_; // const after creation - - private: - friend class SnapshotList; - - // SnapshotImpl is kept in a doubly-linked circular list - SnapshotImpl* prev_; - SnapshotImpl* next_; - - SnapshotList* list_; // just for sanity checks -}; - -class SnapshotList { - public: - SnapshotList() { - list_.prev_ = &list_; - list_.next_ = &list_; - } - - bool empty() const { return list_.next_ == &list_; } - SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } - SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } - - const SnapshotImpl* New(SequenceNumber seq) { - SnapshotImpl* s = new SnapshotImpl; - s->number_ = seq; - s->list_ = this; - s->next_ = &list_; - s->prev_ = list_.prev_; - s->prev_->next_ = s; - s->next_->prev_ = s; - return s; - } - - void Delete(const SnapshotImpl* s) { - assert(s->list_ == this); - s->prev_->next_ = s->next_; - s->next_->prev_ = s->prev_; - delete s; - } - - private: - // Dummy head of doubly-linked list of snapshots - SnapshotImpl list_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/src/leveldb/db/table_cache.cc b/src/leveldb/db/table_cache.cc deleted file mode 100644 index e3d82cd3ea..0000000000 --- a/src/leveldb/db/table_cache.cc +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/table_cache.h" - -#include "db/filename.h" -#include "leveldb/env.h" -#include "leveldb/table.h" -#include "util/coding.h" - -namespace leveldb { - -struct TableAndFile { - RandomAccessFile* file; - Table* table; -}; - -static void DeleteEntry(const Slice& key, void* value) { - TableAndFile* tf = reinterpret_cast(value); - delete tf->table; - delete tf->file; - delete tf; -} - -static void UnrefEntry(void* arg1, void* arg2) { - Cache* cache = reinterpret_cast(arg1); - Cache::Handle* h = reinterpret_cast(arg2); - cache->Release(h); -} - -TableCache::TableCache(const std::string& dbname, - const Options* options, - int entries) - : env_(options->env), - dbname_(dbname), - options_(options), - cache_(NewLRUCache(entries)) { -} - -TableCache::~TableCache() { - delete cache_; -} - -Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, - Cache::Handle** handle) { - Status s; - char buf[sizeof(file_number)]; - EncodeFixed64(buf, file_number); - Slice key(buf, sizeof(buf)); - *handle = cache_->Lookup(key); - if (*handle == NULL) { - std::string fname = TableFileName(dbname_, file_number); - RandomAccessFile* file = NULL; - Table* table = NULL; - s = env_->NewRandomAccessFile(fname, &file); - if (!s.ok()) { - std::string old_fname = SSTTableFileName(dbname_, file_number); - if (env_->NewRandomAccessFile(old_fname, &file).ok()) { - s = Status::OK(); - } - } - if (s.ok()) { - s = Table::Open(*options_, file, file_size, &table); - } - - if (!s.ok()) { - assert(table == NULL); - delete file; - // We do not cache error results so that if the error is transient, - // or somebody repairs the file, we recover automatically. - } else { - TableAndFile* tf = new TableAndFile; - tf->file = file; - tf->table = table; - *handle = cache_->Insert(key, tf, 1, &DeleteEntry); - } - } - return s; -} - -Iterator* TableCache::NewIterator(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - Table** tableptr) { - if (tableptr != NULL) { - *tableptr = NULL; - } - - Cache::Handle* handle = NULL; - Status s = FindTable(file_number, file_size, &handle); - if (!s.ok()) { - return NewErrorIterator(s); - } - - Table* table = reinterpret_cast(cache_->Value(handle))->table; - Iterator* result = table->NewIterator(options); - result->RegisterCleanup(&UnrefEntry, cache_, handle); - if (tableptr != NULL) { - *tableptr = table; - } - return result; -} - -Status TableCache::Get(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - const Slice& k, - void* arg, - void (*saver)(void*, const Slice&, const Slice&)) { - Cache::Handle* handle = NULL; - Status s = FindTable(file_number, file_size, &handle); - if (s.ok()) { - Table* t = reinterpret_cast(cache_->Value(handle))->table; - s = t->InternalGet(options, k, arg, saver); - cache_->Release(handle); - } - return s; -} - -void TableCache::Evict(uint64_t file_number) { - char buf[sizeof(file_number)]; - EncodeFixed64(buf, file_number); - cache_->Erase(Slice(buf, sizeof(buf))); -} - -} // namespace leveldb diff --git a/src/leveldb/db/table_cache.h b/src/leveldb/db/table_cache.h deleted file mode 100644 index 8cf4aaf12d..0000000000 --- a/src/leveldb/db/table_cache.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Thread-safe (provides internal synchronization) - -#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ -#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ - -#include -#include -#include "db/dbformat.h" -#include "leveldb/cache.h" -#include "leveldb/table.h" -#include "port/port.h" - -namespace leveldb { - -class Env; - -class TableCache { - public: - TableCache(const std::string& dbname, const Options* options, int entries); - ~TableCache(); - - // Return an iterator for the specified file number (the corresponding - // file length must be exactly "file_size" bytes). If "tableptr" is - // non-NULL, also sets "*tableptr" to point to the Table object - // underlying the returned iterator, or NULL if no Table object underlies - // the returned iterator. The returned "*tableptr" object is owned by - // the cache and should not be deleted, and is valid for as long as the - // returned iterator is live. - Iterator* NewIterator(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - Table** tableptr = NULL); - - // If a seek to internal key "k" in specified file finds an entry, - // call (*handle_result)(arg, found_key, found_value). - Status Get(const ReadOptions& options, - uint64_t file_number, - uint64_t file_size, - const Slice& k, - void* arg, - void (*handle_result)(void*, const Slice&, const Slice&)); - - // Evict any entry for the specified file number - void Evict(uint64_t file_number); - - private: - Env* const env_; - const std::string dbname_; - const Options* options_; - Cache* cache_; - - Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/src/leveldb/db/version_edit.cc b/src/leveldb/db/version_edit.cc deleted file mode 100644 index f10a2d58b2..0000000000 --- a/src/leveldb/db/version_edit.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_edit.h" - -#include "db/version_set.h" -#include "util/coding.h" - -namespace leveldb { - -// Tag numbers for serialized VersionEdit. These numbers are written to -// disk and should not be changed. -enum Tag { - kComparator = 1, - kLogNumber = 2, - kNextFileNumber = 3, - kLastSequence = 4, - kCompactPointer = 5, - kDeletedFile = 6, - kNewFile = 7, - // 8 was used for large value refs - kPrevLogNumber = 9 -}; - -void VersionEdit::Clear() { - comparator_.clear(); - log_number_ = 0; - prev_log_number_ = 0; - last_sequence_ = 0; - next_file_number_ = 0; - has_comparator_ = false; - has_log_number_ = false; - has_prev_log_number_ = false; - has_next_file_number_ = false; - has_last_sequence_ = false; - deleted_files_.clear(); - new_files_.clear(); -} - -void VersionEdit::EncodeTo(std::string* dst) const { - if (has_comparator_) { - PutVarint32(dst, kComparator); - PutLengthPrefixedSlice(dst, comparator_); - } - if (has_log_number_) { - PutVarint32(dst, kLogNumber); - PutVarint64(dst, log_number_); - } - if (has_prev_log_number_) { - PutVarint32(dst, kPrevLogNumber); - PutVarint64(dst, prev_log_number_); - } - if (has_next_file_number_) { - PutVarint32(dst, kNextFileNumber); - PutVarint64(dst, next_file_number_); - } - if (has_last_sequence_) { - PutVarint32(dst, kLastSequence); - PutVarint64(dst, last_sequence_); - } - - for (size_t i = 0; i < compact_pointers_.size(); i++) { - PutVarint32(dst, kCompactPointer); - PutVarint32(dst, compact_pointers_[i].first); // level - PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); - } - - for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); - iter != deleted_files_.end(); - ++iter) { - PutVarint32(dst, kDeletedFile); - PutVarint32(dst, iter->first); // level - PutVarint64(dst, iter->second); // file number - } - - for (size_t i = 0; i < new_files_.size(); i++) { - const FileMetaData& f = new_files_[i].second; - PutVarint32(dst, kNewFile); - PutVarint32(dst, new_files_[i].first); // level - PutVarint64(dst, f.number); - PutVarint64(dst, f.file_size); - PutLengthPrefixedSlice(dst, f.smallest.Encode()); - PutLengthPrefixedSlice(dst, f.largest.Encode()); - } -} - -static bool GetInternalKey(Slice* input, InternalKey* dst) { - Slice str; - if (GetLengthPrefixedSlice(input, &str)) { - dst->DecodeFrom(str); - return true; - } else { - return false; - } -} - -static bool GetLevel(Slice* input, int* level) { - uint32_t v; - if (GetVarint32(input, &v) && - v < config::kNumLevels) { - *level = v; - return true; - } else { - return false; - } -} - -Status VersionEdit::DecodeFrom(const Slice& src) { - Clear(); - Slice input = src; - const char* msg = NULL; - uint32_t tag; - - // Temporary storage for parsing - int level; - uint64_t number; - FileMetaData f; - Slice str; - InternalKey key; - - while (msg == NULL && GetVarint32(&input, &tag)) { - switch (tag) { - case kComparator: - if (GetLengthPrefixedSlice(&input, &str)) { - comparator_ = str.ToString(); - has_comparator_ = true; - } else { - msg = "comparator name"; - } - break; - - case kLogNumber: - if (GetVarint64(&input, &log_number_)) { - has_log_number_ = true; - } else { - msg = "log number"; - } - break; - - case kPrevLogNumber: - if (GetVarint64(&input, &prev_log_number_)) { - has_prev_log_number_ = true; - } else { - msg = "previous log number"; - } - break; - - case kNextFileNumber: - if (GetVarint64(&input, &next_file_number_)) { - has_next_file_number_ = true; - } else { - msg = "next file number"; - } - break; - - case kLastSequence: - if (GetVarint64(&input, &last_sequence_)) { - has_last_sequence_ = true; - } else { - msg = "last sequence number"; - } - break; - - case kCompactPointer: - if (GetLevel(&input, &level) && - GetInternalKey(&input, &key)) { - compact_pointers_.push_back(std::make_pair(level, key)); - } else { - msg = "compaction pointer"; - } - break; - - case kDeletedFile: - if (GetLevel(&input, &level) && - GetVarint64(&input, &number)) { - deleted_files_.insert(std::make_pair(level, number)); - } else { - msg = "deleted file"; - } - break; - - case kNewFile: - if (GetLevel(&input, &level) && - GetVarint64(&input, &f.number) && - GetVarint64(&input, &f.file_size) && - GetInternalKey(&input, &f.smallest) && - GetInternalKey(&input, &f.largest)) { - new_files_.push_back(std::make_pair(level, f)); - } else { - msg = "new-file entry"; - } - break; - - default: - msg = "unknown tag"; - break; - } - } - - if (msg == NULL && !input.empty()) { - msg = "invalid tag"; - } - - Status result; - if (msg != NULL) { - result = Status::Corruption("VersionEdit", msg); - } - return result; -} - -std::string VersionEdit::DebugString() const { - std::string r; - r.append("VersionEdit {"); - if (has_comparator_) { - r.append("\n Comparator: "); - r.append(comparator_); - } - if (has_log_number_) { - r.append("\n LogNumber: "); - AppendNumberTo(&r, log_number_); - } - if (has_prev_log_number_) { - r.append("\n PrevLogNumber: "); - AppendNumberTo(&r, prev_log_number_); - } - if (has_next_file_number_) { - r.append("\n NextFile: "); - AppendNumberTo(&r, next_file_number_); - } - if (has_last_sequence_) { - r.append("\n LastSeq: "); - AppendNumberTo(&r, last_sequence_); - } - for (size_t i = 0; i < compact_pointers_.size(); i++) { - r.append("\n CompactPointer: "); - AppendNumberTo(&r, compact_pointers_[i].first); - r.append(" "); - r.append(compact_pointers_[i].second.DebugString()); - } - for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); - iter != deleted_files_.end(); - ++iter) { - r.append("\n DeleteFile: "); - AppendNumberTo(&r, iter->first); - r.append(" "); - AppendNumberTo(&r, iter->second); - } - for (size_t i = 0; i < new_files_.size(); i++) { - const FileMetaData& f = new_files_[i].second; - r.append("\n AddFile: "); - AppendNumberTo(&r, new_files_[i].first); - r.append(" "); - AppendNumberTo(&r, f.number); - r.append(" "); - AppendNumberTo(&r, f.file_size); - r.append(" "); - r.append(f.smallest.DebugString()); - r.append(" .. "); - r.append(f.largest.DebugString()); - } - r.append("\n}\n"); - return r; -} - -} // namespace leveldb diff --git a/src/leveldb/db/version_edit.h b/src/leveldb/db/version_edit.h deleted file mode 100644 index eaef77b327..0000000000 --- a/src/leveldb/db/version_edit.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ -#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ - -#include -#include -#include -#include "db/dbformat.h" - -namespace leveldb { - -class VersionSet; - -struct FileMetaData { - int refs; - int allowed_seeks; // Seeks allowed until compaction - uint64_t number; - uint64_t file_size; // File size in bytes - InternalKey smallest; // Smallest internal key served by table - InternalKey largest; // Largest internal key served by table - - FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } -}; - -class VersionEdit { - public: - VersionEdit() { Clear(); } - ~VersionEdit() { } - - void Clear(); - - void SetComparatorName(const Slice& name) { - has_comparator_ = true; - comparator_ = name.ToString(); - } - void SetLogNumber(uint64_t num) { - has_log_number_ = true; - log_number_ = num; - } - void SetPrevLogNumber(uint64_t num) { - has_prev_log_number_ = true; - prev_log_number_ = num; - } - void SetNextFile(uint64_t num) { - has_next_file_number_ = true; - next_file_number_ = num; - } - void SetLastSequence(SequenceNumber seq) { - has_last_sequence_ = true; - last_sequence_ = seq; - } - void SetCompactPointer(int level, const InternalKey& key) { - compact_pointers_.push_back(std::make_pair(level, key)); - } - - // Add the specified file at the specified number. - // REQUIRES: This version has not been saved (see VersionSet::SaveTo) - // REQUIRES: "smallest" and "largest" are smallest and largest keys in file - void AddFile(int level, uint64_t file, - uint64_t file_size, - const InternalKey& smallest, - const InternalKey& largest) { - FileMetaData f; - f.number = file; - f.file_size = file_size; - f.smallest = smallest; - f.largest = largest; - new_files_.push_back(std::make_pair(level, f)); - } - - // Delete the specified "file" from the specified "level". - void DeleteFile(int level, uint64_t file) { - deleted_files_.insert(std::make_pair(level, file)); - } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(const Slice& src); - - std::string DebugString() const; - - private: - friend class VersionSet; - - typedef std::set< std::pair > DeletedFileSet; - - std::string comparator_; - uint64_t log_number_; - uint64_t prev_log_number_; - uint64_t next_file_number_; - SequenceNumber last_sequence_; - bool has_comparator_; - bool has_log_number_; - bool has_prev_log_number_; - bool has_next_file_number_; - bool has_last_sequence_; - - std::vector< std::pair > compact_pointers_; - DeletedFileSet deleted_files_; - std::vector< std::pair > new_files_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/src/leveldb/db/version_edit_test.cc b/src/leveldb/db/version_edit_test.cc deleted file mode 100644 index 280310b49d..0000000000 --- a/src/leveldb/db/version_edit_test.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_edit.h" -#include "util/testharness.h" - -namespace leveldb { - -static void TestEncodeDecode(const VersionEdit& edit) { - std::string encoded, encoded2; - edit.EncodeTo(&encoded); - VersionEdit parsed; - Status s = parsed.DecodeFrom(encoded); - ASSERT_TRUE(s.ok()) << s.ToString(); - parsed.EncodeTo(&encoded2); - ASSERT_EQ(encoded, encoded2); -} - -class VersionEditTest { }; - -TEST(VersionEditTest, EncodeDecode) { - static const uint64_t kBig = 1ull << 50; - - VersionEdit edit; - for (int i = 0; i < 4; i++) { - TestEncodeDecode(edit); - edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, - InternalKey("foo", kBig + 500 + i, kTypeValue), - InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); - edit.DeleteFile(4, kBig + 700 + i); - edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); - } - - edit.SetComparatorName("foo"); - edit.SetLogNumber(kBig + 100); - edit.SetNextFile(kBig + 200); - edit.SetLastSequence(kBig + 1000); - TestEncodeDecode(edit); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc deleted file mode 100644 index aa83df55e4..0000000000 --- a/src/leveldb/db/version_set.cc +++ /dev/null @@ -1,1484 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_set.h" - -#include -#include -#include "db/filename.h" -#include "db/log_reader.h" -#include "db/log_writer.h" -#include "db/memtable.h" -#include "db/table_cache.h" -#include "leveldb/env.h" -#include "leveldb/table_builder.h" -#include "table/merger.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -static const int kTargetFileSize = 2 * 1048576; - -// Maximum bytes of overlaps in grandparent (i.e., level+2) before we -// stop building a single file in a level->level+1 compaction. -static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; - -// Maximum number of bytes in all compacted files. We avoid expanding -// the lower level file set of a compaction if it would make the -// total compaction cover more than this many bytes. -static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; - -static double MaxBytesForLevel(int level) { - // Note: the result for level zero is not really used since we set - // the level-0 compaction threshold based on number of files. - double result = 10 * 1048576.0; // Result for both level-0 and level-1 - while (level > 1) { - result *= 10; - level--; - } - return result; -} - -static uint64_t MaxFileSizeForLevel(int level) { - return kTargetFileSize; // We could vary per level to reduce number of files? -} - -static int64_t TotalFileSize(const std::vector& files) { - int64_t sum = 0; - for (size_t i = 0; i < files.size(); i++) { - sum += files[i]->file_size; - } - return sum; -} - -Version::~Version() { - assert(refs_ == 0); - - // Remove from linked list - prev_->next_ = next_; - next_->prev_ = prev_; - - // Drop references to files - for (int level = 0; level < config::kNumLevels; level++) { - for (size_t i = 0; i < files_[level].size(); i++) { - FileMetaData* f = files_[level][i]; - assert(f->refs > 0); - f->refs--; - if (f->refs <= 0) { - delete f; - } - } - } -} - -int FindFile(const InternalKeyComparator& icmp, - const std::vector& files, - const Slice& key) { - uint32_t left = 0; - uint32_t right = files.size(); - while (left < right) { - uint32_t mid = (left + right) / 2; - const FileMetaData* f = files[mid]; - if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { - // Key at "mid.largest" is < "target". Therefore all - // files at or before "mid" are uninteresting. - left = mid + 1; - } else { - // Key at "mid.largest" is >= "target". Therefore all files - // after "mid" are uninteresting. - right = mid; - } - } - return right; -} - -static bool AfterFile(const Comparator* ucmp, - const Slice* user_key, const FileMetaData* f) { - // NULL user_key occurs before all keys and is therefore never after *f - return (user_key != NULL && - ucmp->Compare(*user_key, f->largest.user_key()) > 0); -} - -static bool BeforeFile(const Comparator* ucmp, - const Slice* user_key, const FileMetaData* f) { - // NULL user_key occurs after all keys and is therefore never before *f - return (user_key != NULL && - ucmp->Compare(*user_key, f->smallest.user_key()) < 0); -} - -bool SomeFileOverlapsRange( - const InternalKeyComparator& icmp, - bool disjoint_sorted_files, - const std::vector& files, - const Slice* smallest_user_key, - const Slice* largest_user_key) { - const Comparator* ucmp = icmp.user_comparator(); - if (!disjoint_sorted_files) { - // Need to check against all files - for (size_t i = 0; i < files.size(); i++) { - const FileMetaData* f = files[i]; - if (AfterFile(ucmp, smallest_user_key, f) || - BeforeFile(ucmp, largest_user_key, f)) { - // No overlap - } else { - return true; // Overlap - } - } - return false; - } - - // Binary search over file list - uint32_t index = 0; - if (smallest_user_key != NULL) { - // Find the earliest possible internal key for smallest_user_key - InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); - index = FindFile(icmp, files, small.Encode()); - } - - if (index >= files.size()) { - // beginning of range is after all files, so no overlap. - return false; - } - - return !BeforeFile(ucmp, largest_user_key, files[index]); -} - -// An internal iterator. For a given version/level pair, yields -// information about the files in the level. For a given entry, key() -// is the largest key that occurs in the file, and value() is an -// 16-byte value containing the file number and file size, both -// encoded using EncodeFixed64. -class Version::LevelFileNumIterator : public Iterator { - public: - LevelFileNumIterator(const InternalKeyComparator& icmp, - const std::vector* flist) - : icmp_(icmp), - flist_(flist), - index_(flist->size()) { // Marks as invalid - } - virtual bool Valid() const { - return index_ < flist_->size(); - } - virtual void Seek(const Slice& target) { - index_ = FindFile(icmp_, *flist_, target); - } - virtual void SeekToFirst() { index_ = 0; } - virtual void SeekToLast() { - index_ = flist_->empty() ? 0 : flist_->size() - 1; - } - virtual void Next() { - assert(Valid()); - index_++; - } - virtual void Prev() { - assert(Valid()); - if (index_ == 0) { - index_ = flist_->size(); // Marks as invalid - } else { - index_--; - } - } - Slice key() const { - assert(Valid()); - return (*flist_)[index_]->largest.Encode(); - } - Slice value() const { - assert(Valid()); - EncodeFixed64(value_buf_, (*flist_)[index_]->number); - EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); - return Slice(value_buf_, sizeof(value_buf_)); - } - virtual Status status() const { return Status::OK(); } - private: - const InternalKeyComparator icmp_; - const std::vector* const flist_; - uint32_t index_; - - // Backing store for value(). Holds the file number and size. - mutable char value_buf_[16]; -}; - -static Iterator* GetFileIterator(void* arg, - const ReadOptions& options, - const Slice& file_value) { - TableCache* cache = reinterpret_cast(arg); - if (file_value.size() != 16) { - return NewErrorIterator( - Status::Corruption("FileReader invoked with unexpected value")); - } else { - return cache->NewIterator(options, - DecodeFixed64(file_value.data()), - DecodeFixed64(file_value.data() + 8)); - } -} - -Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, - int level) const { - return NewTwoLevelIterator( - new LevelFileNumIterator(vset_->icmp_, &files_[level]), - &GetFileIterator, vset_->table_cache_, options); -} - -void Version::AddIterators(const ReadOptions& options, - std::vector* iters) { - // Merge all level zero files together since they may overlap - for (size_t i = 0; i < files_[0].size(); i++) { - iters->push_back( - vset_->table_cache_->NewIterator( - options, files_[0][i]->number, files_[0][i]->file_size)); - } - - // For levels > 0, we can use a concatenating iterator that sequentially - // walks through the non-overlapping files in the level, opening them - // lazily. - for (int level = 1; level < config::kNumLevels; level++) { - if (!files_[level].empty()) { - iters->push_back(NewConcatenatingIterator(options, level)); - } - } -} - -// Callback from TableCache::Get() -namespace { -enum SaverState { - kNotFound, - kFound, - kDeleted, - kCorrupt, -}; -struct Saver { - SaverState state; - const Comparator* ucmp; - Slice user_key; - std::string* value; -}; -} -static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { - Saver* s = reinterpret_cast(arg); - ParsedInternalKey parsed_key; - if (!ParseInternalKey(ikey, &parsed_key)) { - s->state = kCorrupt; - } else { - if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { - s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; - if (s->state == kFound) { - s->value->assign(v.data(), v.size()); - } - } - } -} - -static bool NewestFirst(FileMetaData* a, FileMetaData* b) { - return a->number > b->number; -} - -void Version::ForEachOverlapping(Slice user_key, Slice internal_key, - void* arg, - bool (*func)(void*, int, FileMetaData*)) { - // TODO(sanjay): Change Version::Get() to use this function. - const Comparator* ucmp = vset_->icmp_.user_comparator(); - - // Search level-0 in order from newest to oldest. - std::vector tmp; - tmp.reserve(files_[0].size()); - for (uint32_t i = 0; i < files_[0].size(); i++) { - FileMetaData* f = files_[0][i]; - if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && - ucmp->Compare(user_key, f->largest.user_key()) <= 0) { - tmp.push_back(f); - } - } - if (!tmp.empty()) { - std::sort(tmp.begin(), tmp.end(), NewestFirst); - for (uint32_t i = 0; i < tmp.size(); i++) { - if (!(*func)(arg, 0, tmp[i])) { - return; - } - } - } - - // Search other levels. - for (int level = 1; level < config::kNumLevels; level++) { - size_t num_files = files_[level].size(); - if (num_files == 0) continue; - - // Binary search to find earliest index whose largest key >= internal_key. - uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); - if (index < num_files) { - FileMetaData* f = files_[level][index]; - if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { - // All of "f" is past any data for user_key - } else { - if (!(*func)(arg, level, f)) { - return; - } - } - } - } -} - -Status Version::Get(const ReadOptions& options, - const LookupKey& k, - std::string* value, - GetStats* stats) { - Slice ikey = k.internal_key(); - Slice user_key = k.user_key(); - const Comparator* ucmp = vset_->icmp_.user_comparator(); - Status s; - - stats->seek_file = NULL; - stats->seek_file_level = -1; - FileMetaData* last_file_read = NULL; - int last_file_read_level = -1; - - // We can search level-by-level since entries never hop across - // levels. Therefore we are guaranteed that if we find data - // in an smaller level, later levels are irrelevant. - std::vector tmp; - FileMetaData* tmp2; - for (int level = 0; level < config::kNumLevels; level++) { - size_t num_files = files_[level].size(); - if (num_files == 0) continue; - - // Get the list of files to search in this level - FileMetaData* const* files = &files_[level][0]; - if (level == 0) { - // Level-0 files may overlap each other. Find all files that - // overlap user_key and process them in order from newest to oldest. - tmp.reserve(num_files); - for (uint32_t i = 0; i < num_files; i++) { - FileMetaData* f = files[i]; - if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && - ucmp->Compare(user_key, f->largest.user_key()) <= 0) { - tmp.push_back(f); - } - } - if (tmp.empty()) continue; - - std::sort(tmp.begin(), tmp.end(), NewestFirst); - files = &tmp[0]; - num_files = tmp.size(); - } else { - // Binary search to find earliest index whose largest key >= ikey. - uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); - if (index >= num_files) { - files = NULL; - num_files = 0; - } else { - tmp2 = files[index]; - if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { - // All of "tmp2" is past any data for user_key - files = NULL; - num_files = 0; - } else { - files = &tmp2; - num_files = 1; - } - } - } - - for (uint32_t i = 0; i < num_files; ++i) { - if (last_file_read != NULL && stats->seek_file == NULL) { - // We have had more than one seek for this read. Charge the 1st file. - stats->seek_file = last_file_read; - stats->seek_file_level = last_file_read_level; - } - - FileMetaData* f = files[i]; - last_file_read = f; - last_file_read_level = level; - - Saver saver; - saver.state = kNotFound; - saver.ucmp = ucmp; - saver.user_key = user_key; - saver.value = value; - s = vset_->table_cache_->Get(options, f->number, f->file_size, - ikey, &saver, SaveValue); - if (!s.ok()) { - return s; - } - switch (saver.state) { - case kNotFound: - break; // Keep searching in other files - case kFound: - return s; - case kDeleted: - s = Status::NotFound(Slice()); // Use empty error message for speed - return s; - case kCorrupt: - s = Status::Corruption("corrupted key for ", user_key); - return s; - } - } - } - - return Status::NotFound(Slice()); // Use an empty error message for speed -} - -bool Version::UpdateStats(const GetStats& stats) { - FileMetaData* f = stats.seek_file; - if (f != NULL) { - f->allowed_seeks--; - if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { - file_to_compact_ = f; - file_to_compact_level_ = stats.seek_file_level; - return true; - } - } - return false; -} - -bool Version::RecordReadSample(Slice internal_key) { - ParsedInternalKey ikey; - if (!ParseInternalKey(internal_key, &ikey)) { - return false; - } - - struct State { - GetStats stats; // Holds first matching file - int matches; - - static bool Match(void* arg, int level, FileMetaData* f) { - State* state = reinterpret_cast(arg); - state->matches++; - if (state->matches == 1) { - // Remember first match. - state->stats.seek_file = f; - state->stats.seek_file_level = level; - } - // We can stop iterating once we have a second match. - return state->matches < 2; - } - }; - - State state; - state.matches = 0; - ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); - - // Must have at least two matches since we want to merge across - // files. But what if we have a single file that contains many - // overwrites and deletions? Should we have another mechanism for - // finding such files? - if (state.matches >= 2) { - // 1MB cost is about 1 seek (see comment in Builder::Apply). - return UpdateStats(state.stats); - } - return false; -} - -void Version::Ref() { - ++refs_; -} - -void Version::Unref() { - assert(this != &vset_->dummy_versions_); - assert(refs_ >= 1); - --refs_; - if (refs_ == 0) { - delete this; - } -} - -bool Version::OverlapInLevel(int level, - const Slice* smallest_user_key, - const Slice* largest_user_key) { - return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], - smallest_user_key, largest_user_key); -} - -int Version::PickLevelForMemTableOutput( - const Slice& smallest_user_key, - const Slice& largest_user_key) { - int level = 0; - if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { - // Push to next level if there is no overlap in next level, - // and the #bytes overlapping in the level after that are limited. - InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); - InternalKey limit(largest_user_key, 0, static_cast(0)); - std::vector overlaps; - while (level < config::kMaxMemCompactLevel) { - if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { - break; - } - if (level + 2 < config::kNumLevels) { - // Check that file does not overlap too many grandparent bytes. - GetOverlappingInputs(level + 2, &start, &limit, &overlaps); - const int64_t sum = TotalFileSize(overlaps); - if (sum > kMaxGrandParentOverlapBytes) { - break; - } - } - level++; - } - } - return level; -} - -// Store in "*inputs" all files in "level" that overlap [begin,end] -void Version::GetOverlappingInputs( - int level, - const InternalKey* begin, - const InternalKey* end, - std::vector* inputs) { - assert(level >= 0); - assert(level < config::kNumLevels); - inputs->clear(); - Slice user_begin, user_end; - if (begin != NULL) { - user_begin = begin->user_key(); - } - if (end != NULL) { - user_end = end->user_key(); - } - const Comparator* user_cmp = vset_->icmp_.user_comparator(); - for (size_t i = 0; i < files_[level].size(); ) { - FileMetaData* f = files_[level][i++]; - const Slice file_start = f->smallest.user_key(); - const Slice file_limit = f->largest.user_key(); - if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { - // "f" is completely before specified range; skip it - } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { - // "f" is completely after specified range; skip it - } else { - inputs->push_back(f); - if (level == 0) { - // Level-0 files may overlap each other. So check if the newly - // added file has expanded the range. If so, restart search. - if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { - user_begin = file_start; - inputs->clear(); - i = 0; - } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { - user_end = file_limit; - inputs->clear(); - i = 0; - } - } - } - } -} - -std::string Version::DebugString() const { - std::string r; - for (int level = 0; level < config::kNumLevels; level++) { - // E.g., - // --- level 1 --- - // 17:123['a' .. 'd'] - // 20:43['e' .. 'g'] - r.append("--- level "); - AppendNumberTo(&r, level); - r.append(" ---\n"); - const std::vector& files = files_[level]; - for (size_t i = 0; i < files.size(); i++) { - r.push_back(' '); - AppendNumberTo(&r, files[i]->number); - r.push_back(':'); - AppendNumberTo(&r, files[i]->file_size); - r.append("["); - r.append(files[i]->smallest.DebugString()); - r.append(" .. "); - r.append(files[i]->largest.DebugString()); - r.append("]\n"); - } - } - return r; -} - -// A helper class so we can efficiently apply a whole sequence -// of edits to a particular state without creating intermediate -// Versions that contain full copies of the intermediate state. -class VersionSet::Builder { - private: - // Helper to sort by v->files_[file_number].smallest - struct BySmallestKey { - const InternalKeyComparator* internal_comparator; - - bool operator()(FileMetaData* f1, FileMetaData* f2) const { - int r = internal_comparator->Compare(f1->smallest, f2->smallest); - if (r != 0) { - return (r < 0); - } else { - // Break ties by file number - return (f1->number < f2->number); - } - } - }; - - typedef std::set FileSet; - struct LevelState { - std::set deleted_files; - FileSet* added_files; - }; - - VersionSet* vset_; - Version* base_; - LevelState levels_[config::kNumLevels]; - - public: - // Initialize a builder with the files from *base and other info from *vset - Builder(VersionSet* vset, Version* base) - : vset_(vset), - base_(base) { - base_->Ref(); - BySmallestKey cmp; - cmp.internal_comparator = &vset_->icmp_; - for (int level = 0; level < config::kNumLevels; level++) { - levels_[level].added_files = new FileSet(cmp); - } - } - - ~Builder() { - for (int level = 0; level < config::kNumLevels; level++) { - const FileSet* added = levels_[level].added_files; - std::vector to_unref; - to_unref.reserve(added->size()); - for (FileSet::const_iterator it = added->begin(); - it != added->end(); ++it) { - to_unref.push_back(*it); - } - delete added; - for (uint32_t i = 0; i < to_unref.size(); i++) { - FileMetaData* f = to_unref[i]; - f->refs--; - if (f->refs <= 0) { - delete f; - } - } - } - base_->Unref(); - } - - // Apply all of the edits in *edit to the current state. - void Apply(VersionEdit* edit) { - // Update compaction pointers - for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { - const int level = edit->compact_pointers_[i].first; - vset_->compact_pointer_[level] = - edit->compact_pointers_[i].second.Encode().ToString(); - } - - // Delete files - const VersionEdit::DeletedFileSet& del = edit->deleted_files_; - for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); - iter != del.end(); - ++iter) { - const int level = iter->first; - const uint64_t number = iter->second; - levels_[level].deleted_files.insert(number); - } - - // Add new files - for (size_t i = 0; i < edit->new_files_.size(); i++) { - const int level = edit->new_files_[i].first; - FileMetaData* f = new FileMetaData(edit->new_files_[i].second); - f->refs = 1; - - // We arrange to automatically compact this file after - // a certain number of seeks. Let's assume: - // (1) One seek costs 10ms - // (2) Writing or reading 1MB costs 10ms (100MB/s) - // (3) A compaction of 1MB does 25MB of IO: - // 1MB read from this level - // 10-12MB read from next level (boundaries may be misaligned) - // 10-12MB written to next level - // This implies that 25 seeks cost the same as the compaction - // of 1MB of data. I.e., one seek costs approximately the - // same as the compaction of 40KB of data. We are a little - // conservative and allow approximately one seek for every 16KB - // of data before triggering a compaction. - f->allowed_seeks = (f->file_size / 16384); - if (f->allowed_seeks < 100) f->allowed_seeks = 100; - - levels_[level].deleted_files.erase(f->number); - levels_[level].added_files->insert(f); - } - } - - // Save the current state in *v. - void SaveTo(Version* v) { - BySmallestKey cmp; - cmp.internal_comparator = &vset_->icmp_; - for (int level = 0; level < config::kNumLevels; level++) { - // Merge the set of added files with the set of pre-existing files. - // Drop any deleted files. Store the result in *v. - const std::vector& base_files = base_->files_[level]; - std::vector::const_iterator base_iter = base_files.begin(); - std::vector::const_iterator base_end = base_files.end(); - const FileSet* added = levels_[level].added_files; - v->files_[level].reserve(base_files.size() + added->size()); - for (FileSet::const_iterator added_iter = added->begin(); - added_iter != added->end(); - ++added_iter) { - // Add all smaller files listed in base_ - for (std::vector::const_iterator bpos - = std::upper_bound(base_iter, base_end, *added_iter, cmp); - base_iter != bpos; - ++base_iter) { - MaybeAddFile(v, level, *base_iter); - } - - MaybeAddFile(v, level, *added_iter); - } - - // Add remaining base files - for (; base_iter != base_end; ++base_iter) { - MaybeAddFile(v, level, *base_iter); - } - -#ifndef NDEBUG - // Make sure there is no overlap in levels > 0 - if (level > 0) { - for (uint32_t i = 1; i < v->files_[level].size(); i++) { - const InternalKey& prev_end = v->files_[level][i-1]->largest; - const InternalKey& this_begin = v->files_[level][i]->smallest; - if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { - fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", - prev_end.DebugString().c_str(), - this_begin.DebugString().c_str()); - abort(); - } - } - } -#endif - } - } - - void MaybeAddFile(Version* v, int level, FileMetaData* f) { - if (levels_[level].deleted_files.count(f->number) > 0) { - // File is deleted: do nothing - } else { - std::vector* files = &v->files_[level]; - if (level > 0 && !files->empty()) { - // Must not overlap - assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, - f->smallest) < 0); - } - f->refs++; - files->push_back(f); - } - } -}; - -VersionSet::VersionSet(const std::string& dbname, - const Options* options, - TableCache* table_cache, - const InternalKeyComparator* cmp) - : env_(options->env), - dbname_(dbname), - options_(options), - table_cache_(table_cache), - icmp_(*cmp), - next_file_number_(2), - manifest_file_number_(0), // Filled by Recover() - last_sequence_(0), - log_number_(0), - prev_log_number_(0), - descriptor_file_(NULL), - descriptor_log_(NULL), - dummy_versions_(this), - current_(NULL) { - AppendVersion(new Version(this)); -} - -VersionSet::~VersionSet() { - current_->Unref(); - assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty - delete descriptor_log_; - delete descriptor_file_; -} - -void VersionSet::AppendVersion(Version* v) { - // Make "v" current - assert(v->refs_ == 0); - assert(v != current_); - if (current_ != NULL) { - current_->Unref(); - } - current_ = v; - v->Ref(); - - // Append to linked list - v->prev_ = dummy_versions_.prev_; - v->next_ = &dummy_versions_; - v->prev_->next_ = v; - v->next_->prev_ = v; -} - -Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { - if (edit->has_log_number_) { - assert(edit->log_number_ >= log_number_); - assert(edit->log_number_ < next_file_number_); - } else { - edit->SetLogNumber(log_number_); - } - - if (!edit->has_prev_log_number_) { - edit->SetPrevLogNumber(prev_log_number_); - } - - edit->SetNextFile(next_file_number_); - edit->SetLastSequence(last_sequence_); - - Version* v = new Version(this); - { - Builder builder(this, current_); - builder.Apply(edit); - builder.SaveTo(v); - } - Finalize(v); - - // Initialize new descriptor log file if necessary by creating - // a temporary file that contains a snapshot of the current version. - std::string new_manifest_file; - Status s; - if (descriptor_log_ == NULL) { - // No reason to unlock *mu here since we only hit this path in the - // first call to LogAndApply (when opening the database). - assert(descriptor_file_ == NULL); - new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); - edit->SetNextFile(next_file_number_); - s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); - if (s.ok()) { - descriptor_log_ = new log::Writer(descriptor_file_); - s = WriteSnapshot(descriptor_log_); - } - } - - // Unlock during expensive MANIFEST log write - { - mu->Unlock(); - - // Write new record to MANIFEST log - if (s.ok()) { - std::string record; - edit->EncodeTo(&record); - s = descriptor_log_->AddRecord(record); - if (s.ok()) { - s = descriptor_file_->Sync(); - } - if (!s.ok()) { - Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); - } - } - - // If we just created a new descriptor file, install it by writing a - // new CURRENT file that points to it. - if (s.ok() && !new_manifest_file.empty()) { - s = SetCurrentFile(env_, dbname_, manifest_file_number_); - } - - mu->Lock(); - } - - // Install the new version - if (s.ok()) { - AppendVersion(v); - log_number_ = edit->log_number_; - prev_log_number_ = edit->prev_log_number_; - } else { - delete v; - if (!new_manifest_file.empty()) { - delete descriptor_log_; - delete descriptor_file_; - descriptor_log_ = NULL; - descriptor_file_ = NULL; - env_->DeleteFile(new_manifest_file); - } - } - - return s; -} - -Status VersionSet::Recover() { - struct LogReporter : public log::Reader::Reporter { - Status* status; - virtual void Corruption(size_t bytes, const Status& s) { - if (this->status->ok()) *this->status = s; - } - }; - - // Read "CURRENT" file, which contains a pointer to the current manifest file - std::string current; - Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); - if (!s.ok()) { - return s; - } - if (current.empty() || current[current.size()-1] != '\n') { - return Status::Corruption("CURRENT file does not end with newline"); - } - current.resize(current.size() - 1); - - std::string dscname = dbname_ + "/" + current; - SequentialFile* file; - s = env_->NewSequentialFile(dscname, &file); - if (!s.ok()) { - return s; - } - - bool have_log_number = false; - bool have_prev_log_number = false; - bool have_next_file = false; - bool have_last_sequence = false; - uint64_t next_file = 0; - uint64_t last_sequence = 0; - uint64_t log_number = 0; - uint64_t prev_log_number = 0; - Builder builder(this, current_); - - { - LogReporter reporter; - reporter.status = &s; - log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); - Slice record; - std::string scratch; - while (reader.ReadRecord(&record, &scratch) && s.ok()) { - VersionEdit edit; - s = edit.DecodeFrom(record); - if (s.ok()) { - if (edit.has_comparator_ && - edit.comparator_ != icmp_.user_comparator()->Name()) { - s = Status::InvalidArgument( - edit.comparator_ + " does not match existing comparator ", - icmp_.user_comparator()->Name()); - } - } - - if (s.ok()) { - builder.Apply(&edit); - } - - if (edit.has_log_number_) { - log_number = edit.log_number_; - have_log_number = true; - } - - if (edit.has_prev_log_number_) { - prev_log_number = edit.prev_log_number_; - have_prev_log_number = true; - } - - if (edit.has_next_file_number_) { - next_file = edit.next_file_number_; - have_next_file = true; - } - - if (edit.has_last_sequence_) { - last_sequence = edit.last_sequence_; - have_last_sequence = true; - } - } - } - delete file; - file = NULL; - - if (s.ok()) { - if (!have_next_file) { - s = Status::Corruption("no meta-nextfile entry in descriptor"); - } else if (!have_log_number) { - s = Status::Corruption("no meta-lognumber entry in descriptor"); - } else if (!have_last_sequence) { - s = Status::Corruption("no last-sequence-number entry in descriptor"); - } - - if (!have_prev_log_number) { - prev_log_number = 0; - } - - MarkFileNumberUsed(prev_log_number); - MarkFileNumberUsed(log_number); - } - - if (s.ok()) { - Version* v = new Version(this); - builder.SaveTo(v); - // Install recovered version - Finalize(v); - AppendVersion(v); - manifest_file_number_ = next_file; - next_file_number_ = next_file + 1; - last_sequence_ = last_sequence; - log_number_ = log_number; - prev_log_number_ = prev_log_number; - } - - return s; -} - -void VersionSet::MarkFileNumberUsed(uint64_t number) { - if (next_file_number_ <= number) { - next_file_number_ = number + 1; - } -} - -void VersionSet::Finalize(Version* v) { - // Precomputed best level for next compaction - int best_level = -1; - double best_score = -1; - - for (int level = 0; level < config::kNumLevels-1; level++) { - double score; - if (level == 0) { - // We treat level-0 specially by bounding the number of files - // instead of number of bytes for two reasons: - // - // (1) With larger write-buffer sizes, it is nice not to do too - // many level-0 compactions. - // - // (2) The files in level-0 are merged on every read and - // therefore we wish to avoid too many files when the individual - // file size is small (perhaps because of a small write-buffer - // setting, or very high compression ratios, or lots of - // overwrites/deletions). - score = v->files_[level].size() / - static_cast(config::kL0_CompactionTrigger); - } else { - // Compute the ratio of current size to size limit. - const uint64_t level_bytes = TotalFileSize(v->files_[level]); - score = static_cast(level_bytes) / MaxBytesForLevel(level); - } - - if (score > best_score) { - best_level = level; - best_score = score; - } - } - - v->compaction_level_ = best_level; - v->compaction_score_ = best_score; -} - -Status VersionSet::WriteSnapshot(log::Writer* log) { - // TODO: Break up into multiple records to reduce memory usage on recovery? - - // Save metadata - VersionEdit edit; - edit.SetComparatorName(icmp_.user_comparator()->Name()); - - // Save compaction pointers - for (int level = 0; level < config::kNumLevels; level++) { - if (!compact_pointer_[level].empty()) { - InternalKey key; - key.DecodeFrom(compact_pointer_[level]); - edit.SetCompactPointer(level, key); - } - } - - // Save files - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = current_->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - const FileMetaData* f = files[i]; - edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); - } - } - - std::string record; - edit.EncodeTo(&record); - return log->AddRecord(record); -} - -int VersionSet::NumLevelFiles(int level) const { - assert(level >= 0); - assert(level < config::kNumLevels); - return current_->files_[level].size(); -} - -const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { - // Update code if kNumLevels changes - assert(config::kNumLevels == 7); - snprintf(scratch->buffer, sizeof(scratch->buffer), - "files[ %d %d %d %d %d %d %d ]", - int(current_->files_[0].size()), - int(current_->files_[1].size()), - int(current_->files_[2].size()), - int(current_->files_[3].size()), - int(current_->files_[4].size()), - int(current_->files_[5].size()), - int(current_->files_[6].size())); - return scratch->buffer; -} - -uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { - uint64_t result = 0; - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = v->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - if (icmp_.Compare(files[i]->largest, ikey) <= 0) { - // Entire file is before "ikey", so just add the file size - result += files[i]->file_size; - } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { - // Entire file is after "ikey", so ignore - if (level > 0) { - // Files other than level 0 are sorted by meta->smallest, so - // no further files in this level will contain data for - // "ikey". - break; - } - } else { - // "ikey" falls in the range for this table. Add the - // approximate offset of "ikey" within the table. - Table* tableptr; - Iterator* iter = table_cache_->NewIterator( - ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); - if (tableptr != NULL) { - result += tableptr->ApproximateOffsetOf(ikey.Encode()); - } - delete iter; - } - } - } - return result; -} - -void VersionSet::AddLiveFiles(std::set* live) { - for (Version* v = dummy_versions_.next_; - v != &dummy_versions_; - v = v->next_) { - for (int level = 0; level < config::kNumLevels; level++) { - const std::vector& files = v->files_[level]; - for (size_t i = 0; i < files.size(); i++) { - live->insert(files[i]->number); - } - } - } -} - -int64_t VersionSet::NumLevelBytes(int level) const { - assert(level >= 0); - assert(level < config::kNumLevels); - return TotalFileSize(current_->files_[level]); -} - -int64_t VersionSet::MaxNextLevelOverlappingBytes() { - int64_t result = 0; - std::vector overlaps; - for (int level = 1; level < config::kNumLevels - 1; level++) { - for (size_t i = 0; i < current_->files_[level].size(); i++) { - const FileMetaData* f = current_->files_[level][i]; - current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, - &overlaps); - const int64_t sum = TotalFileSize(overlaps); - if (sum > result) { - result = sum; - } - } - } - return result; -} - -// Stores the minimal range that covers all entries in inputs in -// *smallest, *largest. -// REQUIRES: inputs is not empty -void VersionSet::GetRange(const std::vector& inputs, - InternalKey* smallest, - InternalKey* largest) { - assert(!inputs.empty()); - smallest->Clear(); - largest->Clear(); - for (size_t i = 0; i < inputs.size(); i++) { - FileMetaData* f = inputs[i]; - if (i == 0) { - *smallest = f->smallest; - *largest = f->largest; - } else { - if (icmp_.Compare(f->smallest, *smallest) < 0) { - *smallest = f->smallest; - } - if (icmp_.Compare(f->largest, *largest) > 0) { - *largest = f->largest; - } - } - } -} - -// Stores the minimal range that covers all entries in inputs1 and inputs2 -// in *smallest, *largest. -// REQUIRES: inputs is not empty -void VersionSet::GetRange2(const std::vector& inputs1, - const std::vector& inputs2, - InternalKey* smallest, - InternalKey* largest) { - std::vector all = inputs1; - all.insert(all.end(), inputs2.begin(), inputs2.end()); - GetRange(all, smallest, largest); -} - -Iterator* VersionSet::MakeInputIterator(Compaction* c) { - ReadOptions options; - options.verify_checksums = options_->paranoid_checks; - options.fill_cache = false; - - // Level-0 files have to be merged together. For other levels, - // we will make a concatenating iterator per level. - // TODO(opt): use concatenating iterator for level-0 if there is no overlap - const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); - Iterator** list = new Iterator*[space]; - int num = 0; - for (int which = 0; which < 2; which++) { - if (!c->inputs_[which].empty()) { - if (c->level() + which == 0) { - const std::vector& files = c->inputs_[which]; - for (size_t i = 0; i < files.size(); i++) { - list[num++] = table_cache_->NewIterator( - options, files[i]->number, files[i]->file_size); - } - } else { - // Create concatenating iterator for the files from this level - list[num++] = NewTwoLevelIterator( - new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), - &GetFileIterator, table_cache_, options); - } - } - } - assert(num <= space); - Iterator* result = NewMergingIterator(&icmp_, list, num); - delete[] list; - return result; -} - -Compaction* VersionSet::PickCompaction() { - Compaction* c; - int level; - - // We prefer compactions triggered by too much data in a level over - // the compactions triggered by seeks. - const bool size_compaction = (current_->compaction_score_ >= 1); - const bool seek_compaction = (current_->file_to_compact_ != NULL); - if (size_compaction) { - level = current_->compaction_level_; - assert(level >= 0); - assert(level+1 < config::kNumLevels); - c = new Compaction(level); - - // Pick the first file that comes after compact_pointer_[level] - for (size_t i = 0; i < current_->files_[level].size(); i++) { - FileMetaData* f = current_->files_[level][i]; - if (compact_pointer_[level].empty() || - icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { - c->inputs_[0].push_back(f); - break; - } - } - if (c->inputs_[0].empty()) { - // Wrap-around to the beginning of the key space - c->inputs_[0].push_back(current_->files_[level][0]); - } - } else if (seek_compaction) { - level = current_->file_to_compact_level_; - c = new Compaction(level); - c->inputs_[0].push_back(current_->file_to_compact_); - } else { - return NULL; - } - - c->input_version_ = current_; - c->input_version_->Ref(); - - // Files in level 0 may overlap each other, so pick up all overlapping ones - if (level == 0) { - InternalKey smallest, largest; - GetRange(c->inputs_[0], &smallest, &largest); - // Note that the next call will discard the file we placed in - // c->inputs_[0] earlier and replace it with an overlapping set - // which will include the picked file. - current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); - assert(!c->inputs_[0].empty()); - } - - SetupOtherInputs(c); - - return c; -} - -void VersionSet::SetupOtherInputs(Compaction* c) { - const int level = c->level(); - InternalKey smallest, largest; - GetRange(c->inputs_[0], &smallest, &largest); - - current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); - - // Get entire range covered by compaction - InternalKey all_start, all_limit; - GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); - - // See if we can grow the number of inputs in "level" without - // changing the number of "level+1" files we pick up. - if (!c->inputs_[1].empty()) { - std::vector expanded0; - current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); - const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); - const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); - const int64_t expanded0_size = TotalFileSize(expanded0); - if (expanded0.size() > c->inputs_[0].size() && - inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { - InternalKey new_start, new_limit; - GetRange(expanded0, &new_start, &new_limit); - std::vector expanded1; - current_->GetOverlappingInputs(level+1, &new_start, &new_limit, - &expanded1); - if (expanded1.size() == c->inputs_[1].size()) { - Log(options_->info_log, - "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", - level, - int(c->inputs_[0].size()), - int(c->inputs_[1].size()), - long(inputs0_size), long(inputs1_size), - int(expanded0.size()), - int(expanded1.size()), - long(expanded0_size), long(inputs1_size)); - smallest = new_start; - largest = new_limit; - c->inputs_[0] = expanded0; - c->inputs_[1] = expanded1; - GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); - } - } - } - - // Compute the set of grandparent files that overlap this compaction - // (parent == level+1; grandparent == level+2) - if (level + 2 < config::kNumLevels) { - current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, - &c->grandparents_); - } - - if (false) { - Log(options_->info_log, "Compacting %d '%s' .. '%s'", - level, - smallest.DebugString().c_str(), - largest.DebugString().c_str()); - } - - // Update the place where we will do the next compaction for this level. - // We update this immediately instead of waiting for the VersionEdit - // to be applied so that if the compaction fails, we will try a different - // key range next time. - compact_pointer_[level] = largest.Encode().ToString(); - c->edit_.SetCompactPointer(level, largest); -} - -Compaction* VersionSet::CompactRange( - int level, - const InternalKey* begin, - const InternalKey* end) { - std::vector inputs; - current_->GetOverlappingInputs(level, begin, end, &inputs); - if (inputs.empty()) { - return NULL; - } - - // Avoid compacting too much in one shot in case the range is large. - // But we cannot do this for level-0 since level-0 files can overlap - // and we must not pick one file and drop another older file if the - // two files overlap. - if (level > 0) { - const uint64_t limit = MaxFileSizeForLevel(level); - uint64_t total = 0; - for (size_t i = 0; i < inputs.size(); i++) { - uint64_t s = inputs[i]->file_size; - total += s; - if (total >= limit) { - inputs.resize(i + 1); - break; - } - } - } - - Compaction* c = new Compaction(level); - c->input_version_ = current_; - c->input_version_->Ref(); - c->inputs_[0] = inputs; - SetupOtherInputs(c); - return c; -} - -Compaction::Compaction(int level) - : level_(level), - max_output_file_size_(MaxFileSizeForLevel(level)), - input_version_(NULL), - grandparent_index_(0), - seen_key_(false), - overlapped_bytes_(0) { - for (int i = 0; i < config::kNumLevels; i++) { - level_ptrs_[i] = 0; - } -} - -Compaction::~Compaction() { - if (input_version_ != NULL) { - input_version_->Unref(); - } -} - -bool Compaction::IsTrivialMove() const { - // Avoid a move if there is lots of overlapping grandparent data. - // Otherwise, the move could create a parent file that will require - // a very expensive merge later on. - return (num_input_files(0) == 1 && - num_input_files(1) == 0 && - TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); -} - -void Compaction::AddInputDeletions(VersionEdit* edit) { - for (int which = 0; which < 2; which++) { - for (size_t i = 0; i < inputs_[which].size(); i++) { - edit->DeleteFile(level_ + which, inputs_[which][i]->number); - } - } -} - -bool Compaction::IsBaseLevelForKey(const Slice& user_key) { - // Maybe use binary search to find right entry instead of linear search? - const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); - for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { - const std::vector& files = input_version_->files_[lvl]; - for (; level_ptrs_[lvl] < files.size(); ) { - FileMetaData* f = files[level_ptrs_[lvl]]; - if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { - // We've advanced far enough - if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { - // Key falls in this file's range, so definitely not base level - return false; - } - break; - } - level_ptrs_[lvl]++; - } - } - return true; -} - -bool Compaction::ShouldStopBefore(const Slice& internal_key) { - // Scan to find earliest grandparent file that contains key. - const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; - while (grandparent_index_ < grandparents_.size() && - icmp->Compare(internal_key, - grandparents_[grandparent_index_]->largest.Encode()) > 0) { - if (seen_key_) { - overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; - } - grandparent_index_++; - } - seen_key_ = true; - - if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { - // Too much overlap for current output; start new output - overlapped_bytes_ = 0; - return true; - } else { - return false; - } -} - -void Compaction::ReleaseInputs() { - if (input_version_ != NULL) { - input_version_->Unref(); - input_version_ = NULL; - } -} - -} // namespace leveldb diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h deleted file mode 100644 index 8dc14b8e01..0000000000 --- a/src/leveldb/db/version_set.h +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// The representation of a DBImpl consists of a set of Versions. The -// newest version is called "current". Older versions may be kept -// around to provide a consistent view to live iterators. -// -// Each Version keeps track of a set of Table files per level. The -// entire set of versions is maintained in a VersionSet. -// -// Version,VersionSet are thread-compatible, but require external -// synchronization on all accesses. - -#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ -#define STORAGE_LEVELDB_DB_VERSION_SET_H_ - -#include -#include -#include -#include "db/dbformat.h" -#include "db/version_edit.h" -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -namespace log { class Writer; } - -class Compaction; -class Iterator; -class MemTable; -class TableBuilder; -class TableCache; -class Version; -class VersionSet; -class WritableFile; - -// Return the smallest index i such that files[i]->largest >= key. -// Return files.size() if there is no such file. -// REQUIRES: "files" contains a sorted list of non-overlapping files. -extern int FindFile(const InternalKeyComparator& icmp, - const std::vector& files, - const Slice& key); - -// Returns true iff some file in "files" overlaps the user key range -// [*smallest,*largest]. -// smallest==NULL represents a key smaller than all keys in the DB. -// largest==NULL represents a key largest than all keys in the DB. -// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges -// in sorted order. -extern bool SomeFileOverlapsRange( - const InternalKeyComparator& icmp, - bool disjoint_sorted_files, - const std::vector& files, - const Slice* smallest_user_key, - const Slice* largest_user_key); - -class Version { - public: - // Append to *iters a sequence of iterators that will - // yield the contents of this Version when merged together. - // REQUIRES: This version has been saved (see VersionSet::SaveTo) - void AddIterators(const ReadOptions&, std::vector* iters); - - // Lookup the value for key. If found, store it in *val and - // return OK. Else return a non-OK status. Fills *stats. - // REQUIRES: lock is not held - struct GetStats { - FileMetaData* seek_file; - int seek_file_level; - }; - Status Get(const ReadOptions&, const LookupKey& key, std::string* val, - GetStats* stats); - - // Adds "stats" into the current state. Returns true if a new - // compaction may need to be triggered, false otherwise. - // REQUIRES: lock is held - bool UpdateStats(const GetStats& stats); - - // Record a sample of bytes read at the specified internal key. - // Samples are taken approximately once every config::kReadBytesPeriod - // bytes. Returns true if a new compaction may need to be triggered. - // REQUIRES: lock is held - bool RecordReadSample(Slice key); - - // Reference count management (so Versions do not disappear out from - // under live iterators) - void Ref(); - void Unref(); - - void GetOverlappingInputs( - int level, - const InternalKey* begin, // NULL means before all keys - const InternalKey* end, // NULL means after all keys - std::vector* inputs); - - // Returns true iff some file in the specified level overlaps - // some part of [*smallest_user_key,*largest_user_key]. - // smallest_user_key==NULL represents a key smaller than all keys in the DB. - // largest_user_key==NULL represents a key largest than all keys in the DB. - bool OverlapInLevel(int level, - const Slice* smallest_user_key, - const Slice* largest_user_key); - - // Return the level at which we should place a new memtable compaction - // result that covers the range [smallest_user_key,largest_user_key]. - int PickLevelForMemTableOutput(const Slice& smallest_user_key, - const Slice& largest_user_key); - - int NumFiles(int level) const { return files_[level].size(); } - - // Return a human readable string that describes this version's contents. - std::string DebugString() const; - - private: - friend class Compaction; - friend class VersionSet; - - class LevelFileNumIterator; - Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; - - // Call func(arg, level, f) for every file that overlaps user_key in - // order from newest to oldest. If an invocation of func returns - // false, makes no more calls. - // - // REQUIRES: user portion of internal_key == user_key. - void ForEachOverlapping(Slice user_key, Slice internal_key, - void* arg, - bool (*func)(void*, int, FileMetaData*)); - - VersionSet* vset_; // VersionSet to which this Version belongs - Version* next_; // Next version in linked list - Version* prev_; // Previous version in linked list - int refs_; // Number of live refs to this version - - // List of files per level - std::vector files_[config::kNumLevels]; - - // Next file to compact based on seek stats. - FileMetaData* file_to_compact_; - int file_to_compact_level_; - - // Level that should be compacted next and its compaction score. - // Score < 1 means compaction is not strictly needed. These fields - // are initialized by Finalize(). - double compaction_score_; - int compaction_level_; - - explicit Version(VersionSet* vset) - : vset_(vset), next_(this), prev_(this), refs_(0), - file_to_compact_(NULL), - file_to_compact_level_(-1), - compaction_score_(-1), - compaction_level_(-1) { - } - - ~Version(); - - // No copying allowed - Version(const Version&); - void operator=(const Version&); -}; - -class VersionSet { - public: - VersionSet(const std::string& dbname, - const Options* options, - TableCache* table_cache, - const InternalKeyComparator*); - ~VersionSet(); - - // Apply *edit to the current version to form a new descriptor that - // is both saved to persistent state and installed as the new - // current version. Will release *mu while actually writing to the file. - // REQUIRES: *mu is held on entry. - // REQUIRES: no other thread concurrently calls LogAndApply() - Status LogAndApply(VersionEdit* edit, port::Mutex* mu) - EXCLUSIVE_LOCKS_REQUIRED(mu); - - // Recover the last saved descriptor from persistent storage. - Status Recover(); - - // Return the current version. - Version* current() const { return current_; } - - // Return the current manifest file number - uint64_t ManifestFileNumber() const { return manifest_file_number_; } - - // Allocate and return a new file number - uint64_t NewFileNumber() { return next_file_number_++; } - - // Arrange to reuse "file_number" unless a newer file number has - // already been allocated. - // REQUIRES: "file_number" was returned by a call to NewFileNumber(). - void ReuseFileNumber(uint64_t file_number) { - if (next_file_number_ == file_number + 1) { - next_file_number_ = file_number; - } - } - - // Return the number of Table files at the specified level. - int NumLevelFiles(int level) const; - - // Return the combined file size of all files at the specified level. - int64_t NumLevelBytes(int level) const; - - // Return the last sequence number. - uint64_t LastSequence() const { return last_sequence_; } - - // Set the last sequence number to s. - void SetLastSequence(uint64_t s) { - assert(s >= last_sequence_); - last_sequence_ = s; - } - - // Mark the specified file number as used. - void MarkFileNumberUsed(uint64_t number); - - // Return the current log file number. - uint64_t LogNumber() const { return log_number_; } - - // Return the log file number for the log file that is currently - // being compacted, or zero if there is no such log file. - uint64_t PrevLogNumber() const { return prev_log_number_; } - - // Pick level and inputs for a new compaction. - // Returns NULL if there is no compaction to be done. - // Otherwise returns a pointer to a heap-allocated object that - // describes the compaction. Caller should delete the result. - Compaction* PickCompaction(); - - // Return a compaction object for compacting the range [begin,end] in - // the specified level. Returns NULL if there is nothing in that - // level that overlaps the specified range. Caller should delete - // the result. - Compaction* CompactRange( - int level, - const InternalKey* begin, - const InternalKey* end); - - // Return the maximum overlapping data (in bytes) at next level for any - // file at a level >= 1. - int64_t MaxNextLevelOverlappingBytes(); - - // Create an iterator that reads over the compaction inputs for "*c". - // The caller should delete the iterator when no longer needed. - Iterator* MakeInputIterator(Compaction* c); - - // Returns true iff some level needs a compaction. - bool NeedsCompaction() const { - Version* v = current_; - return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); - } - - // Add all files listed in any live version to *live. - // May also mutate some internal state. - void AddLiveFiles(std::set* live); - - // Return the approximate offset in the database of the data for - // "key" as of version "v". - uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); - - // Return a human-readable short (single-line) summary of the number - // of files per level. Uses *scratch as backing store. - struct LevelSummaryStorage { - char buffer[100]; - }; - const char* LevelSummary(LevelSummaryStorage* scratch) const; - - private: - class Builder; - - friend class Compaction; - friend class Version; - - void Finalize(Version* v); - - void GetRange(const std::vector& inputs, - InternalKey* smallest, - InternalKey* largest); - - void GetRange2(const std::vector& inputs1, - const std::vector& inputs2, - InternalKey* smallest, - InternalKey* largest); - - void SetupOtherInputs(Compaction* c); - - // Save current contents to *log - Status WriteSnapshot(log::Writer* log); - - void AppendVersion(Version* v); - - Env* const env_; - const std::string dbname_; - const Options* const options_; - TableCache* const table_cache_; - const InternalKeyComparator icmp_; - uint64_t next_file_number_; - uint64_t manifest_file_number_; - uint64_t last_sequence_; - uint64_t log_number_; - uint64_t prev_log_number_; // 0 or backing store for memtable being compacted - - // Opened lazily - WritableFile* descriptor_file_; - log::Writer* descriptor_log_; - Version dummy_versions_; // Head of circular doubly-linked list of versions. - Version* current_; // == dummy_versions_.prev_ - - // Per-level key at which the next compaction at that level should start. - // Either an empty string, or a valid InternalKey. - std::string compact_pointer_[config::kNumLevels]; - - // No copying allowed - VersionSet(const VersionSet&); - void operator=(const VersionSet&); -}; - -// A Compaction encapsulates information about a compaction. -class Compaction { - public: - ~Compaction(); - - // Return the level that is being compacted. Inputs from "level" - // and "level+1" will be merged to produce a set of "level+1" files. - int level() const { return level_; } - - // Return the object that holds the edits to the descriptor done - // by this compaction. - VersionEdit* edit() { return &edit_; } - - // "which" must be either 0 or 1 - int num_input_files(int which) const { return inputs_[which].size(); } - - // Return the ith input file at "level()+which" ("which" must be 0 or 1). - FileMetaData* input(int which, int i) const { return inputs_[which][i]; } - - // Maximum size of files to build during this compaction. - uint64_t MaxOutputFileSize() const { return max_output_file_size_; } - - // Is this a trivial compaction that can be implemented by just - // moving a single input file to the next level (no merging or splitting) - bool IsTrivialMove() const; - - // Add all inputs to this compaction as delete operations to *edit. - void AddInputDeletions(VersionEdit* edit); - - // Returns true if the information we have available guarantees that - // the compaction is producing data in "level+1" for which no data exists - // in levels greater than "level+1". - bool IsBaseLevelForKey(const Slice& user_key); - - // Returns true iff we should stop building the current output - // before processing "internal_key". - bool ShouldStopBefore(const Slice& internal_key); - - // Release the input version for the compaction, once the compaction - // is successful. - void ReleaseInputs(); - - private: - friend class Version; - friend class VersionSet; - - explicit Compaction(int level); - - int level_; - uint64_t max_output_file_size_; - Version* input_version_; - VersionEdit edit_; - - // Each compaction reads inputs from "level_" and "level_+1" - std::vector inputs_[2]; // The two sets of inputs - - // State used to check for number of of overlapping grandparent files - // (parent == level_ + 1, grandparent == level_ + 2) - std::vector grandparents_; - size_t grandparent_index_; // Index in grandparent_starts_ - bool seen_key_; // Some output key has been seen - int64_t overlapped_bytes_; // Bytes of overlap between current output - // and grandparent files - - // State for implementing IsBaseLevelForKey - - // level_ptrs_ holds indices into input_version_->levels_: our state - // is that we are positioned at one of the file ranges for each - // higher level than the ones involved in this compaction (i.e. for - // all L >= level_ + 2). - size_t level_ptrs_[config::kNumLevels]; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/src/leveldb/db/version_set_test.cc b/src/leveldb/db/version_set_test.cc deleted file mode 100644 index 501e34d133..0000000000 --- a/src/leveldb/db/version_set_test.cc +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "db/version_set.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -class FindFileTest { - public: - std::vector files_; - bool disjoint_sorted_files_; - - FindFileTest() : disjoint_sorted_files_(true) { } - - ~FindFileTest() { - for (int i = 0; i < files_.size(); i++) { - delete files_[i]; - } - } - - void Add(const char* smallest, const char* largest, - SequenceNumber smallest_seq = 100, - SequenceNumber largest_seq = 100) { - FileMetaData* f = new FileMetaData; - f->number = files_.size() + 1; - f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); - f->largest = InternalKey(largest, largest_seq, kTypeValue); - files_.push_back(f); - } - - int Find(const char* key) { - InternalKey target(key, 100, kTypeValue); - InternalKeyComparator cmp(BytewiseComparator()); - return FindFile(cmp, files_, target.Encode()); - } - - bool Overlaps(const char* smallest, const char* largest) { - InternalKeyComparator cmp(BytewiseComparator()); - Slice s(smallest != NULL ? smallest : ""); - Slice l(largest != NULL ? largest : ""); - return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, - (smallest != NULL ? &s : NULL), - (largest != NULL ? &l : NULL)); - } -}; - -TEST(FindFileTest, Empty) { - ASSERT_EQ(0, Find("foo")); - ASSERT_TRUE(! Overlaps("a", "z")); - ASSERT_TRUE(! Overlaps(NULL, "z")); - ASSERT_TRUE(! Overlaps("a", NULL)); - ASSERT_TRUE(! Overlaps(NULL, NULL)); -} - -TEST(FindFileTest, Single) { - Add("p", "q"); - ASSERT_EQ(0, Find("a")); - ASSERT_EQ(0, Find("p")); - ASSERT_EQ(0, Find("p1")); - ASSERT_EQ(0, Find("q")); - ASSERT_EQ(1, Find("q1")); - ASSERT_EQ(1, Find("z")); - - ASSERT_TRUE(! Overlaps("a", "b")); - ASSERT_TRUE(! Overlaps("z1", "z2")); - ASSERT_TRUE(Overlaps("a", "p")); - ASSERT_TRUE(Overlaps("a", "q")); - ASSERT_TRUE(Overlaps("a", "z")); - ASSERT_TRUE(Overlaps("p", "p1")); - ASSERT_TRUE(Overlaps("p", "q")); - ASSERT_TRUE(Overlaps("p", "z")); - ASSERT_TRUE(Overlaps("p1", "p2")); - ASSERT_TRUE(Overlaps("p1", "z")); - ASSERT_TRUE(Overlaps("q", "q")); - ASSERT_TRUE(Overlaps("q", "q1")); - - ASSERT_TRUE(! Overlaps(NULL, "j")); - ASSERT_TRUE(! Overlaps("r", NULL)); - ASSERT_TRUE(Overlaps(NULL, "p")); - ASSERT_TRUE(Overlaps(NULL, "p1")); - ASSERT_TRUE(Overlaps("q", NULL)); - ASSERT_TRUE(Overlaps(NULL, NULL)); -} - - -TEST(FindFileTest, Multiple) { - Add("150", "200"); - Add("200", "250"); - Add("300", "350"); - Add("400", "450"); - ASSERT_EQ(0, Find("100")); - ASSERT_EQ(0, Find("150")); - ASSERT_EQ(0, Find("151")); - ASSERT_EQ(0, Find("199")); - ASSERT_EQ(0, Find("200")); - ASSERT_EQ(1, Find("201")); - ASSERT_EQ(1, Find("249")); - ASSERT_EQ(1, Find("250")); - ASSERT_EQ(2, Find("251")); - ASSERT_EQ(2, Find("299")); - ASSERT_EQ(2, Find("300")); - ASSERT_EQ(2, Find("349")); - ASSERT_EQ(2, Find("350")); - ASSERT_EQ(3, Find("351")); - ASSERT_EQ(3, Find("400")); - ASSERT_EQ(3, Find("450")); - ASSERT_EQ(4, Find("451")); - - ASSERT_TRUE(! Overlaps("100", "149")); - ASSERT_TRUE(! Overlaps("251", "299")); - ASSERT_TRUE(! Overlaps("451", "500")); - ASSERT_TRUE(! Overlaps("351", "399")); - - ASSERT_TRUE(Overlaps("100", "150")); - ASSERT_TRUE(Overlaps("100", "200")); - ASSERT_TRUE(Overlaps("100", "300")); - ASSERT_TRUE(Overlaps("100", "400")); - ASSERT_TRUE(Overlaps("100", "500")); - ASSERT_TRUE(Overlaps("375", "400")); - ASSERT_TRUE(Overlaps("450", "450")); - ASSERT_TRUE(Overlaps("450", "500")); -} - -TEST(FindFileTest, MultipleNullBoundaries) { - Add("150", "200"); - Add("200", "250"); - Add("300", "350"); - Add("400", "450"); - ASSERT_TRUE(! Overlaps(NULL, "149")); - ASSERT_TRUE(! Overlaps("451", NULL)); - ASSERT_TRUE(Overlaps(NULL, NULL)); - ASSERT_TRUE(Overlaps(NULL, "150")); - ASSERT_TRUE(Overlaps(NULL, "199")); - ASSERT_TRUE(Overlaps(NULL, "200")); - ASSERT_TRUE(Overlaps(NULL, "201")); - ASSERT_TRUE(Overlaps(NULL, "400")); - ASSERT_TRUE(Overlaps(NULL, "800")); - ASSERT_TRUE(Overlaps("100", NULL)); - ASSERT_TRUE(Overlaps("200", NULL)); - ASSERT_TRUE(Overlaps("449", NULL)); - ASSERT_TRUE(Overlaps("450", NULL)); -} - -TEST(FindFileTest, OverlapSequenceChecks) { - Add("200", "200", 5000, 3000); - ASSERT_TRUE(! Overlaps("199", "199")); - ASSERT_TRUE(! Overlaps("201", "300")); - ASSERT_TRUE(Overlaps("200", "200")); - ASSERT_TRUE(Overlaps("190", "200")); - ASSERT_TRUE(Overlaps("200", "210")); -} - -TEST(FindFileTest, OverlappingFiles) { - Add("150", "600"); - Add("400", "500"); - disjoint_sorted_files_ = false; - ASSERT_TRUE(! Overlaps("100", "149")); - ASSERT_TRUE(! Overlaps("601", "700")); - ASSERT_TRUE(Overlaps("100", "150")); - ASSERT_TRUE(Overlaps("100", "200")); - ASSERT_TRUE(Overlaps("100", "300")); - ASSERT_TRUE(Overlaps("100", "400")); - ASSERT_TRUE(Overlaps("100", "500")); - ASSERT_TRUE(Overlaps("375", "400")); - ASSERT_TRUE(Overlaps("450", "450")); - ASSERT_TRUE(Overlaps("450", "500")); - ASSERT_TRUE(Overlaps("450", "700")); - ASSERT_TRUE(Overlaps("600", "700")); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/db/write_batch.cc b/src/leveldb/db/write_batch.cc deleted file mode 100644 index 33f4a4257e..0000000000 --- a/src/leveldb/db/write_batch.cc +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// WriteBatch::rep_ := -// sequence: fixed64 -// count: fixed32 -// data: record[count] -// record := -// kTypeValue varstring varstring | -// kTypeDeletion varstring -// varstring := -// len: varint32 -// data: uint8[len] - -#include "leveldb/write_batch.h" - -#include "leveldb/db.h" -#include "db/dbformat.h" -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "util/coding.h" - -namespace leveldb { - -// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. -static const size_t kHeader = 12; - -WriteBatch::WriteBatch() { - Clear(); -} - -WriteBatch::~WriteBatch() { } - -WriteBatch::Handler::~Handler() { } - -void WriteBatch::Clear() { - rep_.clear(); - rep_.resize(kHeader); -} - -Status WriteBatch::Iterate(Handler* handler) const { - Slice input(rep_); - if (input.size() < kHeader) { - return Status::Corruption("malformed WriteBatch (too small)"); - } - - input.remove_prefix(kHeader); - Slice key, value; - int found = 0; - while (!input.empty()) { - found++; - char tag = input[0]; - input.remove_prefix(1); - switch (tag) { - case kTypeValue: - if (GetLengthPrefixedSlice(&input, &key) && - GetLengthPrefixedSlice(&input, &value)) { - handler->Put(key, value); - } else { - return Status::Corruption("bad WriteBatch Put"); - } - break; - case kTypeDeletion: - if (GetLengthPrefixedSlice(&input, &key)) { - handler->Delete(key); - } else { - return Status::Corruption("bad WriteBatch Delete"); - } - break; - default: - return Status::Corruption("unknown WriteBatch tag"); - } - } - if (found != WriteBatchInternal::Count(this)) { - return Status::Corruption("WriteBatch has wrong count"); - } else { - return Status::OK(); - } -} - -int WriteBatchInternal::Count(const WriteBatch* b) { - return DecodeFixed32(b->rep_.data() + 8); -} - -void WriteBatchInternal::SetCount(WriteBatch* b, int n) { - EncodeFixed32(&b->rep_[8], n); -} - -SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { - return SequenceNumber(DecodeFixed64(b->rep_.data())); -} - -void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { - EncodeFixed64(&b->rep_[0], seq); -} - -void WriteBatch::Put(const Slice& key, const Slice& value) { - WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); - rep_.push_back(static_cast(kTypeValue)); - PutLengthPrefixedSlice(&rep_, key); - PutLengthPrefixedSlice(&rep_, value); -} - -void WriteBatch::Delete(const Slice& key) { - WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); - rep_.push_back(static_cast(kTypeDeletion)); - PutLengthPrefixedSlice(&rep_, key); -} - -namespace { -class MemTableInserter : public WriteBatch::Handler { - public: - SequenceNumber sequence_; - MemTable* mem_; - - virtual void Put(const Slice& key, const Slice& value) { - mem_->Add(sequence_, kTypeValue, key, value); - sequence_++; - } - virtual void Delete(const Slice& key) { - mem_->Add(sequence_, kTypeDeletion, key, Slice()); - sequence_++; - } -}; -} // namespace - -Status WriteBatchInternal::InsertInto(const WriteBatch* b, - MemTable* memtable) { - MemTableInserter inserter; - inserter.sequence_ = WriteBatchInternal::Sequence(b); - inserter.mem_ = memtable; - return b->Iterate(&inserter); -} - -void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { - assert(contents.size() >= kHeader); - b->rep_.assign(contents.data(), contents.size()); -} - -void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { - SetCount(dst, Count(dst) + Count(src)); - assert(src->rep_.size() >= kHeader); - dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); -} - -} // namespace leveldb diff --git a/src/leveldb/db/write_batch_internal.h b/src/leveldb/db/write_batch_internal.h deleted file mode 100644 index 310a3c8912..0000000000 --- a/src/leveldb/db/write_batch_internal.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ -#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ - -#include "leveldb/write_batch.h" - -namespace leveldb { - -class MemTable; - -// WriteBatchInternal provides static methods for manipulating a -// WriteBatch that we don't want in the public WriteBatch interface. -class WriteBatchInternal { - public: - // Return the number of entries in the batch. - static int Count(const WriteBatch* batch); - - // Set the count for the number of entries in the batch. - static void SetCount(WriteBatch* batch, int n); - - // Return the sequence number for the start of this batch. - static SequenceNumber Sequence(const WriteBatch* batch); - - // Store the specified number as the sequence number for the start of - // this batch. - static void SetSequence(WriteBatch* batch, SequenceNumber seq); - - static Slice Contents(const WriteBatch* batch) { - return Slice(batch->rep_); - } - - static size_t ByteSize(const WriteBatch* batch) { - return batch->rep_.size(); - } - - static void SetContents(WriteBatch* batch, const Slice& contents); - - static Status InsertInto(const WriteBatch* batch, MemTable* memtable); - - static void Append(WriteBatch* dst, const WriteBatch* src); -}; - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/src/leveldb/db/write_batch_test.cc b/src/leveldb/db/write_batch_test.cc deleted file mode 100644 index 9064e3d85e..0000000000 --- a/src/leveldb/db/write_batch_test.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/db.h" - -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "leveldb/env.h" -#include "util/logging.h" -#include "util/testharness.h" - -namespace leveldb { - -static std::string PrintContents(WriteBatch* b) { - InternalKeyComparator cmp(BytewiseComparator()); - MemTable* mem = new MemTable(cmp); - mem->Ref(); - std::string state; - Status s = WriteBatchInternal::InsertInto(b, mem); - int count = 0; - Iterator* iter = mem->NewIterator(); - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - ParsedInternalKey ikey; - ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); - switch (ikey.type) { - case kTypeValue: - state.append("Put("); - state.append(ikey.user_key.ToString()); - state.append(", "); - state.append(iter->value().ToString()); - state.append(")"); - count++; - break; - case kTypeDeletion: - state.append("Delete("); - state.append(ikey.user_key.ToString()); - state.append(")"); - count++; - break; - } - state.append("@"); - state.append(NumberToString(ikey.sequence)); - } - delete iter; - if (!s.ok()) { - state.append("ParseError()"); - } else if (count != WriteBatchInternal::Count(b)) { - state.append("CountMismatch()"); - } - mem->Unref(); - return state; -} - -class WriteBatchTest { }; - -TEST(WriteBatchTest, Empty) { - WriteBatch batch; - ASSERT_EQ("", PrintContents(&batch)); - ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); -} - -TEST(WriteBatchTest, Multiple) { - WriteBatch batch; - batch.Put(Slice("foo"), Slice("bar")); - batch.Delete(Slice("box")); - batch.Put(Slice("baz"), Slice("boo")); - WriteBatchInternal::SetSequence(&batch, 100); - ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); - ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); - ASSERT_EQ("Put(baz, boo)@102" - "Delete(box)@101" - "Put(foo, bar)@100", - PrintContents(&batch)); -} - -TEST(WriteBatchTest, Corruption) { - WriteBatch batch; - batch.Put(Slice("foo"), Slice("bar")); - batch.Delete(Slice("box")); - WriteBatchInternal::SetSequence(&batch, 200); - Slice contents = WriteBatchInternal::Contents(&batch); - WriteBatchInternal::SetContents(&batch, - Slice(contents.data(),contents.size()-1)); - ASSERT_EQ("Put(foo, bar)@200" - "ParseError()", - PrintContents(&batch)); -} - -TEST(WriteBatchTest, Append) { - WriteBatch b1, b2; - WriteBatchInternal::SetSequence(&b1, 200); - WriteBatchInternal::SetSequence(&b2, 300); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("", - PrintContents(&b1)); - b2.Put("a", "va"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200", - PrintContents(&b1)); - b2.Clear(); - b2.Put("b", "vb"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200" - "Put(b, vb)@201", - PrintContents(&b1)); - b2.Delete("foo"); - WriteBatchInternal::Append(&b1, &b2); - ASSERT_EQ("Put(a, va)@200" - "Put(b, vb)@202" - "Put(b, vb)@201" - "Delete(foo)@203", - PrintContents(&b1)); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/doc/bench/db_bench_sqlite3.cc b/src/leveldb/doc/bench/db_bench_sqlite3.cc deleted file mode 100644 index e63aaa8dcc..0000000000 --- a/src/leveldb/doc/bench/db_bench_sqlite3.cc +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "util/histogram.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// -// fillseq -- write N values in sequential key order in async mode -// fillseqsync -- write N/100 values in sequential key order in sync mode -// fillseqbatch -- batch write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// fillrandsync -- write N/100 values in random key order in sync mode -// fillrandbatch -- batch write N values in sequential key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillrand100K -- write N/1000 100K values in random order in async mode -// fillseq100K -- write N/1000 100K values in sequential order in async mode -// readseq -- read N times sequentially -// readrandom -- read N times in random order -// readrand100K -- read N/1000 100K values in sequential order in async mode -static const char* FLAGS_benchmarks = - "fillseq," - "fillseqsync," - "fillseqbatch," - "fillrandom," - "fillrandsync," - "fillrandbatch," - "overwrite," - "overwritebatch," - "readrandom," - "readseq," - "fillrand100K," - "fillseq100K," - "readseq," - "readrand100K," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Page size. Default 1 KB. -static int FLAGS_page_size = 1024; - -// Number of pages. -// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB. -static int FLAGS_num_pages = 4096; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// If true, we allow batch writes to occur -static bool FLAGS_transaction = true; - -// If true, we enable Write-Ahead Logging -static bool FLAGS_WAL_enabled = true; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -inline -static void ExecErrorCheck(int status, char *err_msg) { - if (status != SQLITE_OK) { - fprintf(stderr, "SQL error: %s\n", err_msg); - sqlite3_free(err_msg); - exit(1); - } -} - -inline -static void StepErrorCheck(int status) { - if (status != SQLITE_DONE) { - fprintf(stderr, "SQL step error: status = %d\n", status); - exit(1); - } -} - -inline -static void ErrorCheck(int status) { - if (status != SQLITE_OK) { - fprintf(stderr, "sqlite3 error: status = %d\n", status); - exit(1); - } -} - -inline -static void WalCheckpoint(sqlite3* db_) { - // Flush all writes to disk - if (FLAGS_WAL_enabled) { - sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL); - } -} - -namespace leveldb { - -// Helper for quickly generating random data. -namespace { -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(int len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - int start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - int limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -} // namespace - -class Benchmark { - private: - sqlite3* db_; - int db_num_; - int num_; - int reads_; - double start_; - double last_op_finish_; - int64_t bytes_; - std::string message_; - Histogram hist_; - RandomGenerator gen_; - Random rand_; - - // State kept for progress messages - int done_; - int next_report_; // When to report next - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - } - - void PrintEnvironment() { - fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - void Start() { - start_ = Env::Default()->NowMicros() * 1e-6; - bytes_ = 0; - message_.clear(); - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - next_report_ = 100; - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros() * 1e-6; - double micros = (now - last_op_finish_) * 1e6; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void Stop(const Slice& name) { - double finish = Env::Default()->NowMicros() * 1e-6; - - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - if (bytes_ > 0) { - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / (finish - start_)); - if (!message_.empty()) { - message_ = std::string(rate) + " " + message_; - } else { - message_ = rate; - } - } - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - (finish - start_) * 1e6 / done_, - (message_.empty() ? "" : " "), - message_.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } - - public: - enum Order { - SEQUENTIAL, - RANDOM - }; - enum DBState { - FRESH, - EXISTING - }; - - Benchmark() - : db_(NULL), - db_num_(0), - num_(FLAGS_num), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - bytes_(0), - rand_(301) { - std::vector files; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - Env::Default()->GetChildren(test_dir, &files); - if (!FLAGS_use_existing_db) { - for (int i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("dbbench_sqlite3")) { - std::string file_name(test_dir); - file_name += "/"; - file_name += files[i]; - Env::Default()->DeleteFile(file_name.c_str()); - } - } - } - } - - ~Benchmark() { - int status = sqlite3_close(db_); - ErrorCheck(status); - } - - void Run() { - PrintHeader(); - Open(); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - bytes_ = 0; - Start(); - - bool known = true; - bool write_sync = false; - if (name == Slice("fillseq")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseqbatch")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("fillrandom")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillrandbatch")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("overwrite")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("overwritebatch")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000); - WalCheckpoint(db_); - } else if (name == Slice("fillrandsync")) { - write_sync = true; - Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseqsync")) { - write_sync = true; - Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillrand100K")) { - Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); - WalCheckpoint(db_); - } else if (name == Slice("fillseq100K")) { - Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); - WalCheckpoint(db_); - } else if (name == Slice("readseq")) { - ReadSequential(); - } else if (name == Slice("readrandom")) { - Read(RANDOM, 1); - } else if (name == Slice("readrand100K")) { - int n = reads_; - reads_ /= 1000; - Read(RANDOM, 1); - reads_ = n; - } else { - known = false; - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - if (known) { - Stop(name); - } - } - } - - void Open() { - assert(db_ == NULL); - - int status; - char file_name[100]; - char* err_msg = NULL; - db_num_++; - - // Open database - std::string tmp_dir; - Env::Default()->GetTestDirectory(&tmp_dir); - snprintf(file_name, sizeof(file_name), - "%s/dbbench_sqlite3-%d.db", - tmp_dir.c_str(), - db_num_); - status = sqlite3_open(file_name, &db_); - if (status) { - fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_)); - exit(1); - } - - // Change SQLite cache size - char cache_size[100]; - snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d", - FLAGS_num_pages); - status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - - // FLAGS_page_size is defaulted to 1024 - if (FLAGS_page_size != 1024) { - char page_size[100]; - snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d", - FLAGS_page_size); - status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - - // Change journal mode to WAL if WAL enabled flag is on - if (FLAGS_WAL_enabled) { - std::string WAL_stmt = "PRAGMA journal_mode = WAL"; - - // LevelDB's default cache size is a combined 4 MB - std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096"; - status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - status = sqlite3_exec(db_, WAL_checkpoint.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - - // Change locking mode to exclusive and create tables/index for database - std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; - std::string create_stmt = - "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; - std::string stmt_array[] = { locking_stmt, create_stmt }; - int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); - for (int i = 0; i < stmt_array_length; i++) { - status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - } - } - - void Write(bool write_sync, Order order, DBState state, - int num_entries, int value_size, int entries_per_batch) { - // Create new database if state == FRESH - if (state == FRESH) { - if (FLAGS_use_existing_db) { - message_ = "skipping (--use_existing_db is true)"; - return; - } - sqlite3_close(db_); - db_ = NULL; - Open(); - Start(); - } - - if (num_entries != num_) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_entries); - message_ = msg; - } - - char* err_msg = NULL; - int status; - - sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt; - std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)"; - std::string begin_trans_str = "BEGIN TRANSACTION;"; - std::string end_trans_str = "END TRANSACTION;"; - - // Check for synchronous flag in options - std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" : - "PRAGMA synchronous = OFF"; - status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg); - ExecErrorCheck(status, err_msg); - - // Preparing sqlite3 statements - status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, - &replace_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, - &begin_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, - &end_trans_stmt, NULL); - ErrorCheck(status); - - bool transaction = (entries_per_batch > 1); - for (int i = 0; i < num_entries; i += entries_per_batch) { - // Begin write transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(begin_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(begin_trans_stmt); - ErrorCheck(status); - } - - // Create and execute SQL statements - for (int j = 0; j < entries_per_batch; j++) { - const char* value = gen_.Generate(value_size).data(); - - // Create values for key-value pair - const int k = (order == SEQUENTIAL) ? i + j : - (rand_.Next() % num_entries); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - - // Bind KV values into replace_stmt - status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC); - ErrorCheck(status); - status = sqlite3_bind_blob(replace_stmt, 2, value, - value_size, SQLITE_STATIC); - ErrorCheck(status); - - // Execute replace_stmt - bytes_ += value_size + strlen(key); - status = sqlite3_step(replace_stmt); - StepErrorCheck(status); - - // Reset SQLite statement for another use - status = sqlite3_clear_bindings(replace_stmt); - ErrorCheck(status); - status = sqlite3_reset(replace_stmt); - ErrorCheck(status); - - FinishedSingleOp(); - } - - // End write transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(end_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(end_trans_stmt); - ErrorCheck(status); - } - } - - status = sqlite3_finalize(replace_stmt); - ErrorCheck(status); - status = sqlite3_finalize(begin_trans_stmt); - ErrorCheck(status); - status = sqlite3_finalize(end_trans_stmt); - ErrorCheck(status); - } - - void Read(Order order, int entries_per_batch) { - int status; - sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt; - - std::string read_str = "SELECT * FROM test WHERE key = ?"; - std::string begin_trans_str = "BEGIN TRANSACTION;"; - std::string end_trans_str = "END TRANSACTION;"; - - // Preparing sqlite3 statements - status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, - &begin_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, - &end_trans_stmt, NULL); - ErrorCheck(status); - status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL); - ErrorCheck(status); - - bool transaction = (entries_per_batch > 1); - for (int i = 0; i < reads_; i += entries_per_batch) { - // Begin read transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(begin_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(begin_trans_stmt); - ErrorCheck(status); - } - - // Create and execute SQL statements - for (int j = 0; j < entries_per_batch; j++) { - // Create key value - char key[100]; - int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_); - snprintf(key, sizeof(key), "%016d", k); - - // Bind key value into read_stmt - status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC); - ErrorCheck(status); - - // Execute read statement - while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {} - StepErrorCheck(status); - - // Reset SQLite statement for another use - status = sqlite3_clear_bindings(read_stmt); - ErrorCheck(status); - status = sqlite3_reset(read_stmt); - ErrorCheck(status); - FinishedSingleOp(); - } - - // End read transaction - if (FLAGS_transaction && transaction) { - status = sqlite3_step(end_trans_stmt); - StepErrorCheck(status); - status = sqlite3_reset(end_trans_stmt); - ErrorCheck(status); - } - } - - status = sqlite3_finalize(read_stmt); - ErrorCheck(status); - status = sqlite3_finalize(begin_trans_stmt); - ErrorCheck(status); - status = sqlite3_finalize(end_trans_stmt); - ErrorCheck(status); - } - - void ReadSequential() { - int status; - sqlite3_stmt *pStmt; - std::string read_str = "SELECT * FROM test ORDER BY key"; - - status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, NULL); - ErrorCheck(status); - for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) { - bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2); - FinishedSingleOp(); - } - - status = sqlite3_finalize(pStmt); - ErrorCheck(status); - } - -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - std::string default_db_path; - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_use_existing_db = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) { - FLAGS_transaction = false; - } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { - FLAGS_page_size = n; - } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) { - FLAGS_num_pages = n; - } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_WAL_enabled = n; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/doc/bench/db_bench_tree_db.cc b/src/leveldb/doc/bench/db_bench_tree_db.cc deleted file mode 100644 index 4ca381f11f..0000000000 --- a/src/leveldb/doc/bench/db_bench_tree_db.cc +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include -#include "util/histogram.h" -#include "util/random.h" -#include "util/testutil.h" - -// Comma-separated list of operations to run in the specified order -// Actual benchmarks: -// -// fillseq -- write N values in sequential key order in async mode -// fillrandom -- write N values in random key order in async mode -// overwrite -- overwrite N values in random key order in async mode -// fillseqsync -- write N/100 values in sequential key order in sync mode -// fillrandsync -- write N/100 values in random key order in sync mode -// fillrand100K -- write N/1000 100K values in random order in async mode -// fillseq100K -- write N/1000 100K values in seq order in async mode -// readseq -- read N times sequentially -// readseq100K -- read N/1000 100K values in sequential order in async mode -// readrand100K -- read N/1000 100K values in sequential order in async mode -// readrandom -- read N times in random order -static const char* FLAGS_benchmarks = - "fillseq," - "fillseqsync," - "fillrandsync," - "fillrandom," - "overwrite," - "readrandom," - "readseq," - "fillrand100K," - "fillseq100K," - "readseq100K," - "readrand100K," - ; - -// Number of key/values to place in database -static int FLAGS_num = 1000000; - -// Number of read operations to do. If negative, do FLAGS_num reads. -static int FLAGS_reads = -1; - -// Size of each value -static int FLAGS_value_size = 100; - -// Arrange to generate values that shrink to this fraction of -// their original size after compression -static double FLAGS_compression_ratio = 0.5; - -// Print histogram of operation timings -static bool FLAGS_histogram = false; - -// Cache size. Default 4 MB -static int FLAGS_cache_size = 4194304; - -// Page size. Default 1 KB -static int FLAGS_page_size = 1024; - -// If true, do not destroy the existing database. If you set this -// flag and also specify a benchmark that wants a fresh database, that -// benchmark will fail. -static bool FLAGS_use_existing_db = false; - -// Compression flag. If true, compression is on. If false, compression -// is off. -static bool FLAGS_compression = true; - -// Use the db with the following name. -static const char* FLAGS_db = NULL; - -inline -static void DBSynchronize(kyotocabinet::TreeDB* db_) -{ - // Synchronize will flush writes to disk - if (!db_->synchronize()) { - fprintf(stderr, "synchronize error: %s\n", db_->error().name()); - } -} - -namespace leveldb { - -// Helper for quickly generating random data. -namespace { -class RandomGenerator { - private: - std::string data_; - int pos_; - - public: - RandomGenerator() { - // We use a limited amount of data over and over again and ensure - // that it is larger than the compression window (32KB), and also - // large enough to serve all typical value sizes we want to write. - Random rnd(301); - std::string piece; - while (data_.size() < 1048576) { - // Add a short fragment that is as compressible as specified - // by FLAGS_compression_ratio. - test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); - data_.append(piece); - } - pos_ = 0; - } - - Slice Generate(int len) { - if (pos_ + len > data_.size()) { - pos_ = 0; - assert(len < data_.size()); - } - pos_ += len; - return Slice(data_.data() + pos_ - len, len); - } -}; - -static Slice TrimSpace(Slice s) { - int start = 0; - while (start < s.size() && isspace(s[start])) { - start++; - } - int limit = s.size(); - while (limit > start && isspace(s[limit-1])) { - limit--; - } - return Slice(s.data() + start, limit - start); -} - -} // namespace - -class Benchmark { - private: - kyotocabinet::TreeDB* db_; - int db_num_; - int num_; - int reads_; - double start_; - double last_op_finish_; - int64_t bytes_; - std::string message_; - Histogram hist_; - RandomGenerator gen_; - Random rand_; - kyotocabinet::LZOCompressor comp_; - - // State kept for progress messages - int done_; - int next_report_; // When to report next - - void PrintHeader() { - const int kKeySize = 16; - PrintEnvironment(); - fprintf(stdout, "Keys: %d bytes each\n", kKeySize); - fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", - FLAGS_value_size, - static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); - fprintf(stdout, "Entries: %d\n", num_); - fprintf(stdout, "RawSize: %.1f MB (estimated)\n", - ((static_cast(kKeySize + FLAGS_value_size) * num_) - / 1048576.0)); - fprintf(stdout, "FileSize: %.1f MB (estimated)\n", - (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) - / 1048576.0)); - PrintWarnings(); - fprintf(stdout, "------------------------------------------------\n"); - } - - void PrintWarnings() { -#if defined(__GNUC__) && !defined(__OPTIMIZE__) - fprintf(stdout, - "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" - ); -#endif -#ifndef NDEBUG - fprintf(stdout, - "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); -#endif - } - - void PrintEnvironment() { - fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n", - kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV); - -#if defined(__linux) - time_t now = time(NULL); - fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline - - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if (cpuinfo != NULL) { - char line[1000]; - int num_cpus = 0; - std::string cpu_type; - std::string cache_size; - while (fgets(line, sizeof(line), cpuinfo) != NULL) { - const char* sep = strchr(line, ':'); - if (sep == NULL) { - continue; - } - Slice key = TrimSpace(Slice(line, sep - 1 - line)); - Slice val = TrimSpace(Slice(sep + 1)); - if (key == "model name") { - ++num_cpus; - cpu_type = val.ToString(); - } else if (key == "cache size") { - cache_size = val.ToString(); - } - } - fclose(cpuinfo); - fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); - fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); - } -#endif - } - - void Start() { - start_ = Env::Default()->NowMicros() * 1e-6; - bytes_ = 0; - message_.clear(); - last_op_finish_ = start_; - hist_.Clear(); - done_ = 0; - next_report_ = 100; - } - - void FinishedSingleOp() { - if (FLAGS_histogram) { - double now = Env::Default()->NowMicros() * 1e-6; - double micros = (now - last_op_finish_) * 1e6; - hist_.Add(micros); - if (micros > 20000) { - fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); - fflush(stderr); - } - last_op_finish_ = now; - } - - done_++; - if (done_ >= next_report_) { - if (next_report_ < 1000) next_report_ += 100; - else if (next_report_ < 5000) next_report_ += 500; - else if (next_report_ < 10000) next_report_ += 1000; - else if (next_report_ < 50000) next_report_ += 5000; - else if (next_report_ < 100000) next_report_ += 10000; - else if (next_report_ < 500000) next_report_ += 50000; - else next_report_ += 100000; - fprintf(stderr, "... finished %d ops%30s\r", done_, ""); - fflush(stderr); - } - } - - void Stop(const Slice& name) { - double finish = Env::Default()->NowMicros() * 1e-6; - - // Pretend at least one op was done in case we are running a benchmark - // that does not call FinishedSingleOp(). - if (done_ < 1) done_ = 1; - - if (bytes_ > 0) { - char rate[100]; - snprintf(rate, sizeof(rate), "%6.1f MB/s", - (bytes_ / 1048576.0) / (finish - start_)); - if (!message_.empty()) { - message_ = std::string(rate) + " " + message_; - } else { - message_ = rate; - } - } - - fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", - name.ToString().c_str(), - (finish - start_) * 1e6 / done_, - (message_.empty() ? "" : " "), - message_.c_str()); - if (FLAGS_histogram) { - fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); - } - fflush(stdout); - } - - public: - enum Order { - SEQUENTIAL, - RANDOM - }; - enum DBState { - FRESH, - EXISTING - }; - - Benchmark() - : db_(NULL), - num_(FLAGS_num), - reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), - bytes_(0), - rand_(301) { - std::vector files; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - Env::Default()->GetChildren(test_dir.c_str(), &files); - if (!FLAGS_use_existing_db) { - for (int i = 0; i < files.size(); i++) { - if (Slice(files[i]).starts_with("dbbench_polyDB")) { - std::string file_name(test_dir); - file_name += "/"; - file_name += files[i]; - Env::Default()->DeleteFile(file_name.c_str()); - } - } - } - } - - ~Benchmark() { - if (!db_->close()) { - fprintf(stderr, "close error: %s\n", db_->error().name()); - } - } - - void Run() { - PrintHeader(); - Open(false); - - const char* benchmarks = FLAGS_benchmarks; - while (benchmarks != NULL) { - const char* sep = strchr(benchmarks, ','); - Slice name; - if (sep == NULL) { - name = benchmarks; - benchmarks = NULL; - } else { - name = Slice(benchmarks, sep - benchmarks); - benchmarks = sep + 1; - } - - Start(); - - bool known = true; - bool write_sync = false; - if (name == Slice("fillseq")) { - Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillrandom")) { - Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("overwrite")) { - Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillrandsync")) { - write_sync = true; - Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillseqsync")) { - write_sync = true; - Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); - DBSynchronize(db_); - } else if (name == Slice("fillrand100K")) { - Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); - DBSynchronize(db_); - } else if (name == Slice("fillseq100K")) { - Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); - DBSynchronize(db_); - } else if (name == Slice("readseq")) { - ReadSequential(); - } else if (name == Slice("readrandom")) { - ReadRandom(); - } else if (name == Slice("readrand100K")) { - int n = reads_; - reads_ /= 1000; - ReadRandom(); - reads_ = n; - } else if (name == Slice("readseq100K")) { - int n = reads_; - reads_ /= 1000; - ReadSequential(); - reads_ = n; - } else { - known = false; - if (name != Slice()) { // No error message for empty name - fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); - } - } - if (known) { - Stop(name); - } - } - } - - private: - void Open(bool sync) { - assert(db_ == NULL); - - // Initialize db_ - db_ = new kyotocabinet::TreeDB(); - char file_name[100]; - db_num_++; - std::string test_dir; - Env::Default()->GetTestDirectory(&test_dir); - snprintf(file_name, sizeof(file_name), - "%s/dbbench_polyDB-%d.kct", - test_dir.c_str(), - db_num_); - - // Create tuning options and open the database - int open_options = kyotocabinet::PolyDB::OWRITER | - kyotocabinet::PolyDB::OCREATE; - int tune_options = kyotocabinet::TreeDB::TSMALL | - kyotocabinet::TreeDB::TLINEAR; - if (FLAGS_compression) { - tune_options |= kyotocabinet::TreeDB::TCOMPRESS; - db_->tune_compressor(&comp_); - } - db_->tune_options(tune_options); - db_->tune_page_cache(FLAGS_cache_size); - db_->tune_page(FLAGS_page_size); - db_->tune_map(256LL<<20); - if (sync) { - open_options |= kyotocabinet::PolyDB::OAUTOSYNC; - } - if (!db_->open(file_name, open_options)) { - fprintf(stderr, "open error: %s\n", db_->error().name()); - } - } - - void Write(bool sync, Order order, DBState state, - int num_entries, int value_size, int entries_per_batch) { - // Create new database if state == FRESH - if (state == FRESH) { - if (FLAGS_use_existing_db) { - message_ = "skipping (--use_existing_db is true)"; - return; - } - delete db_; - db_ = NULL; - Open(sync); - Start(); // Do not count time taken to destroy/open - } - - if (num_entries != num_) { - char msg[100]; - snprintf(msg, sizeof(msg), "(%d ops)", num_entries); - message_ = msg; - } - - // Write to database - for (int i = 0; i < num_entries; i++) - { - const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries); - char key[100]; - snprintf(key, sizeof(key), "%016d", k); - bytes_ += value_size + strlen(key); - std::string cpp_key = key; - if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) { - fprintf(stderr, "set error: %s\n", db_->error().name()); - } - FinishedSingleOp(); - } - } - - void ReadSequential() { - kyotocabinet::DB::Cursor* cur = db_->cursor(); - cur->jump(); - std::string ckey, cvalue; - while (cur->get(&ckey, &cvalue, true)) { - bytes_ += ckey.size() + cvalue.size(); - FinishedSingleOp(); - } - delete cur; - } - - void ReadRandom() { - std::string value; - for (int i = 0; i < reads_; i++) { - char key[100]; - const int k = rand_.Next() % reads_; - snprintf(key, sizeof(key), "%016d", k); - db_->get(key, &value); - FinishedSingleOp(); - } - } -}; - -} // namespace leveldb - -int main(int argc, char** argv) { - std::string default_db_path; - for (int i = 1; i < argc; i++) { - double d; - int n; - char junk; - if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { - FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); - } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { - FLAGS_compression_ratio = d; - } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_histogram = n; - } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { - FLAGS_num = n; - } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { - FLAGS_reads = n; - } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { - FLAGS_value_size = n; - } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { - FLAGS_cache_size = n; - } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { - FLAGS_page_size = n; - } else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 && - (n == 0 || n == 1)) { - FLAGS_compression = (n == 1) ? true : false; - } else if (strncmp(argv[i], "--db=", 5) == 0) { - FLAGS_db = argv[i] + 5; - } else { - fprintf(stderr, "Invalid flag '%s'\n", argv[i]); - exit(1); - } - } - - // Choose a location for the test database if none given with --db= - if (FLAGS_db == NULL) { - leveldb::Env::Default()->GetTestDirectory(&default_db_path); - default_db_path += "/dbbench"; - FLAGS_db = default_db_path.c_str(); - } - - leveldb::Benchmark benchmark; - benchmark.Run(); - return 0; -} diff --git a/src/leveldb/doc/benchmark.html b/src/leveldb/doc/benchmark.html deleted file mode 100644 index c4639772c1..0000000000 --- a/src/leveldb/doc/benchmark.html +++ /dev/null @@ -1,459 +0,0 @@ - - - -LevelDB Benchmarks - - - - -

      LevelDB Benchmarks

      -

      Google, July 2011

      -
      - -

      In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against SQLite3 (version 3.7.6.3) and Kyoto Cabinet's (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.

      - -

      Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.

      - -

      Benchmark Source Code

      -

      We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's db_bench. The code for each of the benchmarks resides here:

      - - -

      Custom Build Specifications

      -
        -
      • LevelDB: LevelDB was compiled with the tcmalloc library and the Snappy compression library (revision 33). Assertions were disabled.
      • -
      • TreeDB: TreeDB was compiled using the LZO compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.
      • -
      • SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive. We also enabled SQLite's write-ahead logging.
      • -
      - -

      1. Baseline Performance

      -

      This section gives the baseline performance of all the -databases. Following sections show how performance changes as various -parameters are varied. For the baseline:

      -
        -
      • Each database is allowed 4 MB of cache memory.
      • -
      • Databases are opened in asynchronous write mode. - (LevelDB's sync option, TreeDB's OAUTOSYNC option, and - SQLite3's synchronous options are all turned off). I.e., - every write is pushed to the operating system, but the - benchmark does not wait for the write to reach the disk.
      • -
      • Keys are 16 bytes each.
      • -
      • Value are 100 bytes each (with enough redundancy so that - a simple compressor shrinks them to 50% of their original - size).
      • -
      • Sequential reads/writes traverse the key space in increasing order.
      • -
      • Random reads/writes traverse the key space in random order.
      • -
      - -

      A. Sequential Reads

      - - - - - - - - - - -
      LevelDB4,030,000 ops/sec
       
      Kyoto TreeDB1,010,000 ops/sec
       
      SQLite3383,000 ops/sec
       
      -

      B. Random Reads

      - - - - - - - - - - -
      LevelDB129,000 ops/sec
       
      Kyoto TreeDB151,000 ops/sec
       
      SQLite3134,000 ops/sec
       
      -

      C. Sequential Writes

      - - - - - - - - - - -
      LevelDB779,000 ops/sec
       
      Kyoto TreeDB342,000 ops/sec
       
      SQLite348,600 ops/sec
       
      -

      D. Random Writes

      - - - - - - - - - - -
      LevelDB164,000 ops/sec
       
      Kyoto TreeDB88,500 ops/sec
       
      SQLite39,860 ops/sec
       
      - -

      LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.

      - -

      2. Write Performance under Different Configurations

      -

      A. Large Values

      -

      For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.

      -

      Sequential Writes

      - - - - - - - - - - -
      LevelDB1,100 ops/sec
       
      Kyoto TreeDB1,000 ops/sec
       
      SQLite31,600 ops/sec
       
      -

      Random Writes

      - - - - - - - - - - -
      LevelDB480 ops/sec
       
      Kyoto TreeDB1,100 ops/sec
       
      SQLite31,600 ops/sec
       
      -

      LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file. -With larger values, LevelDB's per-operation efficiency is swamped by the -cost of extra copies of large values.

      -

      B. Batch Writes

      -

      A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.

      -

      Sequential Writes

      - - - - - - - - - -
      LevelDB840,000 entries/sec
       
      (1.08x baseline)
      SQLite3124,000 entries/sec
       
      (2.55x baseline)
      -

      Random Writes

      - - - - - - - - - -
      LevelDB221,000 entries/sec
       
      (1.35x baseline)
      SQLite322,000 entries/sec
       
      (2.23x baseline)
      - -

      Because of the way LevelDB persistent storage is organized, batches of -random writes are not much slower (only a factor of 4x) than batches -of sequential writes.

      - -

      C. Synchronous Writes

      -

      In the following benchmark, we enable the synchronous writing modes -of all of the databases. Since this change significantly slows down the -benchmark, we stop after 10,000 writes. For synchronous write tests, we've -disabled hard drive write-caching (using `hdparm -W 0 [device]`).

      -
        -
      • For LevelDB, we set WriteOptions.sync = true.
      • -
      • In TreeDB, we enabled TreeDB's OAUTOSYNC option.
      • -
      • For SQLite3, we set "PRAGMA synchronous = FULL".
      • -
      -

      Sequential Writes

      - - - - - - - - - - - - - -
      LevelDB100 ops/sec
       
      (0.003x baseline)
      Kyoto TreeDB7 ops/sec
       
      (0.0004x baseline)
      SQLite388 ops/sec
       
      (0.002x baseline)
      -

      Random Writes

      - - - - - - - - - - - - - -
      LevelDB100 ops/sec
       
      (0.015x baseline)
      Kyoto TreeDB8 ops/sec
       
      (0.001x baseline)
      SQLite388 ops/sec
       
      (0.009x baseline)
      - -

      Also see the ext4 performance numbers below -since synchronous writes behave significantly differently -on ext3 and ext4.

      - -

      D. Turning Compression Off

      - -

      In the baseline measurements, LevelDB and TreeDB were using -light-weight compression -(Snappy for LevelDB, -and LZO for -TreeDB). SQLite3, by default does not use compression. The -experiments below show what happens when compression is disabled in -all of the databases (the SQLite3 numbers are just a copy of -its baseline measurements):

      - -

      Sequential Writes

      - - - - - - - - - - - - - -
      LevelDB594,000 ops/sec
       
      (0.76x baseline)
      Kyoto TreeDB485,000 ops/sec
       
      (1.42x baseline)
      SQLite348,600 ops/sec
       
      (1.00x baseline)
      -

      Random Writes

      - - - - - - - - - - - - - -
      LevelDB135,000 ops/sec
       
      (0.82x baseline)
      Kyoto TreeDB159,000 ops/sec
       
      (1.80x baseline)
      SQLite39,860 ops/sec
       
      (1.00x baseline)
      - -

      LevelDB's write performance is better with compression than without -since compression decreases the amount of data that has to be written -to disk. Therefore LevelDB users can leave compression enabled in -most scenarios without having worry about a tradeoff between space -usage and performance. TreeDB's performance on the other hand is -better without compression than with compression. Presumably this is -because TreeDB's compression library (LZO) is more expensive than -LevelDB's compression library (Snappy).

      - -

      E. Using More Memory

      -

      We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).

      -

      Sequential Writes

      - - - - - - - - - - - - - -
      LevelDB812,000 ops/sec
       
      (1.04x baseline)
      Kyoto TreeDB321,000 ops/sec
       
      (0.94x baseline)
      SQLite348,500 ops/sec
       
      (1.00x baseline)
      -

      Random Writes

      - - - - - - - - - - - - - -
      LevelDB355,000 ops/sec
       
      (2.16x baseline)
      Kyoto TreeDB284,000 ops/sec
       
      (3.21x baseline)
      SQLite39,670 ops/sec
       
      (0.98x baseline)
      - -

      SQLite's performance does not change substantially when compared to -the baseline, but the random write performance for both LevelDB and -TreeDB increases significantly. LevelDB's performance improves -because a larger write buffer reduces the need to merge sorted files -(since it creates a smaller number of larger sorted files). TreeDB's -performance goes up because the entire database is available in memory -for fast in-place updates.

      - -

      3. Read Performance under Different Configurations

      -

      A. Larger Caches

      -

      We increased the overall memory usage to 128 MB for each database. -For LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB -to LevelDB's cache. The other databases don't differentiate between a -write buffer and a cache, so we simply set their cache size to 128 -MB.

      -

      Sequential Reads

      - - - - - - - - - - - - - -
      LevelDB5,210,000 ops/sec
       
      (1.29x baseline)
      Kyoto TreeDB1,070,000 ops/sec
       
      (1.06x baseline)
      SQLite3609,000 ops/sec
       
      (1.59x baseline)
      - -

      Random Reads

      - - - - - - - - - - - - - -
      LevelDB190,000 ops/sec
       
      (1.47x baseline)
      Kyoto TreeDB463,000 ops/sec
       
      (3.07x baseline)
      SQLite3186,000 ops/sec
       
      (1.39x baseline)
      - -

      As expected, the read performance of all of the databases increases -when the caches are enlarged. In particular, TreeDB seems to make -very effective use of a cache that is large enough to hold the entire -database.

      - -

      B. No Compression Reads

      -

      For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.

      -

      Sequential Reads

      - - - - - - - - - - - - - -
      LevelDB4,880,000 ops/sec
       
      (1.21x baseline)
      Kyoto TreeDB1,230,000 ops/sec
       
      (3.60x baseline)
      SQLite3383,000 ops/sec
       
      (1.00x baseline)
      -

      Random Reads

      - - - - - - - - - - - - - -
      LevelDB149,000 ops/sec
       
      (1.16x baseline)
      Kyoto TreeDB175,000 ops/sec
       
      (1.16x baseline)
      SQLite3134,000 ops/sec
       
      (1.00x baseline)
      - -

      Performance of both LevelDB and TreeDB improves a small amount when -compression is disabled. Note however that under different workloads, -performance may very well be better with compression if it allows more -of the working set to fit in memory.

      - -

      Note about Ext4 Filesystems

      -

      The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.

      - -

      Acknowledgements

      -

      Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.

      - - diff --git a/src/leveldb/doc/doc.css b/src/leveldb/doc/doc.css deleted file mode 100644 index 700c564e43..0000000000 --- a/src/leveldb/doc/doc.css +++ /dev/null @@ -1,89 +0,0 @@ -body { - margin-left: 0.5in; - margin-right: 0.5in; - background: white; - color: black; -} - -h1 { - margin-left: -0.2in; - font-size: 14pt; -} -h2 { - margin-left: -0in; - font-size: 12pt; -} -h3 { - margin-left: -0in; -} -h4 { - margin-left: -0in; -} -hr { - margin-left: -0in; -} - -/* Definition lists: definition term bold */ -dt { - font-weight: bold; -} - -address { - text-align: center; -} -code,samp,var { - color: blue; -} -kbd { - color: #600000; -} -div.note p { - float: right; - width: 3in; - margin-right: 0%; - padding: 1px; - border: 2px solid #6060a0; - background-color: #fffff0; -} - -ul { - margin-top: -0em; - margin-bottom: -0em; -} - -ol { - margin-top: -0em; - margin-bottom: -0em; -} - -UL.nobullets { - list-style-type: none; - list-style-image: none; - margin-left: -1em; -} - -p { - margin: 1em 0 1em 0; - padding: 0 0 0 0; -} - -pre { - line-height: 1.3em; - padding: 0.4em 0 0.8em 0; - margin: 0 0 0 0; - border: 0 0 0 0; - color: blue; -} - -.datatable { - margin-left: auto; - margin-right: auto; - margin-top: 2em; - margin-bottom: 2em; - border: 1px solid; -} - -.datatable td,th { - padding: 0 0.5em 0 0.5em; - text-align: right; -} diff --git a/src/leveldb/doc/impl.html b/src/leveldb/doc/impl.html deleted file mode 100644 index 6a468be095..0000000000 --- a/src/leveldb/doc/impl.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - -Leveldb file layout and compactions - - - - -

      Files

      - -The implementation of leveldb is similar in spirit to the -representation of a single - -Bigtable tablet (section 5.3). -However the organization of the files that make up the representation -is somewhat different and is explained below. - -

      -Each database is represented by a set of files stored in a directory. -There are several different types of files as documented below: -

      -

      Log files

      -

      -A log file (*.log) stores a sequence of recent updates. Each update -is appended to the current log file. When the log file reaches a -pre-determined size (approximately 4MB by default), it is converted -to a sorted table (see below) and a new log file is created for future -updates. -

      -A copy of the current log file is kept in an in-memory structure (the -memtable). This copy is consulted on every read so that read -operations reflect all logged updates. -

      -

      Sorted tables

      -

      -A sorted table (*.sst) stores a sequence of entries sorted by key. -Each entry is either a value for the key, or a deletion marker for the -key. (Deletion markers are kept around to hide obsolete values -present in older sorted tables). -

      -The set of sorted tables are organized into a sequence of levels. The -sorted table generated from a log file is placed in a special young -level (also called level-0). When the number of young files exceeds a -certain threshold (currently four), all of the young files are merged -together with all of the overlapping level-1 files to produce a -sequence of new level-1 files (we create a new level-1 file for every -2MB of data.) -

      -Files in the young level may contain overlapping keys. However files -in other levels have distinct non-overlapping key ranges. Consider -level number L where L >= 1. When the combined size of files in -level-L exceeds (10^L) MB (i.e., 10MB for level-1, 100MB for level-2, -...), one file in level-L, and all of the overlapping files in -level-(L+1) are merged to form a set of new files for level-(L+1). -These merges have the effect of gradually migrating new updates from -the young level to the largest level using only bulk reads and writes -(i.e., minimizing expensive seeks). - -

      Manifest

      -

      -A MANIFEST file lists the set of sorted tables that make up each -level, the corresponding key ranges, and other important metadata. -A new MANIFEST file (with a new number embedded in the file name) -is created whenever the database is reopened. The MANIFEST file is -formatted as a log, and changes made to the serving state (as files -are added or removed) are appended to this log. -

      -

      Current

      -

      -CURRENT is a simple text file that contains the name of the latest -MANIFEST file. -

      -

      Info logs

      -

      -Informational messages are printed to files named LOG and LOG.old. -

      -

      Others

      -

      -Other files used for miscellaneous purposes may also be present -(LOCK, *.dbtmp). - -

      Level 0

      -When the log file grows above a certain size (1MB by default): -
        -
      • Create a brand new memtable and log file and direct future updates here -
      • In the background: -
          -
        • Write the contents of the previous memtable to an sstable -
        • Discard the memtable -
        • Delete the old log file and the old memtable -
        • Add the new sstable to the young (level-0) level. -
        -
      - -

      Compactions

      - -

      -When the size of level L exceeds its limit, we compact it in a -background thread. The compaction picks a file from level L and all -overlapping files from the next level L+1. Note that if a level-L -file overlaps only part of a level-(L+1) file, the entire file at -level-(L+1) is used as an input to the compaction and will be -discarded after the compaction. Aside: because level-0 is special -(files in it may overlap each other), we treat compactions from -level-0 to level-1 specially: a level-0 compaction may pick more than -one level-0 file in case some of these files overlap each other. - -

      -A compaction merges the contents of the picked files to produce a -sequence of level-(L+1) files. We switch to producing a new -level-(L+1) file after the current output file has reached the target -file size (2MB). We also switch to a new output file when the key -range of the current output file has grown enough to overlap more than -ten level-(L+2) files. This last rule ensures that a later compaction -of a level-(L+1) file will not pick up too much data from level-(L+2). - -

      -The old files are discarded and the new files are added to the serving -state. - -

      -Compactions for a particular level rotate through the key space. In -more detail, for each level L, we remember the ending key of the last -compaction at level L. The next compaction for level L will pick the -first file that starts after this key (wrapping around to the -beginning of the key space if there is no such file). - -

      -Compactions drop overwritten values. They also drop deletion markers -if there are no higher numbered levels that contain a file whose range -overlaps the current key. - -

      Timing

      - -Level-0 compactions will read up to four 1MB files from level-0, and -at worst all the level-1 files (10MB). I.e., we will read 14MB and -write 14MB. - -

      -Other than the special level-0 compactions, we will pick one 2MB file -from level L. In the worst case, this will overlap ~ 12 files from -level L+1 (10 because level-(L+1) is ten times the size of level-L, -and another two at the boundaries since the file ranges at level-L -will usually not be aligned with the file ranges at level-L+1). The -compaction will therefore read 26MB and write 26MB. Assuming a disk -IO rate of 100MB/s (ballpark range for modern drives), the worst -compaction cost will be approximately 0.5 second. - -

      -If we throttle the background writing to something small, say 10% of -the full 100MB/s speed, a compaction may take up to 5 seconds. If the -user is writing at 10MB/s, we might build up lots of level-0 files -(~50 to hold the 5*10MB). This may significantly increase the cost of -reads due to the overhead of merging more files together on every -read. - -

      -Solution 1: To reduce this problem, we might want to increase the log -switching threshold when the number of level-0 files is large. Though -the downside is that the larger this threshold, the more memory we will -need to hold the corresponding memtable. - -

      -Solution 2: We might want to decrease write rate artificially when the -number of level-0 files goes up. - -

      -Solution 3: We work on reducing the cost of very wide merges. -Perhaps most of the level-0 files will have their blocks sitting -uncompressed in the cache and we will only need to worry about the -O(N) complexity in the merging iterator. - -

      Number of files

      - -Instead of always making 2MB files, we could make larger files for -larger levels to reduce the total file count, though at the expense of -more bursty compactions. Alternatively, we could shard the set of -files into multiple directories. - -

      -An experiment on an ext3 filesystem on Feb 04, 2011 shows -the following timings to do 100K file opens in directories with -varying number of files: - - - - - -
      Files in directoryMicroseconds to open a file
      10009
      1000010
      10000016
      -So maybe even the sharding is not necessary on modern filesystems? - -

      Recovery

      - -
        -
      • Read CURRENT to find name of the latest committed MANIFEST -
      • Read the named MANIFEST file -
      • Clean up stale files -
      • We could open all sstables here, but it is probably better to be lazy... -
      • Convert log chunk to a new level-0 sstable -
      • Start directing new writes to a new log file with recovered sequence# -
      - -

      Garbage collection of files

      - -DeleteObsoleteFiles() is called at the end of every -compaction and at the end of recovery. It finds the names of all -files in the database. It deletes all log files that are not the -current log file. It deletes all table files that are not referenced -from some level and are not the output of an active compaction. - - - diff --git a/src/leveldb/doc/impl.md b/src/leveldb/doc/impl.md deleted file mode 100644 index 4b13f2a6ba..0000000000 --- a/src/leveldb/doc/impl.md +++ /dev/null @@ -1,170 +0,0 @@ -## Files - -The implementation of leveldb is similar in spirit to the representation of a -single [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html). -However the organization of the files that make up the representation is -somewhat different and is explained below. - -Each database is represented by a set of files stored in a directory. There are -several different types of files as documented below: - -### Log files - -A log file (*.log) stores a sequence of recent updates. Each update is appended -to the current log file. When the log file reaches a pre-determined size -(approximately 4MB by default), it is converted to a sorted table (see below) -and a new log file is created for future updates. - -A copy of the current log file is kept in an in-memory structure (the -`memtable`). This copy is consulted on every read so that read operations -reflect all logged updates. - -## Sorted tables - -A sorted table (*.ldb) stores a sequence of entries sorted by key. Each entry is -either a value for the key, or a deletion marker for the key. (Deletion markers -are kept around to hide obsolete values present in older sorted tables). - -The set of sorted tables are organized into a sequence of levels. The sorted -table generated from a log file is placed in a special **young** level (also -called level-0). When the number of young files exceeds a certain threshold -(currently four), all of the young files are merged together with all of the -overlapping level-1 files to produce a sequence of new level-1 files (we create -a new level-1 file for every 2MB of data.) - -Files in the young level may contain overlapping keys. However files in other -levels have distinct non-overlapping key ranges. Consider level number L where -L >= 1. When the combined size of files in level-L exceeds (10^L) MB (i.e., 10MB -for level-1, 100MB for level-2, ...), one file in level-L, and all of the -overlapping files in level-(L+1) are merged to form a set of new files for -level-(L+1). These merges have the effect of gradually migrating new updates -from the young level to the largest level using only bulk reads and writes -(i.e., minimizing expensive seeks). - -### Manifest - -A MANIFEST file lists the set of sorted tables that make up each level, the -corresponding key ranges, and other important metadata. A new MANIFEST file -(with a new number embedded in the file name) is created whenever the database -is reopened. The MANIFEST file is formatted as a log, and changes made to the -serving state (as files are added or removed) are appended to this log. - -### Current - -CURRENT is a simple text file that contains the name of the latest MANIFEST -file. - -### Info logs - -Informational messages are printed to files named LOG and LOG.old. - -### Others - -Other files used for miscellaneous purposes may also be present (LOCK, *.dbtmp). - -## Level 0 - -When the log file grows above a certain size (1MB by default): -Create a brand new memtable and log file and direct future updates here -In the background: -Write the contents of the previous memtable to an sstable -Discard the memtable -Delete the old log file and the old memtable -Add the new sstable to the young (level-0) level. - -## Compactions - -When the size of level L exceeds its limit, we compact it in a background -thread. The compaction picks a file from level L and all overlapping files from -the next level L+1. Note that if a level-L file overlaps only part of a -level-(L+1) file, the entire file at level-(L+1) is used as an input to the -compaction and will be discarded after the compaction. Aside: because level-0 -is special (files in it may overlap each other), we treat compactions from -level-0 to level-1 specially: a level-0 compaction may pick more than one -level-0 file in case some of these files overlap each other. - -A compaction merges the contents of the picked files to produce a sequence of -level-(L+1) files. We switch to producing a new level-(L+1) file after the -current output file has reached the target file size (2MB). We also switch to a -new output file when the key range of the current output file has grown enough -to overlap more than ten level-(L+2) files. This last rule ensures that a later -compaction of a level-(L+1) file will not pick up too much data from -level-(L+2). - -The old files are discarded and the new files are added to the serving state. - -Compactions for a particular level rotate through the key space. In more detail, -for each level L, we remember the ending key of the last compaction at level L. -The next compaction for level L will pick the first file that starts after this -key (wrapping around to the beginning of the key space if there is no such -file). - -Compactions drop overwritten values. They also drop deletion markers if there -are no higher numbered levels that contain a file whose range overlaps the -current key. - -### Timing - -Level-0 compactions will read up to four 1MB files from level-0, and at worst -all the level-1 files (10MB). I.e., we will read 14MB and write 14MB. - -Other than the special level-0 compactions, we will pick one 2MB file from level -L. In the worst case, this will overlap ~ 12 files from level L+1 (10 because -level-(L+1) is ten times the size of level-L, and another two at the boundaries -since the file ranges at level-L will usually not be aligned with the file -ranges at level-L+1). The compaction will therefore read 26MB and write 26MB. -Assuming a disk IO rate of 100MB/s (ballpark range for modern drives), the worst -compaction cost will be approximately 0.5 second. - -If we throttle the background writing to something small, say 10% of the full -100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at -10MB/s, we might build up lots of level-0 files (~50 to hold the 5*10MB). This -may significantly increase the cost of reads due to the overhead of merging more -files together on every read. - -Solution 1: To reduce this problem, we might want to increase the log switching -threshold when the number of level-0 files is large. Though the downside is that -the larger this threshold, the more memory we will need to hold the -corresponding memtable. - -Solution 2: We might want to decrease write rate artificially when the number of -level-0 files goes up. - -Solution 3: We work on reducing the cost of very wide merges. Perhaps most of -the level-0 files will have their blocks sitting uncompressed in the cache and -we will only need to worry about the O(N) complexity in the merging iterator. - -### Number of files - -Instead of always making 2MB files, we could make larger files for larger levels -to reduce the total file count, though at the expense of more bursty -compactions. Alternatively, we could shard the set of files into multiple -directories. - -An experiment on an ext3 filesystem on Feb 04, 2011 shows the following timings -to do 100K file opens in directories with varying number of files: - - -| Files in directory | Microseconds to open a file | -|-------------------:|----------------------------:| -| 1000 | 9 | -| 10000 | 10 | -| 100000 | 16 | - -So maybe even the sharding is not necessary on modern filesystems? - -## Recovery - -* Read CURRENT to find name of the latest committed MANIFEST -* Read the named MANIFEST file -* Clean up stale files -* We could open all sstables here, but it is probably better to be lazy... -* Convert log chunk to a new level-0 sstable -* Start directing new writes to a new log file with recovered sequence# - -## Garbage collection of files - -`DeleteObsoleteFiles()` is called at the end of every compaction and at the end -of recovery. It finds the names of all files in the database. It deletes all log -files that are not the current log file. It deletes all table files that are not -referenced from some level and are not the output of an active compaction. diff --git a/src/leveldb/doc/index.html b/src/leveldb/doc/index.html deleted file mode 100644 index 3ed0ed9d9e..0000000000 --- a/src/leveldb/doc/index.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - -Leveldb - - - -

      Leveldb

      -
      Jeff Dean, Sanjay Ghemawat
      -

      -The leveldb library provides a persistent key value store. Keys and -values are arbitrary byte arrays. The keys are ordered within the key -value store according to a user-specified comparator function. - -

      -

      Opening A Database

      -

      -A leveldb database has a name which corresponds to a file system -directory. All of the contents of database are stored in this -directory. The following example shows how to open a database, -creating it if necessary: -

      -

      -  #include <assert>
      -  #include "leveldb/db.h"
      -
      -  leveldb::DB* db;
      -  leveldb::Options options;
      -  options.create_if_missing = true;
      -  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
      -  assert(status.ok());
      -  ...
      -
      -If you want to raise an error if the database already exists, add -the following line before the leveldb::DB::Open call: -
      -  options.error_if_exists = true;
      -
      -

      Status

      -

      -You may have noticed the leveldb::Status type above. Values of this -type are returned by most functions in leveldb that may encounter an -error. You can check if such a result is ok, and also print an -associated error message: -

      -

      -   leveldb::Status s = ...;
      -   if (!s.ok()) cerr << s.ToString() << endl;
      -
      -

      Closing A Database

      -

      -When you are done with a database, just delete the database object. -Example: -

      -

      -  ... open the db as described above ...
      -  ... do something with db ...
      -  delete db;
      -
      -

      Reads And Writes

      -

      -The database provides Put, Delete, and Get methods to -modify/query the database. For example, the following code -moves the value stored under key1 to key2. -

      -  std::string value;
      -  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
      -  if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
      -  if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
      -
      - -

      Atomic Updates

      -

      -Note that if the process dies after the Put of key2 but before the -delete of key1, the same value may be left stored under multiple keys. -Such problems can be avoided by using the WriteBatch class to -atomically apply a set of updates: -

      -

      -  #include "leveldb/write_batch.h"
      -  ...
      -  std::string value;
      -  leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
      -  if (s.ok()) {
      -    leveldb::WriteBatch batch;
      -    batch.Delete(key1);
      -    batch.Put(key2, value);
      -    s = db->Write(leveldb::WriteOptions(), &batch);
      -  }
      -
      -The WriteBatch holds a sequence of edits to be made to the database, -and these edits within the batch are applied in order. Note that we -called Delete before Put so that if key1 is identical to key2, -we do not end up erroneously dropping the value entirely. -

      -Apart from its atomicity benefits, WriteBatch may also be used to -speed up bulk updates by placing lots of individual mutations into the -same batch. - -

      Synchronous Writes

      -By default, each write to leveldb is asynchronous: it -returns after pushing the write from the process into the operating -system. The transfer from operating system memory to the underlying -persistent storage happens asynchronously. The sync flag -can be turned on for a particular write to make the write operation -not return until the data being written has been pushed all the way to -persistent storage. (On Posix systems, this is implemented by calling -either fsync(...) or fdatasync(...) or -msync(..., MS_SYNC) before the write operation returns.) -
      -  leveldb::WriteOptions write_options;
      -  write_options.sync = true;
      -  db->Put(write_options, ...);
      -
      -Asynchronous writes are often more than a thousand times as fast as -synchronous writes. The downside of asynchronous writes is that a -crash of the machine may cause the last few updates to be lost. Note -that a crash of just the writing process (i.e., not a reboot) will not -cause any loss since even when sync is false, an update -is pushed from the process memory into the operating system before it -is considered done. - -

      -Asynchronous writes can often be used safely. For example, when -loading a large amount of data into the database you can handle lost -updates by restarting the bulk load after a crash. A hybrid scheme is -also possible where every Nth write is synchronous, and in the event -of a crash, the bulk load is restarted just after the last synchronous -write finished by the previous run. (The synchronous write can update -a marker that describes where to restart on a crash.) - -

      -WriteBatch provides an alternative to asynchronous writes. -Multiple updates may be placed in the same WriteBatch and -applied together using a synchronous write (i.e., -write_options.sync is set to true). The extra cost of -the synchronous write will be amortized across all of the writes in -the batch. - -

      -

      Concurrency

      -

      -A database may only be opened by one process at a time. -The leveldb implementation acquires a lock from the -operating system to prevent misuse. Within a single process, the -same leveldb::DB object may be safely shared by multiple -concurrent threads. I.e., different threads may write into or fetch -iterators or call Get on the same database without any -external synchronization (the leveldb implementation will -automatically do the required synchronization). However other objects -(like Iterator and WriteBatch) may require external synchronization. -If two threads share such an object, they must protect access to it -using their own locking protocol. More details are available in -the public header files. -

      -

      Iteration

      -

      -The following example demonstrates how to print all key,value pairs -in a database. -

      -

      -  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
      -  for (it->SeekToFirst(); it->Valid(); it->Next()) {
      -    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
      -  }
      -  assert(it->status().ok());  // Check for any errors found during the scan
      -  delete it;
      -
      -The following variation shows how to process just the keys in the -range [start,limit): -

      -

      -  for (it->Seek(start);
      -       it->Valid() && it->key().ToString() < limit;
      -       it->Next()) {
      -    ...
      -  }
      -
      -You can also process entries in reverse order. (Caveat: reverse -iteration may be somewhat slower than forward iteration.) -

      -

      -  for (it->SeekToLast(); it->Valid(); it->Prev()) {
      -    ...
      -  }
      -
      -

      Snapshots

      -

      -Snapshots provide consistent read-only views over the entire state of -the key-value store. ReadOptions::snapshot may be non-NULL to indicate -that a read should operate on a particular version of the DB state. -If ReadOptions::snapshot is NULL, the read will operate on an -implicit snapshot of the current state. -

      -Snapshots are created by the DB::GetSnapshot() method: -

      -

      -  leveldb::ReadOptions options;
      -  options.snapshot = db->GetSnapshot();
      -  ... apply some updates to db ...
      -  leveldb::Iterator* iter = db->NewIterator(options);
      -  ... read using iter to view the state when the snapshot was created ...
      -  delete iter;
      -  db->ReleaseSnapshot(options.snapshot);
      -
      -Note that when a snapshot is no longer needed, it should be released -using the DB::ReleaseSnapshot interface. This allows the -implementation to get rid of state that was being maintained just to -support reading as of that snapshot. -

      Slice

      -

      -The return value of the it->key() and it->value() calls above -are instances of the leveldb::Slice type. Slice is a simple -structure that contains a length and a pointer to an external byte -array. Returning a Slice is a cheaper alternative to returning a -std::string since we do not need to copy potentially large keys and -values. In addition, leveldb methods do not return null-terminated -C-style strings since leveldb keys and values are allowed to -contain '\0' bytes. -

      -C++ strings and null-terminated C-style strings can be easily converted -to a Slice: -

      -

      -   leveldb::Slice s1 = "hello";
      -
      -   std::string str("world");
      -   leveldb::Slice s2 = str;
      -
      -A Slice can be easily converted back to a C++ string: -
      -   std::string str = s1.ToString();
      -   assert(str == std::string("hello"));
      -
      -Be careful when using Slices since it is up to the caller to ensure that -the external byte array into which the Slice points remains live while -the Slice is in use. For example, the following is buggy: -

      -

      -   leveldb::Slice slice;
      -   if (...) {
      -     std::string str = ...;
      -     slice = str;
      -   }
      -   Use(slice);
      -
      -When the if statement goes out of scope, str will be destroyed and the -backing storage for slice will disappear. -

      -

      Comparators

      -

      -The preceding examples used the default ordering function for key, -which orders bytes lexicographically. You can however supply a custom -comparator when opening a database. For example, suppose each -database key consists of two numbers and we should sort by the first -number, breaking ties by the second number. First, define a proper -subclass of leveldb::Comparator that expresses these rules: -

      -

      -  class TwoPartComparator : public leveldb::Comparator {
      -   public:
      -    // Three-way comparison function:
      -    //   if a < b: negative result
      -    //   if a > b: positive result
      -    //   else: zero result
      -    int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
      -      int a1, a2, b1, b2;
      -      ParseKey(a, &a1, &a2);
      -      ParseKey(b, &b1, &b2);
      -      if (a1 < b1) return -1;
      -      if (a1 > b1) return +1;
      -      if (a2 < b2) return -1;
      -      if (a2 > b2) return +1;
      -      return 0;
      -    }
      -
      -    // Ignore the following methods for now:
      -    const char* Name() const { return "TwoPartComparator"; }
      -    void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
      -    void FindShortSuccessor(std::string*) const { }
      -  };
      -
      -Now create a database using this custom comparator: -

      -

      -  TwoPartComparator cmp;
      -  leveldb::DB* db;
      -  leveldb::Options options;
      -  options.create_if_missing = true;
      -  options.comparator = &cmp;
      -  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
      -  ...
      -
      -

      Backwards compatibility

      -

      -The result of the comparator's Name method is attached to the -database when it is created, and is checked on every subsequent -database open. If the name changes, the leveldb::DB::Open call will -fail. Therefore, change the name if and only if the new key format -and comparison function are incompatible with existing databases, and -it is ok to discard the contents of all existing databases. -

      -You can however still gradually evolve your key format over time with -a little bit of pre-planning. For example, you could store a version -number at the end of each key (one byte should suffice for most uses). -When you wish to switch to a new key format (e.g., adding an optional -third part to the keys processed by TwoPartComparator), -(a) keep the same comparator name (b) increment the version number -for new keys (c) change the comparator function so it uses the -version numbers found in the keys to decide how to interpret them. -

      -

      Performance

      -

      -Performance can be tuned by changing the default values of the -types defined in include/leveldb/options.h. - -

      -

      Block size

      -

      -leveldb groups adjacent keys together into the same block and such a -block is the unit of transfer to and from persistent storage. The -default block size is approximately 4096 uncompressed bytes. -Applications that mostly do bulk scans over the contents of the -database may wish to increase this size. Applications that do a lot -of point reads of small values may wish to switch to a smaller block -size if performance measurements indicate an improvement. There isn't -much benefit in using blocks smaller than one kilobyte, or larger than -a few megabytes. Also note that compression will be more effective -with larger block sizes. -

      -

      Compression

      -

      -Each block is individually compressed before being written to -persistent storage. Compression is on by default since the default -compression method is very fast, and is automatically disabled for -uncompressible data. In rare cases, applications may want to disable -compression entirely, but should only do so if benchmarks show a -performance improvement: -

      -

      -  leveldb::Options options;
      -  options.compression = leveldb::kNoCompression;
      -  ... leveldb::DB::Open(options, name, ...) ....
      -
      -

      Cache

      -

      -The contents of the database are stored in a set of files in the -filesystem and each file stores a sequence of compressed blocks. If -options.cache is non-NULL, it is used to cache frequently used -uncompressed block contents. -

      -

      -  #include "leveldb/cache.h"
      -
      -  leveldb::Options options;
      -  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
      -  leveldb::DB* db;
      -  leveldb::DB::Open(options, name, &db);
      -  ... use the db ...
      -  delete db
      -  delete options.cache;
      -
      -Note that the cache holds uncompressed data, and therefore it should -be sized according to application level data sizes, without any -reduction from compression. (Caching of compressed blocks is left to -the operating system buffer cache, or any custom Env -implementation provided by the client.) -

      -When performing a bulk read, the application may wish to disable -caching so that the data processed by the bulk read does not end up -displacing most of the cached contents. A per-iterator option can be -used to achieve this: -

      -

      -  leveldb::ReadOptions options;
      -  options.fill_cache = false;
      -  leveldb::Iterator* it = db->NewIterator(options);
      -  for (it->SeekToFirst(); it->Valid(); it->Next()) {
      -    ...
      -  }
      -
      -

      Key Layout

      -

      -Note that the unit of disk transfer and caching is a block. Adjacent -keys (according to the database sort order) will usually be placed in -the same block. Therefore the application can improve its performance -by placing keys that are accessed together near each other and placing -infrequently used keys in a separate region of the key space. -

      -For example, suppose we are implementing a simple file system on top -of leveldb. The types of entries we might wish to store are: -

      -

      -   filename -> permission-bits, length, list of file_block_ids
      -   file_block_id -> data
      -
      -We might want to prefix filename keys with one letter (say '/') and the -file_block_id keys with a different letter (say '0') so that scans -over just the metadata do not force us to fetch and cache bulky file -contents. -

      -

      Filters

      -

      -Because of the way leveldb data is organized on disk, -a single Get() call may involve multiple reads from disk. -The optional FilterPolicy mechanism can be used to reduce -the number of disk reads substantially. -

      -   leveldb::Options options;
      -   options.filter_policy = NewBloomFilterPolicy(10);
      -   leveldb::DB* db;
      -   leveldb::DB::Open(options, "/tmp/testdb", &db);
      -   ... use the database ...
      -   delete db;
      -   delete options.filter_policy;
      -
      -The preceding code associates a -Bloom filter -based filtering policy with the database. Bloom filter based -filtering relies on keeping some number of bits of data in memory per -key (in this case 10 bits per key since that is the argument we passed -to NewBloomFilterPolicy). This filter will reduce the number of unnecessary -disk reads needed for Get() calls by a factor of -approximately a 100. Increasing the bits per key will lead to a -larger reduction at the cost of more memory usage. We recommend that -applications whose working set does not fit in memory and that do a -lot of random reads set a filter policy. -

      -If you are using a custom comparator, you should ensure that the filter -policy you are using is compatible with your comparator. For example, -consider a comparator that ignores trailing spaces when comparing keys. -NewBloomFilterPolicy must not be used with such a comparator. -Instead, the application should provide a custom filter policy that -also ignores trailing spaces. For example: -

      -  class CustomFilterPolicy : public leveldb::FilterPolicy {
      -   private:
      -    FilterPolicy* builtin_policy_;
      -   public:
      -    CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) { }
      -    ~CustomFilterPolicy() { delete builtin_policy_; }
      -
      -    const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
      -
      -    void CreateFilter(const Slice* keys, int n, std::string* dst) const {
      -      // Use builtin bloom filter code after removing trailing spaces
      -      std::vector<Slice> trimmed(n);
      -      for (int i = 0; i < n; i++) {
      -        trimmed[i] = RemoveTrailingSpaces(keys[i]);
      -      }
      -      return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
      -    }
      -
      -    bool KeyMayMatch(const Slice& key, const Slice& filter) const {
      -      // Use builtin bloom filter code after removing trailing spaces
      -      return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
      -    }
      -  };
      -
      -

      -Advanced applications may provide a filter policy that does not use -a bloom filter but uses some other mechanism for summarizing a set -of keys. See leveldb/filter_policy.h for detail. -

      -

      Checksums

      -

      -leveldb associates checksums with all data it stores in the file system. -There are two separate controls provided over how aggressively these -checksums are verified: -

      -

        -
      • ReadOptions::verify_checksums may be set to true to force - checksum verification of all data that is read from the file system on - behalf of a particular read. By default, no such verification is - done. -

        -

      • Options::paranoid_checks may be set to true before opening a - database to make the database implementation raise an error as soon as - it detects an internal corruption. Depending on which portion of the - database has been corrupted, the error may be raised when the database - is opened, or later by another database operation. By default, - paranoid checking is off so that the database can be used even if - parts of its persistent storage have been corrupted. -

        - If a database is corrupted (perhaps it cannot be opened when - paranoid checking is turned on), the leveldb::RepairDB function - may be used to recover as much of the data as possible -

        -

      -

      Approximate Sizes

      -

      -The GetApproximateSizes method can used to get the approximate -number of bytes of file system space used by one or more key ranges. -

      -

      -   leveldb::Range ranges[2];
      -   ranges[0] = leveldb::Range("a", "c");
      -   ranges[1] = leveldb::Range("x", "z");
      -   uint64_t sizes[2];
      -   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
      -
      -The preceding call will set sizes[0] to the approximate number of -bytes of file system space used by the key range [a..c) and -sizes[1] to the approximate number of bytes used by the key range -[x..z). -

      -

      Environment

      -

      -All file operations (and other operating system calls) issued by the -leveldb implementation are routed through a leveldb::Env object. -Sophisticated clients may wish to provide their own Env -implementation to get better control. For example, an application may -introduce artificial delays in the file IO paths to limit the impact -of leveldb on other activities in the system. -

      -

      -  class SlowEnv : public leveldb::Env {
      -    .. implementation of the Env interface ...
      -  };
      -
      -  SlowEnv env;
      -  leveldb::Options options;
      -  options.env = &env;
      -  Status s = leveldb::DB::Open(options, ...);
      -
      -

      Porting

      -

      -leveldb may be ported to a new platform by providing platform -specific implementations of the types/methods/functions exported by -leveldb/port/port.h. See leveldb/port/port_example.h for more -details. -

      -In addition, the new platform may need a new default leveldb::Env -implementation. See leveldb/util/env_posix.h for an example. - -

      Other Information

      - -

      -Details about the leveldb implementation may be found in -the following documents: -

      - - - diff --git a/src/leveldb/doc/index.md b/src/leveldb/doc/index.md deleted file mode 100644 index be8569692b..0000000000 --- a/src/leveldb/doc/index.md +++ /dev/null @@ -1,523 +0,0 @@ -leveldb -======= - -_Jeff Dean, Sanjay Ghemawat_ - -The leveldb library provides a persistent key value store. Keys and values are -arbitrary byte arrays. The keys are ordered within the key value store -according to a user-specified comparator function. - -## Opening A Database - -A leveldb database has a name which corresponds to a file system directory. All -of the contents of database are stored in this directory. The following example -shows how to open a database, creating it if necessary: - -```c++ -#include -#include "leveldb/db.h" - -leveldb::DB* db; -leveldb::Options options; -options.create_if_missing = true; -leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); -assert(status.ok()); -... -``` - -If you want to raise an error if the database already exists, add the following -line before the `leveldb::DB::Open` call: - -```c++ -options.error_if_exists = true; -``` - -## Status - -You may have noticed the `leveldb::Status` type above. Values of this type are -returned by most functions in leveldb that may encounter an error. You can check -if such a result is ok, and also print an associated error message: - -```c++ -leveldb::Status s = ...; -if (!s.ok()) cerr << s.ToString() << endl; -``` - -## Closing A Database - -When you are done with a database, just delete the database object. Example: - -```c++ -... open the db as described above ... -... do something with db ... -delete db; -``` - -## Reads And Writes - -The database provides Put, Delete, and Get methods to modify/query the database. -For example, the following code moves the value stored under key1 to key2. - -```c++ -std::string value; -leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); -if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value); -if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1); -``` - -## Atomic Updates - -Note that if the process dies after the Put of key2 but before the delete of -key1, the same value may be left stored under multiple keys. Such problems can -be avoided by using the `WriteBatch` class to atomically apply a set of updates: - -```c++ -#include "leveldb/write_batch.h" -... -std::string value; -leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); -if (s.ok()) { - leveldb::WriteBatch batch; - batch.Delete(key1); - batch.Put(key2, value); - s = db->Write(leveldb::WriteOptions(), &batch); -} -``` - -The `WriteBatch` holds a sequence of edits to be made to the database, and these -edits within the batch are applied in order. Note that we called Delete before -Put so that if key1 is identical to key2, we do not end up erroneously dropping -the value entirely. - -Apart from its atomicity benefits, `WriteBatch` may also be used to speed up -bulk updates by placing lots of individual mutations into the same batch. - -## Synchronous Writes - -By default, each write to leveldb is asynchronous: it returns after pushing the -write from the process into the operating system. The transfer from operating -system memory to the underlying persistent storage happens asynchronously. The -sync flag can be turned on for a particular write to make the write operation -not return until the data being written has been pushed all the way to -persistent storage. (On Posix systems, this is implemented by calling either -`fsync(...)` or `fdatasync(...)` or `msync(..., MS_SYNC)` before the write -operation returns.) - -```c++ -leveldb::WriteOptions write_options; -write_options.sync = true; -db->Put(write_options, ...); -``` - -Asynchronous writes are often more than a thousand times as fast as synchronous -writes. The downside of asynchronous writes is that a crash of the machine may -cause the last few updates to be lost. Note that a crash of just the writing -process (i.e., not a reboot) will not cause any loss since even when sync is -false, an update is pushed from the process memory into the operating system -before it is considered done. - -Asynchronous writes can often be used safely. For example, when loading a large -amount of data into the database you can handle lost updates by restarting the -bulk load after a crash. A hybrid scheme is also possible where every Nth write -is synchronous, and in the event of a crash, the bulk load is restarted just -after the last synchronous write finished by the previous run. (The synchronous -write can update a marker that describes where to restart on a crash.) - -`WriteBatch` provides an alternative to asynchronous writes. Multiple updates -may be placed in the same WriteBatch and applied together using a synchronous -write (i.e., `write_options.sync` is set to true). The extra cost of the -synchronous write will be amortized across all of the writes in the batch. - -## Concurrency - -A database may only be opened by one process at a time. The leveldb -implementation acquires a lock from the operating system to prevent misuse. -Within a single process, the same `leveldb::DB` object may be safely shared by -multiple concurrent threads. I.e., different threads may write into or fetch -iterators or call Get on the same database without any external synchronization -(the leveldb implementation will automatically do the required synchronization). -However other objects (like Iterator and `WriteBatch`) may require external -synchronization. If two threads share such an object, they must protect access -to it using their own locking protocol. More details are available in the public -header files. - -## Iteration - -The following example demonstrates how to print all key,value pairs in a -database. - -```c++ -leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); -for (it->SeekToFirst(); it->Valid(); it->Next()) { - cout << it->key().ToString() << ": " << it->value().ToString() << endl; -} -assert(it->status().ok()); // Check for any errors found during the scan -delete it; -``` - -The following variation shows how to process just the keys in the range -[start,limit): - -```c++ -for (it->Seek(start); - it->Valid() && it->key().ToString() < limit; - it->Next()) { - ... -} -``` - -You can also process entries in reverse order. (Caveat: reverse iteration may be -somewhat slower than forward iteration.) - -```c++ -for (it->SeekToLast(); it->Valid(); it->Prev()) { - ... -} -``` - -## Snapshots - -Snapshots provide consistent read-only views over the entire state of the -key-value store. `ReadOptions::snapshot` may be non-NULL to indicate that a -read should operate on a particular version of the DB state. If -`ReadOptions::snapshot` is NULL, the read will operate on an implicit snapshot -of the current state. - -Snapshots are created by the `DB::GetSnapshot()` method: - -```c++ -leveldb::ReadOptions options; -options.snapshot = db->GetSnapshot(); -... apply some updates to db ... -leveldb::Iterator* iter = db->NewIterator(options); -... read using iter to view the state when the snapshot was created ... -delete iter; -db->ReleaseSnapshot(options.snapshot); -``` - -Note that when a snapshot is no longer needed, it should be released using the -`DB::ReleaseSnapshot` interface. This allows the implementation to get rid of -state that was being maintained just to support reading as of that snapshot. - -## Slice - -The return value of the `it->key()` and `it->value()` calls above are instances -of the `leveldb::Slice` type. Slice is a simple structure that contains a length -and a pointer to an external byte array. Returning a Slice is a cheaper -alternative to returning a `std::string` since we do not need to copy -potentially large keys and values. In addition, leveldb methods do not return -null-terminated C-style strings since leveldb keys and values are allowed to -contain `'\0'` bytes. - -C++ strings and null-terminated C-style strings can be easily converted to a -Slice: - -```c++ -leveldb::Slice s1 = "hello"; - -std::string str("world"); -leveldb::Slice s2 = str; -``` - -A Slice can be easily converted back to a C++ string: - -```c++ -std::string str = s1.ToString(); -assert(str == std::string("hello")); -``` - -Be careful when using Slices since it is up to the caller to ensure that the -external byte array into which the Slice points remains live while the Slice is -in use. For example, the following is buggy: - -```c++ -leveldb::Slice slice; -if (...) { - std::string str = ...; - slice = str; -} -Use(slice); -``` - -When the if statement goes out of scope, str will be destroyed and the backing -storage for slice will disappear. - -## Comparators - -The preceding examples used the default ordering function for key, which orders -bytes lexicographically. You can however supply a custom comparator when opening -a database. For example, suppose each database key consists of two numbers and -we should sort by the first number, breaking ties by the second number. First, -define a proper subclass of `leveldb::Comparator` that expresses these rules: - -```c++ -class TwoPartComparator : public leveldb::Comparator { - public: - // Three-way comparison function: - // if a < b: negative result - // if a > b: positive result - // else: zero result - int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const { - int a1, a2, b1, b2; - ParseKey(a, &a1, &a2); - ParseKey(b, &b1, &b2); - if (a1 < b1) return -1; - if (a1 > b1) return +1; - if (a2 < b2) return -1; - if (a2 > b2) return +1; - return 0; - } - - // Ignore the following methods for now: - const char* Name() const { return "TwoPartComparator"; } - void FindShortestSeparator(std::string*, const leveldb::Slice&) const {} - void FindShortSuccessor(std::string*) const {} -}; -``` - -Now create a database using this custom comparator: - -```c++ -TwoPartComparator cmp; -leveldb::DB* db; -leveldb::Options options; -options.create_if_missing = true; -options.comparator = &cmp; -leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); -... -``` - -### Backwards compatibility - -The result of the comparator's Name method is attached to the database when it -is created, and is checked on every subsequent database open. If the name -changes, the `leveldb::DB::Open` call will fail. Therefore, change the name if -and only if the new key format and comparison function are incompatible with -existing databases, and it is ok to discard the contents of all existing -databases. - -You can however still gradually evolve your key format over time with a little -bit of pre-planning. For example, you could store a version number at the end of -each key (one byte should suffice for most uses). When you wish to switch to a -new key format (e.g., adding an optional third part to the keys processed by -`TwoPartComparator`), (a) keep the same comparator name (b) increment the -version number for new keys (c) change the comparator function so it uses the -version numbers found in the keys to decide how to interpret them. - -## Performance - -Performance can be tuned by changing the default values of the types defined in -`include/leveldb/options.h`. - -### Block size - -leveldb groups adjacent keys together into the same block and such a block is -the unit of transfer to and from persistent storage. The default block size is -approximately 4096 uncompressed bytes. Applications that mostly do bulk scans -over the contents of the database may wish to increase this size. Applications -that do a lot of point reads of small values may wish to switch to a smaller -block size if performance measurements indicate an improvement. There isn't much -benefit in using blocks smaller than one kilobyte, or larger than a few -megabytes. Also note that compression will be more effective with larger block -sizes. - -### Compression - -Each block is individually compressed before being written to persistent -storage. Compression is on by default since the default compression method is -very fast, and is automatically disabled for uncompressible data. In rare cases, -applications may want to disable compression entirely, but should only do so if -benchmarks show a performance improvement: - -```c++ -leveldb::Options options; -options.compression = leveldb::kNoCompression; -... leveldb::DB::Open(options, name, ...) .... -``` - -### Cache - -The contents of the database are stored in a set of files in the filesystem and -each file stores a sequence of compressed blocks. If options.cache is non-NULL, -it is used to cache frequently used uncompressed block contents. - -```c++ -#include "leveldb/cache.h" - -leveldb::Options options; -options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache -leveldb::DB* db; -leveldb::DB::Open(options, name, &db); -... use the db ... -delete db -delete options.cache; -``` - -Note that the cache holds uncompressed data, and therefore it should be sized -according to application level data sizes, without any reduction from -compression. (Caching of compressed blocks is left to the operating system -buffer cache, or any custom Env implementation provided by the client.) - -When performing a bulk read, the application may wish to disable caching so that -the data processed by the bulk read does not end up displacing most of the -cached contents. A per-iterator option can be used to achieve this: - -```c++ -leveldb::ReadOptions options; -options.fill_cache = false; -leveldb::Iterator* it = db->NewIterator(options); -for (it->SeekToFirst(); it->Valid(); it->Next()) { - ... -} -``` - -### Key Layout - -Note that the unit of disk transfer and caching is a block. Adjacent keys -(according to the database sort order) will usually be placed in the same block. -Therefore the application can improve its performance by placing keys that are -accessed together near each other and placing infrequently used keys in a -separate region of the key space. - -For example, suppose we are implementing a simple file system on top of leveldb. -The types of entries we might wish to store are: - - filename -> permission-bits, length, list of file_block_ids - file_block_id -> data - -We might want to prefix filename keys with one letter (say '/') and the -`file_block_id` keys with a different letter (say '0') so that scans over just -the metadata do not force us to fetch and cache bulky file contents. - -### Filters - -Because of the way leveldb data is organized on disk, a single `Get()` call may -involve multiple reads from disk. The optional FilterPolicy mechanism can be -used to reduce the number of disk reads substantially. - -```c++ -leveldb::Options options; -options.filter_policy = NewBloomFilterPolicy(10); -leveldb::DB* db; -leveldb::DB::Open(options, "/tmp/testdb", &db); -... use the database ... -delete db; -delete options.filter_policy; -``` - -The preceding code associates a Bloom filter based filtering policy with the -database. Bloom filter based filtering relies on keeping some number of bits of -data in memory per key (in this case 10 bits per key since that is the argument -we passed to `NewBloomFilterPolicy`). This filter will reduce the number of -unnecessary disk reads needed for Get() calls by a factor of approximately -a 100. Increasing the bits per key will lead to a larger reduction at the cost -of more memory usage. We recommend that applications whose working set does not -fit in memory and that do a lot of random reads set a filter policy. - -If you are using a custom comparator, you should ensure that the filter policy -you are using is compatible with your comparator. For example, consider a -comparator that ignores trailing spaces when comparing keys. -`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the -application should provide a custom filter policy that also ignores trailing -spaces. For example: - -```c++ -class CustomFilterPolicy : public leveldb::FilterPolicy { - private: - FilterPolicy* builtin_policy_; - - public: - CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {} - ~CustomFilterPolicy() { delete builtin_policy_; } - - const char* Name() const { return "IgnoreTrailingSpacesFilter"; } - - void CreateFilter(const Slice* keys, int n, std::string* dst) const { - // Use builtin bloom filter code after removing trailing spaces - std::vector trimmed(n); - for (int i = 0; i < n; i++) { - trimmed[i] = RemoveTrailingSpaces(keys[i]); - } - return builtin_policy_->CreateFilter(&trimmed[i], n, dst); - } -}; -``` - -Advanced applications may provide a filter policy that does not use a bloom -filter but uses some other mechanism for summarizing a set of keys. See -`leveldb/filter_policy.h` for detail. - -## Checksums - -leveldb associates checksums with all data it stores in the file system. There -are two separate controls provided over how aggressively these checksums are -verified: - -`ReadOptions::verify_checksums` may be set to true to force checksum -verification of all data that is read from the file system on behalf of a -particular read. By default, no such verification is done. - -`Options::paranoid_checks` may be set to true before opening a database to make -the database implementation raise an error as soon as it detects an internal -corruption. Depending on which portion of the database has been corrupted, the -error may be raised when the database is opened, or later by another database -operation. By default, paranoid checking is off so that the database can be used -even if parts of its persistent storage have been corrupted. - -If a database is corrupted (perhaps it cannot be opened when paranoid checking -is turned on), the `leveldb::RepairDB` function may be used to recover as much -of the data as possible - -## Approximate Sizes - -The `GetApproximateSizes` method can used to get the approximate number of bytes -of file system space used by one or more key ranges. - -```c++ -leveldb::Range ranges[2]; -ranges[0] = leveldb::Range("a", "c"); -ranges[1] = leveldb::Range("x", "z"); -uint64_t sizes[2]; -leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes); -``` - -The preceding call will set `sizes[0]` to the approximate number of bytes of -file system space used by the key range `[a..c)` and `sizes[1]` to the -approximate number of bytes used by the key range `[x..z)`. - -## Environment - -All file operations (and other operating system calls) issued by the leveldb -implementation are routed through a `leveldb::Env` object. Sophisticated clients -may wish to provide their own Env implementation to get better control. -For example, an application may introduce artificial delays in the file IO -paths to limit the impact of leveldb on other activities in the system. - -```c++ -class SlowEnv : public leveldb::Env { - ... implementation of the Env interface ... -}; - -SlowEnv env; -leveldb::Options options; -options.env = &env; -Status s = leveldb::DB::Open(options, ...); -``` - -## Porting - -leveldb may be ported to a new platform by providing platform specific -implementations of the types/methods/functions exported by -`leveldb/port/port.h`. See `leveldb/port/port_example.h` for more details. - -In addition, the new platform may need a new default `leveldb::Env` -implementation. See `leveldb/util/env_posix.h` for an example. - -## Other Information - -Details about the leveldb implementation may be found in the following -documents: - -1. [Implementation notes](impl.md) -2. [Format of an immutable Table file](table_format.md) -3. [Format of a log file](log_format.md) diff --git a/src/leveldb/doc/log_format.md b/src/leveldb/doc/log_format.md deleted file mode 100644 index f32cb5d7da..0000000000 --- a/src/leveldb/doc/log_format.md +++ /dev/null @@ -1,75 +0,0 @@ -leveldb Log format -================== -The log file contents are a sequence of 32KB blocks. The only exception is that -the tail of the file may contain a partial block. - -Each block consists of a sequence of records: - - block := record* trailer? - record := - checksum: uint32 // crc32c of type and data[] ; little-endian - length: uint16 // little-endian - type: uint8 // One of FULL, FIRST, MIDDLE, LAST - data: uint8[length] - -A record never starts within the last six bytes of a block (since it won't fit). -Any leftover bytes here form the trailer, which must consist entirely of zero -bytes and must be skipped by readers. - -Aside: if exactly seven bytes are left in the current block, and a new non-zero -length record is added, the writer must emit a FIRST record (which contains zero -bytes of user data) to fill up the trailing seven bytes of the block and then -emit all of the user data in subsequent blocks. - -More types may be added in the future. Some Readers may skip record types they -do not understand, others may report that some data was skipped. - - FULL == 1 - FIRST == 2 - MIDDLE == 3 - LAST == 4 - -The FULL record contains the contents of an entire user record. - -FIRST, MIDDLE, LAST are types used for user records that have been split into -multiple fragments (typically because of block boundaries). FIRST is the type -of the first fragment of a user record, LAST is the type of the last fragment of -a user record, and MIDDLE is the type of all interior fragments of a user -record. - -Example: consider a sequence of user records: - - A: length 1000 - B: length 97270 - C: length 8000 - -**A** will be stored as a FULL record in the first block. - -**B** will be split into three fragments: first fragment occupies the rest of -the first block, second fragment occupies the entirety of the second block, and -the third fragment occupies a prefix of the third block. This will leave six -bytes free in the third block, which will be left empty as the trailer. - -**C** will be stored as a FULL record in the fourth block. - ----- - -## Some benefits over the recordio format: - -1. We do not need any heuristics for resyncing - just go to next block boundary - and scan. If there is a corruption, skip to the next block. As a - side-benefit, we do not get confused when part of the contents of one log - file are embedded as a record inside another log file. - -2. Splitting at approximate boundaries (e.g., for mapreduce) is simple: find the - next block boundary and skip records until we hit a FULL or FIRST record. - -3. We do not need extra buffering for large records. - -## Some downsides compared to recordio format: - -1. No packing of tiny records. This could be fixed by adding a new record type, - so it is a shortcoming of the current implementation, not necessarily the - format. - -2. No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/log_format.txt b/src/leveldb/doc/log_format.txt deleted file mode 100644 index 4cca5ef6ea..0000000000 --- a/src/leveldb/doc/log_format.txt +++ /dev/null @@ -1,75 +0,0 @@ -The log file contents are a sequence of 32KB blocks. The only -exception is that the tail of the file may contain a partial block. - -Each block consists of a sequence of records: - block := record* trailer? - record := - checksum: uint32 // crc32c of type and data[] ; little-endian - length: uint16 // little-endian - type: uint8 // One of FULL, FIRST, MIDDLE, LAST - data: uint8[length] - -A record never starts within the last six bytes of a block (since it -won't fit). Any leftover bytes here form the trailer, which must -consist entirely of zero bytes and must be skipped by readers. - -Aside: if exactly seven bytes are left in the current block, and a new -non-zero length record is added, the writer must emit a FIRST record -(which contains zero bytes of user data) to fill up the trailing seven -bytes of the block and then emit all of the user data in subsequent -blocks. - -More types may be added in the future. Some Readers may skip record -types they do not understand, others may report that some data was -skipped. - -FULL == 1 -FIRST == 2 -MIDDLE == 3 -LAST == 4 - -The FULL record contains the contents of an entire user record. - -FIRST, MIDDLE, LAST are types used for user records that have been -split into multiple fragments (typically because of block boundaries). -FIRST is the type of the first fragment of a user record, LAST is the -type of the last fragment of a user record, and MIDDLE is the type of -all interior fragments of a user record. - -Example: consider a sequence of user records: - A: length 1000 - B: length 97270 - C: length 8000 -A will be stored as a FULL record in the first block. - -B will be split into three fragments: first fragment occupies the rest -of the first block, second fragment occupies the entirety of the -second block, and the third fragment occupies a prefix of the third -block. This will leave six bytes free in the third block, which will -be left empty as the trailer. - -C will be stored as a FULL record in the fourth block. - -=================== - -Some benefits over the recordio format: - -(1) We do not need any heuristics for resyncing - just go to next -block boundary and scan. If there is a corruption, skip to the next -block. As a side-benefit, we do not get confused when part of the -contents of one log file are embedded as a record inside another log -file. - -(2) Splitting at approximate boundaries (e.g., for mapreduce) is -simple: find the next block boundary and skip records until we -hit a FULL or FIRST record. - -(3) We do not need extra buffering for large records. - -Some downsides compared to recordio format: - -(1) No packing of tiny records. This could be fixed by adding a new -record type, so it is a shortcoming of the current implementation, -not necessarily the format. - -(2) No compression. Again, this could be fixed by adding new record types. diff --git a/src/leveldb/doc/table_format.md b/src/leveldb/doc/table_format.md deleted file mode 100644 index 5fe7e72411..0000000000 --- a/src/leveldb/doc/table_format.md +++ /dev/null @@ -1,107 +0,0 @@ -leveldb File format -=================== - - - [data block 1] - [data block 2] - ... - [data block N] - [meta block 1] - ... - [meta block K] - [metaindex block] - [index block] - [Footer] (fixed size; starts at file_size - sizeof(Footer)) - - -The file contains internal pointers. Each such pointer is called -a BlockHandle and contains the following information: - - offset: varint64 - size: varint64 - -See [varints](https://developers.google.com/protocol-buffers/docs/encoding#varints) -for an explanation of varint64 format. - -1. The sequence of key/value pairs in the file are stored in sorted -order and partitioned into a sequence of data blocks. These blocks -come one after another at the beginning of the file. Each data block -is formatted according to the code in `block_builder.cc`, and then -optionally compressed. - -2. After the data blocks we store a bunch of meta blocks. The -supported meta block types are described below. More meta block types -may be added in the future. Each meta block is again formatted using -`block_builder.cc` and then optionally compressed. - -3. A "metaindex" block. It contains one entry for every other meta -block where the key is the name of the meta block and the value is a -BlockHandle pointing to that meta block. - -4. An "index" block. This block contains one entry per data block, -where the key is a string >= last key in that data block and before -the first key in the successive data block. The value is the -BlockHandle for the data block. - -5. At the very end of the file is a fixed length footer that contains -the BlockHandle of the metaindex and index blocks as well as a magic number. - - metaindex_handle: char[p]; // Block handle for metaindex - index_handle: char[q]; // Block handle for index - padding: char[40-p-q];// zeroed bytes to make fixed length - // (40==2*BlockHandle::kMaxEncodedLength) - magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) - -## "filter" Meta Block - -If a `FilterPolicy` was specified when the database was opened, a -filter block is stored in each table. The "metaindex" block contains -an entry that maps from `filter.` to the BlockHandle for the filter -block where `` is the string returned by the filter policy's -`Name()` method. - -The filter block stores a sequence of filters, where filter i contains -the output of `FilterPolicy::CreateFilter()` on all keys that are stored -in a block whose file offset falls within the range - - [ i*base ... (i+1)*base-1 ] - -Currently, "base" is 2KB. So for example, if blocks X and Y start in -the range `[ 0KB .. 2KB-1 ]`, all of the keys in X and Y will be -converted to a filter by calling `FilterPolicy::CreateFilter()`, and the -resulting filter will be stored as the first filter in the filter -block. - -The filter block is formatted as follows: - - [filter 0] - [filter 1] - [filter 2] - ... - [filter N-1] - - [offset of filter 0] : 4 bytes - [offset of filter 1] : 4 bytes - [offset of filter 2] : 4 bytes - ... - [offset of filter N-1] : 4 bytes - - [offset of beginning of offset array] : 4 bytes - lg(base) : 1 byte - -The offset array at the end of the filter block allows efficient -mapping from a data block offset to the corresponding filter. - -## "stats" Meta Block - -This meta block contains a bunch of stats. The key is the name -of the statistic. The value contains the statistic. - -TODO(postrelease): record following stats. - - data size - index size - key size (uncompressed) - value size (uncompressed) - number of entries - number of data blocks diff --git a/src/leveldb/doc/table_format.txt b/src/leveldb/doc/table_format.txt deleted file mode 100644 index ca8f9b4460..0000000000 --- a/src/leveldb/doc/table_format.txt +++ /dev/null @@ -1,104 +0,0 @@ -File format -=========== - - - [data block 1] - [data block 2] - ... - [data block N] - [meta block 1] - ... - [meta block K] - [metaindex block] - [index block] - [Footer] (fixed size; starts at file_size - sizeof(Footer)) - - -The file contains internal pointers. Each such pointer is called -a BlockHandle and contains the following information: - offset: varint64 - size: varint64 -See https://developers.google.com/protocol-buffers/docs/encoding#varints -for an explanation of varint64 format. - -(1) The sequence of key/value pairs in the file are stored in sorted -order and partitioned into a sequence of data blocks. These blocks -come one after another at the beginning of the file. Each data block -is formatted according to the code in block_builder.cc, and then -optionally compressed. - -(2) After the data blocks we store a bunch of meta blocks. The -supported meta block types are described below. More meta block types -may be added in the future. Each meta block is again formatted using -block_builder.cc and then optionally compressed. - -(3) A "metaindex" block. It contains one entry for every other meta -block where the key is the name of the meta block and the value is a -BlockHandle pointing to that meta block. - -(4) An "index" block. This block contains one entry per data block, -where the key is a string >= last key in that data block and before -the first key in the successive data block. The value is the -BlockHandle for the data block. - -(6) At the very end of the file is a fixed length footer that contains -the BlockHandle of the metaindex and index blocks as well as a magic number. - metaindex_handle: char[p]; // Block handle for metaindex - index_handle: char[q]; // Block handle for index - padding: char[40-p-q]; // zeroed bytes to make fixed length - // (40==2*BlockHandle::kMaxEncodedLength) - magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) - -"filter" Meta Block -------------------- - -If a "FilterPolicy" was specified when the database was opened, a -filter block is stored in each table. The "metaindex" block contains -an entry that maps from "filter." to the BlockHandle for the filter -block where "" is the string returned by the filter policy's -"Name()" method. - -The filter block stores a sequence of filters, where filter i contains -the output of FilterPolicy::CreateFilter() on all keys that are stored -in a block whose file offset falls within the range - - [ i*base ... (i+1)*base-1 ] - -Currently, "base" is 2KB. So for example, if blocks X and Y start in -the range [ 0KB .. 2KB-1 ], all of the keys in X and Y will be -converted to a filter by calling FilterPolicy::CreateFilter(), and the -resulting filter will be stored as the first filter in the filter -block. - -The filter block is formatted as follows: - - [filter 0] - [filter 1] - [filter 2] - ... - [filter N-1] - - [offset of filter 0] : 4 bytes - [offset of filter 1] : 4 bytes - [offset of filter 2] : 4 bytes - ... - [offset of filter N-1] : 4 bytes - - [offset of beginning of offset array] : 4 bytes - lg(base) : 1 byte - -The offset array at the end of the filter block allows efficient -mapping from a data block offset to the corresponding filter. - -"stats" Meta Block ------------------- - -This meta block contains a bunch of stats. The key is the name -of the statistic. The value contains the statistic. -TODO(postrelease): record following stats. - data size - index size - key size (uncompressed) - value size (uncompressed) - number of entries - number of data blocks diff --git a/src/leveldb/helpers/memenv/memenv.cc b/src/leveldb/helpers/memenv/memenv.cc deleted file mode 100644 index 43ef2e0729..0000000000 --- a/src/leveldb/helpers/memenv/memenv.cc +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "helpers/memenv/memenv.h" - -#include "leveldb/env.h" -#include "leveldb/status.h" -#include "port/port.h" -#include "util/mutexlock.h" -#include -#include -#include -#include - -namespace leveldb { - -namespace { - -class FileState { - public: - // FileStates are reference counted. The initial reference count is zero - // and the caller must call Ref() at least once. - FileState() : refs_(0), size_(0) {} - - // Increase the reference count. - void Ref() { - MutexLock lock(&refs_mutex_); - ++refs_; - } - - // Decrease the reference count. Delete if this is the last reference. - void Unref() { - bool do_delete = false; - - { - MutexLock lock(&refs_mutex_); - --refs_; - assert(refs_ >= 0); - if (refs_ <= 0) { - do_delete = true; - } - } - - if (do_delete) { - delete this; - } - } - - uint64_t Size() const { return size_; } - - Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { - if (offset > size_) { - return Status::IOError("Offset greater than file size."); - } - const uint64_t available = size_ - offset; - if (n > available) { - n = static_cast(available); - } - if (n == 0) { - *result = Slice(); - return Status::OK(); - } - - assert(offset / kBlockSize <= SIZE_MAX); - size_t block = static_cast(offset / kBlockSize); - size_t block_offset = offset % kBlockSize; - - if (n <= kBlockSize - block_offset) { - // The requested bytes are all in the first block. - *result = Slice(blocks_[block] + block_offset, n); - return Status::OK(); - } - - size_t bytes_to_copy = n; - char* dst = scratch; - - while (bytes_to_copy > 0) { - size_t avail = kBlockSize - block_offset; - if (avail > bytes_to_copy) { - avail = bytes_to_copy; - } - memcpy(dst, blocks_[block] + block_offset, avail); - - bytes_to_copy -= avail; - dst += avail; - block++; - block_offset = 0; - } - - *result = Slice(scratch, n); - return Status::OK(); - } - - Status Append(const Slice& data) { - const char* src = data.data(); - size_t src_len = data.size(); - - while (src_len > 0) { - size_t avail; - size_t offset = size_ % kBlockSize; - - if (offset != 0) { - // There is some room in the last block. - avail = kBlockSize - offset; - } else { - // No room in the last block; push new one. - blocks_.push_back(new char[kBlockSize]); - avail = kBlockSize; - } - - if (avail > src_len) { - avail = src_len; - } - memcpy(blocks_.back() + offset, src, avail); - src_len -= avail; - src += avail; - size_ += avail; - } - - return Status::OK(); - } - - private: - // Private since only Unref() should be used to delete it. - ~FileState() { - for (std::vector::iterator i = blocks_.begin(); i != blocks_.end(); - ++i) { - delete [] *i; - } - } - - // No copying allowed. - FileState(const FileState&); - void operator=(const FileState&); - - port::Mutex refs_mutex_; - int refs_; // Protected by refs_mutex_; - - // The following fields are not protected by any mutex. They are only mutable - // while the file is being written, and concurrent access is not allowed - // to writable files. - std::vector blocks_; - uint64_t size_; - - enum { kBlockSize = 8 * 1024 }; -}; - -class SequentialFileImpl : public SequentialFile { - public: - explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) { - file_->Ref(); - } - - ~SequentialFileImpl() { - file_->Unref(); - } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - Status s = file_->Read(pos_, n, result, scratch); - if (s.ok()) { - pos_ += result->size(); - } - return s; - } - - virtual Status Skip(uint64_t n) { - if (pos_ > file_->Size()) { - return Status::IOError("pos_ > file_->Size()"); - } - const uint64_t available = file_->Size() - pos_; - if (n > available) { - n = available; - } - pos_ += n; - return Status::OK(); - } - - private: - FileState* file_; - uint64_t pos_; -}; - -class RandomAccessFileImpl : public RandomAccessFile { - public: - explicit RandomAccessFileImpl(FileState* file) : file_(file) { - file_->Ref(); - } - - ~RandomAccessFileImpl() { - file_->Unref(); - } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - return file_->Read(offset, n, result, scratch); - } - - private: - FileState* file_; -}; - -class WritableFileImpl : public WritableFile { - public: - WritableFileImpl(FileState* file) : file_(file) { - file_->Ref(); - } - - ~WritableFileImpl() { - file_->Unref(); - } - - virtual Status Append(const Slice& data) { - return file_->Append(data); - } - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - - private: - FileState* file_; -}; - -class NoOpLogger : public Logger { - public: - virtual void Logv(const char* format, va_list ap) { } -}; - -class InMemoryEnv : public EnvWrapper { - public: - explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { } - - virtual ~InMemoryEnv() { - for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ - i->second->Unref(); - } - } - - // Partial implementation of the Env interface. - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - *result = NULL; - return Status::IOError(fname, "File not found"); - } - - *result = new SequentialFileImpl(file_map_[fname]); - return Status::OK(); - } - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - *result = NULL; - return Status::IOError(fname, "File not found"); - } - - *result = new RandomAccessFileImpl(file_map_[fname]); - return Status::OK(); - } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) != file_map_.end()) { - DeleteFileInternal(fname); - } - - FileState* file = new FileState(); - file->Ref(); - file_map_[fname] = file; - - *result = new WritableFileImpl(file); - return Status::OK(); - } - - virtual bool FileExists(const std::string& fname) { - MutexLock lock(&mutex_); - return file_map_.find(fname) != file_map_.end(); - } - - virtual Status GetChildren(const std::string& dir, - std::vector* result) { - MutexLock lock(&mutex_); - result->clear(); - - for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ - const std::string& filename = i->first; - - if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' && - Slice(filename).starts_with(Slice(dir))) { - result->push_back(filename.substr(dir.size() + 1)); - } - } - - return Status::OK(); - } - - void DeleteFileInternal(const std::string& fname) { - if (file_map_.find(fname) == file_map_.end()) { - return; - } - - file_map_[fname]->Unref(); - file_map_.erase(fname); - } - - virtual Status DeleteFile(const std::string& fname) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - return Status::IOError(fname, "File not found"); - } - - DeleteFileInternal(fname); - return Status::OK(); - } - - virtual Status CreateDir(const std::string& dirname) { - return Status::OK(); - } - - virtual Status DeleteDir(const std::string& dirname) { - return Status::OK(); - } - - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) { - MutexLock lock(&mutex_); - if (file_map_.find(fname) == file_map_.end()) { - return Status::IOError(fname, "File not found"); - } - - *file_size = file_map_[fname]->Size(); - return Status::OK(); - } - - virtual Status RenameFile(const std::string& src, - const std::string& target) { - MutexLock lock(&mutex_); - if (file_map_.find(src) == file_map_.end()) { - return Status::IOError(src, "File not found"); - } - - DeleteFileInternal(target); - file_map_[target] = file_map_[src]; - file_map_.erase(src); - return Status::OK(); - } - - virtual Status LockFile(const std::string& fname, FileLock** lock) { - *lock = new FileLock; - return Status::OK(); - } - - virtual Status UnlockFile(FileLock* lock) { - delete lock; - return Status::OK(); - } - - virtual Status GetTestDirectory(std::string* path) { - *path = "/test"; - return Status::OK(); - } - - virtual Status NewLogger(const std::string& fname, Logger** result) { - *result = new NoOpLogger; - return Status::OK(); - } - - private: - // Map from filenames to FileState objects, representing a simple file system. - typedef std::map FileSystem; - port::Mutex mutex_; - FileSystem file_map_; // Protected by mutex_. -}; - -} // namespace - -Env* NewMemEnv(Env* base_env) { - return new InMemoryEnv(base_env); -} - -} // namespace leveldb diff --git a/src/leveldb/helpers/memenv/memenv.h b/src/leveldb/helpers/memenv/memenv.h deleted file mode 100644 index 03b88de761..0000000000 --- a/src/leveldb/helpers/memenv/memenv.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ -#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ - -namespace leveldb { - -class Env; - -// Returns a new environment that stores its data in memory and delegates -// all non-file-storage tasks to base_env. The caller must delete the result -// when it is no longer needed. -// *base_env must remain live while the result is in use. -Env* NewMemEnv(Env* base_env); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ diff --git a/src/leveldb/helpers/memenv/memenv_test.cc b/src/leveldb/helpers/memenv/memenv_test.cc deleted file mode 100644 index a44310fed8..0000000000 --- a/src/leveldb/helpers/memenv/memenv_test.cc +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "helpers/memenv/memenv.h" - -#include "db/db_impl.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "util/testharness.h" -#include -#include - -namespace leveldb { - -class MemEnvTest { - public: - Env* env_; - - MemEnvTest() - : env_(NewMemEnv(Env::Default())) { - } - ~MemEnvTest() { - delete env_; - } -}; - -TEST(MemEnvTest, Basics) { - uint64_t file_size; - WritableFile* writable_file; - std::vector children; - - ASSERT_OK(env_->CreateDir("/dir")); - - // Check that the directory is empty. - ASSERT_TRUE(!env_->FileExists("/dir/non_existent")); - ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(0, children.size()); - - // Create a file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - delete writable_file; - - // Check that the file exists. - ASSERT_TRUE(env_->FileExists("/dir/f")); - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); - ASSERT_EQ(0, file_size); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(1, children.size()); - ASSERT_EQ("f", children[0]); - - // Write to the file. - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("abc")); - delete writable_file; - - // Check for expected size. - ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); - ASSERT_EQ(3, file_size); - - // Check that renaming works. - ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); - ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); - ASSERT_TRUE(!env_->FileExists("/dir/f")); - ASSERT_TRUE(env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); - ASSERT_EQ(3, file_size); - - // Check that opening non-existent file fails. - SequentialFile* seq_file; - RandomAccessFile* rand_file; - ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok()); - ASSERT_TRUE(!seq_file); - ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok()); - ASSERT_TRUE(!rand_file); - - // Check that deleting works. - ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); - ASSERT_OK(env_->DeleteFile("/dir/g")); - ASSERT_TRUE(!env_->FileExists("/dir/g")); - ASSERT_OK(env_->GetChildren("/dir", &children)); - ASSERT_EQ(0, children.size()); - ASSERT_OK(env_->DeleteDir("/dir")); -} - -TEST(MemEnvTest, ReadWrite) { - WritableFile* writable_file; - SequentialFile* seq_file; - RandomAccessFile* rand_file; - Slice result; - char scratch[100]; - - ASSERT_OK(env_->CreateDir("/dir")); - - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("hello ")); - ASSERT_OK(writable_file->Append("world")); - delete writable_file; - - // Read sequentially. - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); - ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". - ASSERT_EQ(0, result.compare("hello")); - ASSERT_OK(seq_file->Skip(1)); - ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world". - ASSERT_EQ(0, result.compare("world")); - ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF. - ASSERT_EQ(0, result.size()); - ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file. - ASSERT_OK(seq_file->Read(1000, &result, scratch)); - ASSERT_EQ(0, result.size()); - delete seq_file; - - // Random reads. - ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file)); - ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". - ASSERT_EQ(0, result.compare("world")); - ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". - ASSERT_EQ(0, result.compare("hello")); - ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d". - ASSERT_EQ(0, result.compare("d")); - - // Too high offset. - ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok()); - delete rand_file; -} - -TEST(MemEnvTest, Locks) { - FileLock* lock; - - // These are no-ops, but we test they return success. - ASSERT_OK(env_->LockFile("some file", &lock)); - ASSERT_OK(env_->UnlockFile(lock)); -} - -TEST(MemEnvTest, Misc) { - std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); - ASSERT_TRUE(!test_dir.empty()); - - WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file)); - - // These are no-ops, but we test they return success. - ASSERT_OK(writable_file->Sync()); - ASSERT_OK(writable_file->Flush()); - ASSERT_OK(writable_file->Close()); - delete writable_file; -} - -TEST(MemEnvTest, LargeWrite) { - const size_t kWriteSize = 300 * 1024; - char* scratch = new char[kWriteSize * 2]; - - std::string write_data; - for (size_t i = 0; i < kWriteSize; ++i) { - write_data.append(1, static_cast(i)); - } - - WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); - ASSERT_OK(writable_file->Append("foo")); - ASSERT_OK(writable_file->Append(write_data)); - delete writable_file; - - SequentialFile* seq_file; - Slice result; - ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); - ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". - ASSERT_EQ(0, result.compare("foo")); - - size_t read = 0; - std::string read_data; - while (read < kWriteSize) { - ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch)); - read_data.append(result.data(), result.size()); - read += result.size(); - } - ASSERT_TRUE(write_data == read_data); - delete seq_file; - delete [] scratch; -} - -TEST(MemEnvTest, DBTest) { - Options options; - options.create_if_missing = true; - options.env = env_; - DB* db; - - const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")}; - const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")}; - - ASSERT_OK(DB::Open(options, "/dir/db", &db)); - for (size_t i = 0; i < 3; ++i) { - ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i])); - } - - for (size_t i = 0; i < 3; ++i) { - std::string res; - ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); - ASSERT_TRUE(res == vals[i]); - } - - Iterator* iterator = db->NewIterator(ReadOptions()); - iterator->SeekToFirst(); - for (size_t i = 0; i < 3; ++i) { - ASSERT_TRUE(iterator->Valid()); - ASSERT_TRUE(keys[i] == iterator->key()); - ASSERT_TRUE(vals[i] == iterator->value()); - iterator->Next(); - } - ASSERT_TRUE(!iterator->Valid()); - delete iterator; - - DBImpl* dbi = reinterpret_cast(db); - ASSERT_OK(dbi->TEST_CompactMemTable()); - - for (size_t i = 0; i < 3; ++i) { - std::string res; - ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); - ASSERT_TRUE(res == vals[i]); - } - - delete db; -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/include/leveldb/c.h b/src/leveldb/include/leveldb/c.h deleted file mode 100644 index 1048fe3b86..0000000000 --- a/src/leveldb/include/leveldb/c.h +++ /dev/null @@ -1,290 +0,0 @@ -/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. See the AUTHORS file for names of contributors. - - C bindings for leveldb. May be useful as a stable ABI that can be - used by programs that keep leveldb in a shared library, or for - a JNI api. - - Does not support: - . getters for the option types - . custom comparators that implement key shortening - . custom iter, db, env, cache implementations using just the C bindings - - Some conventions: - - (1) We expose just opaque struct pointers and functions to clients. - This allows us to change internal representations without having to - recompile clients. - - (2) For simplicity, there is no equivalent to the Slice type. Instead, - the caller has to pass the pointer and length as separate - arguments. - - (3) Errors are represented by a null-terminated c string. NULL - means no error. All operations that can raise an error are passed - a "char** errptr" as the last argument. One of the following must - be true on entry: - *errptr == NULL - *errptr points to a malloc()ed null-terminated error message - (On Windows, *errptr must have been malloc()-ed by this library.) - On success, a leveldb routine leaves *errptr unchanged. - On failure, leveldb frees the old value of *errptr and - set *errptr to a malloc()ed error message. - - (4) Bools have the type unsigned char (0 == false; rest == true) - - (5) All of the pointer arguments must be non-NULL. -*/ - -#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ -#define STORAGE_LEVELDB_INCLUDE_C_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/* Exported types */ - -typedef struct leveldb_t leveldb_t; -typedef struct leveldb_cache_t leveldb_cache_t; -typedef struct leveldb_comparator_t leveldb_comparator_t; -typedef struct leveldb_env_t leveldb_env_t; -typedef struct leveldb_filelock_t leveldb_filelock_t; -typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; -typedef struct leveldb_iterator_t leveldb_iterator_t; -typedef struct leveldb_logger_t leveldb_logger_t; -typedef struct leveldb_options_t leveldb_options_t; -typedef struct leveldb_randomfile_t leveldb_randomfile_t; -typedef struct leveldb_readoptions_t leveldb_readoptions_t; -typedef struct leveldb_seqfile_t leveldb_seqfile_t; -typedef struct leveldb_snapshot_t leveldb_snapshot_t; -typedef struct leveldb_writablefile_t leveldb_writablefile_t; -typedef struct leveldb_writebatch_t leveldb_writebatch_t; -typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; - -/* DB operations */ - -extern leveldb_t* leveldb_open( - const leveldb_options_t* options, - const char* name, - char** errptr); - -extern void leveldb_close(leveldb_t* db); - -extern void leveldb_put( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - const char* val, size_t vallen, - char** errptr); - -extern void leveldb_delete( - leveldb_t* db, - const leveldb_writeoptions_t* options, - const char* key, size_t keylen, - char** errptr); - -extern void leveldb_write( - leveldb_t* db, - const leveldb_writeoptions_t* options, - leveldb_writebatch_t* batch, - char** errptr); - -/* Returns NULL if not found. A malloc()ed array otherwise. - Stores the length of the array in *vallen. */ -extern char* leveldb_get( - leveldb_t* db, - const leveldb_readoptions_t* options, - const char* key, size_t keylen, - size_t* vallen, - char** errptr); - -extern leveldb_iterator_t* leveldb_create_iterator( - leveldb_t* db, - const leveldb_readoptions_t* options); - -extern const leveldb_snapshot_t* leveldb_create_snapshot( - leveldb_t* db); - -extern void leveldb_release_snapshot( - leveldb_t* db, - const leveldb_snapshot_t* snapshot); - -/* Returns NULL if property name is unknown. - Else returns a pointer to a malloc()-ed null-terminated value. */ -extern char* leveldb_property_value( - leveldb_t* db, - const char* propname); - -extern void leveldb_approximate_sizes( - leveldb_t* db, - int num_ranges, - const char* const* range_start_key, const size_t* range_start_key_len, - const char* const* range_limit_key, const size_t* range_limit_key_len, - uint64_t* sizes); - -extern void leveldb_compact_range( - leveldb_t* db, - const char* start_key, size_t start_key_len, - const char* limit_key, size_t limit_key_len); - -/* Management operations */ - -extern void leveldb_destroy_db( - const leveldb_options_t* options, - const char* name, - char** errptr); - -extern void leveldb_repair_db( - const leveldb_options_t* options, - const char* name, - char** errptr); - -/* Iterator */ - -extern void leveldb_iter_destroy(leveldb_iterator_t*); -extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); -extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); -extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); -extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); -extern void leveldb_iter_next(leveldb_iterator_t*); -extern void leveldb_iter_prev(leveldb_iterator_t*); -extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); -extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); -extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); - -/* Write batch */ - -extern leveldb_writebatch_t* leveldb_writebatch_create(); -extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); -extern void leveldb_writebatch_clear(leveldb_writebatch_t*); -extern void leveldb_writebatch_put( - leveldb_writebatch_t*, - const char* key, size_t klen, - const char* val, size_t vlen); -extern void leveldb_writebatch_delete( - leveldb_writebatch_t*, - const char* key, size_t klen); -extern void leveldb_writebatch_iterate( - leveldb_writebatch_t*, - void* state, - void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), - void (*deleted)(void*, const char* k, size_t klen)); - -/* Options */ - -extern leveldb_options_t* leveldb_options_create(); -extern void leveldb_options_destroy(leveldb_options_t*); -extern void leveldb_options_set_comparator( - leveldb_options_t*, - leveldb_comparator_t*); -extern void leveldb_options_set_filter_policy( - leveldb_options_t*, - leveldb_filterpolicy_t*); -extern void leveldb_options_set_create_if_missing( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_error_if_exists( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_paranoid_checks( - leveldb_options_t*, unsigned char); -extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); -extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); -extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); -extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); -extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); -extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); -extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); - -enum { - leveldb_no_compression = 0, - leveldb_snappy_compression = 1 -}; -extern void leveldb_options_set_compression(leveldb_options_t*, int); - -/* Comparator */ - -extern leveldb_comparator_t* leveldb_comparator_create( - void* state, - void (*destructor)(void*), - int (*compare)( - void*, - const char* a, size_t alen, - const char* b, size_t blen), - const char* (*name)(void*)); -extern void leveldb_comparator_destroy(leveldb_comparator_t*); - -/* Filter policy */ - -extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( - void* state, - void (*destructor)(void*), - char* (*create_filter)( - void*, - const char* const* key_array, const size_t* key_length_array, - int num_keys, - size_t* filter_length), - unsigned char (*key_may_match)( - void*, - const char* key, size_t length, - const char* filter, size_t filter_length), - const char* (*name)(void*)); -extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); - -extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( - int bits_per_key); - -/* Read options */ - -extern leveldb_readoptions_t* leveldb_readoptions_create(); -extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); -extern void leveldb_readoptions_set_verify_checksums( - leveldb_readoptions_t*, - unsigned char); -extern void leveldb_readoptions_set_fill_cache( - leveldb_readoptions_t*, unsigned char); -extern void leveldb_readoptions_set_snapshot( - leveldb_readoptions_t*, - const leveldb_snapshot_t*); - -/* Write options */ - -extern leveldb_writeoptions_t* leveldb_writeoptions_create(); -extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); -extern void leveldb_writeoptions_set_sync( - leveldb_writeoptions_t*, unsigned char); - -/* Cache */ - -extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); -extern void leveldb_cache_destroy(leveldb_cache_t* cache); - -/* Env */ - -extern leveldb_env_t* leveldb_create_default_env(); -extern void leveldb_env_destroy(leveldb_env_t*); - -/* Utility */ - -/* Calls free(ptr). - REQUIRES: ptr was malloc()-ed and returned by one of the routines - in this file. Note that in certain cases (typically on Windows), you - may need to call this routine instead of free(ptr) to dispose of - malloc()-ed memory returned by this library. */ -extern void leveldb_free(void* ptr); - -/* Return the major version number for this release. */ -extern int leveldb_major_version(); - -/* Return the minor version number for this release. */ -extern int leveldb_minor_version(); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/src/leveldb/include/leveldb/cache.h b/src/leveldb/include/leveldb/cache.h deleted file mode 100644 index 1a201e5e0a..0000000000 --- a/src/leveldb/include/leveldb/cache.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A Cache is an interface that maps keys to values. It has internal -// synchronization and may be safely accessed concurrently from -// multiple threads. It may automatically evict entries to make room -// for new entries. Values have a specified charge against the cache -// capacity. For example, a cache where the values are variable -// length strings, may use the length of the string as the charge for -// the string. -// -// A builtin cache implementation with a least-recently-used eviction -// policy is provided. Clients may use their own implementations if -// they want something more sophisticated (like scan-resistance, a -// custom eviction policy, variable cache sizing, etc.) - -#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ -#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -class Cache; - -// Create a new cache with a fixed size capacity. This implementation -// of Cache uses a least-recently-used eviction policy. -extern Cache* NewLRUCache(size_t capacity); - -class Cache { - public: - Cache() { } - - // Destroys all existing entries by calling the "deleter" - // function that was passed to the constructor. - virtual ~Cache(); - - // Opaque handle to an entry stored in the cache. - struct Handle { }; - - // Insert a mapping from key->value into the cache and assign it - // the specified charge against the total cache capacity. - // - // Returns a handle that corresponds to the mapping. The caller - // must call this->Release(handle) when the returned mapping is no - // longer needed. - // - // When the inserted entry is no longer needed, the key and - // value will be passed to "deleter". - virtual Handle* Insert(const Slice& key, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) = 0; - - // If the cache has no mapping for "key", returns NULL. - // - // Else return a handle that corresponds to the mapping. The caller - // must call this->Release(handle) when the returned mapping is no - // longer needed. - virtual Handle* Lookup(const Slice& key) = 0; - - // Release a mapping returned by a previous Lookup(). - // REQUIRES: handle must not have been released yet. - // REQUIRES: handle must have been returned by a method on *this. - virtual void Release(Handle* handle) = 0; - - // Return the value encapsulated in a handle returned by a - // successful Lookup(). - // REQUIRES: handle must not have been released yet. - // REQUIRES: handle must have been returned by a method on *this. - virtual void* Value(Handle* handle) = 0; - - // If the cache contains entry for key, erase it. Note that the - // underlying entry will be kept around until all existing handles - // to it have been released. - virtual void Erase(const Slice& key) = 0; - - // Return a new numeric id. May be used by multiple clients who are - // sharing the same cache to partition the key space. Typically the - // client will allocate a new id at startup and prepend the id to - // its cache keys. - virtual uint64_t NewId() = 0; - - private: - void LRU_Remove(Handle* e); - void LRU_Append(Handle* e); - void Unref(Handle* e); - - struct Rep; - Rep* rep_; - - // No copying allowed - Cache(const Cache&); - void operator=(const Cache&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_CACHE_H_ diff --git a/src/leveldb/include/leveldb/comparator.h b/src/leveldb/include/leveldb/comparator.h deleted file mode 100644 index 556b984c76..0000000000 --- a/src/leveldb/include/leveldb/comparator.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ -#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ - -#include - -namespace leveldb { - -class Slice; - -// A Comparator object provides a total order across slices that are -// used as keys in an sstable or a database. A Comparator implementation -// must be thread-safe since leveldb may invoke its methods concurrently -// from multiple threads. -class Comparator { - public: - virtual ~Comparator(); - - // Three-way comparison. Returns value: - // < 0 iff "a" < "b", - // == 0 iff "a" == "b", - // > 0 iff "a" > "b" - virtual int Compare(const Slice& a, const Slice& b) const = 0; - - // The name of the comparator. Used to check for comparator - // mismatches (i.e., a DB created with one comparator is - // accessed using a different comparator. - // - // The client of this package should switch to a new name whenever - // the comparator implementation changes in a way that will cause - // the relative ordering of any two keys to change. - // - // Names starting with "leveldb." are reserved and should not be used - // by any clients of this package. - virtual const char* Name() const = 0; - - // Advanced functions: these are used to reduce the space requirements - // for internal data structures like index blocks. - - // If *start < limit, changes *start to a short string in [start,limit). - // Simple comparator implementations may return with *start unchanged, - // i.e., an implementation of this method that does nothing is correct. - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const = 0; - - // Changes *key to a short string >= *key. - // Simple comparator implementations may return with *key unchanged, - // i.e., an implementation of this method that does nothing is correct. - virtual void FindShortSuccessor(std::string* key) const = 0; -}; - -// Return a builtin comparator that uses lexicographic byte-wise -// ordering. The result remains the property of this module and -// must not be deleted. -extern const Comparator* BytewiseComparator(); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/src/leveldb/include/leveldb/db.h b/src/leveldb/include/leveldb/db.h deleted file mode 100644 index 4c169bf22e..0000000000 --- a/src/leveldb/include/leveldb/db.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ -#define STORAGE_LEVELDB_INCLUDE_DB_H_ - -#include -#include -#include "leveldb/iterator.h" -#include "leveldb/options.h" - -namespace leveldb { - -// Update Makefile if you change these -static const int kMajorVersion = 1; -static const int kMinorVersion = 18; - -struct Options; -struct ReadOptions; -struct WriteOptions; -class WriteBatch; - -// Abstract handle to particular state of a DB. -// A Snapshot is an immutable object and can therefore be safely -// accessed from multiple threads without any external synchronization. -class Snapshot { - protected: - virtual ~Snapshot(); -}; - -// A range of keys -struct Range { - Slice start; // Included in the range - Slice limit; // Not included in the range - - Range() { } - Range(const Slice& s, const Slice& l) : start(s), limit(l) { } -}; - -// A DB is a persistent ordered map from keys to values. -// A DB is safe for concurrent access from multiple threads without -// any external synchronization. -class DB { - public: - // Open the database with the specified "name". - // Stores a pointer to a heap-allocated database in *dbptr and returns - // OK on success. - // Stores NULL in *dbptr and returns a non-OK status on error. - // Caller should delete *dbptr when it is no longer needed. - static Status Open(const Options& options, - const std::string& name, - DB** dbptr); - - DB() { } - virtual ~DB(); - - // Set the database entry for "key" to "value". Returns OK on success, - // and a non-OK status on error. - // Note: consider setting options.sync = true. - virtual Status Put(const WriteOptions& options, - const Slice& key, - const Slice& value) = 0; - - // Remove the database entry (if any) for "key". Returns OK on - // success, and a non-OK status on error. It is not an error if "key" - // did not exist in the database. - // Note: consider setting options.sync = true. - virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; - - // Apply the specified updates to the database. - // Returns OK on success, non-OK on failure. - // Note: consider setting options.sync = true. - virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; - - // If the database contains an entry for "key" store the - // corresponding value in *value and return OK. - // - // If there is no entry for "key" leave *value unchanged and return - // a status for which Status::IsNotFound() returns true. - // - // May return some other Status on an error. - virtual Status Get(const ReadOptions& options, - const Slice& key, std::string* value) = 0; - - // Return a heap-allocated iterator over the contents of the database. - // The result of NewIterator() is initially invalid (caller must - // call one of the Seek methods on the iterator before using it). - // - // Caller should delete the iterator when it is no longer needed. - // The returned iterator should be deleted before this db is deleted. - virtual Iterator* NewIterator(const ReadOptions& options) = 0; - - // Return a handle to the current DB state. Iterators created with - // this handle will all observe a stable snapshot of the current DB - // state. The caller must call ReleaseSnapshot(result) when the - // snapshot is no longer needed. - virtual const Snapshot* GetSnapshot() = 0; - - // Release a previously acquired snapshot. The caller must not - // use "snapshot" after this call. - virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; - - // DB implementations can export properties about their state - // via this method. If "property" is a valid property understood by this - // DB implementation, fills "*value" with its current value and returns - // true. Otherwise returns false. - // - // - // Valid property names include: - // - // "leveldb.num-files-at-level" - return the number of files at level , - // where is an ASCII representation of a level number (e.g. "0"). - // "leveldb.stats" - returns a multi-line string that describes statistics - // about the internal operation of the DB. - // "leveldb.sstables" - returns a multi-line string that describes all - // of the sstables that make up the db contents. - virtual bool GetProperty(const Slice& property, std::string* value) = 0; - - // For each i in [0,n-1], store in "sizes[i]", the approximate - // file system space used by keys in "[range[i].start .. range[i].limit)". - // - // Note that the returned sizes measure file system space usage, so - // if the user data compresses by a factor of ten, the returned - // sizes will be one-tenth the size of the corresponding user data size. - // - // The results may not include the sizes of recently written data. - virtual void GetApproximateSizes(const Range* range, int n, - uint64_t* sizes) = 0; - - // Compact the underlying storage for the key range [*begin,*end]. - // In particular, deleted and overwritten versions are discarded, - // and the data is rearranged to reduce the cost of operations - // needed to access the data. This operation should typically only - // be invoked by users who understand the underlying implementation. - // - // begin==NULL is treated as a key before all keys in the database. - // end==NULL is treated as a key after all keys in the database. - // Therefore the following call will compact the entire database: - // db->CompactRange(NULL, NULL); - virtual void CompactRange(const Slice* begin, const Slice* end) = 0; - - private: - // No copying allowed - DB(const DB&); - void operator=(const DB&); -}; - -// Destroy the contents of the specified database. -// Be very careful using this method. -Status DestroyDB(const std::string& name, const Options& options); - -// If a DB cannot be opened, you may attempt to call this method to -// resurrect as much of the contents of the database as possible. -// Some data may be lost, so be careful when calling this function -// on a database that contains important information. -Status RepairDB(const std::string& dbname, const Options& options); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/src/leveldb/include/leveldb/dumpfile.h b/src/leveldb/include/leveldb/dumpfile.h deleted file mode 100644 index 3f97fda16b..0000000000 --- a/src/leveldb/include/leveldb/dumpfile.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2014 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ -#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ - -#include -#include "leveldb/env.h" -#include "leveldb/status.h" - -namespace leveldb { - -// Dump the contents of the file named by fname in text format to -// *dst. Makes a sequence of dst->Append() calls; each call is passed -// the newline-terminated text corresponding to a single item found -// in the file. -// -// Returns a non-OK result if fname does not name a leveldb storage -// file, or if the file cannot be read. -Status DumpFile(Env* env, const std::string& fname, WritableFile* dst); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ diff --git a/src/leveldb/include/leveldb/env.h b/src/leveldb/include/leveldb/env.h deleted file mode 100644 index f709514da6..0000000000 --- a/src/leveldb/include/leveldb/env.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// An Env is an interface used by the leveldb implementation to access -// operating system functionality like the filesystem etc. Callers -// may wish to provide a custom Env object when opening a database to -// get fine gain control; e.g., to rate limit file system operations. -// -// All Env implementations are safe for concurrent access from -// multiple threads without any external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ -#define STORAGE_LEVELDB_INCLUDE_ENV_H_ - -#include -#include -#include -#include -#include "leveldb/status.h" - -namespace leveldb { - -class FileLock; -class Logger; -class RandomAccessFile; -class SequentialFile; -class Slice; -class WritableFile; - -class Env { - public: - Env() { } - virtual ~Env(); - - // Return a default environment suitable for the current operating - // system. Sophisticated users may wish to provide their own Env - // implementation instead of relying on this default environment. - // - // The result of Default() belongs to leveldb and must never be deleted. - static Env* Default(); - - // Create a brand new sequentially-readable file with the specified name. - // On success, stores a pointer to the new file in *result and returns OK. - // On failure stores NULL in *result and returns non-OK. If the file does - // not exist, returns a non-OK status. - // - // The returned file will only be accessed by one thread at a time. - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) = 0; - - // Create a brand new random access read-only file with the - // specified name. On success, stores a pointer to the new file in - // *result and returns OK. On failure stores NULL in *result and - // returns non-OK. If the file does not exist, returns a non-OK - // status. - // - // The returned file may be concurrently accessed by multiple threads. - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) = 0; - - // Create an object that writes to a new file with the specified - // name. Deletes any existing file with the same name and creates a - // new file. On success, stores a pointer to the new file in - // *result and returns OK. On failure stores NULL in *result and - // returns non-OK. - // - // The returned file will only be accessed by one thread at a time. - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) = 0; - - // Returns true iff the named file exists. - virtual bool FileExists(const std::string& fname) = 0; - - // Store in *result the names of the children of the specified directory. - // The names are relative to "dir". - // Original contents of *results are dropped. - virtual Status GetChildren(const std::string& dir, - std::vector* result) = 0; - - // Delete the named file. - virtual Status DeleteFile(const std::string& fname) = 0; - - // Create the specified directory. - virtual Status CreateDir(const std::string& dirname) = 0; - - // Delete the specified directory. - virtual Status DeleteDir(const std::string& dirname) = 0; - - // Store the size of fname in *file_size. - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; - - // Rename file src to target. - virtual Status RenameFile(const std::string& src, - const std::string& target) = 0; - - // Lock the specified file. Used to prevent concurrent access to - // the same db by multiple processes. On failure, stores NULL in - // *lock and returns non-OK. - // - // On success, stores a pointer to the object that represents the - // acquired lock in *lock and returns OK. The caller should call - // UnlockFile(*lock) to release the lock. If the process exits, - // the lock will be automatically released. - // - // If somebody else already holds the lock, finishes immediately - // with a failure. I.e., this call does not wait for existing locks - // to go away. - // - // May create the named file if it does not already exist. - virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; - - // Release the lock acquired by a previous successful call to LockFile. - // REQUIRES: lock was returned by a successful LockFile() call - // REQUIRES: lock has not already been unlocked. - virtual Status UnlockFile(FileLock* lock) = 0; - - // Arrange to run "(*function)(arg)" once in a background thread. - // - // "function" may run in an unspecified thread. Multiple functions - // added to the same Env may run concurrently in different threads. - // I.e., the caller may not assume that background work items are - // serialized. - virtual void Schedule( - void (*function)(void* arg), - void* arg) = 0; - - // Start a new thread, invoking "function(arg)" within the new thread. - // When "function(arg)" returns, the thread will be destroyed. - virtual void StartThread(void (*function)(void* arg), void* arg) = 0; - - // *path is set to a temporary directory that can be used for testing. It may - // or many not have just been created. The directory may or may not differ - // between runs of the same process, but subsequent calls will return the - // same directory. - virtual Status GetTestDirectory(std::string* path) = 0; - - // Create and return a log file for storing informational messages. - virtual Status NewLogger(const std::string& fname, Logger** result) = 0; - - // Returns the number of micro-seconds since some fixed point in time. Only - // useful for computing deltas of time. - virtual uint64_t NowMicros() = 0; - - // Sleep/delay the thread for the prescribed number of micro-seconds. - virtual void SleepForMicroseconds(int micros) = 0; - - private: - // No copying allowed - Env(const Env&); - void operator=(const Env&); -}; - -// A file abstraction for reading sequentially through a file -class SequentialFile { - public: - SequentialFile() { } - virtual ~SequentialFile(); - - // Read up to "n" bytes from the file. "scratch[0..n-1]" may be - // written by this routine. Sets "*result" to the data that was - // read (including if fewer than "n" bytes were successfully read). - // May set "*result" to point at data in "scratch[0..n-1]", so - // "scratch[0..n-1]" must be live when "*result" is used. - // If an error was encountered, returns a non-OK status. - // - // REQUIRES: External synchronization - virtual Status Read(size_t n, Slice* result, char* scratch) = 0; - - // Skip "n" bytes from the file. This is guaranteed to be no - // slower that reading the same data, but may be faster. - // - // If end of file is reached, skipping will stop at the end of the - // file, and Skip will return OK. - // - // REQUIRES: External synchronization - virtual Status Skip(uint64_t n) = 0; - - private: - // No copying allowed - SequentialFile(const SequentialFile&); - void operator=(const SequentialFile&); -}; - -// A file abstraction for randomly reading the contents of a file. -class RandomAccessFile { - public: - RandomAccessFile() { } - virtual ~RandomAccessFile(); - - // Read up to "n" bytes from the file starting at "offset". - // "scratch[0..n-1]" may be written by this routine. Sets "*result" - // to the data that was read (including if fewer than "n" bytes were - // successfully read). May set "*result" to point at data in - // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when - // "*result" is used. If an error was encountered, returns a non-OK - // status. - // - // Safe for concurrent use by multiple threads. - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const = 0; - - private: - // No copying allowed - RandomAccessFile(const RandomAccessFile&); - void operator=(const RandomAccessFile&); -}; - -// A file abstraction for sequential writing. The implementation -// must provide buffering since callers may append small fragments -// at a time to the file. -class WritableFile { - public: - WritableFile() { } - virtual ~WritableFile(); - - virtual Status Append(const Slice& data) = 0; - virtual Status Close() = 0; - virtual Status Flush() = 0; - virtual Status Sync() = 0; - - private: - // No copying allowed - WritableFile(const WritableFile&); - void operator=(const WritableFile&); -}; - -// An interface for writing log messages. -class Logger { - public: - Logger() { } - virtual ~Logger(); - - // Write an entry to the log file with the specified format. - virtual void Logv(const char* format, va_list ap) = 0; - - private: - // No copying allowed - Logger(const Logger&); - void operator=(const Logger&); -}; - - -// Identifies a locked file. -class FileLock { - public: - FileLock() { } - virtual ~FileLock(); - private: - // No copying allowed - FileLock(const FileLock&); - void operator=(const FileLock&); -}; - -// Log the specified data to *info_log if info_log is non-NULL. -extern void Log(Logger* info_log, const char* format, ...) -# if defined(__GNUC__) || defined(__clang__) - __attribute__((__format__ (__printf__, 2, 3))) -# endif - ; - -// A utility routine: write "data" to the named file. -extern Status WriteStringToFile(Env* env, const Slice& data, - const std::string& fname); - -// A utility routine: read contents of named file into *data -extern Status ReadFileToString(Env* env, const std::string& fname, - std::string* data); - -// An implementation of Env that forwards all calls to another Env. -// May be useful to clients who wish to override just part of the -// functionality of another Env. -class EnvWrapper : public Env { - public: - // Initialize an EnvWrapper that delegates all calls to *t - explicit EnvWrapper(Env* t) : target_(t) { } - virtual ~EnvWrapper(); - - // Return the target to which this Env forwards all calls - Env* target() const { return target_; } - - // The following text is boilerplate that forwards all methods to target() - Status NewSequentialFile(const std::string& f, SequentialFile** r) { - return target_->NewSequentialFile(f, r); - } - Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { - return target_->NewRandomAccessFile(f, r); - } - Status NewWritableFile(const std::string& f, WritableFile** r) { - return target_->NewWritableFile(f, r); - } - bool FileExists(const std::string& f) { return target_->FileExists(f); } - Status GetChildren(const std::string& dir, std::vector* r) { - return target_->GetChildren(dir, r); - } - Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } - Status CreateDir(const std::string& d) { return target_->CreateDir(d); } - Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } - Status GetFileSize(const std::string& f, uint64_t* s) { - return target_->GetFileSize(f, s); - } - Status RenameFile(const std::string& s, const std::string& t) { - return target_->RenameFile(s, t); - } - Status LockFile(const std::string& f, FileLock** l) { - return target_->LockFile(f, l); - } - Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } - void Schedule(void (*f)(void*), void* a) { - return target_->Schedule(f, a); - } - void StartThread(void (*f)(void*), void* a) { - return target_->StartThread(f, a); - } - virtual Status GetTestDirectory(std::string* path) { - return target_->GetTestDirectory(path); - } - virtual Status NewLogger(const std::string& fname, Logger** result) { - return target_->NewLogger(fname, result); - } - uint64_t NowMicros() { - return target_->NowMicros(); - } - void SleepForMicroseconds(int micros) { - target_->SleepForMicroseconds(micros); - } - private: - Env* target_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/src/leveldb/include/leveldb/filter_policy.h b/src/leveldb/include/leveldb/filter_policy.h deleted file mode 100644 index 1fba08001f..0000000000 --- a/src/leveldb/include/leveldb/filter_policy.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A database can be configured with a custom FilterPolicy object. -// This object is responsible for creating a small filter from a set -// of keys. These filters are stored in leveldb and are consulted -// automatically by leveldb to decide whether or not to read some -// information from disk. In many cases, a filter can cut down the -// number of disk seeks form a handful to a single disk seek per -// DB::Get() call. -// -// Most people will want to use the builtin bloom filter support (see -// NewBloomFilterPolicy() below). - -#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ -#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ - -#include - -namespace leveldb { - -class Slice; - -class FilterPolicy { - public: - virtual ~FilterPolicy(); - - // Return the name of this policy. Note that if the filter encoding - // changes in an incompatible way, the name returned by this method - // must be changed. Otherwise, old incompatible filters may be - // passed to methods of this type. - virtual const char* Name() const = 0; - - // keys[0,n-1] contains a list of keys (potentially with duplicates) - // that are ordered according to the user supplied comparator. - // Append a filter that summarizes keys[0,n-1] to *dst. - // - // Warning: do not change the initial contents of *dst. Instead, - // append the newly constructed filter to *dst. - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) - const = 0; - - // "filter" contains the data appended by a preceding call to - // CreateFilter() on this class. This method must return true if - // the key was in the list of keys passed to CreateFilter(). - // This method may return true or false if the key was not on the - // list, but it should aim to return false with a high probability. - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; -}; - -// Return a new filter policy that uses a bloom filter with approximately -// the specified number of bits per key. A good value for bits_per_key -// is 10, which yields a filter with ~ 1% false positive rate. -// -// Callers must delete the result after any database that is using the -// result has been closed. -// -// Note: if you are using a custom comparator that ignores some parts -// of the keys being compared, you must not use NewBloomFilterPolicy() -// and must provide your own FilterPolicy that also ignores the -// corresponding parts of the keys. For example, if the comparator -// ignores trailing spaces, it would be incorrect to use a -// FilterPolicy (like NewBloomFilterPolicy) that does not ignore -// trailing spaces in keys. -extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); - -} - -#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/src/leveldb/include/leveldb/iterator.h b/src/leveldb/include/leveldb/iterator.h deleted file mode 100644 index 76aced04bd..0000000000 --- a/src/leveldb/include/leveldb/iterator.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// An iterator yields a sequence of key/value pairs from a source. -// The following class defines the interface. Multiple implementations -// are provided by this library. In particular, iterators are provided -// to access the contents of a Table or a DB. -// -// Multiple threads can invoke const methods on an Iterator without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Iterator must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ -#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ - -#include "leveldb/slice.h" -#include "leveldb/status.h" - -namespace leveldb { - -class Iterator { - public: - Iterator(); - virtual ~Iterator(); - - // An iterator is either positioned at a key/value pair, or - // not valid. This method returns true iff the iterator is valid. - virtual bool Valid() const = 0; - - // Position at the first key in the source. The iterator is Valid() - // after this call iff the source is not empty. - virtual void SeekToFirst() = 0; - - // Position at the last key in the source. The iterator is - // Valid() after this call iff the source is not empty. - virtual void SeekToLast() = 0; - - // Position at the first key in the source that at or past target - // The iterator is Valid() after this call iff the source contains - // an entry that comes at or past target. - virtual void Seek(const Slice& target) = 0; - - // Moves to the next entry in the source. After this call, Valid() is - // true iff the iterator was not positioned at the last entry in the source. - // REQUIRES: Valid() - virtual void Next() = 0; - - // Moves to the previous entry in the source. After this call, Valid() is - // true iff the iterator was not positioned at the first entry in source. - // REQUIRES: Valid() - virtual void Prev() = 0; - - // Return the key for the current entry. The underlying storage for - // the returned slice is valid only until the next modification of - // the iterator. - // REQUIRES: Valid() - virtual Slice key() const = 0; - - // Return the value for the current entry. The underlying storage for - // the returned slice is valid only until the next modification of - // the iterator. - // REQUIRES: Valid() - virtual Slice value() const = 0; - - // If an error has occurred, return it. Else return an ok status. - virtual Status status() const = 0; - - // Clients are allowed to register function/arg1/arg2 triples that - // will be invoked when this iterator is destroyed. - // - // Note that unlike all of the preceding methods, this method is - // not abstract and therefore clients should not override it. - typedef void (*CleanupFunction)(void* arg1, void* arg2); - void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); - - private: - struct Cleanup { - CleanupFunction function; - void* arg1; - void* arg2; - Cleanup* next; - }; - Cleanup cleanup_; - - // No copying allowed - Iterator(const Iterator&); - void operator=(const Iterator&); -}; - -// Return an empty iterator (yields nothing). -extern Iterator* NewEmptyIterator(); - -// Return an empty iterator with the specified status. -extern Iterator* NewErrorIterator(const Status& status); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/src/leveldb/include/leveldb/options.h b/src/leveldb/include/leveldb/options.h deleted file mode 100644 index 7c9b973454..0000000000 --- a/src/leveldb/include/leveldb/options.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ -#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ - -#include - -namespace leveldb { - -class Cache; -class Comparator; -class Env; -class FilterPolicy; -class Logger; -class Snapshot; - -// DB contents are stored in a set of blocks, each of which holds a -// sequence of key,value pairs. Each block may be compressed before -// being stored in a file. The following enum describes which -// compression method (if any) is used to compress a block. -enum CompressionType { - // NOTE: do not change the values of existing entries, as these are - // part of the persistent format on disk. - kNoCompression = 0x0, - kSnappyCompression = 0x1 -}; - -// Options to control the behavior of a database (passed to DB::Open) -struct Options { - // ------------------- - // Parameters that affect behavior - - // Comparator used to define the order of keys in the table. - // Default: a comparator that uses lexicographic byte-wise ordering - // - // REQUIRES: The client must ensure that the comparator supplied - // here has the same name and orders keys *exactly* the same as the - // comparator provided to previous open calls on the same DB. - const Comparator* comparator; - - // If true, the database will be created if it is missing. - // Default: false - bool create_if_missing; - - // If true, an error is raised if the database already exists. - // Default: false - bool error_if_exists; - - // If true, the implementation will do aggressive checking of the - // data it is processing and will stop early if it detects any - // errors. This may have unforeseen ramifications: for example, a - // corruption of one DB entry may cause a large number of entries to - // become unreadable or for the entire DB to become unopenable. - // Default: false - bool paranoid_checks; - - // Use the specified object to interact with the environment, - // e.g. to read/write files, schedule background work, etc. - // Default: Env::Default() - Env* env; - - // Any internal progress/error information generated by the db will - // be written to info_log if it is non-NULL, or to a file stored - // in the same directory as the DB contents if info_log is NULL. - // Default: NULL - Logger* info_log; - - // ------------------- - // Parameters that affect performance - - // Amount of data to build up in memory (backed by an unsorted log - // on disk) before converting to a sorted on-disk file. - // - // Larger values increase performance, especially during bulk loads. - // Up to two write buffers may be held in memory at the same time, - // so you may wish to adjust this parameter to control memory usage. - // Also, a larger write buffer will result in a longer recovery time - // the next time the database is opened. - // - // Default: 4MB - size_t write_buffer_size; - - // Number of open files that can be used by the DB. You may need to - // increase this if your database has a large working set (budget - // one open file per 2MB of working set). - // - // Default: 1000 - int max_open_files; - - // Control over blocks (user data is stored in a set of blocks, and - // a block is the unit of reading from disk). - - // If non-NULL, use the specified cache for blocks. - // If NULL, leveldb will automatically create and use an 8MB internal cache. - // Default: NULL - Cache* block_cache; - - // Approximate size of user data packed per block. Note that the - // block size specified here corresponds to uncompressed data. The - // actual size of the unit read from disk may be smaller if - // compression is enabled. This parameter can be changed dynamically. - // - // Default: 4K - size_t block_size; - - // Number of keys between restart points for delta encoding of keys. - // This parameter can be changed dynamically. Most clients should - // leave this parameter alone. - // - // Default: 16 - int block_restart_interval; - - // Compress blocks using the specified compression algorithm. This - // parameter can be changed dynamically. - // - // Default: kSnappyCompression, which gives lightweight but fast - // compression. - // - // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: - // ~200-500MB/s compression - // ~400-800MB/s decompression - // Note that these speeds are significantly faster than most - // persistent storage speeds, and therefore it is typically never - // worth switching to kNoCompression. Even if the input data is - // incompressible, the kSnappyCompression implementation will - // efficiently detect that and will switch to uncompressed mode. - CompressionType compression; - - // If non-NULL, use the specified filter policy to reduce disk reads. - // Many applications will benefit from passing the result of - // NewBloomFilterPolicy() here. - // - // Default: NULL - const FilterPolicy* filter_policy; - - // Create an Options object with default values for all fields. - Options(); -}; - -// Options that control read operations -struct ReadOptions { - // If true, all data read from underlying storage will be - // verified against corresponding checksums. - // Default: false - bool verify_checksums; - - // Should the data read for this iteration be cached in memory? - // Callers may wish to set this field to false for bulk scans. - // Default: true - bool fill_cache; - - // If "snapshot" is non-NULL, read as of the supplied snapshot - // (which must belong to the DB that is being read and which must - // not have been released). If "snapshot" is NULL, use an implicit - // snapshot of the state at the beginning of this read operation. - // Default: NULL - const Snapshot* snapshot; - - ReadOptions() - : verify_checksums(false), - fill_cache(true), - snapshot(NULL) { - } -}; - -// Options that control write operations -struct WriteOptions { - // If true, the write will be flushed from the operating system - // buffer cache (by calling WritableFile::Sync()) before the write - // is considered complete. If this flag is true, writes will be - // slower. - // - // If this flag is false, and the machine crashes, some recent - // writes may be lost. Note that if it is just the process that - // crashes (i.e., the machine does not reboot), no writes will be - // lost even if sync==false. - // - // In other words, a DB write with sync==false has similar - // crash semantics as the "write()" system call. A DB write - // with sync==true has similar crash semantics to a "write()" - // system call followed by "fsync()". - // - // Default: false - bool sync; - - WriteOptions() - : sync(false) { - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/src/leveldb/include/leveldb/slice.h b/src/leveldb/include/leveldb/slice.h deleted file mode 100644 index bc367986f7..0000000000 --- a/src/leveldb/include/leveldb/slice.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Slice is a simple structure containing a pointer into some external -// storage and a size. The user of a Slice must ensure that the slice -// is not used after the corresponding external storage has been -// deallocated. -// -// Multiple threads can invoke const methods on a Slice without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Slice must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ -#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ - -#include -#include -#include -#include - -namespace leveldb { - -class Slice { - public: - // Create an empty slice. - Slice() : data_(""), size_(0) { } - - // Create a slice that refers to d[0,n-1]. - Slice(const char* d, size_t n) : data_(d), size_(n) { } - - // Create a slice that refers to the contents of "s" - Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } - - // Create a slice that refers to s[0,strlen(s)-1] - Slice(const char* s) : data_(s), size_(strlen(s)) { } - - // Return a pointer to the beginning of the referenced data - const char* data() const { return data_; } - - // Return the length (in bytes) of the referenced data - size_t size() const { return size_; } - - // Return true iff the length of the referenced data is zero - bool empty() const { return size_ == 0; } - - // Return the ith byte in the referenced data. - // REQUIRES: n < size() - char operator[](size_t n) const { - assert(n < size()); - return data_[n]; - } - - // Change this slice to refer to an empty array - void clear() { data_ = ""; size_ = 0; } - - // Drop the first "n" bytes from this slice. - void remove_prefix(size_t n) { - assert(n <= size()); - data_ += n; - size_ -= n; - } - - // Return a string that contains the copy of the referenced data. - std::string ToString() const { return std::string(data_, size_); } - - // Three-way comparison. Returns value: - // < 0 iff "*this" < "b", - // == 0 iff "*this" == "b", - // > 0 iff "*this" > "b" - int compare(const Slice& b) const; - - // Return true iff "x" is a prefix of "*this" - bool starts_with(const Slice& x) const { - return ((size_ >= x.size_) && - (memcmp(data_, x.data_, x.size_) == 0)); - } - - private: - const char* data_; - size_t size_; - - // Intentionally copyable -}; - -inline bool operator==(const Slice& x, const Slice& y) { - return ((x.size() == y.size()) && - (memcmp(x.data(), y.data(), x.size()) == 0)); -} - -inline bool operator!=(const Slice& x, const Slice& y) { - return !(x == y); -} - -inline int Slice::compare(const Slice& b) const { - const size_t min_len = (size_ < b.size_) ? size_ : b.size_; - int r = memcmp(data_, b.data_, min_len); - if (r == 0) { - if (size_ < b.size_) r = -1; - else if (size_ > b.size_) r = +1; - } - return r; -} - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/src/leveldb/include/leveldb/status.h b/src/leveldb/include/leveldb/status.h deleted file mode 100644 index 11dbd4b47e..0000000000 --- a/src/leveldb/include/leveldb/status.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A Status encapsulates the result of an operation. It may indicate success, -// or it may indicate an error with an associated error message. -// -// Multiple threads can invoke const methods on a Status without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same Status must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ -#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -class Status { - public: - // Create a success status. - Status() : state_(NULL) { } - ~Status() { delete[] state_; } - - // Copy the specified status. - Status(const Status& s); - void operator=(const Status& s); - - // Return a success status. - static Status OK() { return Status(); } - - // Return error status of an appropriate type. - static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kNotFound, msg, msg2); - } - static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kCorruption, msg, msg2); - } - static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kNotSupported, msg, msg2); - } - static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kInvalidArgument, msg, msg2); - } - static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { - return Status(kIOError, msg, msg2); - } - - // Returns true iff the status indicates success. - bool ok() const { return (state_ == NULL); } - - // Returns true iff the status indicates a NotFound error. - bool IsNotFound() const { return code() == kNotFound; } - - // Returns true iff the status indicates a Corruption error. - bool IsCorruption() const { return code() == kCorruption; } - - // Returns true iff the status indicates an IOError. - bool IsIOError() const { return code() == kIOError; } - - // Return a string representation of this status suitable for printing. - // Returns the string "OK" for success. - std::string ToString() const; - - private: - // OK status has a NULL state_. Otherwise, state_ is a new[] array - // of the following form: - // state_[0..3] == length of message - // state_[4] == code - // state_[5..] == message - const char* state_; - - enum Code { - kOk = 0, - kNotFound = 1, - kCorruption = 2, - kNotSupported = 3, - kInvalidArgument = 4, - kIOError = 5 - }; - - Code code() const { - return (state_ == NULL) ? kOk : static_cast(state_[4]); - } - - Status(Code code, const Slice& msg, const Slice& msg2); - static const char* CopyState(const char* s); -}; - -inline Status::Status(const Status& s) { - state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); -} -inline void Status::operator=(const Status& s) { - // The following condition catches both aliasing (when this == &s), - // and the common case where both s and *this are ok. - if (state_ != s.state_) { - delete[] state_; - state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); - } -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/src/leveldb/include/leveldb/table.h b/src/leveldb/include/leveldb/table.h deleted file mode 100644 index a9746c3f5e..0000000000 --- a/src/leveldb/include/leveldb/table.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ -#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ - -#include -#include "leveldb/iterator.h" - -namespace leveldb { - -class Block; -class BlockHandle; -class Footer; -struct Options; -class RandomAccessFile; -struct ReadOptions; -class TableCache; - -// A Table is a sorted map from strings to strings. Tables are -// immutable and persistent. A Table may be safely accessed from -// multiple threads without external synchronization. -class Table { - public: - // Attempt to open the table that is stored in bytes [0..file_size) - // of "file", and read the metadata entries necessary to allow - // retrieving data from the table. - // - // If successful, returns ok and sets "*table" to the newly opened - // table. The client should delete "*table" when no longer needed. - // If there was an error while initializing the table, sets "*table" - // to NULL and returns a non-ok status. Does not take ownership of - // "*source", but the client must ensure that "source" remains live - // for the duration of the returned table's lifetime. - // - // *file must remain live while this Table is in use. - static Status Open(const Options& options, - RandomAccessFile* file, - uint64_t file_size, - Table** table); - - ~Table(); - - // Returns a new iterator over the table contents. - // The result of NewIterator() is initially invalid (caller must - // call one of the Seek methods on the iterator before using it). - Iterator* NewIterator(const ReadOptions&) const; - - // Given a key, return an approximate byte offset in the file where - // the data for that key begins (or would begin if the key were - // present in the file). The returned value is in terms of file - // bytes, and so includes effects like compression of the underlying data. - // E.g., the approximate offset of the last key in the table will - // be close to the file length. - uint64_t ApproximateOffsetOf(const Slice& key) const; - - private: - struct Rep; - Rep* rep_; - - explicit Table(Rep* rep) { rep_ = rep; } - static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); - - // Calls (*handle_result)(arg, ...) with the entry found after a call - // to Seek(key). May not make such a call if filter policy says - // that key is not present. - friend class TableCache; - Status InternalGet( - const ReadOptions&, const Slice& key, - void* arg, - void (*handle_result)(void* arg, const Slice& k, const Slice& v)); - - - void ReadMeta(const Footer& footer); - void ReadFilter(const Slice& filter_handle_value); - - // No copying allowed - Table(const Table&); - void operator=(const Table&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/src/leveldb/include/leveldb/table_builder.h b/src/leveldb/include/leveldb/table_builder.h deleted file mode 100644 index 5fd1dc71f1..0000000000 --- a/src/leveldb/include/leveldb/table_builder.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// TableBuilder provides the interface used to build a Table -// (an immutable and sorted map from keys to values). -// -// Multiple threads can invoke const methods on a TableBuilder without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same TableBuilder must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ -#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ - -#include -#include "leveldb/options.h" -#include "leveldb/status.h" - -namespace leveldb { - -class BlockBuilder; -class BlockHandle; -class WritableFile; - -class TableBuilder { - public: - // Create a builder that will store the contents of the table it is - // building in *file. Does not close the file. It is up to the - // caller to close the file after calling Finish(). - TableBuilder(const Options& options, WritableFile* file); - - // REQUIRES: Either Finish() or Abandon() has been called. - ~TableBuilder(); - - // Change the options used by this builder. Note: only some of the - // option fields can be changed after construction. If a field is - // not allowed to change dynamically and its value in the structure - // passed to the constructor is different from its value in the - // structure passed to this method, this method will return an error - // without changing any fields. - Status ChangeOptions(const Options& options); - - // Add key,value to the table being constructed. - // REQUIRES: key is after any previously added key according to comparator. - // REQUIRES: Finish(), Abandon() have not been called - void Add(const Slice& key, const Slice& value); - - // Advanced operation: flush any buffered key/value pairs to file. - // Can be used to ensure that two adjacent entries never live in - // the same data block. Most clients should not need to use this method. - // REQUIRES: Finish(), Abandon() have not been called - void Flush(); - - // Return non-ok iff some error has been detected. - Status status() const; - - // Finish building the table. Stops using the file passed to the - // constructor after this function returns. - // REQUIRES: Finish(), Abandon() have not been called - Status Finish(); - - // Indicate that the contents of this builder should be abandoned. Stops - // using the file passed to the constructor after this function returns. - // If the caller is not going to call Finish(), it must call Abandon() - // before destroying this builder. - // REQUIRES: Finish(), Abandon() have not been called - void Abandon(); - - // Number of calls to Add() so far. - uint64_t NumEntries() const; - - // Size of the file generated so far. If invoked after a successful - // Finish() call, returns the size of the final generated file. - uint64_t FileSize() const; - - private: - bool ok() const { return status().ok(); } - void WriteBlock(BlockBuilder* block, BlockHandle* handle); - void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); - - struct Rep; - Rep* rep_; - - // No copying allowed - TableBuilder(const TableBuilder&); - void operator=(const TableBuilder&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/src/leveldb/include/leveldb/write_batch.h b/src/leveldb/include/leveldb/write_batch.h deleted file mode 100644 index ee9aab68e0..0000000000 --- a/src/leveldb/include/leveldb/write_batch.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// WriteBatch holds a collection of updates to apply atomically to a DB. -// -// The updates are applied in the order in which they are added -// to the WriteBatch. For example, the value of "key" will be "v3" -// after the following batch is written: -// -// batch.Put("key", "v1"); -// batch.Delete("key"); -// batch.Put("key", "v2"); -// batch.Put("key", "v3"); -// -// Multiple threads can invoke const methods on a WriteBatch without -// external synchronization, but if any of the threads may call a -// non-const method, all threads accessing the same WriteBatch must use -// external synchronization. - -#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ -#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ - -#include -#include "leveldb/status.h" - -namespace leveldb { - -class Slice; - -class WriteBatch { - public: - WriteBatch(); - ~WriteBatch(); - - // Store the mapping "key->value" in the database. - void Put(const Slice& key, const Slice& value); - - // If the database contains a mapping for "key", erase it. Else do nothing. - void Delete(const Slice& key); - - // Clear all updates buffered in this batch. - void Clear(); - - // Support for iterating over the contents of a batch. - class Handler { - public: - virtual ~Handler(); - virtual void Put(const Slice& key, const Slice& value) = 0; - virtual void Delete(const Slice& key) = 0; - }; - Status Iterate(Handler* handler) const; - - private: - friend class WriteBatchInternal; - - std::string rep_; // See comment in write_batch.cc for the format of rep_ - - // Intentionally copyable -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/src/leveldb/issues/issue178_test.cc b/src/leveldb/issues/issue178_test.cc deleted file mode 100644 index 1b1cf8bb28..0000000000 --- a/src/leveldb/issues/issue178_test.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2013 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// Test for issue 178: a manual compaction causes deleted data to reappear. -#include -#include -#include - -#include "leveldb/db.h" -#include "leveldb/write_batch.h" -#include "util/testharness.h" - -namespace { - -const int kNumKeys = 1100000; - -std::string Key1(int i) { - char buf[100]; - snprintf(buf, sizeof(buf), "my_key_%d", i); - return buf; -} - -std::string Key2(int i) { - return Key1(i) + "_xxx"; -} - -class Issue178 { }; - -TEST(Issue178, Test) { - // Get rid of any state from an old run. - std::string dbpath = leveldb::test::TmpDir() + "/leveldb_cbug_test"; - DestroyDB(dbpath, leveldb::Options()); - - // Open database. Disable compression since it affects the creation - // of layers and the code below is trying to test against a very - // specific scenario. - leveldb::DB* db; - leveldb::Options db_options; - db_options.create_if_missing = true; - db_options.compression = leveldb::kNoCompression; - ASSERT_OK(leveldb::DB::Open(db_options, dbpath, &db)); - - // create first key range - leveldb::WriteBatch batch; - for (size_t i = 0; i < kNumKeys; i++) { - batch.Put(Key1(i), "value for range 1 key"); - } - ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); - - // create second key range - batch.Clear(); - for (size_t i = 0; i < kNumKeys; i++) { - batch.Put(Key2(i), "value for range 2 key"); - } - ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); - - // delete second key range - batch.Clear(); - for (size_t i = 0; i < kNumKeys; i++) { - batch.Delete(Key2(i)); - } - ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); - - // compact database - std::string start_key = Key1(0); - std::string end_key = Key1(kNumKeys - 1); - leveldb::Slice least(start_key.data(), start_key.size()); - leveldb::Slice greatest(end_key.data(), end_key.size()); - - // commenting out the line below causes the example to work correctly - db->CompactRange(&least, &greatest); - - // count the keys - leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions()); - size_t num_keys = 0; - for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { - num_keys++; - } - delete iter; - ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys"; - - // close database - delete db; - DestroyDB(dbpath, leveldb::Options()); -} - -} // anonymous namespace - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/issues/issue200_test.cc b/src/leveldb/issues/issue200_test.cc deleted file mode 100644 index 1cec79f443..0000000000 --- a/src/leveldb/issues/issue200_test.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2013 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// Test for issue 200: when iterator switches direction from backward -// to forward, the current key can be yielded unexpectedly if a new -// mutation has been added just before the current key. - -#include "leveldb/db.h" -#include "util/testharness.h" - -namespace leveldb { - -class Issue200 { }; - -TEST(Issue200, Test) { - // Get rid of any state from an old run. - std::string dbpath = test::TmpDir() + "/leveldb_issue200_test"; - DestroyDB(dbpath, Options()); - - DB *db; - Options options; - options.create_if_missing = true; - ASSERT_OK(DB::Open(options, dbpath, &db)); - - WriteOptions write_options; - ASSERT_OK(db->Put(write_options, "1", "b")); - ASSERT_OK(db->Put(write_options, "2", "c")); - ASSERT_OK(db->Put(write_options, "3", "d")); - ASSERT_OK(db->Put(write_options, "4", "e")); - ASSERT_OK(db->Put(write_options, "5", "f")); - - ReadOptions read_options; - Iterator *iter = db->NewIterator(read_options); - - // Add an element that should not be reflected in the iterator. - ASSERT_OK(db->Put(write_options, "25", "cd")); - - iter->Seek("5"); - ASSERT_EQ(iter->key().ToString(), "5"); - iter->Prev(); - ASSERT_EQ(iter->key().ToString(), "4"); - iter->Prev(); - ASSERT_EQ(iter->key().ToString(), "3"); - iter->Next(); - ASSERT_EQ(iter->key().ToString(), "4"); - iter->Next(); - ASSERT_EQ(iter->key().ToString(), "5"); - - delete iter; - delete db; - DestroyDB(dbpath, options); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/port/README b/src/leveldb/port/README deleted file mode 100644 index 422563e25c..0000000000 --- a/src/leveldb/port/README +++ /dev/null @@ -1,10 +0,0 @@ -This directory contains interfaces and implementations that isolate the -rest of the package from platform details. - -Code in the rest of the package includes "port.h" from this directory. -"port.h" in turn includes a platform specific "port_.h" file -that provides the platform specific implementation. - -See port_posix.h for an example of what must be provided in a platform -specific header file. - diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h deleted file mode 100644 index 9bf091f757..0000000000 --- a/src/leveldb/port/atomic_pointer.h +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// AtomicPointer provides storage for a lock-free pointer. -// Platform-dependent implementation of AtomicPointer: -// - If the platform provides a cheap barrier, we use it with raw pointers -// - If is present (on newer versions of gcc, it is), we use -// a -based AtomicPointer. However we prefer the memory -// barrier based version, because at least on a gcc 4.4 32-bit build -// on linux, we have encountered a buggy implementation. -// Also, some implementations are much slower than a memory-barrier -// based implementation (~16ns for based acquire-load vs. ~1ns for -// a barrier based acquire-load). -// This code is based on atomicops-internals-* in Google's perftools: -// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase - -#ifndef PORT_ATOMIC_POINTER_H_ -#define PORT_ATOMIC_POINTER_H_ - -#include -#ifdef LEVELDB_ATOMIC_PRESENT -#include -#endif -#ifdef OS_WIN -#include -#endif -#ifdef OS_MACOSX -#include -#endif - -#if defined(_M_X64) || defined(__x86_64__) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(__ARMEL__) -#define ARCH_CPU_ARM_FAMILY 1 -#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) -#define ARCH_CPU_PPC_FAMILY 1 -#endif - -namespace leveldb { -namespace port { - -// Define MemoryBarrier() if available -// Windows on x86 -#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) -// windows.h already provides a MemoryBarrier(void) macro -// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Mac OS -#elif defined(OS_MACOSX) -inline void MemoryBarrier() { - OSMemoryBarrier(); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Gcc on x86 -#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) -inline void MemoryBarrier() { - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on - // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. - __asm__ __volatile__("" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// Sun Studio -#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) -inline void MemoryBarrier() { - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on - // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. - asm volatile("" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// ARM Linux -#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) -typedef void (*LinuxKernelMemoryBarrierFunc)(void); -// The Linux ARM kernel provides a highly optimized device-specific memory -// barrier function at a fixed memory address that is mapped in every -// user-level process. -// -// This beats using CPU-specific instructions which are, on single-core -// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more -// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking -// shows that the extra function call cost is completely negligible on -// multi-core devices. -// -inline void MemoryBarrier() { - (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -// PPC -#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) -inline void MemoryBarrier() { - // TODO for some powerpc expert: is there a cheaper suitable variant? - // Perhaps by having separate barriers for acquire and release ops. - asm volatile("sync" : : : "memory"); -} -#define LEVELDB_HAVE_MEMORY_BARRIER - -#endif - -// AtomicPointer built using platform-specific MemoryBarrier() -#if defined(LEVELDB_HAVE_MEMORY_BARRIER) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* p) : rep_(p) {} - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } - inline void* Acquire_Load() const { - void* result = rep_; - MemoryBarrier(); - return result; - } - inline void Release_Store(void* v) { - MemoryBarrier(); - rep_ = v; - } -}; - -// AtomicPointer based on -#elif defined(LEVELDB_ATOMIC_PRESENT) -class AtomicPointer { - private: - std::atomic rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - return rep_.load(std::memory_order_acquire); - } - inline void Release_Store(void* v) { - rep_.store(v, std::memory_order_release); - } - inline void* NoBarrier_Load() const { - return rep_.load(std::memory_order_relaxed); - } - inline void NoBarrier_Store(void* v) { - rep_.store(v, std::memory_order_relaxed); - } -}; - -// Atomic pointer based on sparc memory barriers -#elif defined(__sparcv9) && defined(__GNUC__) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - void* val; - __asm__ __volatile__ ( - "ldx [%[rep_]], %[val] \n\t" - "membar #LoadLoad|#LoadStore \n\t" - : [val] "=r" (val) - : [rep_] "r" (&rep_) - : "memory"); - return val; - } - inline void Release_Store(void* v) { - __asm__ __volatile__ ( - "membar #LoadStore|#StoreStore \n\t" - "stx %[v], [%[rep_]] \n\t" - : - : [rep_] "r" (&rep_), [v] "r" (v) - : "memory"); - } - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } -}; - -// Atomic pointer based on ia64 acq/rel -#elif defined(__ia64) && defined(__GNUC__) -class AtomicPointer { - private: - void* rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - void* val ; - __asm__ __volatile__ ( - "ld8.acq %[val] = [%[rep_]] \n\t" - : [val] "=r" (val) - : [rep_] "r" (&rep_) - : "memory" - ); - return val; - } - inline void Release_Store(void* v) { - __asm__ __volatile__ ( - "st8.rel [%[rep_]] = %[v] \n\t" - : - : [rep_] "r" (&rep_), [v] "r" (v) - : "memory" - ); - } - inline void* NoBarrier_Load() const { return rep_; } - inline void NoBarrier_Store(void* v) { rep_ = v; } -}; - -// We have neither MemoryBarrier(), nor -#else -#error Please implement AtomicPointer for this platform. - -#endif - -#undef LEVELDB_HAVE_MEMORY_BARRIER -#undef ARCH_CPU_X86_FAMILY -#undef ARCH_CPU_ARM_FAMILY -#undef ARCH_CPU_PPC_FAMILY - -} // namespace port -} // namespace leveldb - -#endif // PORT_ATOMIC_POINTER_H_ diff --git a/src/leveldb/port/port.h b/src/leveldb/port/port.h deleted file mode 100644 index 4baafa8e22..0000000000 --- a/src/leveldb/port/port.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_PORT_PORT_H_ -#define STORAGE_LEVELDB_PORT_PORT_H_ - -#include - -// Include the appropriate platform specific file below. If you are -// porting to a new platform, see "port_example.h" for documentation -// of what the new port_.h file must provide. -#if defined(LEVELDB_PLATFORM_POSIX) -# include "port/port_posix.h" -#elif defined(LEVELDB_PLATFORM_CHROMIUM) -# include "port/port_chromium.h" -#elif defined(LEVELDB_PLATFORM_WINDOWS) -# include "port/port_win.h" -#endif - -#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h deleted file mode 100644 index ab9e489b32..0000000000 --- a/src/leveldb/port/port_example.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// This file contains the specification, but not the implementations, -// of the types/operations/etc. that should be defined by a platform -// specific port_.h file. Use this file as a reference for -// how to port this package to a new platform. - -#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ -#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ - -namespace leveldb { -namespace port { - -// TODO(jorlow): Many of these belong more in the environment class rather than -// here. We should try moving them and see if it affects perf. - -// The following boolean constant must be true on a little-endian machine -// and false otherwise. -static const bool kLittleEndian = true /* or some other expression */; - -// ------------------ Threading ------------------- - -// A Mutex represents an exclusive lock. -class Mutex { - public: - Mutex(); - ~Mutex(); - - // Lock the mutex. Waits until other lockers have exited. - // Will deadlock if the mutex is already locked by this thread. - void Lock(); - - // Unlock the mutex. - // REQUIRES: This mutex was locked by this thread. - void Unlock(); - - // Optionally crash if this thread does not hold this mutex. - // The implementation must be fast, especially if NDEBUG is - // defined. The implementation is allowed to skip all checks. - void AssertHeld(); -}; - -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - - // Atomically release *mu and block on this condition variable until - // either a call to SignalAll(), or a call to Signal() that picks - // this thread to wakeup. - // REQUIRES: this thread holds *mu - void Wait(); - - // If there are some threads waiting, wake up at least one of them. - void Signal(); - - // Wake up all waiting threads. - void SignallAll(); -}; - -// Thread-safe initialization. -// Used as follows: -// static port::OnceType init_control = LEVELDB_ONCE_INIT; -// static void Initializer() { ... do something ...; } -// ... -// port::InitOnce(&init_control, &Initializer); -typedef intptr_t OnceType; -#define LEVELDB_ONCE_INIT 0 -extern void InitOnce(port::OnceType*, void (*initializer)()); - -// A type that holds a pointer that can be read or written atomically -// (i.e., without word-tearing.) -class AtomicPointer { - private: - intptr_t rep_; - public: - // Initialize to arbitrary value - AtomicPointer(); - - // Initialize to hold v - explicit AtomicPointer(void* v) : rep_(v) { } - - // Read and return the stored pointer with the guarantee that no - // later memory access (read or write) by this thread can be - // reordered ahead of this read. - void* Acquire_Load() const; - - // Set v as the stored pointer with the guarantee that no earlier - // memory access (read or write) by this thread can be reordered - // after this store. - void Release_Store(void* v); - - // Read the stored pointer with no ordering guarantees. - void* NoBarrier_Load() const; - - // Set va as the stored pointer with no ordering guarantees. - void NoBarrier_Store(void* v); -}; - -// ------------------ Compression ------------------- - -// Store the snappy compression of "input[0,input_length-1]" in *output. -// Returns false if snappy is not supported by this port. -extern bool Snappy_Compress(const char* input, size_t input_length, - std::string* output); - -// If input[0,input_length-1] looks like a valid snappy compressed -// buffer, store the size of the uncompressed data in *result and -// return true. Else return false. -extern bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result); - -// Attempt to snappy uncompress input[0,input_length-1] into *output. -// Returns true if successful, false if the input is invalid lightweight -// compressed data. -// -// REQUIRES: at least the first "n" bytes of output[] must be writable -// where "n" is the result of a successful call to -// Snappy_GetUncompressedLength. -extern bool Snappy_Uncompress(const char* input_data, size_t input_length, - char* output); - -// ------------------ Miscellaneous ------------------- - -// If heap profiling is not supported, returns false. -// Else repeatedly calls (*func)(arg, data, n) and then returns true. -// The concatenation of all "data[0,n-1]" fragments is the heap profile. -extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); - -} // namespace port -} // namespace leveldb - -#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc deleted file mode 100644 index 5ba127a5b9..0000000000 --- a/src/leveldb/port/port_posix.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "port/port_posix.h" - -#include -#include -#include -#include "util/logging.h" - -namespace leveldb { -namespace port { - -static void PthreadCall(const char* label, int result) { - if (result != 0) { - fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - abort(); - } -} - -Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } - -Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } - -void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } - -void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } - -CondVar::CondVar(Mutex* mu) - : mu_(mu) { - PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); -} - -CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } - -void CondVar::Wait() { - PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); -} - -void CondVar::Signal() { - PthreadCall("signal", pthread_cond_signal(&cv_)); -} - -void CondVar::SignalAll() { - PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); -} - -void InitOnce(OnceType* once, void (*initializer)()) { - PthreadCall("once", pthread_once(once, initializer)); -} - -} // namespace port -} // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h deleted file mode 100644 index ccca9939d3..0000000000 --- a/src/leveldb/port/port_posix.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ -#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ - -#undef PLATFORM_IS_LITTLE_ENDIAN -#if defined(OS_MACOSX) - #include - #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) - #define PLATFORM_IS_LITTLE_ENDIAN \ - (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) - #endif -#elif defined(OS_SOLARIS) - #include - #ifdef _LITTLE_ENDIAN - #define PLATFORM_IS_LITTLE_ENDIAN true - #else - #define PLATFORM_IS_LITTLE_ENDIAN false - #endif -#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) ||\ - defined(OS_NETBSD) || defined(OS_DRAGONFLYBSD) - #include - #include - #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) -#elif defined(OS_HPUX) - #define PLATFORM_IS_LITTLE_ENDIAN false -#elif defined(OS_ANDROID) - // Due to a bug in the NDK x86 definition, - // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. - // See http://code.google.com/p/android/issues/detail?id=39824 - #include - #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) -#else - #include -#endif - -#include -#ifdef SNAPPY -#include -#endif -#include -#include -#include "port/atomic_pointer.h" - -#ifndef PLATFORM_IS_LITTLE_ENDIAN -#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) -#endif - -#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ - defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ - defined(OS_ANDROID) || defined(OS_HPUX) || defined(CYGWIN) -// Use fread/fwrite/fflush on platforms without _unlocked variants -#define fread_unlocked fread -#define fwrite_unlocked fwrite -#define fflush_unlocked fflush -#endif - -#if defined(OS_FREEBSD) ||\ - defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) -// Use fsync() on platforms without fdatasync() -#define fdatasync fsync -#endif - -#if defined(OS_MACOSX) -#define fdatasync(fd) fcntl(fd, F_FULLFSYNC, 0) -#endif - -#if defined(OS_ANDROID) && __ANDROID_API__ < 9 -// fdatasync() was only introduced in API level 9 on Android. Use fsync() -// when targetting older platforms. -#define fdatasync fsync -#endif - -namespace leveldb { -namespace port { - -static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; -#undef PLATFORM_IS_LITTLE_ENDIAN - -class CondVar; - -class Mutex { - public: - Mutex(); - ~Mutex(); - - void Lock(); - void Unlock(); - void AssertHeld() { } - - private: - friend class CondVar; - pthread_mutex_t mu_; - - // No copying - Mutex(const Mutex&); - void operator=(const Mutex&); -}; - -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - void Wait(); - void Signal(); - void SignalAll(); - private: - pthread_cond_t cv_; - Mutex* mu_; -}; - -typedef pthread_once_t OnceType; -#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT -extern void InitOnce(OnceType* once, void (*initializer)()); - -inline bool Snappy_Compress(const char* input, size_t length, - ::std::string* output) { -#ifdef SNAPPY - output->resize(snappy::MaxCompressedLength(length)); - size_t outlen; - snappy::RawCompress(input, length, &(*output)[0], &outlen); - output->resize(outlen); - return true; -#endif - - return false; -} - -inline bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result) { -#ifdef SNAPPY - return snappy::GetUncompressedLength(input, length, result); -#else - return false; -#endif -} - -inline bool Snappy_Uncompress(const char* input, size_t length, - char* output) { -#ifdef SNAPPY - return snappy::RawUncompress(input, length, output); -#else - return false; -#endif -} - -inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { - return false; -} - -} // namespace port -} // namespace leveldb - -#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/src/leveldb/port/port_posix_sse.cc b/src/leveldb/port/port_posix_sse.cc deleted file mode 100644 index 2d49c21dd8..0000000000 --- a/src/leveldb/port/port_posix_sse.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2016 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A portable implementation of crc32c, optimized to handle -// four bytes at a time. -// -// In a separate source file to allow this accelerated CRC32C function to be -// compiled with the appropriate compiler flags to enable x86 SSE 4.2 -// instructions. - -#include -#include -#include "port/port.h" - -#if defined(LEVELDB_PLATFORM_POSIX_SSE) - -#if defined(_MSC_VER) -#include -#elif defined(__GNUC__) && defined(__SSE4_2__) -#include -#endif - -#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) - -namespace leveldb { -namespace port { - -#if defined(LEVELDB_PLATFORM_POSIX_SSE) - -// Used to fetch a naturally-aligned 32-bit word in little endian byte-order -static inline uint32_t LE_LOAD32(const uint8_t *p) { - // SSE is x86 only, so ensured that |p| is always little-endian. - uint32_t word; - memcpy(&word, p, sizeof(word)); - return word; -} - -#if defined(_M_X64) || defined(__x86_64__) // LE_LOAD64 is only used on x64. - -// Used to fetch a naturally-aligned 64-bit word in little endian byte-order -static inline uint64_t LE_LOAD64(const uint8_t *p) { - uint64_t dword; - memcpy(&dword, p, sizeof(dword)); - return dword; -} - -#endif // defined(_M_X64) || defined(__x86_64__) - -#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) - -// For further improvements see Intel publication at: -// http://download.intel.com/design/intarch/papers/323405.pdf -uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { -#if !defined(LEVELDB_PLATFORM_POSIX_SSE) - return 0; -#else - - const uint8_t *p = reinterpret_cast(buf); - const uint8_t *e = p + size; - uint32_t l = crc ^ 0xffffffffu; - -#define STEP1 do { \ - l = _mm_crc32_u8(l, *p++); \ -} while (0) -#define STEP4 do { \ - l = _mm_crc32_u32(l, LE_LOAD32(p)); \ - p += 4; \ -} while (0) -#define STEP8 do { \ - l = _mm_crc32_u64(l, LE_LOAD64(p)); \ - p += 8; \ -} while (0) - - if (size > 16) { - // Process unaligned bytes - for (unsigned int i = reinterpret_cast(p) % 8; i; --i) { - STEP1; - } - - // _mm_crc32_u64 is only available on x64. -#if defined(_M_X64) || defined(__x86_64__) - // Process 8 bytes at a time - while ((e-p) >= 8) { - STEP8; - } - // Process 4 bytes at a time - if ((e-p) >= 4) { - STEP4; - } -#else // !(defined(_M_X64) || defined(__x86_64__)) - // Process 4 bytes at a time - while ((e-p) >= 4) { - STEP4; - } -#endif // defined(_M_X64) || defined(__x86_64__) - } - // Process the last few bytes - while (p != e) { - STEP1; - } -#undef STEP8 -#undef STEP4 -#undef STEP1 - return l ^ 0xffffffffu; -#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) -} - -} // namespace port -} // namespace leveldb diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc deleted file mode 100644 index 1b0f060a19..0000000000 --- a/src/leveldb/port/port_win.cc +++ /dev/null @@ -1,147 +0,0 @@ -// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the University of California, Berkeley nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#include "port/port_win.h" - -#include -#include - -namespace leveldb { -namespace port { - -Mutex::Mutex() : - cs_(NULL) { - assert(!cs_); - cs_ = static_cast(new CRITICAL_SECTION()); - ::InitializeCriticalSection(static_cast(cs_)); - assert(cs_); -} - -Mutex::~Mutex() { - assert(cs_); - ::DeleteCriticalSection(static_cast(cs_)); - delete static_cast(cs_); - cs_ = NULL; - assert(!cs_); -} - -void Mutex::Lock() { - assert(cs_); - ::EnterCriticalSection(static_cast(cs_)); -} - -void Mutex::Unlock() { - assert(cs_); - ::LeaveCriticalSection(static_cast(cs_)); -} - -void Mutex::AssertHeld() { - assert(cs_); - assert(1); -} - -CondVar::CondVar(Mutex* mu) : - waiting_(0), - mu_(mu), - sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)), - sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) { - assert(mu_); -} - -CondVar::~CondVar() { - ::CloseHandle(sem1_); - ::CloseHandle(sem2_); -} - -void CondVar::Wait() { - mu_->AssertHeld(); - - wait_mtx_.Lock(); - ++waiting_; - wait_mtx_.Unlock(); - - mu_->Unlock(); - - // initiate handshake - ::WaitForSingleObject(sem1_, INFINITE); - ::ReleaseSemaphore(sem2_, 1, NULL); - mu_->Lock(); -} - -void CondVar::Signal() { - wait_mtx_.Lock(); - if (waiting_ > 0) { - --waiting_; - - // finalize handshake - ::ReleaseSemaphore(sem1_, 1, NULL); - ::WaitForSingleObject(sem2_, INFINITE); - } - wait_mtx_.Unlock(); -} - -void CondVar::SignalAll() { - wait_mtx_.Lock(); - ::ReleaseSemaphore(sem1_, waiting_, NULL); - while(waiting_ > 0) { - --waiting_; - ::WaitForSingleObject(sem2_, INFINITE); - } - wait_mtx_.Unlock(); -} - -AtomicPointer::AtomicPointer(void* v) { - Release_Store(v); -} - -void InitOnce(OnceType* once, void (*initializer)()) { - once->InitOnce(initializer); -} - -void* AtomicPointer::Acquire_Load() const { - void * p = NULL; - InterlockedExchangePointer(&p, rep_); - return p; -} - -void AtomicPointer::Release_Store(void* v) { - InterlockedExchangePointer(&rep_, v); -} - -void* AtomicPointer::NoBarrier_Load() const { - return rep_; -} - -void AtomicPointer::NoBarrier_Store(void* v) { - rep_ = v; -} - -} -} diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h deleted file mode 100644 index 45bf2f0ea7..0000000000 --- a/src/leveldb/port/port_win.h +++ /dev/null @@ -1,174 +0,0 @@ -// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the University of California, Berkeley nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// - -#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ -#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ - -#ifdef _MSC_VER -#define snprintf _snprintf -#define close _close -#define fread_unlocked _fread_nolock -#endif - -#include -#include -#ifdef SNAPPY -#include -#endif - -namespace leveldb { -namespace port { - -// Windows is little endian (for now :p) -static const bool kLittleEndian = true; - -class CondVar; - -class Mutex { - public: - Mutex(); - ~Mutex(); - - void Lock(); - void Unlock(); - void AssertHeld(); - - private: - friend class CondVar; - // critical sections are more efficient than mutexes - // but they are not recursive and can only be used to synchronize threads within the same process - // we use opaque void * to avoid including windows.h in port_win.h - void * cs_; - - // No copying - Mutex(const Mutex&); - void operator=(const Mutex&); -}; - -// the Win32 API offers a dependable condition variable mechanism, but only starting with -// Windows 2008 and Vista -// no matter what we will implement our own condition variable with a semaphore -// implementation as described in a paper written by Andrew D. Birrell in 2003 -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - void Wait(); - void Signal(); - void SignalAll(); - private: - Mutex* mu_; - - Mutex wait_mtx_; - long waiting_; - - void * sem1_; - void * sem2_; - - -}; - -class OnceType { -public: -// OnceType() : init_(false) {} - OnceType(const OnceType &once) : init_(once.init_) {} - OnceType(bool f) : init_(f) {} - void InitOnce(void (*initializer)()) { - mutex_.Lock(); - if (!init_) { - init_ = true; - initializer(); - } - mutex_.Unlock(); - } - -private: - bool init_; - Mutex mutex_; -}; - -#define LEVELDB_ONCE_INIT false -extern void InitOnce(port::OnceType*, void (*initializer)()); - -// Storage for a lock-free pointer -class AtomicPointer { - private: - void * rep_; - public: - AtomicPointer() : rep_(NULL) { } - explicit AtomicPointer(void* v); - void* Acquire_Load() const; - - void Release_Store(void* v); - - void* NoBarrier_Load() const; - - void NoBarrier_Store(void* v); -}; - -inline bool Snappy_Compress(const char* input, size_t length, - ::std::string* output) { -#ifdef SNAPPY - output->resize(snappy::MaxCompressedLength(length)); - size_t outlen; - snappy::RawCompress(input, length, &(*output)[0], &outlen); - output->resize(outlen); - return true; -#endif - - return false; -} - -inline bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result) { -#ifdef SNAPPY - return snappy::GetUncompressedLength(input, length, result); -#else - return false; -#endif -} - -inline bool Snappy_Uncompress(const char* input, size_t length, - char* output) { -#ifdef SNAPPY - return snappy::RawUncompress(input, length, output); -#else - return false; -#endif -} - -inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { - return false; -} - -} -} - -#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/src/leveldb/port/thread_annotations.h b/src/leveldb/port/thread_annotations.h deleted file mode 100644 index 9470ef587c..0000000000 --- a/src/leveldb/port/thread_annotations.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ -#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ - -// Some environments provide custom macros to aid in static thread-safety -// analysis. Provide empty definitions of such macros unless they are already -// defined. - -#ifndef EXCLUSIVE_LOCKS_REQUIRED -#define EXCLUSIVE_LOCKS_REQUIRED(...) -#endif - -#ifndef SHARED_LOCKS_REQUIRED -#define SHARED_LOCKS_REQUIRED(...) -#endif - -#ifndef LOCKS_EXCLUDED -#define LOCKS_EXCLUDED(...) -#endif - -#ifndef LOCK_RETURNED -#define LOCK_RETURNED(x) -#endif - -#ifndef LOCKABLE -#define LOCKABLE -#endif - -#ifndef SCOPED_LOCKABLE -#define SCOPED_LOCKABLE -#endif - -#ifndef EXCLUSIVE_LOCK_FUNCTION -#define EXCLUSIVE_LOCK_FUNCTION(...) -#endif - -#ifndef SHARED_LOCK_FUNCTION -#define SHARED_LOCK_FUNCTION(...) -#endif - -#ifndef EXCLUSIVE_TRYLOCK_FUNCTION -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) -#endif - -#ifndef SHARED_TRYLOCK_FUNCTION -#define SHARED_TRYLOCK_FUNCTION(...) -#endif - -#ifndef UNLOCK_FUNCTION -#define UNLOCK_FUNCTION(...) -#endif - -#ifndef NO_THREAD_SAFETY_ANALYSIS -#define NO_THREAD_SAFETY_ANALYSIS -#endif - -#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ diff --git a/src/leveldb/port/win/stdint.h b/src/leveldb/port/win/stdint.h deleted file mode 100644 index 39edd0db13..0000000000 --- a/src/leveldb/port/win/stdint.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -// MSVC didn't ship with this file until the 2010 version. - -#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ -#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ - -#if !defined(_MSC_VER) -#error This file should only be included when compiling with MSVC. -#endif - -// Define C99 equivalent types. -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/src/leveldb/table/block.cc b/src/leveldb/table/block.cc deleted file mode 100644 index 43e402c9c0..0000000000 --- a/src/leveldb/table/block.cc +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Decodes the blocks generated by block_builder.cc. - -#include "table/block.h" - -#include -#include -#include "leveldb/comparator.h" -#include "table/format.h" -#include "util/coding.h" -#include "util/logging.h" - -namespace leveldb { - -inline uint32_t Block::NumRestarts() const { - assert(size_ >= sizeof(uint32_t)); - return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); -} - -Block::Block(const BlockContents& contents) - : data_(contents.data.data()), - size_(contents.data.size()), - owned_(contents.heap_allocated) { - if (size_ < sizeof(uint32_t)) { - size_ = 0; // Error marker - } else { - size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); - if (NumRestarts() > max_restarts_allowed) { - // The size is too small for NumRestarts() - size_ = 0; - } else { - restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); - } - } -} - -Block::~Block() { - if (owned_) { - delete[] data_; - } -} - -// Helper routine: decode the next block entry starting at "p", -// storing the number of shared key bytes, non_shared key bytes, -// and the length of the value in "*shared", "*non_shared", and -// "*value_length", respectively. Will not dereference past "limit". -// -// If any errors are detected, returns NULL. Otherwise, returns a -// pointer to the key delta (just past the three decoded values). -static inline const char* DecodeEntry(const char* p, const char* limit, - uint32_t* shared, - uint32_t* non_shared, - uint32_t* value_length) { - if (limit - p < 3) return NULL; - *shared = reinterpret_cast(p)[0]; - *non_shared = reinterpret_cast(p)[1]; - *value_length = reinterpret_cast(p)[2]; - if ((*shared | *non_shared | *value_length) < 128) { - // Fast path: all three values are encoded in one byte each - p += 3; - } else { - if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; - if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; - if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; - } - - if (static_cast(limit - p) < (*non_shared + *value_length)) { - return NULL; - } - return p; -} - -class Block::Iter : public Iterator { - private: - const Comparator* const comparator_; - const char* const data_; // underlying block contents - uint32_t const restarts_; // Offset of restart array (list of fixed32) - uint32_t const num_restarts_; // Number of uint32_t entries in restart array - - // current_ is offset in data_ of current entry. >= restarts_ if !Valid - uint32_t current_; - uint32_t restart_index_; // Index of restart block in which current_ falls - std::string key_; - Slice value_; - Status status_; - - inline int Compare(const Slice& a, const Slice& b) const { - return comparator_->Compare(a, b); - } - - // Return the offset in data_ just past the end of the current entry. - inline uint32_t NextEntryOffset() const { - return (value_.data() + value_.size()) - data_; - } - - uint32_t GetRestartPoint(uint32_t index) { - assert(index < num_restarts_); - return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); - } - - void SeekToRestartPoint(uint32_t index) { - key_.clear(); - restart_index_ = index; - // current_ will be fixed by ParseNextKey(); - - // ParseNextKey() starts at the end of value_, so set value_ accordingly - uint32_t offset = GetRestartPoint(index); - value_ = Slice(data_ + offset, 0); - } - - public: - Iter(const Comparator* comparator, - const char* data, - uint32_t restarts, - uint32_t num_restarts) - : comparator_(comparator), - data_(data), - restarts_(restarts), - num_restarts_(num_restarts), - current_(restarts_), - restart_index_(num_restarts_) { - assert(num_restarts_ > 0); - } - - virtual bool Valid() const { return current_ < restarts_; } - virtual Status status() const { return status_; } - virtual Slice key() const { - assert(Valid()); - return key_; - } - virtual Slice value() const { - assert(Valid()); - return value_; - } - - virtual void Next() { - assert(Valid()); - ParseNextKey(); - } - - virtual void Prev() { - assert(Valid()); - - // Scan backwards to a restart point before current_ - const uint32_t original = current_; - while (GetRestartPoint(restart_index_) >= original) { - if (restart_index_ == 0) { - // No more entries - current_ = restarts_; - restart_index_ = num_restarts_; - return; - } - restart_index_--; - } - - SeekToRestartPoint(restart_index_); - do { - // Loop until end of current entry hits the start of original entry - } while (ParseNextKey() && NextEntryOffset() < original); - } - - virtual void Seek(const Slice& target) { - // Binary search in restart array to find the last restart point - // with a key < target - uint32_t left = 0; - uint32_t right = num_restarts_ - 1; - while (left < right) { - uint32_t mid = (left + right + 1) / 2; - uint32_t region_offset = GetRestartPoint(mid); - uint32_t shared, non_shared, value_length; - const char* key_ptr = DecodeEntry(data_ + region_offset, - data_ + restarts_, - &shared, &non_shared, &value_length); - if (key_ptr == NULL || (shared != 0)) { - CorruptionError(); - return; - } - Slice mid_key(key_ptr, non_shared); - if (Compare(mid_key, target) < 0) { - // Key at "mid" is smaller than "target". Therefore all - // blocks before "mid" are uninteresting. - left = mid; - } else { - // Key at "mid" is >= "target". Therefore all blocks at or - // after "mid" are uninteresting. - right = mid - 1; - } - } - - // Linear search (within restart block) for first key >= target - SeekToRestartPoint(left); - while (true) { - if (!ParseNextKey()) { - return; - } - if (Compare(key_, target) >= 0) { - return; - } - } - } - - virtual void SeekToFirst() { - SeekToRestartPoint(0); - ParseNextKey(); - } - - virtual void SeekToLast() { - SeekToRestartPoint(num_restarts_ - 1); - while (ParseNextKey() && NextEntryOffset() < restarts_) { - // Keep skipping - } - } - - private: - void CorruptionError() { - current_ = restarts_; - restart_index_ = num_restarts_; - status_ = Status::Corruption("bad entry in block"); - key_.clear(); - value_.clear(); - } - - bool ParseNextKey() { - current_ = NextEntryOffset(); - const char* p = data_ + current_; - const char* limit = data_ + restarts_; // Restarts come right after data - if (p >= limit) { - // No more entries to return. Mark as invalid. - current_ = restarts_; - restart_index_ = num_restarts_; - return false; - } - - // Decode next entry - uint32_t shared, non_shared, value_length; - p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); - if (p == NULL || key_.size() < shared) { - CorruptionError(); - return false; - } else { - key_.resize(shared); - key_.append(p, non_shared); - value_ = Slice(p + non_shared, value_length); - while (restart_index_ + 1 < num_restarts_ && - GetRestartPoint(restart_index_ + 1) < current_) { - ++restart_index_; - } - return true; - } - } -}; - -Iterator* Block::NewIterator(const Comparator* cmp) { - if (size_ < sizeof(uint32_t)) { - return NewErrorIterator(Status::Corruption("bad block contents")); - } - const uint32_t num_restarts = NumRestarts(); - if (num_restarts == 0) { - return NewEmptyIterator(); - } else { - return new Iter(cmp, data_, restart_offset_, num_restarts); - } -} - -} // namespace leveldb diff --git a/src/leveldb/table/block.h b/src/leveldb/table/block.h deleted file mode 100644 index 2493eb9f9f..0000000000 --- a/src/leveldb/table/block.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ -#define STORAGE_LEVELDB_TABLE_BLOCK_H_ - -#include -#include -#include "leveldb/iterator.h" - -namespace leveldb { - -struct BlockContents; -class Comparator; - -class Block { - public: - // Initialize the block with the specified contents. - explicit Block(const BlockContents& contents); - - ~Block(); - - size_t size() const { return size_; } - Iterator* NewIterator(const Comparator* comparator); - - private: - uint32_t NumRestarts() const; - - const char* data_; - size_t size_; - uint32_t restart_offset_; // Offset in data_ of restart array - bool owned_; // Block owns data_[] - - // No copying allowed - Block(const Block&); - void operator=(const Block&); - - class Iter; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/src/leveldb/table/block_builder.cc b/src/leveldb/table/block_builder.cc deleted file mode 100644 index db660cd07c..0000000000 --- a/src/leveldb/table/block_builder.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// BlockBuilder generates blocks where keys are prefix-compressed: -// -// When we store a key, we drop the prefix shared with the previous -// string. This helps reduce the space requirement significantly. -// Furthermore, once every K keys, we do not apply the prefix -// compression and store the entire key. We call this a "restart -// point". The tail end of the block stores the offsets of all of the -// restart points, and can be used to do a binary search when looking -// for a particular key. Values are stored as-is (without compression) -// immediately following the corresponding key. -// -// An entry for a particular key-value pair has the form: -// shared_bytes: varint32 -// unshared_bytes: varint32 -// value_length: varint32 -// key_delta: char[unshared_bytes] -// value: char[value_length] -// shared_bytes == 0 for restart points. -// -// The trailer of the block has the form: -// restarts: uint32[num_restarts] -// num_restarts: uint32 -// restarts[i] contains the offset within the block of the ith restart point. - -#include "table/block_builder.h" - -#include -#include -#include "leveldb/comparator.h" -#include "leveldb/table_builder.h" -#include "util/coding.h" - -namespace leveldb { - -BlockBuilder::BlockBuilder(const Options* options) - : options_(options), - restarts_(), - counter_(0), - finished_(false) { - assert(options->block_restart_interval >= 1); - restarts_.push_back(0); // First restart point is at offset 0 -} - -void BlockBuilder::Reset() { - buffer_.clear(); - restarts_.clear(); - restarts_.push_back(0); // First restart point is at offset 0 - counter_ = 0; - finished_ = false; - last_key_.clear(); -} - -size_t BlockBuilder::CurrentSizeEstimate() const { - return (buffer_.size() + // Raw data buffer - restarts_.size() * sizeof(uint32_t) + // Restart array - sizeof(uint32_t)); // Restart array length -} - -Slice BlockBuilder::Finish() { - // Append restart array - for (size_t i = 0; i < restarts_.size(); i++) { - PutFixed32(&buffer_, restarts_[i]); - } - PutFixed32(&buffer_, restarts_.size()); - finished_ = true; - return Slice(buffer_); -} - -void BlockBuilder::Add(const Slice& key, const Slice& value) { - Slice last_key_piece(last_key_); - assert(!finished_); - assert(counter_ <= options_->block_restart_interval); - assert(buffer_.empty() // No values yet? - || options_->comparator->Compare(key, last_key_piece) > 0); - size_t shared = 0; - if (counter_ < options_->block_restart_interval) { - // See how much sharing to do with previous string - const size_t min_length = std::min(last_key_piece.size(), key.size()); - while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { - shared++; - } - } else { - // Restart compression - restarts_.push_back(buffer_.size()); - counter_ = 0; - } - const size_t non_shared = key.size() - shared; - - // Add "" to buffer_ - PutVarint32(&buffer_, shared); - PutVarint32(&buffer_, non_shared); - PutVarint32(&buffer_, value.size()); - - // Add string delta to buffer_ followed by value - buffer_.append(key.data() + shared, non_shared); - buffer_.append(value.data(), value.size()); - - // Update state - last_key_.resize(shared); - last_key_.append(key.data() + shared, non_shared); - assert(Slice(last_key_) == key); - counter_++; -} - -} // namespace leveldb diff --git a/src/leveldb/table/block_builder.h b/src/leveldb/table/block_builder.h deleted file mode 100644 index 4fbcb33972..0000000000 --- a/src/leveldb/table/block_builder.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ -#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ - -#include - -#include -#include "leveldb/slice.h" - -namespace leveldb { - -struct Options; - -class BlockBuilder { - public: - explicit BlockBuilder(const Options* options); - - // Reset the contents as if the BlockBuilder was just constructed. - void Reset(); - - // REQUIRES: Finish() has not been called since the last call to Reset(). - // REQUIRES: key is larger than any previously added key - void Add(const Slice& key, const Slice& value); - - // Finish building the block and return a slice that refers to the - // block contents. The returned slice will remain valid for the - // lifetime of this builder or until Reset() is called. - Slice Finish(); - - // Returns an estimate of the current (uncompressed) size of the block - // we are building. - size_t CurrentSizeEstimate() const; - - // Return true iff no entries have been added since the last Reset() - bool empty() const { - return buffer_.empty(); - } - - private: - const Options* options_; - std::string buffer_; // Destination buffer - std::vector restarts_; // Restart points - int counter_; // Number of entries emitted since restart - bool finished_; // Has Finish() been called? - std::string last_key_; - - // No copying allowed - BlockBuilder(const BlockBuilder&); - void operator=(const BlockBuilder&); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/src/leveldb/table/filter_block.cc b/src/leveldb/table/filter_block.cc deleted file mode 100644 index 203e15c8bc..0000000000 --- a/src/leveldb/table/filter_block.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/filter_block.h" - -#include "leveldb/filter_policy.h" -#include "util/coding.h" - -namespace leveldb { - -// See doc/table_format.txt for an explanation of the filter block format. - -// Generate new filter every 2KB of data -static const size_t kFilterBaseLg = 11; -static const size_t kFilterBase = 1 << kFilterBaseLg; - -FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) - : policy_(policy) { -} - -void FilterBlockBuilder::StartBlock(uint64_t block_offset) { - uint64_t filter_index = (block_offset / kFilterBase); - assert(filter_index >= filter_offsets_.size()); - while (filter_index > filter_offsets_.size()) { - GenerateFilter(); - } -} - -void FilterBlockBuilder::AddKey(const Slice& key) { - Slice k = key; - start_.push_back(keys_.size()); - keys_.append(k.data(), k.size()); -} - -Slice FilterBlockBuilder::Finish() { - if (!start_.empty()) { - GenerateFilter(); - } - - // Append array of per-filter offsets - const uint32_t array_offset = result_.size(); - for (size_t i = 0; i < filter_offsets_.size(); i++) { - PutFixed32(&result_, filter_offsets_[i]); - } - - PutFixed32(&result_, array_offset); - result_.push_back(kFilterBaseLg); // Save encoding parameter in result - return Slice(result_); -} - -void FilterBlockBuilder::GenerateFilter() { - const size_t num_keys = start_.size(); - if (num_keys == 0) { - // Fast path if there are no keys for this filter - filter_offsets_.push_back(result_.size()); - return; - } - - // Make list of keys from flattened key structure - start_.push_back(keys_.size()); // Simplify length computation - tmp_keys_.resize(num_keys); - for (size_t i = 0; i < num_keys; i++) { - const char* base = keys_.data() + start_[i]; - size_t length = start_[i+1] - start_[i]; - tmp_keys_[i] = Slice(base, length); - } - - // Generate filter for current set of keys and append to result_. - filter_offsets_.push_back(result_.size()); - policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_); - - tmp_keys_.clear(); - keys_.clear(); - start_.clear(); -} - -FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, - const Slice& contents) - : policy_(policy), - data_(NULL), - offset_(NULL), - num_(0), - base_lg_(0) { - size_t n = contents.size(); - if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array - base_lg_ = contents[n-1]; - uint32_t last_word = DecodeFixed32(contents.data() + n - 5); - if (last_word > n - 5) return; - data_ = contents.data(); - offset_ = data_ + last_word; - num_ = (n - 5 - last_word) / 4; -} - -bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { - uint64_t index = block_offset >> base_lg_; - if (index < num_) { - uint32_t start = DecodeFixed32(offset_ + index*4); - uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); - if (start <= limit && limit <= (offset_ - data_)) { - Slice filter = Slice(data_ + start, limit - start); - return policy_->KeyMayMatch(key, filter); - } else if (start == limit) { - // Empty filters do not match any keys - return false; - } - } - return true; // Errors are treated as potential matches -} - -} diff --git a/src/leveldb/table/filter_block.h b/src/leveldb/table/filter_block.h deleted file mode 100644 index c67d010bd1..0000000000 --- a/src/leveldb/table/filter_block.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A filter block is stored near the end of a Table file. It contains -// filters (e.g., bloom filters) for all data blocks in the table combined -// into a single filter block. - -#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ -#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ - -#include -#include -#include -#include -#include "leveldb/slice.h" -#include "util/hash.h" - -namespace leveldb { - -class FilterPolicy; - -// A FilterBlockBuilder is used to construct all of the filters for a -// particular Table. It generates a single string which is stored as -// a special block in the Table. -// -// The sequence of calls to FilterBlockBuilder must match the regexp: -// (StartBlock AddKey*)* Finish -class FilterBlockBuilder { - public: - explicit FilterBlockBuilder(const FilterPolicy*); - - void StartBlock(uint64_t block_offset); - void AddKey(const Slice& key); - Slice Finish(); - - private: - void GenerateFilter(); - - const FilterPolicy* policy_; - std::string keys_; // Flattened key contents - std::vector start_; // Starting index in keys_ of each key - std::string result_; // Filter data computed so far - std::vector tmp_keys_; // policy_->CreateFilter() argument - std::vector filter_offsets_; - - // No copying allowed - FilterBlockBuilder(const FilterBlockBuilder&); - void operator=(const FilterBlockBuilder&); -}; - -class FilterBlockReader { - public: - // REQUIRES: "contents" and *policy must stay live while *this is live. - FilterBlockReader(const FilterPolicy* policy, const Slice& contents); - bool KeyMayMatch(uint64_t block_offset, const Slice& key); - - private: - const FilterPolicy* policy_; - const char* data_; // Pointer to filter data (at block-start) - const char* offset_; // Pointer to beginning of offset array (at block-end) - size_t num_; // Number of entries in offset array - size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) -}; - -} - -#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/src/leveldb/table/filter_block_test.cc b/src/leveldb/table/filter_block_test.cc deleted file mode 100644 index 8c4a4741f2..0000000000 --- a/src/leveldb/table/filter_block_test.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/filter_block.h" - -#include "leveldb/filter_policy.h" -#include "util/coding.h" -#include "util/hash.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -// For testing: emit an array with one hash value per key -class TestHashFilter : public FilterPolicy { - public: - virtual const char* Name() const { - return "TestHashFilter"; - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - for (int i = 0; i < n; i++) { - uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); - PutFixed32(dst, h); - } - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { - uint32_t h = Hash(key.data(), key.size(), 1); - for (size_t i = 0; i + 4 <= filter.size(); i += 4) { - if (h == DecodeFixed32(filter.data() + i)) { - return true; - } - } - return false; - } -}; - -class FilterBlockTest { - public: - TestHashFilter policy_; -}; - -TEST(FilterBlockTest, EmptyBuilder) { - FilterBlockBuilder builder(&policy_); - Slice block = builder.Finish(); - ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); - FilterBlockReader reader(&policy_, block); - ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); -} - -TEST(FilterBlockTest, SingleChunk) { - FilterBlockBuilder builder(&policy_); - builder.StartBlock(100); - builder.AddKey("foo"); - builder.AddKey("bar"); - builder.AddKey("box"); - builder.StartBlock(200); - builder.AddKey("box"); - builder.StartBlock(300); - builder.AddKey("hello"); - Slice block = builder.Finish(); - FilterBlockReader reader(&policy_, block); - ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); - ASSERT_TRUE(reader.KeyMayMatch(100, "box")); - ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); - ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); - ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); -} - -TEST(FilterBlockTest, MultiChunk) { - FilterBlockBuilder builder(&policy_); - - // First filter - builder.StartBlock(0); - builder.AddKey("foo"); - builder.StartBlock(2000); - builder.AddKey("bar"); - - // Second filter - builder.StartBlock(3100); - builder.AddKey("box"); - - // Third filter is empty - - // Last filter - builder.StartBlock(9000); - builder.AddKey("box"); - builder.AddKey("hello"); - - Slice block = builder.Finish(); - FilterBlockReader reader(&policy_, block); - - // Check first filter - ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); - ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); - - // Check second filter - ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); - - // Check third filter (empty) - ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); - ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); - - // Check last filter - ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); - ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); - ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); - ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/table/format.cc b/src/leveldb/table/format.cc deleted file mode 100644 index aa63144c9e..0000000000 --- a/src/leveldb/table/format.cc +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/format.h" - -#include "leveldb/env.h" -#include "port/port.h" -#include "table/block.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { - -void BlockHandle::EncodeTo(std::string* dst) const { - // Sanity check that all fields have been set - assert(offset_ != ~static_cast(0)); - assert(size_ != ~static_cast(0)); - PutVarint64(dst, offset_); - PutVarint64(dst, size_); -} - -Status BlockHandle::DecodeFrom(Slice* input) { - if (GetVarint64(input, &offset_) && - GetVarint64(input, &size_)) { - return Status::OK(); - } else { - return Status::Corruption("bad block handle"); - } -} - -void Footer::EncodeTo(std::string* dst) const { -#ifndef NDEBUG - const size_t original_size = dst->size(); -#endif - metaindex_handle_.EncodeTo(dst); - index_handle_.EncodeTo(dst); - dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding - PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); - PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); - assert(dst->size() == original_size + kEncodedLength); -} - -Status Footer::DecodeFrom(Slice* input) { - const char* magic_ptr = input->data() + kEncodedLength - 8; - const uint32_t magic_lo = DecodeFixed32(magic_ptr); - const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); - const uint64_t magic = ((static_cast(magic_hi) << 32) | - (static_cast(magic_lo))); - if (magic != kTableMagicNumber) { - return Status::Corruption("not an sstable (bad magic number)"); - } - - Status result = metaindex_handle_.DecodeFrom(input); - if (result.ok()) { - result = index_handle_.DecodeFrom(input); - } - if (result.ok()) { - // We skip over any leftover data (just padding for now) in "input" - const char* end = magic_ptr + 8; - *input = Slice(end, input->data() + input->size() - end); - } - return result; -} - -Status ReadBlock(RandomAccessFile* file, - const ReadOptions& options, - const BlockHandle& handle, - BlockContents* result) { - result->data = Slice(); - result->cachable = false; - result->heap_allocated = false; - - // Read the block contents as well as the type/crc footer. - // See table_builder.cc for the code that built this structure. - size_t n = static_cast(handle.size()); - char* buf = new char[n + kBlockTrailerSize]; - Slice contents; - Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); - if (!s.ok()) { - delete[] buf; - return s; - } - if (contents.size() != n + kBlockTrailerSize) { - delete[] buf; - return Status::Corruption("truncated block read"); - } - - // Check the crc of the type and the block contents - const char* data = contents.data(); // Pointer to where Read put the data - if (options.verify_checksums) { - const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); - const uint32_t actual = crc32c::Value(data, n + 1); - if (actual != crc) { - delete[] buf; - s = Status::Corruption("block checksum mismatch"); - return s; - } - } - - switch (data[n]) { - case kNoCompression: - if (data != buf) { - // File implementation gave us pointer to some other data. - // Use it directly under the assumption that it will be live - // while the file is open. - delete[] buf; - result->data = Slice(data, n); - result->heap_allocated = false; - result->cachable = false; // Do not double-cache - } else { - result->data = Slice(buf, n); - result->heap_allocated = true; - result->cachable = true; - } - - // Ok - break; - case kSnappyCompression: { - size_t ulength = 0; - if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { - delete[] buf; - return Status::Corruption("corrupted compressed block contents"); - } - char* ubuf = new char[ulength]; - if (!port::Snappy_Uncompress(data, n, ubuf)) { - delete[] buf; - delete[] ubuf; - return Status::Corruption("corrupted compressed block contents"); - } - delete[] buf; - result->data = Slice(ubuf, ulength); - result->heap_allocated = true; - result->cachable = true; - break; - } - default: - delete[] buf; - return Status::Corruption("bad block type"); - } - - return Status::OK(); -} - -} // namespace leveldb diff --git a/src/leveldb/table/format.h b/src/leveldb/table/format.h deleted file mode 100644 index 6c0b80c017..0000000000 --- a/src/leveldb/table/format.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ -#define STORAGE_LEVELDB_TABLE_FORMAT_H_ - -#include -#include -#include "leveldb/slice.h" -#include "leveldb/status.h" -#include "leveldb/table_builder.h" - -namespace leveldb { - -class Block; -class RandomAccessFile; -struct ReadOptions; - -// BlockHandle is a pointer to the extent of a file that stores a data -// block or a meta block. -class BlockHandle { - public: - BlockHandle(); - - // The offset of the block in the file. - uint64_t offset() const { return offset_; } - void set_offset(uint64_t offset) { offset_ = offset; } - - // The size of the stored block - uint64_t size() const { return size_; } - void set_size(uint64_t size) { size_ = size; } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(Slice* input); - - // Maximum encoding length of a BlockHandle - enum { kMaxEncodedLength = 10 + 10 }; - - private: - uint64_t offset_; - uint64_t size_; -}; - -// Footer encapsulates the fixed information stored at the tail -// end of every table file. -class Footer { - public: - Footer() { } - - // The block handle for the metaindex block of the table - const BlockHandle& metaindex_handle() const { return metaindex_handle_; } - void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } - - // The block handle for the index block of the table - const BlockHandle& index_handle() const { - return index_handle_; - } - void set_index_handle(const BlockHandle& h) { - index_handle_ = h; - } - - void EncodeTo(std::string* dst) const; - Status DecodeFrom(Slice* input); - - // Encoded length of a Footer. Note that the serialization of a - // Footer will always occupy exactly this many bytes. It consists - // of two block handles and a magic number. - enum { - kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 - }; - - private: - BlockHandle metaindex_handle_; - BlockHandle index_handle_; -}; - -// kTableMagicNumber was picked by running -// echo http://code.google.com/p/leveldb/ | sha1sum -// and taking the leading 64 bits. -static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; - -// 1-byte type + 32-bit crc -static const size_t kBlockTrailerSize = 5; - -struct BlockContents { - Slice data; // Actual contents of data - bool cachable; // True iff data can be cached - bool heap_allocated; // True iff caller should delete[] data.data() -}; - -// Read the block identified by "handle" from "file". On failure -// return non-OK. On success fill *result and return OK. -extern Status ReadBlock(RandomAccessFile* file, - const ReadOptions& options, - const BlockHandle& handle, - BlockContents* result); - -// Implementation details follow. Clients should ignore, - -inline BlockHandle::BlockHandle() - : offset_(~static_cast(0)), - size_(~static_cast(0)) { -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/src/leveldb/table/iterator.cc b/src/leveldb/table/iterator.cc deleted file mode 100644 index 3d1c87fdec..0000000000 --- a/src/leveldb/table/iterator.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/iterator.h" - -namespace leveldb { - -Iterator::Iterator() { - cleanup_.function = NULL; - cleanup_.next = NULL; -} - -Iterator::~Iterator() { - if (cleanup_.function != NULL) { - (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); - for (Cleanup* c = cleanup_.next; c != NULL; ) { - (*c->function)(c->arg1, c->arg2); - Cleanup* next = c->next; - delete c; - c = next; - } - } -} - -void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { - assert(func != NULL); - Cleanup* c; - if (cleanup_.function == NULL) { - c = &cleanup_; - } else { - c = new Cleanup; - c->next = cleanup_.next; - cleanup_.next = c; - } - c->function = func; - c->arg1 = arg1; - c->arg2 = arg2; -} - -namespace { -class EmptyIterator : public Iterator { - public: - EmptyIterator(const Status& s) : status_(s) { } - virtual bool Valid() const { return false; } - virtual void Seek(const Slice& target) { } - virtual void SeekToFirst() { } - virtual void SeekToLast() { } - virtual void Next() { assert(false); } - virtual void Prev() { assert(false); } - Slice key() const { assert(false); return Slice(); } - Slice value() const { assert(false); return Slice(); } - virtual Status status() const { return status_; } - private: - Status status_; -}; -} // namespace - -Iterator* NewEmptyIterator() { - return new EmptyIterator(Status::OK()); -} - -Iterator* NewErrorIterator(const Status& status) { - return new EmptyIterator(status); -} - -} // namespace leveldb diff --git a/src/leveldb/table/iterator_wrapper.h b/src/leveldb/table/iterator_wrapper.h deleted file mode 100644 index 9e16b3dbed..0000000000 --- a/src/leveldb/table/iterator_wrapper.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ -#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ - -namespace leveldb { - -// A internal wrapper class with an interface similar to Iterator that -// caches the valid() and key() results for an underlying iterator. -// This can help avoid virtual function calls and also gives better -// cache locality. -class IteratorWrapper { - public: - IteratorWrapper(): iter_(NULL), valid_(false) { } - explicit IteratorWrapper(Iterator* iter): iter_(NULL) { - Set(iter); - } - ~IteratorWrapper() { delete iter_; } - Iterator* iter() const { return iter_; } - - // Takes ownership of "iter" and will delete it when destroyed, or - // when Set() is invoked again. - void Set(Iterator* iter) { - delete iter_; - iter_ = iter; - if (iter_ == NULL) { - valid_ = false; - } else { - Update(); - } - } - - - // Iterator interface methods - bool Valid() const { return valid_; } - Slice key() const { assert(Valid()); return key_; } - Slice value() const { assert(Valid()); return iter_->value(); } - // Methods below require iter() != NULL - Status status() const { assert(iter_); return iter_->status(); } - void Next() { assert(iter_); iter_->Next(); Update(); } - void Prev() { assert(iter_); iter_->Prev(); Update(); } - void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } - void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } - void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } - - private: - void Update() { - valid_ = iter_->Valid(); - if (valid_) { - key_ = iter_->key(); - } - } - - Iterator* iter_; - bool valid_; - Slice key_; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/src/leveldb/table/merger.cc b/src/leveldb/table/merger.cc deleted file mode 100644 index 2dde4dc21f..0000000000 --- a/src/leveldb/table/merger.cc +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/merger.h" - -#include "leveldb/comparator.h" -#include "leveldb/iterator.h" -#include "table/iterator_wrapper.h" - -namespace leveldb { - -namespace { -class MergingIterator : public Iterator { - public: - MergingIterator(const Comparator* comparator, Iterator** children, int n) - : comparator_(comparator), - children_(new IteratorWrapper[n]), - n_(n), - current_(NULL), - direction_(kForward) { - for (int i = 0; i < n; i++) { - children_[i].Set(children[i]); - } - } - - virtual ~MergingIterator() { - delete[] children_; - } - - virtual bool Valid() const { - return (current_ != NULL); - } - - virtual void SeekToFirst() { - for (int i = 0; i < n_; i++) { - children_[i].SeekToFirst(); - } - FindSmallest(); - direction_ = kForward; - } - - virtual void SeekToLast() { - for (int i = 0; i < n_; i++) { - children_[i].SeekToLast(); - } - FindLargest(); - direction_ = kReverse; - } - - virtual void Seek(const Slice& target) { - for (int i = 0; i < n_; i++) { - children_[i].Seek(target); - } - FindSmallest(); - direction_ = kForward; - } - - virtual void Next() { - assert(Valid()); - - // Ensure that all children are positioned after key(). - // If we are moving in the forward direction, it is already - // true for all of the non-current_ children since current_ is - // the smallest child and key() == current_->key(). Otherwise, - // we explicitly position the non-current_ children. - if (direction_ != kForward) { - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child != current_) { - child->Seek(key()); - if (child->Valid() && - comparator_->Compare(key(), child->key()) == 0) { - child->Next(); - } - } - } - direction_ = kForward; - } - - current_->Next(); - FindSmallest(); - } - - virtual void Prev() { - assert(Valid()); - - // Ensure that all children are positioned before key(). - // If we are moving in the reverse direction, it is already - // true for all of the non-current_ children since current_ is - // the largest child and key() == current_->key(). Otherwise, - // we explicitly position the non-current_ children. - if (direction_ != kReverse) { - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child != current_) { - child->Seek(key()); - if (child->Valid()) { - // Child is at first entry >= key(). Step back one to be < key() - child->Prev(); - } else { - // Child has no entries >= key(). Position at last entry. - child->SeekToLast(); - } - } - } - direction_ = kReverse; - } - - current_->Prev(); - FindLargest(); - } - - virtual Slice key() const { - assert(Valid()); - return current_->key(); - } - - virtual Slice value() const { - assert(Valid()); - return current_->value(); - } - - virtual Status status() const { - Status status; - for (int i = 0; i < n_; i++) { - status = children_[i].status(); - if (!status.ok()) { - break; - } - } - return status; - } - - private: - void FindSmallest(); - void FindLargest(); - - // We might want to use a heap in case there are lots of children. - // For now we use a simple array since we expect a very small number - // of children in leveldb. - const Comparator* comparator_; - IteratorWrapper* children_; - int n_; - IteratorWrapper* current_; - - // Which direction is the iterator moving? - enum Direction { - kForward, - kReverse - }; - Direction direction_; -}; - -void MergingIterator::FindSmallest() { - IteratorWrapper* smallest = NULL; - for (int i = 0; i < n_; i++) { - IteratorWrapper* child = &children_[i]; - if (child->Valid()) { - if (smallest == NULL) { - smallest = child; - } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { - smallest = child; - } - } - } - current_ = smallest; -} - -void MergingIterator::FindLargest() { - IteratorWrapper* largest = NULL; - for (int i = n_-1; i >= 0; i--) { - IteratorWrapper* child = &children_[i]; - if (child->Valid()) { - if (largest == NULL) { - largest = child; - } else if (comparator_->Compare(child->key(), largest->key()) > 0) { - largest = child; - } - } - } - current_ = largest; -} -} // namespace - -Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { - assert(n >= 0); - if (n == 0) { - return NewEmptyIterator(); - } else if (n == 1) { - return list[0]; - } else { - return new MergingIterator(cmp, list, n); - } -} - -} // namespace leveldb diff --git a/src/leveldb/table/merger.h b/src/leveldb/table/merger.h deleted file mode 100644 index 91ddd80faa..0000000000 --- a/src/leveldb/table/merger.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ -#define STORAGE_LEVELDB_TABLE_MERGER_H_ - -namespace leveldb { - -class Comparator; -class Iterator; - -// Return an iterator that provided the union of the data in -// children[0,n-1]. Takes ownership of the child iterators and -// will delete them when the result iterator is deleted. -// -// The result does no duplicate suppression. I.e., if a particular -// key is present in K child iterators, it will be yielded K times. -// -// REQUIRES: n >= 0 -extern Iterator* NewMergingIterator( - const Comparator* comparator, Iterator** children, int n); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/src/leveldb/table/table.cc b/src/leveldb/table/table.cc deleted file mode 100644 index dff8a82590..0000000000 --- a/src/leveldb/table/table.cc +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table.h" - -#include "leveldb/cache.h" -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/options.h" -#include "table/block.h" -#include "table/filter_block.h" -#include "table/format.h" -#include "table/two_level_iterator.h" -#include "util/coding.h" - -namespace leveldb { - -struct Table::Rep { - ~Rep() { - delete filter; - delete [] filter_data; - delete index_block; - } - - Options options; - Status status; - RandomAccessFile* file; - uint64_t cache_id; - FilterBlockReader* filter; - const char* filter_data; - - BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer - Block* index_block; -}; - -Status Table::Open(const Options& options, - RandomAccessFile* file, - uint64_t size, - Table** table) { - *table = NULL; - if (size < Footer::kEncodedLength) { - return Status::Corruption("file is too short to be an sstable"); - } - - char footer_space[Footer::kEncodedLength]; - Slice footer_input; - Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, - &footer_input, footer_space); - if (!s.ok()) return s; - - Footer footer; - s = footer.DecodeFrom(&footer_input); - if (!s.ok()) return s; - - // Read the index block - BlockContents contents; - Block* index_block = NULL; - if (s.ok()) { - ReadOptions opt; - if (options.paranoid_checks) { - opt.verify_checksums = true; - } - s = ReadBlock(file, opt, footer.index_handle(), &contents); - if (s.ok()) { - index_block = new Block(contents); - } - } - - if (s.ok()) { - // We've successfully read the footer and the index block: we're - // ready to serve requests. - Rep* rep = new Table::Rep; - rep->options = options; - rep->file = file; - rep->metaindex_handle = footer.metaindex_handle(); - rep->index_block = index_block; - rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); - rep->filter_data = NULL; - rep->filter = NULL; - *table = new Table(rep); - (*table)->ReadMeta(footer); - } else { - if (index_block) delete index_block; - } - - return s; -} - -void Table::ReadMeta(const Footer& footer) { - if (rep_->options.filter_policy == NULL) { - return; // Do not need any metadata - } - - // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates - // it is an empty block. - ReadOptions opt; - if (rep_->options.paranoid_checks) { - opt.verify_checksums = true; - } - BlockContents contents; - if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { - // Do not propagate errors since meta info is not needed for operation - return; - } - Block* meta = new Block(contents); - - Iterator* iter = meta->NewIterator(BytewiseComparator()); - std::string key = "filter."; - key.append(rep_->options.filter_policy->Name()); - iter->Seek(key); - if (iter->Valid() && iter->key() == Slice(key)) { - ReadFilter(iter->value()); - } - delete iter; - delete meta; -} - -void Table::ReadFilter(const Slice& filter_handle_value) { - Slice v = filter_handle_value; - BlockHandle filter_handle; - if (!filter_handle.DecodeFrom(&v).ok()) { - return; - } - - // We might want to unify with ReadBlock() if we start - // requiring checksum verification in Table::Open. - ReadOptions opt; - if (rep_->options.paranoid_checks) { - opt.verify_checksums = true; - } - BlockContents block; - if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { - return; - } - if (block.heap_allocated) { - rep_->filter_data = block.data.data(); // Will need to delete later - } - rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); -} - -Table::~Table() { - delete rep_; -} - -static void DeleteBlock(void* arg, void* ignored) { - delete reinterpret_cast(arg); -} - -static void DeleteCachedBlock(const Slice& key, void* value) { - Block* block = reinterpret_cast(value); - delete block; -} - -static void ReleaseBlock(void* arg, void* h) { - Cache* cache = reinterpret_cast(arg); - Cache::Handle* handle = reinterpret_cast(h); - cache->Release(handle); -} - -// Convert an index iterator value (i.e., an encoded BlockHandle) -// into an iterator over the contents of the corresponding block. -Iterator* Table::BlockReader(void* arg, - const ReadOptions& options, - const Slice& index_value) { - Table* table = reinterpret_cast(arg); - Cache* block_cache = table->rep_->options.block_cache; - Block* block = NULL; - Cache::Handle* cache_handle = NULL; - - BlockHandle handle; - Slice input = index_value; - Status s = handle.DecodeFrom(&input); - // We intentionally allow extra stuff in index_value so that we - // can add more features in the future. - - if (s.ok()) { - BlockContents contents; - if (block_cache != NULL) { - char cache_key_buffer[16]; - EncodeFixed64(cache_key_buffer, table->rep_->cache_id); - EncodeFixed64(cache_key_buffer+8, handle.offset()); - Slice key(cache_key_buffer, sizeof(cache_key_buffer)); - cache_handle = block_cache->Lookup(key); - if (cache_handle != NULL) { - block = reinterpret_cast(block_cache->Value(cache_handle)); - } else { - s = ReadBlock(table->rep_->file, options, handle, &contents); - if (s.ok()) { - block = new Block(contents); - if (contents.cachable && options.fill_cache) { - cache_handle = block_cache->Insert( - key, block, block->size(), &DeleteCachedBlock); - } - } - } - } else { - s = ReadBlock(table->rep_->file, options, handle, &contents); - if (s.ok()) { - block = new Block(contents); - } - } - } - - Iterator* iter; - if (block != NULL) { - iter = block->NewIterator(table->rep_->options.comparator); - if (cache_handle == NULL) { - iter->RegisterCleanup(&DeleteBlock, block, NULL); - } else { - iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); - } - } else { - iter = NewErrorIterator(s); - } - return iter; -} - -Iterator* Table::NewIterator(const ReadOptions& options) const { - return NewTwoLevelIterator( - rep_->index_block->NewIterator(rep_->options.comparator), - &Table::BlockReader, const_cast(this), options); -} - -Status Table::InternalGet(const ReadOptions& options, const Slice& k, - void* arg, - void (*saver)(void*, const Slice&, const Slice&)) { - Status s; - Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); - iiter->Seek(k); - if (iiter->Valid()) { - Slice handle_value = iiter->value(); - FilterBlockReader* filter = rep_->filter; - BlockHandle handle; - if (filter != NULL && - handle.DecodeFrom(&handle_value).ok() && - !filter->KeyMayMatch(handle.offset(), k)) { - // Not found - } else { - Iterator* block_iter = BlockReader(this, options, iiter->value()); - block_iter->Seek(k); - if (block_iter->Valid()) { - (*saver)(arg, block_iter->key(), block_iter->value()); - } - s = block_iter->status(); - delete block_iter; - } - } - if (s.ok()) { - s = iiter->status(); - } - delete iiter; - return s; -} - - -uint64_t Table::ApproximateOffsetOf(const Slice& key) const { - Iterator* index_iter = - rep_->index_block->NewIterator(rep_->options.comparator); - index_iter->Seek(key); - uint64_t result; - if (index_iter->Valid()) { - BlockHandle handle; - Slice input = index_iter->value(); - Status s = handle.DecodeFrom(&input); - if (s.ok()) { - result = handle.offset(); - } else { - // Strange: we can't decode the block handle in the index block. - // We'll just return the offset of the metaindex block, which is - // close to the whole file size for this case. - result = rep_->metaindex_handle.offset(); - } - } else { - // key is past the last key in the file. Approximate the offset - // by returning the offset of the metaindex block (which is - // right near the end of the file). - result = rep_->metaindex_handle.offset(); - } - delete index_iter; - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/table/table_builder.cc b/src/leveldb/table/table_builder.cc deleted file mode 100644 index 62002c84f2..0000000000 --- a/src/leveldb/table/table_builder.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table_builder.h" - -#include -#include "leveldb/comparator.h" -#include "leveldb/env.h" -#include "leveldb/filter_policy.h" -#include "leveldb/options.h" -#include "table/block_builder.h" -#include "table/filter_block.h" -#include "table/format.h" -#include "util/coding.h" -#include "util/crc32c.h" - -namespace leveldb { - -struct TableBuilder::Rep { - Options options; - Options index_block_options; - WritableFile* file; - uint64_t offset; - Status status; - BlockBuilder data_block; - BlockBuilder index_block; - std::string last_key; - int64_t num_entries; - bool closed; // Either Finish() or Abandon() has been called. - FilterBlockBuilder* filter_block; - - // We do not emit the index entry for a block until we have seen the - // first key for the next data block. This allows us to use shorter - // keys in the index block. For example, consider a block boundary - // between the keys "the quick brown fox" and "the who". We can use - // "the r" as the key for the index block entry since it is >= all - // entries in the first block and < all entries in subsequent - // blocks. - // - // Invariant: r->pending_index_entry is true only if data_block is empty. - bool pending_index_entry; - BlockHandle pending_handle; // Handle to add to index block - - std::string compressed_output; - - Rep(const Options& opt, WritableFile* f) - : options(opt), - index_block_options(opt), - file(f), - offset(0), - data_block(&options), - index_block(&index_block_options), - num_entries(0), - closed(false), - filter_block(opt.filter_policy == NULL ? NULL - : new FilterBlockBuilder(opt.filter_policy)), - pending_index_entry(false) { - index_block_options.block_restart_interval = 1; - } -}; - -TableBuilder::TableBuilder(const Options& options, WritableFile* file) - : rep_(new Rep(options, file)) { - if (rep_->filter_block != NULL) { - rep_->filter_block->StartBlock(0); - } -} - -TableBuilder::~TableBuilder() { - assert(rep_->closed); // Catch errors where caller forgot to call Finish() - delete rep_->filter_block; - delete rep_; -} - -Status TableBuilder::ChangeOptions(const Options& options) { - // Note: if more fields are added to Options, update - // this function to catch changes that should not be allowed to - // change in the middle of building a Table. - if (options.comparator != rep_->options.comparator) { - return Status::InvalidArgument("changing comparator while building table"); - } - - // Note that any live BlockBuilders point to rep_->options and therefore - // will automatically pick up the updated options. - rep_->options = options; - rep_->index_block_options = options; - rep_->index_block_options.block_restart_interval = 1; - return Status::OK(); -} - -void TableBuilder::Add(const Slice& key, const Slice& value) { - Rep* r = rep_; - assert(!r->closed); - if (!ok()) return; - if (r->num_entries > 0) { - assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); - } - - if (r->pending_index_entry) { - assert(r->data_block.empty()); - r->options.comparator->FindShortestSeparator(&r->last_key, key); - std::string handle_encoding; - r->pending_handle.EncodeTo(&handle_encoding); - r->index_block.Add(r->last_key, Slice(handle_encoding)); - r->pending_index_entry = false; - } - - if (r->filter_block != NULL) { - r->filter_block->AddKey(key); - } - - r->last_key.assign(key.data(), key.size()); - r->num_entries++; - r->data_block.Add(key, value); - - const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); - if (estimated_block_size >= r->options.block_size) { - Flush(); - } -} - -void TableBuilder::Flush() { - Rep* r = rep_; - assert(!r->closed); - if (!ok()) return; - if (r->data_block.empty()) return; - assert(!r->pending_index_entry); - WriteBlock(&r->data_block, &r->pending_handle); - if (ok()) { - r->pending_index_entry = true; - r->status = r->file->Flush(); - } - if (r->filter_block != NULL) { - r->filter_block->StartBlock(r->offset); - } -} - -void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { - // File format contains a sequence of blocks where each block has: - // block_data: uint8[n] - // type: uint8 - // crc: uint32 - assert(ok()); - Rep* r = rep_; - Slice raw = block->Finish(); - - Slice block_contents; - CompressionType type = r->options.compression; - // TODO(postrelease): Support more compression options: zlib? - switch (type) { - case kNoCompression: - block_contents = raw; - break; - - case kSnappyCompression: { - std::string* compressed = &r->compressed_output; - if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && - compressed->size() < raw.size() - (raw.size() / 8u)) { - block_contents = *compressed; - } else { - // Snappy not supported, or compressed less than 12.5%, so just - // store uncompressed form - block_contents = raw; - type = kNoCompression; - } - break; - } - } - WriteRawBlock(block_contents, type, handle); - r->compressed_output.clear(); - block->Reset(); -} - -void TableBuilder::WriteRawBlock(const Slice& block_contents, - CompressionType type, - BlockHandle* handle) { - Rep* r = rep_; - handle->set_offset(r->offset); - handle->set_size(block_contents.size()); - r->status = r->file->Append(block_contents); - if (r->status.ok()) { - char trailer[kBlockTrailerSize]; - trailer[0] = type; - uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); - crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type - EncodeFixed32(trailer+1, crc32c::Mask(crc)); - r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); - if (r->status.ok()) { - r->offset += block_contents.size() + kBlockTrailerSize; - } - } -} - -Status TableBuilder::status() const { - return rep_->status; -} - -Status TableBuilder::Finish() { - Rep* r = rep_; - Flush(); - assert(!r->closed); - r->closed = true; - - BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; - - // Write filter block - if (ok() && r->filter_block != NULL) { - WriteRawBlock(r->filter_block->Finish(), kNoCompression, - &filter_block_handle); - } - - // Write metaindex block - if (ok()) { - BlockBuilder meta_index_block(&r->options); - if (r->filter_block != NULL) { - // Add mapping from "filter.Name" to location of filter data - std::string key = "filter."; - key.append(r->options.filter_policy->Name()); - std::string handle_encoding; - filter_block_handle.EncodeTo(&handle_encoding); - meta_index_block.Add(key, handle_encoding); - } - - // TODO(postrelease): Add stats and other meta blocks - WriteBlock(&meta_index_block, &metaindex_block_handle); - } - - // Write index block - if (ok()) { - if (r->pending_index_entry) { - r->options.comparator->FindShortSuccessor(&r->last_key); - std::string handle_encoding; - r->pending_handle.EncodeTo(&handle_encoding); - r->index_block.Add(r->last_key, Slice(handle_encoding)); - r->pending_index_entry = false; - } - WriteBlock(&r->index_block, &index_block_handle); - } - - // Write footer - if (ok()) { - Footer footer; - footer.set_metaindex_handle(metaindex_block_handle); - footer.set_index_handle(index_block_handle); - std::string footer_encoding; - footer.EncodeTo(&footer_encoding); - r->status = r->file->Append(footer_encoding); - if (r->status.ok()) { - r->offset += footer_encoding.size(); - } - } - return r->status; -} - -void TableBuilder::Abandon() { - Rep* r = rep_; - assert(!r->closed); - r->closed = true; -} - -uint64_t TableBuilder::NumEntries() const { - return rep_->num_entries; -} - -uint64_t TableBuilder::FileSize() const { - return rep_->offset; -} - -} // namespace leveldb diff --git a/src/leveldb/table/table_test.cc b/src/leveldb/table/table_test.cc deleted file mode 100644 index c723bf84cf..0000000000 --- a/src/leveldb/table/table_test.cc +++ /dev/null @@ -1,868 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/table.h" - -#include -#include -#include "db/dbformat.h" -#include "db/memtable.h" -#include "db/write_batch_internal.h" -#include "leveldb/db.h" -#include "leveldb/env.h" -#include "leveldb/iterator.h" -#include "leveldb/table_builder.h" -#include "table/block.h" -#include "table/block_builder.h" -#include "table/format.h" -#include "util/random.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -// Return reverse of "key". -// Used to test non-lexicographic comparators. -static std::string Reverse(const Slice& key) { - std::string str(key.ToString()); - std::string rev(""); - for (std::string::reverse_iterator rit = str.rbegin(); - rit != str.rend(); ++rit) { - rev.push_back(*rit); - } - return rev; -} - -namespace { -class ReverseKeyComparator : public Comparator { - public: - virtual const char* Name() const { - return "leveldb.ReverseBytewiseComparator"; - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); - } - - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const { - std::string s = Reverse(*start); - std::string l = Reverse(limit); - BytewiseComparator()->FindShortestSeparator(&s, l); - *start = Reverse(s); - } - - virtual void FindShortSuccessor(std::string* key) const { - std::string s = Reverse(*key); - BytewiseComparator()->FindShortSuccessor(&s); - *key = Reverse(s); - } -}; -} // namespace -static ReverseKeyComparator reverse_key_comparator; - -static void Increment(const Comparator* cmp, std::string* key) { - if (cmp == BytewiseComparator()) { - key->push_back('\0'); - } else { - assert(cmp == &reverse_key_comparator); - std::string rev = Reverse(*key); - rev.push_back('\0'); - *key = Reverse(rev); - } -} - -// An STL comparator that uses a Comparator -namespace { -struct STLLessThan { - const Comparator* cmp; - - STLLessThan() : cmp(BytewiseComparator()) { } - STLLessThan(const Comparator* c) : cmp(c) { } - bool operator()(const std::string& a, const std::string& b) const { - return cmp->Compare(Slice(a), Slice(b)) < 0; - } -}; -} // namespace - -class StringSink: public WritableFile { - public: - ~StringSink() { } - - const std::string& contents() const { return contents_; } - - virtual Status Close() { return Status::OK(); } - virtual Status Flush() { return Status::OK(); } - virtual Status Sync() { return Status::OK(); } - - virtual Status Append(const Slice& data) { - contents_.append(data.data(), data.size()); - return Status::OK(); - } - - private: - std::string contents_; -}; - - -class StringSource: public RandomAccessFile { - public: - StringSource(const Slice& contents) - : contents_(contents.data(), contents.size()) { - } - - virtual ~StringSource() { } - - uint64_t Size() const { return contents_.size(); } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - if (offset > contents_.size()) { - return Status::InvalidArgument("invalid Read offset"); - } - if (offset + n > contents_.size()) { - n = contents_.size() - offset; - } - memcpy(scratch, &contents_[offset], n); - *result = Slice(scratch, n); - return Status::OK(); - } - - private: - std::string contents_; -}; - -typedef std::map KVMap; - -// Helper class for tests to unify the interface between -// BlockBuilder/TableBuilder and Block/Table. -class Constructor { - public: - explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } - virtual ~Constructor() { } - - void Add(const std::string& key, const Slice& value) { - data_[key] = value.ToString(); - } - - // Finish constructing the data structure with all the keys that have - // been added so far. Returns the keys in sorted order in "*keys" - // and stores the key/value pairs in "*kvmap" - void Finish(const Options& options, - std::vector* keys, - KVMap* kvmap) { - *kvmap = data_; - keys->clear(); - for (KVMap::const_iterator it = data_.begin(); - it != data_.end(); - ++it) { - keys->push_back(it->first); - } - data_.clear(); - Status s = FinishImpl(options, *kvmap); - ASSERT_TRUE(s.ok()) << s.ToString(); - } - - // Construct the data structure from the data in "data" - virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; - - virtual Iterator* NewIterator() const = 0; - - virtual const KVMap& data() { return data_; } - - virtual DB* db() const { return NULL; } // Overridden in DBConstructor - - private: - KVMap data_; -}; - -class BlockConstructor: public Constructor { - public: - explicit BlockConstructor(const Comparator* cmp) - : Constructor(cmp), - comparator_(cmp), - block_(NULL) { } - ~BlockConstructor() { - delete block_; - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - delete block_; - block_ = NULL; - BlockBuilder builder(&options); - - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - builder.Add(it->first, it->second); - } - // Open the block - data_ = builder.Finish().ToString(); - BlockContents contents; - contents.data = data_; - contents.cachable = false; - contents.heap_allocated = false; - block_ = new Block(contents); - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return block_->NewIterator(comparator_); - } - - private: - const Comparator* comparator_; - std::string data_; - Block* block_; - - BlockConstructor(); -}; - -class TableConstructor: public Constructor { - public: - TableConstructor(const Comparator* cmp) - : Constructor(cmp), - source_(NULL), table_(NULL) { - } - ~TableConstructor() { - Reset(); - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - Reset(); - StringSink sink; - TableBuilder builder(options, &sink); - - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - builder.Add(it->first, it->second); - ASSERT_TRUE(builder.status().ok()); - } - Status s = builder.Finish(); - ASSERT_TRUE(s.ok()) << s.ToString(); - - ASSERT_EQ(sink.contents().size(), builder.FileSize()); - - // Open the table - source_ = new StringSource(sink.contents()); - Options table_options; - table_options.comparator = options.comparator; - return Table::Open(table_options, source_, sink.contents().size(), &table_); - } - - virtual Iterator* NewIterator() const { - return table_->NewIterator(ReadOptions()); - } - - uint64_t ApproximateOffsetOf(const Slice& key) const { - return table_->ApproximateOffsetOf(key); - } - - private: - void Reset() { - delete table_; - delete source_; - table_ = NULL; - source_ = NULL; - } - - StringSource* source_; - Table* table_; - - TableConstructor(); -}; - -// A helper class that converts internal format keys into user keys -class KeyConvertingIterator: public Iterator { - public: - explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } - virtual ~KeyConvertingIterator() { delete iter_; } - virtual bool Valid() const { return iter_->Valid(); } - virtual void Seek(const Slice& target) { - ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); - std::string encoded; - AppendInternalKey(&encoded, ikey); - iter_->Seek(encoded); - } - virtual void SeekToFirst() { iter_->SeekToFirst(); } - virtual void SeekToLast() { iter_->SeekToLast(); } - virtual void Next() { iter_->Next(); } - virtual void Prev() { iter_->Prev(); } - - virtual Slice key() const { - assert(Valid()); - ParsedInternalKey key; - if (!ParseInternalKey(iter_->key(), &key)) { - status_ = Status::Corruption("malformed internal key"); - return Slice("corrupted key"); - } - return key.user_key; - } - - virtual Slice value() const { return iter_->value(); } - virtual Status status() const { - return status_.ok() ? iter_->status() : status_; - } - - private: - mutable Status status_; - Iterator* iter_; - - // No copying allowed - KeyConvertingIterator(const KeyConvertingIterator&); - void operator=(const KeyConvertingIterator&); -}; - -class MemTableConstructor: public Constructor { - public: - explicit MemTableConstructor(const Comparator* cmp) - : Constructor(cmp), - internal_comparator_(cmp) { - memtable_ = new MemTable(internal_comparator_); - memtable_->Ref(); - } - ~MemTableConstructor() { - memtable_->Unref(); - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - memtable_->Unref(); - memtable_ = new MemTable(internal_comparator_); - memtable_->Ref(); - int seq = 1; - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - memtable_->Add(seq, kTypeValue, it->first, it->second); - seq++; - } - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return new KeyConvertingIterator(memtable_->NewIterator()); - } - - private: - InternalKeyComparator internal_comparator_; - MemTable* memtable_; -}; - -class DBConstructor: public Constructor { - public: - explicit DBConstructor(const Comparator* cmp) - : Constructor(cmp), - comparator_(cmp) { - db_ = NULL; - NewDB(); - } - ~DBConstructor() { - delete db_; - } - virtual Status FinishImpl(const Options& options, const KVMap& data) { - delete db_; - db_ = NULL; - NewDB(); - for (KVMap::const_iterator it = data.begin(); - it != data.end(); - ++it) { - WriteBatch batch; - batch.Put(it->first, it->second); - ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); - } - return Status::OK(); - } - virtual Iterator* NewIterator() const { - return db_->NewIterator(ReadOptions()); - } - - virtual DB* db() const { return db_; } - - private: - void NewDB() { - std::string name = test::TmpDir() + "/table_testdb"; - - Options options; - options.comparator = comparator_; - Status status = DestroyDB(name, options); - ASSERT_TRUE(status.ok()) << status.ToString(); - - options.create_if_missing = true; - options.error_if_exists = true; - options.write_buffer_size = 10000; // Something small to force merging - status = DB::Open(options, name, &db_); - ASSERT_TRUE(status.ok()) << status.ToString(); - } - - const Comparator* comparator_; - DB* db_; -}; - -enum TestType { - TABLE_TEST, - BLOCK_TEST, - MEMTABLE_TEST, - DB_TEST -}; - -struct TestArgs { - TestType type; - bool reverse_compare; - int restart_interval; -}; - -static const TestArgs kTestArgList[] = { - { TABLE_TEST, false, 16 }, - { TABLE_TEST, false, 1 }, - { TABLE_TEST, false, 1024 }, - { TABLE_TEST, true, 16 }, - { TABLE_TEST, true, 1 }, - { TABLE_TEST, true, 1024 }, - - { BLOCK_TEST, false, 16 }, - { BLOCK_TEST, false, 1 }, - { BLOCK_TEST, false, 1024 }, - { BLOCK_TEST, true, 16 }, - { BLOCK_TEST, true, 1 }, - { BLOCK_TEST, true, 1024 }, - - // Restart interval does not matter for memtables - { MEMTABLE_TEST, false, 16 }, - { MEMTABLE_TEST, true, 16 }, - - // Do not bother with restart interval variations for DB - { DB_TEST, false, 16 }, - { DB_TEST, true, 16 }, -}; -static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); - -class Harness { - public: - Harness() : constructor_(NULL) { } - - void Init(const TestArgs& args) { - delete constructor_; - constructor_ = NULL; - options_ = Options(); - - options_.block_restart_interval = args.restart_interval; - // Use shorter block size for tests to exercise block boundary - // conditions more. - options_.block_size = 256; - if (args.reverse_compare) { - options_.comparator = &reverse_key_comparator; - } - switch (args.type) { - case TABLE_TEST: - constructor_ = new TableConstructor(options_.comparator); - break; - case BLOCK_TEST: - constructor_ = new BlockConstructor(options_.comparator); - break; - case MEMTABLE_TEST: - constructor_ = new MemTableConstructor(options_.comparator); - break; - case DB_TEST: - constructor_ = new DBConstructor(options_.comparator); - break; - } - } - - ~Harness() { - delete constructor_; - } - - void Add(const std::string& key, const std::string& value) { - constructor_->Add(key, value); - } - - void Test(Random* rnd) { - std::vector keys; - KVMap data; - constructor_->Finish(options_, &keys, &data); - - TestForwardScan(keys, data); - TestBackwardScan(keys, data); - TestRandomAccess(rnd, keys, data); - } - - void TestForwardScan(const std::vector& keys, - const KVMap& data) { - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - iter->SeekToFirst(); - for (KVMap::const_iterator model_iter = data.begin(); - model_iter != data.end(); - ++model_iter) { - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - iter->Next(); - } - ASSERT_TRUE(!iter->Valid()); - delete iter; - } - - void TestBackwardScan(const std::vector& keys, - const KVMap& data) { - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - iter->SeekToLast(); - for (KVMap::const_reverse_iterator model_iter = data.rbegin(); - model_iter != data.rend(); - ++model_iter) { - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - iter->Prev(); - } - ASSERT_TRUE(!iter->Valid()); - delete iter; - } - - void TestRandomAccess(Random* rnd, - const std::vector& keys, - const KVMap& data) { - static const bool kVerbose = false; - Iterator* iter = constructor_->NewIterator(); - ASSERT_TRUE(!iter->Valid()); - KVMap::const_iterator model_iter = data.begin(); - if (kVerbose) fprintf(stderr, "---\n"); - for (int i = 0; i < 200; i++) { - const int toss = rnd->Uniform(5); - switch (toss) { - case 0: { - if (iter->Valid()) { - if (kVerbose) fprintf(stderr, "Next\n"); - iter->Next(); - ++model_iter; - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - } - break; - } - - case 1: { - if (kVerbose) fprintf(stderr, "SeekToFirst\n"); - iter->SeekToFirst(); - model_iter = data.begin(); - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - - case 2: { - std::string key = PickRandomKey(rnd, keys); - model_iter = data.lower_bound(key); - if (kVerbose) fprintf(stderr, "Seek '%s'\n", - EscapeString(key).c_str()); - iter->Seek(Slice(key)); - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - - case 3: { - if (iter->Valid()) { - if (kVerbose) fprintf(stderr, "Prev\n"); - iter->Prev(); - if (model_iter == data.begin()) { - model_iter = data.end(); // Wrap around to invalid value - } else { - --model_iter; - } - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - } - break; - } - - case 4: { - if (kVerbose) fprintf(stderr, "SeekToLast\n"); - iter->SeekToLast(); - if (keys.empty()) { - model_iter = data.end(); - } else { - std::string last = data.rbegin()->first; - model_iter = data.lower_bound(last); - } - ASSERT_EQ(ToString(data, model_iter), ToString(iter)); - break; - } - } - } - delete iter; - } - - std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { - if (it == data.end()) { - return "END"; - } else { - return "'" + it->first + "->" + it->second + "'"; - } - } - - std::string ToString(const KVMap& data, - const KVMap::const_reverse_iterator& it) { - if (it == data.rend()) { - return "END"; - } else { - return "'" + it->first + "->" + it->second + "'"; - } - } - - std::string ToString(const Iterator* it) { - if (!it->Valid()) { - return "END"; - } else { - return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; - } - } - - std::string PickRandomKey(Random* rnd, const std::vector& keys) { - if (keys.empty()) { - return "foo"; - } else { - const int index = rnd->Uniform(keys.size()); - std::string result = keys[index]; - switch (rnd->Uniform(3)) { - case 0: - // Return an existing key - break; - case 1: { - // Attempt to return something smaller than an existing key - if (result.size() > 0 && result[result.size()-1] > '\0') { - result[result.size()-1]--; - } - break; - } - case 2: { - // Return something larger than an existing key - Increment(options_.comparator, &result); - break; - } - } - return result; - } - } - - // Returns NULL if not running against a DB - DB* db() const { return constructor_->db(); } - - private: - Options options_; - Constructor* constructor_; -}; - -// Test empty table/block. -TEST(Harness, Empty) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 1); - Test(&rnd); - } -} - -// Special test for a block with no restart entries. The C++ leveldb -// code never generates such blocks, but the Java version of leveldb -// seems to. -TEST(Harness, ZeroRestartPointsInBlock) { - char data[sizeof(uint32_t)]; - memset(data, 0, sizeof(data)); - BlockContents contents; - contents.data = Slice(data, sizeof(data)); - contents.cachable = false; - contents.heap_allocated = false; - Block block(contents); - Iterator* iter = block.NewIterator(BytewiseComparator()); - iter->SeekToFirst(); - ASSERT_TRUE(!iter->Valid()); - iter->SeekToLast(); - ASSERT_TRUE(!iter->Valid()); - iter->Seek("foo"); - ASSERT_TRUE(!iter->Valid()); - delete iter; -} - -// Test the empty key -TEST(Harness, SimpleEmptyKey) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 1); - Add("", "v"); - Test(&rnd); - } -} - -TEST(Harness, SimpleSingle) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 2); - Add("abc", "v"); - Test(&rnd); - } -} - -TEST(Harness, SimpleMulti) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 3); - Add("abc", "v"); - Add("abcd", "v"); - Add("ac", "v2"); - Test(&rnd); - } -} - -TEST(Harness, SimpleSpecialKey) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 4); - Add("\xff\xff", "v3"); - Test(&rnd); - } -} - -TEST(Harness, Randomized) { - for (int i = 0; i < kNumTestArgs; i++) { - Init(kTestArgList[i]); - Random rnd(test::RandomSeed() + 5); - for (int num_entries = 0; num_entries < 2000; - num_entries += (num_entries < 50 ? 1 : 200)) { - if ((num_entries % 10) == 0) { - fprintf(stderr, "case %d of %d: num_entries = %d\n", - (i + 1), int(kNumTestArgs), num_entries); - } - for (int e = 0; e < num_entries; e++) { - std::string v; - Add(test::RandomKey(&rnd, rnd.Skewed(4)), - test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); - } - Test(&rnd); - } - } -} - -TEST(Harness, RandomizedLongDB) { - Random rnd(test::RandomSeed()); - TestArgs args = { DB_TEST, false, 16 }; - Init(args); - int num_entries = 100000; - for (int e = 0; e < num_entries; e++) { - std::string v; - Add(test::RandomKey(&rnd, rnd.Skewed(4)), - test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); - } - Test(&rnd); - - // We must have created enough data to force merging - int files = 0; - for (int level = 0; level < config::kNumLevels; level++) { - std::string value; - char name[100]; - snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); - ASSERT_TRUE(db()->GetProperty(name, &value)); - files += atoi(value.c_str()); - } - ASSERT_GT(files, 0); -} - -class MemTableTest { }; - -TEST(MemTableTest, Simple) { - InternalKeyComparator cmp(BytewiseComparator()); - MemTable* memtable = new MemTable(cmp); - memtable->Ref(); - WriteBatch batch; - WriteBatchInternal::SetSequence(&batch, 100); - batch.Put(std::string("k1"), std::string("v1")); - batch.Put(std::string("k2"), std::string("v2")); - batch.Put(std::string("k3"), std::string("v3")); - batch.Put(std::string("largekey"), std::string("vlarge")); - ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); - - Iterator* iter = memtable->NewIterator(); - iter->SeekToFirst(); - while (iter->Valid()) { - fprintf(stderr, "key: '%s' -> '%s'\n", - iter->key().ToString().c_str(), - iter->value().ToString().c_str()); - iter->Next(); - } - - delete iter; - memtable->Unref(); -} - -static bool Between(uint64_t val, uint64_t low, uint64_t high) { - bool result = (val >= low) && (val <= high); - if (!result) { - fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", - (unsigned long long)(val), - (unsigned long long)(low), - (unsigned long long)(high)); - } - return result; -} - -class TableTest { }; - -TEST(TableTest, ApproximateOffsetOfPlain) { - TableConstructor c(BytewiseComparator()); - c.Add("k01", "hello"); - c.Add("k02", "hello2"); - c.Add("k03", std::string(10000, 'x')); - c.Add("k04", std::string(200000, 'x')); - c.Add("k05", std::string(300000, 'x')); - c.Add("k06", "hello3"); - c.Add("k07", std::string(100000, 'x')); - std::vector keys; - KVMap kvmap; - Options options; - options.block_size = 1024; - options.compression = kNoCompression; - c.Finish(options, &keys, &kvmap); - - ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); - -} - -static bool SnappyCompressionSupported() { - std::string out; - Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - return port::Snappy_Compress(in.data(), in.size(), &out); -} - -TEST(TableTest, ApproximateOffsetOfCompressed) { - if (!SnappyCompressionSupported()) { - fprintf(stderr, "skipping compression tests\n"); - return; - } - - Random rnd(301); - TableConstructor c(BytewiseComparator()); - std::string tmp; - c.Add("k01", "hello"); - c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); - c.Add("k03", "hello3"); - c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); - std::vector keys; - KVMap kvmap; - Options options; - options.block_size = 1024; - options.compression = kSnappyCompression; - c.Finish(options, &keys, &kvmap); - - ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000)); - ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000)); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/table/two_level_iterator.cc b/src/leveldb/table/two_level_iterator.cc deleted file mode 100644 index 7822ebab9c..0000000000 --- a/src/leveldb/table/two_level_iterator.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "table/two_level_iterator.h" - -#include "leveldb/table.h" -#include "table/block.h" -#include "table/format.h" -#include "table/iterator_wrapper.h" - -namespace leveldb { - -namespace { - -typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); - -class TwoLevelIterator: public Iterator { - public: - TwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options); - - virtual ~TwoLevelIterator(); - - virtual void Seek(const Slice& target); - virtual void SeekToFirst(); - virtual void SeekToLast(); - virtual void Next(); - virtual void Prev(); - - virtual bool Valid() const { - return data_iter_.Valid(); - } - virtual Slice key() const { - assert(Valid()); - return data_iter_.key(); - } - virtual Slice value() const { - assert(Valid()); - return data_iter_.value(); - } - virtual Status status() const { - // It'd be nice if status() returned a const Status& instead of a Status - if (!index_iter_.status().ok()) { - return index_iter_.status(); - } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { - return data_iter_.status(); - } else { - return status_; - } - } - - private: - void SaveError(const Status& s) { - if (status_.ok() && !s.ok()) status_ = s; - } - void SkipEmptyDataBlocksForward(); - void SkipEmptyDataBlocksBackward(); - void SetDataIterator(Iterator* data_iter); - void InitDataBlock(); - - BlockFunction block_function_; - void* arg_; - const ReadOptions options_; - Status status_; - IteratorWrapper index_iter_; - IteratorWrapper data_iter_; // May be NULL - // If data_iter_ is non-NULL, then "data_block_handle_" holds the - // "index_value" passed to block_function_ to create the data_iter_. - std::string data_block_handle_; -}; - -TwoLevelIterator::TwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options) - : block_function_(block_function), - arg_(arg), - options_(options), - index_iter_(index_iter), - data_iter_(NULL) { -} - -TwoLevelIterator::~TwoLevelIterator() { -} - -void TwoLevelIterator::Seek(const Slice& target) { - index_iter_.Seek(target); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.Seek(target); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::SeekToFirst() { - index_iter_.SeekToFirst(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::SeekToLast() { - index_iter_.SeekToLast(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); - SkipEmptyDataBlocksBackward(); -} - -void TwoLevelIterator::Next() { - assert(Valid()); - data_iter_.Next(); - SkipEmptyDataBlocksForward(); -} - -void TwoLevelIterator::Prev() { - assert(Valid()); - data_iter_.Prev(); - SkipEmptyDataBlocksBackward(); -} - - -void TwoLevelIterator::SkipEmptyDataBlocksForward() { - while (data_iter_.iter() == NULL || !data_iter_.Valid()) { - // Move to next block - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - return; - } - index_iter_.Next(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); - } -} - -void TwoLevelIterator::SkipEmptyDataBlocksBackward() { - while (data_iter_.iter() == NULL || !data_iter_.Valid()) { - // Move to next block - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - return; - } - index_iter_.Prev(); - InitDataBlock(); - if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); - } -} - -void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { - if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); - data_iter_.Set(data_iter); -} - -void TwoLevelIterator::InitDataBlock() { - if (!index_iter_.Valid()) { - SetDataIterator(NULL); - } else { - Slice handle = index_iter_.value(); - if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { - // data_iter_ is already constructed with this iterator, so - // no need to change anything - } else { - Iterator* iter = (*block_function_)(arg_, options_, handle); - data_block_handle_.assign(handle.data(), handle.size()); - SetDataIterator(iter); - } - } -} - -} // namespace - -Iterator* NewTwoLevelIterator( - Iterator* index_iter, - BlockFunction block_function, - void* arg, - const ReadOptions& options) { - return new TwoLevelIterator(index_iter, block_function, arg, options); -} - -} // namespace leveldb diff --git a/src/leveldb/table/two_level_iterator.h b/src/leveldb/table/two_level_iterator.h deleted file mode 100644 index 629ca34525..0000000000 --- a/src/leveldb/table/two_level_iterator.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ -#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ - -#include "leveldb/iterator.h" - -namespace leveldb { - -struct ReadOptions; - -// Return a new two level iterator. A two-level iterator contains an -// index iterator whose values point to a sequence of blocks where -// each block is itself a sequence of key,value pairs. The returned -// two-level iterator yields the concatenation of all key/value pairs -// in the sequence of blocks. Takes ownership of "index_iter" and -// will delete it when no longer needed. -// -// Uses a supplied function to convert an index_iter value into -// an iterator over the contents of the corresponding block. -extern Iterator* NewTwoLevelIterator( - Iterator* index_iter, - Iterator* (*block_function)( - void* arg, - const ReadOptions& options, - const Slice& index_value), - void* arg, - const ReadOptions& options); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/src/leveldb/util/arena.cc b/src/leveldb/util/arena.cc deleted file mode 100644 index 9367f71492..0000000000 --- a/src/leveldb/util/arena.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/arena.h" -#include - -namespace leveldb { - -static const int kBlockSize = 4096; - -Arena::Arena() { - blocks_memory_ = 0; - alloc_ptr_ = NULL; // First allocation will allocate a block - alloc_bytes_remaining_ = 0; -} - -Arena::~Arena() { - for (size_t i = 0; i < blocks_.size(); i++) { - delete[] blocks_[i]; - } -} - -char* Arena::AllocateFallback(size_t bytes) { - if (bytes > kBlockSize / 4) { - // Object is more than a quarter of our block size. Allocate it separately - // to avoid wasting too much space in leftover bytes. - char* result = AllocateNewBlock(bytes); - return result; - } - - // We waste the remaining space in the current block. - alloc_ptr_ = AllocateNewBlock(kBlockSize); - alloc_bytes_remaining_ = kBlockSize; - - char* result = alloc_ptr_; - alloc_ptr_ += bytes; - alloc_bytes_remaining_ -= bytes; - return result; -} - -char* Arena::AllocateAligned(size_t bytes) { - const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; - assert((align & (align-1)) == 0); // Pointer size should be a power of 2 - size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); - size_t slop = (current_mod == 0 ? 0 : align - current_mod); - size_t needed = bytes + slop; - char* result; - if (needed <= alloc_bytes_remaining_) { - result = alloc_ptr_ + slop; - alloc_ptr_ += needed; - alloc_bytes_remaining_ -= needed; - } else { - // AllocateFallback always returned aligned memory - result = AllocateFallback(bytes); - } - assert((reinterpret_cast(result) & (align-1)) == 0); - return result; -} - -char* Arena::AllocateNewBlock(size_t block_bytes) { - char* result = new char[block_bytes]; - blocks_memory_ += block_bytes; - blocks_.push_back(result); - return result; -} - -} // namespace leveldb diff --git a/src/leveldb/util/arena.h b/src/leveldb/util/arena.h deleted file mode 100644 index 73bbf1cb9b..0000000000 --- a/src/leveldb/util/arena.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ -#define STORAGE_LEVELDB_UTIL_ARENA_H_ - -#include -#include -#include -#include - -namespace leveldb { - -class Arena { - public: - Arena(); - ~Arena(); - - // Return a pointer to a newly allocated memory block of "bytes" bytes. - char* Allocate(size_t bytes); - - // Allocate memory with the normal alignment guarantees provided by malloc - char* AllocateAligned(size_t bytes); - - // Returns an estimate of the total memory usage of data allocated - // by the arena (including space allocated but not yet used for user - // allocations). - size_t MemoryUsage() const { - return blocks_memory_ + blocks_.capacity() * sizeof(char*); - } - - private: - char* AllocateFallback(size_t bytes); - char* AllocateNewBlock(size_t block_bytes); - - // Allocation state - char* alloc_ptr_; - size_t alloc_bytes_remaining_; - - // Array of new[] allocated memory blocks - std::vector blocks_; - - // Bytes of memory in blocks allocated so far - size_t blocks_memory_; - - // No copying allowed - Arena(const Arena&); - void operator=(const Arena&); -}; - -inline char* Arena::Allocate(size_t bytes) { - // The semantics of what to return are a bit messy if we allow - // 0-byte allocations, so we disallow them here (we don't need - // them for our internal use). - assert(bytes > 0); - if (bytes <= alloc_bytes_remaining_) { - char* result = alloc_ptr_; - alloc_ptr_ += bytes; - alloc_bytes_remaining_ -= bytes; - return result; - } - return AllocateFallback(bytes); -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/src/leveldb/util/arena_test.cc b/src/leveldb/util/arena_test.cc deleted file mode 100644 index 58e870ec44..0000000000 --- a/src/leveldb/util/arena_test.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/arena.h" - -#include "util/random.h" -#include "util/testharness.h" - -namespace leveldb { - -class ArenaTest { }; - -TEST(ArenaTest, Empty) { - Arena arena; -} - -TEST(ArenaTest, Simple) { - std::vector > allocated; - Arena arena; - const int N = 100000; - size_t bytes = 0; - Random rnd(301); - for (int i = 0; i < N; i++) { - size_t s; - if (i % (N / 10) == 0) { - s = i; - } else { - s = rnd.OneIn(4000) ? rnd.Uniform(6000) : - (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); - } - if (s == 0) { - // Our arena disallows size 0 allocations. - s = 1; - } - char* r; - if (rnd.OneIn(10)) { - r = arena.AllocateAligned(s); - } else { - r = arena.Allocate(s); - } - - for (size_t b = 0; b < s; b++) { - // Fill the "i"th allocation with a known bit pattern - r[b] = i % 256; - } - bytes += s; - allocated.push_back(std::make_pair(s, r)); - ASSERT_GE(arena.MemoryUsage(), bytes); - if (i > N/10) { - ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); - } - } - for (size_t i = 0; i < allocated.size(); i++) { - size_t num_bytes = allocated[i].first; - const char* p = allocated[i].second; - for (size_t b = 0; b < num_bytes; b++) { - // Check the "i"th allocation for the known bit pattern - ASSERT_EQ(int(p[b]) & 0xff, i % 256); - } - } -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc deleted file mode 100644 index 79276b8476..0000000000 --- a/src/leveldb/util/bloom.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -#include "leveldb/slice.h" -#include "util/hash.h" - -namespace leveldb { - -namespace { -static uint32_t BloomHash(const Slice& key) { - return Hash(key.data(), key.size(), 0xbc9f1d34); -} - -class BloomFilterPolicy : public FilterPolicy { - private: - size_t bits_per_key_; - size_t k_; - - public: - explicit BloomFilterPolicy(int bits_per_key) - : bits_per_key_(bits_per_key) { - // We intentionally round down to reduce probing cost a little bit - k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) - if (k_ < 1) k_ = 1; - if (k_ > 30) k_ = 30; - } - - virtual const char* Name() const { - return "leveldb.BuiltinBloomFilter2"; - } - - virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { - // Compute bloom filter size (in both bits and bytes) - size_t bits = n * bits_per_key_; - - // For small n, we can see a very high false positive rate. Fix it - // by enforcing a minimum bloom filter length. - if (bits < 64) bits = 64; - - size_t bytes = (bits + 7) / 8; - bits = bytes * 8; - - const size_t init_size = dst->size(); - dst->resize(init_size + bytes, 0); - dst->push_back(static_cast(k_)); // Remember # of probes in filter - char* array = &(*dst)[init_size]; - for (size_t i = 0; i < (size_t)n; i++) { - // Use double-hashing to generate a sequence of hash values. - // See analysis in [Kirsch,Mitzenmacher 2006]. - uint32_t h = BloomHash(keys[i]); - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (size_t j = 0; j < k_; j++) { - const uint32_t bitpos = h % bits; - array[bitpos/8] |= (1 << (bitpos % 8)); - h += delta; - } - } - } - - virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { - const size_t len = bloom_filter.size(); - if (len < 2) return false; - - const char* array = bloom_filter.data(); - const size_t bits = (len - 1) * 8; - - // Use the encoded k so that we can read filters generated by - // bloom filters created using different parameters. - const size_t k = array[len-1]; - if (k > 30) { - // Reserved for potentially new encodings for short bloom filters. - // Consider it a match. - return true; - } - - uint32_t h = BloomHash(key); - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (size_t j = 0; j < k; j++) { - const uint32_t bitpos = h % bits; - if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; - h += delta; - } - return true; - } -}; -} - -const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { - return new BloomFilterPolicy(bits_per_key); -} - -} // namespace leveldb diff --git a/src/leveldb/util/bloom_test.cc b/src/leveldb/util/bloom_test.cc deleted file mode 100644 index 77fb1b3159..0000000000 --- a/src/leveldb/util/bloom_test.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -#include "util/coding.h" -#include "util/logging.h" -#include "util/testharness.h" -#include "util/testutil.h" - -namespace leveldb { - -static const int kVerbose = 1; - -static Slice Key(int i, char* buffer) { - EncodeFixed32(buffer, i); - return Slice(buffer, sizeof(uint32_t)); -} - -class BloomTest { - private: - const FilterPolicy* policy_; - std::string filter_; - std::vector keys_; - - public: - BloomTest() : policy_(NewBloomFilterPolicy(10)) { } - - ~BloomTest() { - delete policy_; - } - - void Reset() { - keys_.clear(); - filter_.clear(); - } - - void Add(const Slice& s) { - keys_.push_back(s.ToString()); - } - - void Build() { - std::vector key_slices; - for (size_t i = 0; i < keys_.size(); i++) { - key_slices.push_back(Slice(keys_[i])); - } - filter_.clear(); - policy_->CreateFilter(&key_slices[0], key_slices.size(), &filter_); - keys_.clear(); - if (kVerbose >= 2) DumpFilter(); - } - - size_t FilterSize() const { - return filter_.size(); - } - - void DumpFilter() { - fprintf(stderr, "F("); - for (size_t i = 0; i+1 < filter_.size(); i++) { - const unsigned int c = static_cast(filter_[i]); - for (int j = 0; j < 8; j++) { - fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); - } - - double FalsePositiveRate() { - char buffer[sizeof(int)]; - int result = 0; - for (int i = 0; i < 10000; i++) { - if (Matches(Key(i + 1000000000, buffer))) { - result++; - } - } - return result / 10000.0; - } -}; - -TEST(BloomTest, EmptyFilter) { - ASSERT_TRUE(! Matches("hello")); - ASSERT_TRUE(! Matches("world")); -} - -TEST(BloomTest, Small) { - Add("hello"); - Add("world"); - ASSERT_TRUE(Matches("hello")); - ASSERT_TRUE(Matches("world")); - ASSERT_TRUE(! Matches("x")); - ASSERT_TRUE(! Matches("foo")); -} - -static int NextLength(int length) { - if (length < 10) { - length += 1; - } else if (length < 100) { - length += 10; - } else if (length < 1000) { - length += 100; - } else { - length += 1000; - } - return length; -} - -TEST(BloomTest, VaryingLengths) { - char buffer[sizeof(int)]; - - // Count number of filters that significantly exceed the false positive rate - int mediocre_filters = 0; - int good_filters = 0; - - for (int length = 1; length <= 10000; length = NextLength(length)) { - Reset(); - for (int i = 0; i < length; i++) { - Add(Key(i, buffer)); - } - Build(); - - ASSERT_LE(FilterSize(), static_cast((length * 10 / 8) + 40)) - << length; - - // All added keys must match - for (int i = 0; i < length; i++) { - ASSERT_TRUE(Matches(Key(i, buffer))) - << "Length " << length << "; key " << i; - } - - // Check false positive rate - double rate = FalsePositiveRate(); - if (kVerbose >= 1) { - fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", - rate*100.0, length, static_cast(FilterSize())); - } - ASSERT_LE(rate, 0.02); // Must not be over 2% - if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often - else good_filters++; - } - if (kVerbose >= 1) { - fprintf(stderr, "Filters: %d good, %d mediocre\n", - good_filters, mediocre_filters); - } - ASSERT_LE(mediocre_filters, good_filters/5); -} - -// Different bits-per-byte - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/cache.cc b/src/leveldb/util/cache.cc deleted file mode 100644 index 8b197bc02a..0000000000 --- a/src/leveldb/util/cache.cc +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include - -#include "leveldb/cache.h" -#include "port/port.h" -#include "util/hash.h" -#include "util/mutexlock.h" - -namespace leveldb { - -Cache::~Cache() { -} - -namespace { - -// LRU cache implementation - -// An entry is a variable length heap-allocated structure. Entries -// are kept in a circular doubly linked list ordered by access time. -struct LRUHandle { - void* value; - void (*deleter)(const Slice&, void* value); - LRUHandle* next_hash; - LRUHandle* next; - LRUHandle* prev; - size_t charge; // TODO(opt): Only allow uint32_t? - size_t key_length; - uint32_t refs; - uint32_t hash; // Hash of key(); used for fast sharding and comparisons - char key_data[1]; // Beginning of key - - Slice key() const { - // For cheaper lookups, we allow a temporary Handle object - // to store a pointer to a key in "value". - if (next == this) { - return *(reinterpret_cast(value)); - } else { - return Slice(key_data, key_length); - } - } -}; - -// We provide our own simple hash table since it removes a whole bunch -// of porting hacks and is also faster than some of the built-in hash -// table implementations in some of the compiler/runtime combinations -// we have tested. E.g., readrandom speeds up by ~5% over the g++ -// 4.4.3's builtin hashtable. -class HandleTable { - public: - HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } - ~HandleTable() { delete[] list_; } - - LRUHandle* Lookup(const Slice& key, uint32_t hash) { - return *FindPointer(key, hash); - } - - LRUHandle* Insert(LRUHandle* h) { - LRUHandle** ptr = FindPointer(h->key(), h->hash); - LRUHandle* old = *ptr; - h->next_hash = (old == NULL ? NULL : old->next_hash); - *ptr = h; - if (old == NULL) { - ++elems_; - if (elems_ > length_) { - // Since each cache entry is fairly large, we aim for a small - // average linked list length (<= 1). - Resize(); - } - } - return old; - } - - LRUHandle* Remove(const Slice& key, uint32_t hash) { - LRUHandle** ptr = FindPointer(key, hash); - LRUHandle* result = *ptr; - if (result != NULL) { - *ptr = result->next_hash; - --elems_; - } - return result; - } - - private: - // The table consists of an array of buckets where each bucket is - // a linked list of cache entries that hash into the bucket. - uint32_t length_; - uint32_t elems_; - LRUHandle** list_; - - // Return a pointer to slot that points to a cache entry that - // matches key/hash. If there is no such cache entry, return a - // pointer to the trailing slot in the corresponding linked list. - LRUHandle** FindPointer(const Slice& key, uint32_t hash) { - LRUHandle** ptr = &list_[hash & (length_ - 1)]; - while (*ptr != NULL && - ((*ptr)->hash != hash || key != (*ptr)->key())) { - ptr = &(*ptr)->next_hash; - } - return ptr; - } - - void Resize() { - uint32_t new_length = 4; - while (new_length < elems_) { - new_length *= 2; - } - LRUHandle** new_list = new LRUHandle*[new_length]; - memset(new_list, 0, sizeof(new_list[0]) * new_length); - uint32_t count = 0; - for (uint32_t i = 0; i < length_; i++) { - LRUHandle* h = list_[i]; - while (h != NULL) { - LRUHandle* next = h->next_hash; - uint32_t hash = h->hash; - LRUHandle** ptr = &new_list[hash & (new_length - 1)]; - h->next_hash = *ptr; - *ptr = h; - h = next; - count++; - } - } - assert(elems_ == count); - delete[] list_; - list_ = new_list; - length_ = new_length; - } -}; - -// A single shard of sharded cache. -class LRUCache { - public: - LRUCache(); - ~LRUCache(); - - // Separate from constructor so caller can easily make an array of LRUCache - void SetCapacity(size_t capacity) { capacity_ = capacity; } - - // Like Cache methods, but with an extra "hash" parameter. - Cache::Handle* Insert(const Slice& key, uint32_t hash, - void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)); - Cache::Handle* Lookup(const Slice& key, uint32_t hash); - void Release(Cache::Handle* handle); - void Erase(const Slice& key, uint32_t hash); - - private: - void LRU_Remove(LRUHandle* e); - void LRU_Append(LRUHandle* e); - void Unref(LRUHandle* e); - - // Initialized before use. - size_t capacity_; - - // mutex_ protects the following state. - port::Mutex mutex_; - size_t usage_; - - // Dummy head of LRU list. - // lru.prev is newest entry, lru.next is oldest entry. - LRUHandle lru_; - - HandleTable table_; -}; - -LRUCache::LRUCache() - : usage_(0) { - // Make empty circular linked list - lru_.next = &lru_; - lru_.prev = &lru_; -} - -LRUCache::~LRUCache() { - for (LRUHandle* e = lru_.next; e != &lru_; ) { - LRUHandle* next = e->next; - assert(e->refs == 1); // Error if caller has an unreleased handle - Unref(e); - e = next; - } -} - -void LRUCache::Unref(LRUHandle* e) { - assert(e->refs > 0); - e->refs--; - if (e->refs <= 0) { - usage_ -= e->charge; - (*e->deleter)(e->key(), e->value); - free(e); - } -} - -void LRUCache::LRU_Remove(LRUHandle* e) { - e->next->prev = e->prev; - e->prev->next = e->next; -} - -void LRUCache::LRU_Append(LRUHandle* e) { - // Make "e" newest entry by inserting just before lru_ - e->next = &lru_; - e->prev = lru_.prev; - e->prev->next = e; - e->next->prev = e; -} - -Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { - MutexLock l(&mutex_); - LRUHandle* e = table_.Lookup(key, hash); - if (e != NULL) { - e->refs++; - LRU_Remove(e); - LRU_Append(e); - } - return reinterpret_cast(e); -} - -void LRUCache::Release(Cache::Handle* handle) { - MutexLock l(&mutex_); - Unref(reinterpret_cast(handle)); -} - -Cache::Handle* LRUCache::Insert( - const Slice& key, uint32_t hash, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) { - MutexLock l(&mutex_); - - LRUHandle* e = reinterpret_cast( - malloc(sizeof(LRUHandle)-1 + key.size())); - e->value = value; - e->deleter = deleter; - e->charge = charge; - e->key_length = key.size(); - e->hash = hash; - e->refs = 2; // One from LRUCache, one for the returned handle - memcpy(e->key_data, key.data(), key.size()); - LRU_Append(e); - usage_ += charge; - - LRUHandle* old = table_.Insert(e); - if (old != NULL) { - LRU_Remove(old); - Unref(old); - } - - while (usage_ > capacity_ && lru_.next != &lru_) { - LRUHandle* old = lru_.next; - LRU_Remove(old); - table_.Remove(old->key(), old->hash); - Unref(old); - } - - return reinterpret_cast(e); -} - -void LRUCache::Erase(const Slice& key, uint32_t hash) { - MutexLock l(&mutex_); - LRUHandle* e = table_.Remove(key, hash); - if (e != NULL) { - LRU_Remove(e); - Unref(e); - } -} - -static const int kNumShardBits = 4; -static const int kNumShards = 1 << kNumShardBits; - -class ShardedLRUCache : public Cache { - private: - LRUCache shard_[kNumShards]; - port::Mutex id_mutex_; - uint64_t last_id_; - - static inline uint32_t HashSlice(const Slice& s) { - return Hash(s.data(), s.size(), 0); - } - - static uint32_t Shard(uint32_t hash) { - return hash >> (32 - kNumShardBits); - } - - public: - explicit ShardedLRUCache(size_t capacity) - : last_id_(0) { - const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; - for (int s = 0; s < kNumShards; s++) { - shard_[s].SetCapacity(per_shard); - } - } - virtual ~ShardedLRUCache() { } - virtual Handle* Insert(const Slice& key, void* value, size_t charge, - void (*deleter)(const Slice& key, void* value)) { - const uint32_t hash = HashSlice(key); - return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); - } - virtual Handle* Lookup(const Slice& key) { - const uint32_t hash = HashSlice(key); - return shard_[Shard(hash)].Lookup(key, hash); - } - virtual void Release(Handle* handle) { - LRUHandle* h = reinterpret_cast(handle); - shard_[Shard(h->hash)].Release(handle); - } - virtual void Erase(const Slice& key) { - const uint32_t hash = HashSlice(key); - shard_[Shard(hash)].Erase(key, hash); - } - virtual void* Value(Handle* handle) { - return reinterpret_cast(handle)->value; - } - virtual uint64_t NewId() { - MutexLock l(&id_mutex_); - return ++(last_id_); - } -}; - -} // end anonymous namespace - -Cache* NewLRUCache(size_t capacity) { - return new ShardedLRUCache(capacity); -} - -} // namespace leveldb diff --git a/src/leveldb/util/cache_test.cc b/src/leveldb/util/cache_test.cc deleted file mode 100644 index 43716715a8..0000000000 --- a/src/leveldb/util/cache_test.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/cache.h" - -#include -#include "util/coding.h" -#include "util/testharness.h" - -namespace leveldb { - -// Conversions between numeric keys/values and the types expected by Cache. -static std::string EncodeKey(int k) { - std::string result; - PutFixed32(&result, k); - return result; -} -static int DecodeKey(const Slice& k) { - assert(k.size() == 4); - return DecodeFixed32(k.data()); -} -static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } -static int DecodeValue(void* v) { return reinterpret_cast(v); } - -class CacheTest { - public: - static CacheTest* current_; - - static void Deleter(const Slice& key, void* v) { - current_->deleted_keys_.push_back(DecodeKey(key)); - current_->deleted_values_.push_back(DecodeValue(v)); - } - - static const int kCacheSize = 1000; - std::vector deleted_keys_; - std::vector deleted_values_; - Cache* cache_; - - CacheTest() : cache_(NewLRUCache(kCacheSize)) { - current_ = this; - } - - ~CacheTest() { - delete cache_; - } - - int Lookup(int key) { - Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); - const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); - if (handle != NULL) { - cache_->Release(handle); - } - return r; - } - - void Insert(int key, int value, int charge = 1) { - cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, - &CacheTest::Deleter)); - } - - void Erase(int key) { - cache_->Erase(EncodeKey(key)); - } -}; -CacheTest* CacheTest::current_; - -TEST(CacheTest, HitAndMiss) { - ASSERT_EQ(-1, Lookup(100)); - - Insert(100, 101); - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(-1, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - Insert(200, 201); - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - Insert(100, 102); - ASSERT_EQ(102, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(-1, Lookup(300)); - - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); -} - -TEST(CacheTest, Erase) { - Erase(200); - ASSERT_EQ(0, deleted_keys_.size()); - - Insert(100, 101); - Insert(200, 201); - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); - - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(201, Lookup(200)); - ASSERT_EQ(1, deleted_keys_.size()); -} - -TEST(CacheTest, EntriesArePinned) { - Insert(100, 101); - Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); - ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); - - Insert(100, 102); - Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); - ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); - ASSERT_EQ(0, deleted_keys_.size()); - - cache_->Release(h1); - ASSERT_EQ(1, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[0]); - ASSERT_EQ(101, deleted_values_[0]); - - Erase(100); - ASSERT_EQ(-1, Lookup(100)); - ASSERT_EQ(1, deleted_keys_.size()); - - cache_->Release(h2); - ASSERT_EQ(2, deleted_keys_.size()); - ASSERT_EQ(100, deleted_keys_[1]); - ASSERT_EQ(102, deleted_values_[1]); -} - -TEST(CacheTest, EvictionPolicy) { - Insert(100, 101); - Insert(200, 201); - - // Frequently used entry must be kept around - for (int i = 0; i < kCacheSize + 100; i++) { - Insert(1000+i, 2000+i); - ASSERT_EQ(2000+i, Lookup(1000+i)); - ASSERT_EQ(101, Lookup(100)); - } - ASSERT_EQ(101, Lookup(100)); - ASSERT_EQ(-1, Lookup(200)); -} - -TEST(CacheTest, HeavyEntries) { - // Add a bunch of light and heavy entries and then count the combined - // size of items still in the cache, which must be approximately the - // same as the total capacity. - const int kLight = 1; - const int kHeavy = 10; - int added = 0; - int index = 0; - while (added < 2*kCacheSize) { - const int weight = (index & 1) ? kLight : kHeavy; - Insert(index, 1000+index, weight); - added += weight; - index++; - } - - int cached_weight = 0; - for (int i = 0; i < index; i++) { - const int weight = (i & 1 ? kLight : kHeavy); - int r = Lookup(i); - if (r >= 0) { - cached_weight += weight; - ASSERT_EQ(1000+i, r); - } - } - ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); -} - -TEST(CacheTest, NewId) { - uint64_t a = cache_->NewId(); - uint64_t b = cache_->NewId(); - ASSERT_NE(a, b); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/coding.cc b/src/leveldb/util/coding.cc deleted file mode 100644 index 21e3186d5d..0000000000 --- a/src/leveldb/util/coding.cc +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/coding.h" - -namespace leveldb { - -void EncodeFixed32(char* buf, uint32_t value) { - if (port::kLittleEndian) { - memcpy(buf, &value, sizeof(value)); - } else { - buf[0] = value & 0xff; - buf[1] = (value >> 8) & 0xff; - buf[2] = (value >> 16) & 0xff; - buf[3] = (value >> 24) & 0xff; - } -} - -void EncodeFixed64(char* buf, uint64_t value) { - if (port::kLittleEndian) { - memcpy(buf, &value, sizeof(value)); - } else { - buf[0] = value & 0xff; - buf[1] = (value >> 8) & 0xff; - buf[2] = (value >> 16) & 0xff; - buf[3] = (value >> 24) & 0xff; - buf[4] = (value >> 32) & 0xff; - buf[5] = (value >> 40) & 0xff; - buf[6] = (value >> 48) & 0xff; - buf[7] = (value >> 56) & 0xff; - } -} - -void PutFixed32(std::string* dst, uint32_t value) { - char buf[sizeof(value)]; - EncodeFixed32(buf, value); - dst->append(buf, sizeof(buf)); -} - -void PutFixed64(std::string* dst, uint64_t value) { - char buf[sizeof(value)]; - EncodeFixed64(buf, value); - dst->append(buf, sizeof(buf)); -} - -char* EncodeVarint32(char* dst, uint32_t v) { - // Operate on characters as unsigneds - unsigned char* ptr = reinterpret_cast(dst); - static const int B = 128; - if (v < (1<<7)) { - *(ptr++) = v; - } else if (v < (1<<14)) { - *(ptr++) = v | B; - *(ptr++) = v>>7; - } else if (v < (1<<21)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = v>>14; - } else if (v < (1<<28)) { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = v>>21; - } else { - *(ptr++) = v | B; - *(ptr++) = (v>>7) | B; - *(ptr++) = (v>>14) | B; - *(ptr++) = (v>>21) | B; - *(ptr++) = v>>28; - } - return reinterpret_cast(ptr); -} - -void PutVarint32(std::string* dst, uint32_t v) { - char buf[5]; - char* ptr = EncodeVarint32(buf, v); - dst->append(buf, ptr - buf); -} - -char* EncodeVarint64(char* dst, uint64_t v) { - static const int B = 128; - unsigned char* ptr = reinterpret_cast(dst); - while (v >= B) { - *(ptr++) = (v & (B-1)) | B; - v >>= 7; - } - *(ptr++) = static_cast(v); - return reinterpret_cast(ptr); -} - -void PutVarint64(std::string* dst, uint64_t v) { - char buf[10]; - char* ptr = EncodeVarint64(buf, v); - dst->append(buf, ptr - buf); -} - -void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { - PutVarint32(dst, value.size()); - dst->append(value.data(), value.size()); -} - -int VarintLength(uint64_t v) { - int len = 1; - while (v >= 128) { - v >>= 7; - len++; - } - return len; -} - -const char* GetVarint32PtrFallback(const char* p, - const char* limit, - uint32_t* value) { - uint32_t result = 0; - for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { - uint32_t byte = *(reinterpret_cast(p)); - p++; - if (byte & 128) { - // More bytes are present - result |= ((byte & 127) << shift); - } else { - result |= (byte << shift); - *value = result; - return reinterpret_cast(p); - } - } - return NULL; -} - -bool GetVarint32(Slice* input, uint32_t* value) { - const char* p = input->data(); - const char* limit = p + input->size(); - const char* q = GetVarint32Ptr(p, limit, value); - if (q == NULL) { - return false; - } else { - *input = Slice(q, limit - q); - return true; - } -} - -const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { - uint64_t result = 0; - for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { - uint64_t byte = *(reinterpret_cast(p)); - p++; - if (byte & 128) { - // More bytes are present - result |= ((byte & 127) << shift); - } else { - result |= (byte << shift); - *value = result; - return reinterpret_cast(p); - } - } - return NULL; -} - -bool GetVarint64(Slice* input, uint64_t* value) { - const char* p = input->data(); - const char* limit = p + input->size(); - const char* q = GetVarint64Ptr(p, limit, value); - if (q == NULL) { - return false; - } else { - *input = Slice(q, limit - q); - return true; - } -} - -const char* GetLengthPrefixedSlice(const char* p, const char* limit, - Slice* result) { - uint32_t len; - p = GetVarint32Ptr(p, limit, &len); - if (p == NULL) return NULL; - if (p + len > limit) return NULL; - *result = Slice(p, len); - return p + len; -} - -bool GetLengthPrefixedSlice(Slice* input, Slice* result) { - uint32_t len; - if (GetVarint32(input, &len) && - input->size() >= len) { - *result = Slice(input->data(), len); - input->remove_prefix(len); - return true; - } else { - return false; - } -} - -} // namespace leveldb diff --git a/src/leveldb/util/coding.h b/src/leveldb/util/coding.h deleted file mode 100644 index 3993c4a755..0000000000 --- a/src/leveldb/util/coding.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Endian-neutral encoding: -// * Fixed-length numbers are encoded with least-significant byte first -// * In addition we support variable length "varint" encoding -// * Strings are encoded prefixed by their length in varint format - -#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ -#define STORAGE_LEVELDB_UTIL_CODING_H_ - -#include -#include -#include -#include "leveldb/slice.h" -#include "port/port.h" - -namespace leveldb { - -// Standard Put... routines append to a string -extern void PutFixed32(std::string* dst, uint32_t value); -extern void PutFixed64(std::string* dst, uint64_t value); -extern void PutVarint32(std::string* dst, uint32_t value); -extern void PutVarint64(std::string* dst, uint64_t value); -extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); - -// Standard Get... routines parse a value from the beginning of a Slice -// and advance the slice past the parsed value. -extern bool GetVarint32(Slice* input, uint32_t* value); -extern bool GetVarint64(Slice* input, uint64_t* value); -extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); - -// Pointer-based variants of GetVarint... These either store a value -// in *v and return a pointer just past the parsed value, or return -// NULL on error. These routines only look at bytes in the range -// [p..limit-1] -extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); -extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); - -// Returns the length of the varint32 or varint64 encoding of "v" -extern int VarintLength(uint64_t v); - -// Lower-level versions of Put... that write directly into a character buffer -// REQUIRES: dst has enough space for the value being written -extern void EncodeFixed32(char* dst, uint32_t value); -extern void EncodeFixed64(char* dst, uint64_t value); - -// Lower-level versions of Put... that write directly into a character buffer -// and return a pointer just past the last byte written. -// REQUIRES: dst has enough space for the value being written -extern char* EncodeVarint32(char* dst, uint32_t value); -extern char* EncodeVarint64(char* dst, uint64_t value); - -// Lower-level versions of Get... that read directly from a character buffer -// without any bounds checking. - -inline uint32_t DecodeFixed32(const char* ptr) { - if (port::kLittleEndian) { - // Load the raw bytes - uint32_t result; - memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load - return result; - } else { - return ((static_cast(static_cast(ptr[0]))) - | (static_cast(static_cast(ptr[1])) << 8) - | (static_cast(static_cast(ptr[2])) << 16) - | (static_cast(static_cast(ptr[3])) << 24)); - } -} - -inline uint64_t DecodeFixed64(const char* ptr) { - if (port::kLittleEndian) { - // Load the raw bytes - uint64_t result; - memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load - return result; - } else { - uint64_t lo = DecodeFixed32(ptr); - uint64_t hi = DecodeFixed32(ptr + 4); - return (hi << 32) | lo; - } -} - -// Internal routine for use by fallback path of GetVarint32Ptr -extern const char* GetVarint32PtrFallback(const char* p, - const char* limit, - uint32_t* value); -inline const char* GetVarint32Ptr(const char* p, - const char* limit, - uint32_t* value) { - if (p < limit) { - uint32_t result = *(reinterpret_cast(p)); - if ((result & 128) == 0) { - *value = result; - return p + 1; - } - } - return GetVarint32PtrFallback(p, limit, value); -} - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/src/leveldb/util/coding_test.cc b/src/leveldb/util/coding_test.cc deleted file mode 100644 index 521541ea61..0000000000 --- a/src/leveldb/util/coding_test.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/coding.h" - -#include "util/testharness.h" - -namespace leveldb { - -class Coding { }; - -TEST(Coding, Fixed32) { - std::string s; - for (uint32_t v = 0; v < 100000; v++) { - PutFixed32(&s, v); - } - - const char* p = s.data(); - for (uint32_t v = 0; v < 100000; v++) { - uint32_t actual = DecodeFixed32(p); - ASSERT_EQ(v, actual); - p += sizeof(uint32_t); - } -} - -TEST(Coding, Fixed64) { - std::string s; - for (int power = 0; power <= 63; power++) { - uint64_t v = static_cast(1) << power; - PutFixed64(&s, v - 1); - PutFixed64(&s, v + 0); - PutFixed64(&s, v + 1); - } - - const char* p = s.data(); - for (int power = 0; power <= 63; power++) { - uint64_t v = static_cast(1) << power; - uint64_t actual; - actual = DecodeFixed64(p); - ASSERT_EQ(v-1, actual); - p += sizeof(uint64_t); - - actual = DecodeFixed64(p); - ASSERT_EQ(v+0, actual); - p += sizeof(uint64_t); - - actual = DecodeFixed64(p); - ASSERT_EQ(v+1, actual); - p += sizeof(uint64_t); - } -} - -// Test that encoding routines generate little-endian encodings -TEST(Coding, EncodingOutput) { - std::string dst; - PutFixed32(&dst, 0x04030201); - ASSERT_EQ(4, dst.size()); - ASSERT_EQ(0x01, static_cast(dst[0])); - ASSERT_EQ(0x02, static_cast(dst[1])); - ASSERT_EQ(0x03, static_cast(dst[2])); - ASSERT_EQ(0x04, static_cast(dst[3])); - - dst.clear(); - PutFixed64(&dst, 0x0807060504030201ull); - ASSERT_EQ(8, dst.size()); - ASSERT_EQ(0x01, static_cast(dst[0])); - ASSERT_EQ(0x02, static_cast(dst[1])); - ASSERT_EQ(0x03, static_cast(dst[2])); - ASSERT_EQ(0x04, static_cast(dst[3])); - ASSERT_EQ(0x05, static_cast(dst[4])); - ASSERT_EQ(0x06, static_cast(dst[5])); - ASSERT_EQ(0x07, static_cast(dst[6])); - ASSERT_EQ(0x08, static_cast(dst[7])); -} - -TEST(Coding, Varint32) { - std::string s; - for (uint32_t i = 0; i < (32 * 32); i++) { - uint32_t v = (i / 32) << (i % 32); - PutVarint32(&s, v); - } - - const char* p = s.data(); - const char* limit = p + s.size(); - for (uint32_t i = 0; i < (32 * 32); i++) { - uint32_t expected = (i / 32) << (i % 32); - uint32_t actual; - const char* start = p; - p = GetVarint32Ptr(p, limit, &actual); - ASSERT_TRUE(p != NULL); - ASSERT_EQ(expected, actual); - ASSERT_EQ(VarintLength(actual), p - start); - } - ASSERT_EQ(p, s.data() + s.size()); -} - -TEST(Coding, Varint64) { - // Construct the list of values to check - std::vector values; - // Some special values - values.push_back(0); - values.push_back(100); - values.push_back(~static_cast(0)); - values.push_back(~static_cast(0) - 1); - for (uint32_t k = 0; k < 64; k++) { - // Test values near powers of two - const uint64_t power = 1ull << k; - values.push_back(power); - values.push_back(power-1); - values.push_back(power+1); - } - - std::string s; - for (size_t i = 0; i < values.size(); i++) { - PutVarint64(&s, values[i]); - } - - const char* p = s.data(); - const char* limit = p + s.size(); - for (size_t i = 0; i < values.size(); i++) { - ASSERT_TRUE(p < limit); - uint64_t actual; - const char* start = p; - p = GetVarint64Ptr(p, limit, &actual); - ASSERT_TRUE(p != NULL); - ASSERT_EQ(values[i], actual); - ASSERT_EQ(VarintLength(actual), p - start); - } - ASSERT_EQ(p, limit); - -} - -TEST(Coding, Varint32Overflow) { - uint32_t result; - std::string input("\x81\x82\x83\x84\x85\x11"); - ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) - == NULL); -} - -TEST(Coding, Varint32Truncation) { - uint32_t large_value = (1u << 31) + 100; - std::string s; - PutVarint32(&s, large_value); - uint32_t result; - for (size_t len = 0; len < s.size() - 1; len++) { - ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); - } - ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); - ASSERT_EQ(large_value, result); -} - -TEST(Coding, Varint64Overflow) { - uint64_t result; - std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); - ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) - == NULL); -} - -TEST(Coding, Varint64Truncation) { - uint64_t large_value = (1ull << 63) + 100ull; - std::string s; - PutVarint64(&s, large_value); - uint64_t result; - for (size_t len = 0; len < s.size() - 1; len++) { - ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); - } - ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); - ASSERT_EQ(large_value, result); -} - -TEST(Coding, Strings) { - std::string s; - PutLengthPrefixedSlice(&s, Slice("")); - PutLengthPrefixedSlice(&s, Slice("foo")); - PutLengthPrefixedSlice(&s, Slice("bar")); - PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); - - Slice input(s); - Slice v; - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("foo", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ("bar", v.ToString()); - ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); - ASSERT_EQ(std::string(200, 'x'), v.ToString()); - ASSERT_EQ("", input.ToString()); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/comparator.cc b/src/leveldb/util/comparator.cc deleted file mode 100644 index 4b7b5724ef..0000000000 --- a/src/leveldb/util/comparator.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "leveldb/comparator.h" -#include "leveldb/slice.h" -#include "port/port.h" -#include "util/logging.h" - -namespace leveldb { - -Comparator::~Comparator() { } - -namespace { -class BytewiseComparatorImpl : public Comparator { - public: - BytewiseComparatorImpl() { } - - virtual const char* Name() const { - return "leveldb.BytewiseComparator"; - } - - virtual int Compare(const Slice& a, const Slice& b) const { - return a.compare(b); - } - - virtual void FindShortestSeparator( - std::string* start, - const Slice& limit) const { - // Find length of common prefix - size_t min_length = std::min(start->size(), limit.size()); - size_t diff_index = 0; - while ((diff_index < min_length) && - ((*start)[diff_index] == limit[diff_index])) { - diff_index++; - } - - if (diff_index >= min_length) { - // Do not shorten if one string is a prefix of the other - } else { - uint8_t diff_byte = static_cast((*start)[diff_index]); - if (diff_byte < static_cast(0xff) && - diff_byte + 1 < static_cast(limit[diff_index])) { - (*start)[diff_index]++; - start->resize(diff_index + 1); - assert(Compare(*start, limit) < 0); - } - } - } - - virtual void FindShortSuccessor(std::string* key) const { - // Find first character that can be incremented - size_t n = key->size(); - for (size_t i = 0; i < n; i++) { - const uint8_t byte = (*key)[i]; - if (byte != static_cast(0xff)) { - (*key)[i] = byte + 1; - key->resize(i+1); - return; - } - } - // *key is a run of 0xffs. Leave it alone. - } -}; -} // namespace - -static port::OnceType once = LEVELDB_ONCE_INIT; -static const Comparator* bytewise; - -static void InitModule() { - bytewise = new BytewiseComparatorImpl; -} - -const Comparator* BytewiseComparator() { - port::InitOnce(&once, InitModule); - return bytewise; -} - -} // namespace leveldb diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc deleted file mode 100644 index 6db9e77077..0000000000 --- a/src/leveldb/util/crc32c.cc +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// A portable implementation of crc32c, optimized to handle -// four bytes at a time. - -#include "util/crc32c.h" - -#include -#include "util/coding.h" - -namespace leveldb { -namespace crc32c { - -static const uint32_t table0_[256] = { - 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, - 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, - 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, - 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, - 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, - 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, - 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, - 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, - 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, - 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, - 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, - 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, - 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, - 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, - 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, - 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, - 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, - 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, - 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, - 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, - 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, - 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, - 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, - 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, - 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, - 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, - 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, - 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, - 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, - 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, - 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, - 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, - 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, - 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, - 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, - 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, - 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, - 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, - 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, - 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, - 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, - 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, - 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, - 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, - 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, - 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, - 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, - 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, - 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, - 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, - 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, - 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, - 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, - 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, - 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, - 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, - 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, - 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, - 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, - 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, - 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, - 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, - 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, - 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 -}; -static const uint32_t table1_[256] = { - 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, - 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, - 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, - 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, - 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, - 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, - 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, - 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, - 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, - 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, - 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, - 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, - 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, - 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, - 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, - 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, - 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, - 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, - 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, - 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, - 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, - 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, - 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, - 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, - 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, - 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, - 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, - 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, - 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, - 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, - 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, - 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, - 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, - 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, - 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, - 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, - 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, - 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, - 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, - 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, - 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, - 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, - 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, - 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, - 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, - 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, - 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, - 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, - 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, - 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, - 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, - 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, - 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, - 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, - 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, - 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, - 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, - 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, - 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, - 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, - 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, - 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, - 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, - 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 -}; -static const uint32_t table2_[256] = { - 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, - 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, - 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, - 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, - 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, - 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, - 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, - 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, - 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, - 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, - 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, - 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, - 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, - 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, - 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, - 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, - 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, - 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, - 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, - 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, - 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, - 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, - 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, - 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, - 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, - 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, - 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, - 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, - 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, - 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, - 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, - 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, - 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, - 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, - 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, - 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, - 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, - 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, - 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, - 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, - 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, - 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, - 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, - 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, - 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, - 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, - 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, - 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, - 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, - 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, - 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, - 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, - 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, - 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, - 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, - 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, - 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, - 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, - 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, - 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, - 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, - 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, - 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, - 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 -}; -static const uint32_t table3_[256] = { - 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, - 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, - 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, - 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, - 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, - 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, - 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, - 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, - 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, - 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, - 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, - 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, - 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, - 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, - 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, - 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, - 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, - 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, - 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, - 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, - 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, - 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, - 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, - 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, - 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, - 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, - 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, - 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, - 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, - 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, - 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, - 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, - 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, - 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, - 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, - 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, - 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, - 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, - 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, - 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, - 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, - 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, - 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, - 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, - 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, - 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, - 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, - 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, - 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, - 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, - 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, - 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, - 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, - 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, - 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, - 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, - 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, - 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, - 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, - 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, - 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, - 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, - 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, - 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 -}; - -// Used to fetch a naturally-aligned 32-bit word in little endian byte-order -static inline uint32_t LE_LOAD32(const uint8_t *p) { - return DecodeFixed32(reinterpret_cast(p)); -} - -uint32_t Extend(uint32_t crc, const char* buf, size_t size) { - const uint8_t *p = reinterpret_cast(buf); - const uint8_t *e = p + size; - uint32_t l = crc ^ 0xffffffffu; - -#define STEP1 do { \ - int c = (l & 0xff) ^ *p++; \ - l = table0_[c] ^ (l >> 8); \ -} while (0) -#define STEP4 do { \ - uint32_t c = l ^ LE_LOAD32(p); \ - p += 4; \ - l = table3_[c & 0xff] ^ \ - table2_[(c >> 8) & 0xff] ^ \ - table1_[(c >> 16) & 0xff] ^ \ - table0_[c >> 24]; \ -} while (0) - - // Point x at first 4-byte aligned byte in string. This might be - // just past the end of the string. - const uintptr_t pval = reinterpret_cast(p); - const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); - if (x <= e) { - // Process bytes until finished or p is 4-byte aligned - while (p != x) { - STEP1; - } - } - // Process bytes 16 at a time - while ((e-p) >= 16) { - STEP4; STEP4; STEP4; STEP4; - } - // Process bytes 4 at a time - while ((e-p) >= 4) { - STEP4; - } - // Process the last few bytes - while (p != e) { - STEP1; - } -#undef STEP4 -#undef STEP1 - return l ^ 0xffffffffu; -} - -} // namespace crc32c -} // namespace leveldb diff --git a/src/leveldb/util/crc32c.h b/src/leveldb/util/crc32c.h deleted file mode 100644 index 1d7e5c075d..0000000000 --- a/src/leveldb/util/crc32c.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ -#define STORAGE_LEVELDB_UTIL_CRC32C_H_ - -#include -#include - -namespace leveldb { -namespace crc32c { - -// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the -// crc32c of some string A. Extend() is often used to maintain the -// crc32c of a stream of data. -extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); - -// Return the crc32c of data[0,n-1] -inline uint32_t Value(const char* data, size_t n) { - return Extend(0, data, n); -} - -static const uint32_t kMaskDelta = 0xa282ead8ul; - -// Return a masked representation of crc. -// -// Motivation: it is problematic to compute the CRC of a string that -// contains embedded CRCs. Therefore we recommend that CRCs stored -// somewhere (e.g., in files) should be masked before being stored. -inline uint32_t Mask(uint32_t crc) { - // Rotate right by 15 bits and add a constant. - return ((crc >> 15) | (crc << 17)) + kMaskDelta; -} - -// Return the crc whose masked representation is masked_crc. -inline uint32_t Unmask(uint32_t masked_crc) { - uint32_t rot = masked_crc - kMaskDelta; - return ((rot >> 17) | (rot << 15)); -} - -} // namespace crc32c -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/src/leveldb/util/crc32c_test.cc b/src/leveldb/util/crc32c_test.cc deleted file mode 100644 index 4b957ee120..0000000000 --- a/src/leveldb/util/crc32c_test.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/crc32c.h" -#include "util/testharness.h" - -namespace leveldb { -namespace crc32c { - -class CRC { }; - -TEST(CRC, StandardResults) { - // From rfc3720 section B.4. - char buf[32]; - - memset(buf, 0, sizeof(buf)); - ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); - - memset(buf, 0xff, sizeof(buf)); - ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); - - for (int i = 0; i < 32; i++) { - buf[i] = i; - } - ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); - - for (int i = 0; i < 32; i++) { - buf[i] = 31 - i; - } - ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); - - unsigned char data[48] = { - 0x01, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x18, - 0x28, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); -} - -TEST(CRC, Values) { - ASSERT_NE(Value("a", 1), Value("foo", 3)); -} - -TEST(CRC, Extend) { - ASSERT_EQ(Value("hello world", 11), - Extend(Value("hello ", 6), "world", 5)); -} - -TEST(CRC, Mask) { - uint32_t crc = Value("foo", 3); - ASSERT_NE(crc, Mask(crc)); - ASSERT_NE(crc, Mask(Mask(crc))); - ASSERT_EQ(crc, Unmask(Mask(crc))); - ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); -} - -} // namespace crc32c -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/env.cc b/src/leveldb/util/env.cc deleted file mode 100644 index c2600e964a..0000000000 --- a/src/leveldb/util/env.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/env.h" - -namespace leveldb { - -Env::~Env() { -} - -SequentialFile::~SequentialFile() { -} - -RandomAccessFile::~RandomAccessFile() { -} - -WritableFile::~WritableFile() { -} - -Logger::~Logger() { -} - -FileLock::~FileLock() { -} - -void Log(Logger* info_log, const char* format, ...) { - if (info_log != NULL) { - va_list ap; - va_start(ap, format); - info_log->Logv(format, ap); - va_end(ap); - } -} - -static Status DoWriteStringToFile(Env* env, const Slice& data, - const std::string& fname, - bool should_sync) { - WritableFile* file; - Status s = env->NewWritableFile(fname, &file); - if (!s.ok()) { - return s; - } - s = file->Append(data); - if (s.ok() && should_sync) { - s = file->Sync(); - } - if (s.ok()) { - s = file->Close(); - } - delete file; // Will auto-close if we did not close above - if (!s.ok()) { - env->DeleteFile(fname); - } - return s; -} - -Status WriteStringToFile(Env* env, const Slice& data, - const std::string& fname) { - return DoWriteStringToFile(env, data, fname, false); -} - -Status WriteStringToFileSync(Env* env, const Slice& data, - const std::string& fname) { - return DoWriteStringToFile(env, data, fname, true); -} - -Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { - data->clear(); - SequentialFile* file; - Status s = env->NewSequentialFile(fname, &file); - if (!s.ok()) { - return s; - } - static const int kBufferSize = 8192; - char* space = new char[kBufferSize]; - while (true) { - Slice fragment; - s = file->Read(kBufferSize, &fragment, space); - if (!s.ok()) { - break; - } - data->append(fragment.data(), fragment.size()); - if (fragment.empty()) { - break; - } - } - delete[] space; - delete file; - return s; -} - -EnvWrapper::~EnvWrapper() { -} - -} // namespace leveldb diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc deleted file mode 100644 index ba2667864a..0000000000 --- a/src/leveldb/util/env_posix.cc +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -#if !defined(LEVELDB_PLATFORM_WINDOWS) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "port/port.h" -#include "util/logging.h" -#include "util/mutexlock.h" -#include "util/posix_logger.h" - -namespace leveldb { - -namespace { - -static Status IOError(const std::string& context, int err_number) { - return Status::IOError(context, strerror(err_number)); -} - -class PosixSequentialFile: public SequentialFile { - private: - std::string filename_; - FILE* file_; - - public: - PosixSequentialFile(const std::string& fname, FILE* f) - : filename_(fname), file_(f) { } - virtual ~PosixSequentialFile() { fclose(file_); } - - virtual Status Read(size_t n, Slice* result, char* scratch) { - Status s; - size_t r = fread_unlocked(scratch, 1, n, file_); - *result = Slice(scratch, r); - if (r < n) { - if (feof(file_)) { - // We leave status as ok if we hit the end of the file - } else { - // A partial read with an error: return a non-ok status - s = IOError(filename_, errno); - } - } - return s; - } - - virtual Status Skip(uint64_t n) { - if (fseek(file_, n, SEEK_CUR)) { - return IOError(filename_, errno); - } - return Status::OK(); - } -}; - -// pread() based random-access -class PosixRandomAccessFile: public RandomAccessFile { - private: - std::string filename_; - int fd_; - - public: - PosixRandomAccessFile(const std::string& fname, int fd) - : filename_(fname), fd_(fd) { } - virtual ~PosixRandomAccessFile() { close(fd_); } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - Status s; - ssize_t r = pread(fd_, scratch, n, static_cast(offset)); - *result = Slice(scratch, (r < 0) ? 0 : r); - if (r < 0) { - // An error: return a non-ok status - s = IOError(filename_, errno); - } - return s; - } -}; - -// Helper class to limit mmap file usage so that we do not end up -// running out virtual memory or running into kernel performance -// problems for very large databases. -class MmapLimiter { - public: - // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. - MmapLimiter() { - SetAllowed(sizeof(void*) >= 8 ? 1000 : 0); - } - - // If another mmap slot is available, acquire it and return true. - // Else return false. - bool Acquire() { - if (GetAllowed() <= 0) { - return false; - } - MutexLock l(&mu_); - intptr_t x = GetAllowed(); - if (x <= 0) { - return false; - } else { - SetAllowed(x - 1); - return true; - } - } - - // Release a slot acquired by a previous call to Acquire() that returned true. - void Release() { - MutexLock l(&mu_); - SetAllowed(GetAllowed() + 1); - } - - private: - port::Mutex mu_; - port::AtomicPointer allowed_; - - intptr_t GetAllowed() const { - return reinterpret_cast(allowed_.Acquire_Load()); - } - - // REQUIRES: mu_ must be held - void SetAllowed(intptr_t v) { - allowed_.Release_Store(reinterpret_cast(v)); - } - - MmapLimiter(const MmapLimiter&); - void operator=(const MmapLimiter&); -}; - -// mmap() based random-access -class PosixMmapReadableFile: public RandomAccessFile { - private: - std::string filename_; - void* mmapped_region_; - size_t length_; - MmapLimiter* limiter_; - - public: - // base[0,length-1] contains the mmapped contents of the file. - PosixMmapReadableFile(const std::string& fname, void* base, size_t length, - MmapLimiter* limiter) - : filename_(fname), mmapped_region_(base), length_(length), - limiter_(limiter) { - } - - virtual ~PosixMmapReadableFile() { - munmap(mmapped_region_, length_); - limiter_->Release(); - } - - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - Status s; - if (offset + n > length_) { - *result = Slice(); - s = IOError(filename_, EINVAL); - } else { - *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); - } - return s; - } -}; - -class PosixWritableFile : public WritableFile { - private: - std::string filename_; - FILE* file_; - - public: - PosixWritableFile(const std::string& fname, FILE* f) - : filename_(fname), file_(f) { } - - ~PosixWritableFile() { - if (file_ != NULL) { - // Ignoring any potential errors - fclose(file_); - } - } - - virtual Status Append(const Slice& data) { - size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); - if (r != data.size()) { - return IOError(filename_, errno); - } - return Status::OK(); - } - - virtual Status Close() { - Status result; - if (fclose(file_) != 0) { - result = IOError(filename_, errno); - } - file_ = NULL; - return result; - } - - virtual Status Flush() { - if (fflush_unlocked(file_) != 0) { - return IOError(filename_, errno); - } - return Status::OK(); - } - - Status SyncDirIfManifest() { - const char* f = filename_.c_str(); - const char* sep = strrchr(f, '/'); - Slice basename; - std::string dir; - if (sep == NULL) { - dir = "."; - basename = f; - } else { - dir = std::string(f, sep - f); - basename = sep + 1; - } - Status s; - if (basename.starts_with("MANIFEST")) { - int fd = open(dir.c_str(), O_RDONLY); - if (fd < 0) { - s = IOError(dir, errno); - } else { - if (fsync(fd) < 0) { - s = IOError(dir, errno); - } - close(fd); - } - } - return s; - } - - virtual Status Sync() { - // Ensure new files referred to by the manifest are in the filesystem. - Status s = SyncDirIfManifest(); - if (!s.ok()) { - return s; - } - if (fflush_unlocked(file_) != 0 || - fdatasync(fileno(file_)) != 0) { - s = Status::IOError(filename_, strerror(errno)); - } - return s; - } -}; - -static int LockOrUnlock(int fd, bool lock) { - errno = 0; - struct flock f; - memset(&f, 0, sizeof(f)); - f.l_type = (lock ? F_WRLCK : F_UNLCK); - f.l_whence = SEEK_SET; - f.l_start = 0; - f.l_len = 0; // Lock/unlock entire file - return fcntl(fd, F_SETLK, &f); -} - -class PosixFileLock : public FileLock { - public: - int fd_; - std::string name_; -}; - -// Set of locked files. We keep a separate set instead of just -// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide -// any protection against multiple uses from the same process. -class PosixLockTable { - private: - port::Mutex mu_; - std::set locked_files_; - public: - bool Insert(const std::string& fname) { - MutexLock l(&mu_); - return locked_files_.insert(fname).second; - } - void Remove(const std::string& fname) { - MutexLock l(&mu_); - locked_files_.erase(fname); - } -}; - -class PosixEnv : public Env { - public: - PosixEnv(); - virtual ~PosixEnv() { - char msg[] = "Destroying Env::Default()\n"; - fwrite(msg, 1, sizeof(msg), stderr); - abort(); - } - - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result) { - FILE* f = fopen(fname.c_str(), "r"); - if (f == NULL) { - *result = NULL; - return IOError(fname, errno); - } else { - *result = new PosixSequentialFile(fname, f); - return Status::OK(); - } - } - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result) { - *result = NULL; - Status s; - int fd = open(fname.c_str(), O_RDONLY); - if (fd < 0) { - s = IOError(fname, errno); - } else if (mmap_limit_.Acquire()) { - uint64_t size; - s = GetFileSize(fname, &size); - if (s.ok()) { - void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (base != MAP_FAILED) { - *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); - } else { - s = IOError(fname, errno); - } - } - close(fd); - if (!s.ok()) { - mmap_limit_.Release(); - } - } else { - *result = new PosixRandomAccessFile(fname, fd); - } - return s; - } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - Status s; - FILE* f = fopen(fname.c_str(), "w"); - if (f == NULL) { - *result = NULL; - s = IOError(fname, errno); - } else { - *result = new PosixWritableFile(fname, f); - } - return s; - } - - virtual bool FileExists(const std::string& fname) { - return access(fname.c_str(), F_OK) == 0; - } - - virtual Status GetChildren(const std::string& dir, - std::vector* result) { - result->clear(); - DIR* d = opendir(dir.c_str()); - if (d == NULL) { - return IOError(dir, errno); - } - struct dirent* entry; - while ((entry = readdir(d)) != NULL) { - result->push_back(entry->d_name); - } - closedir(d); - return Status::OK(); - } - - virtual Status DeleteFile(const std::string& fname) { - Status result; - if (unlink(fname.c_str()) != 0) { - result = IOError(fname, errno); - } - return result; - } - - virtual Status CreateDir(const std::string& name) { - Status result; - if (mkdir(name.c_str(), 0755) != 0) { - result = IOError(name, errno); - } - return result; - } - - virtual Status DeleteDir(const std::string& name) { - Status result; - if (rmdir(name.c_str()) != 0) { - result = IOError(name, errno); - } - return result; - } - - virtual Status GetFileSize(const std::string& fname, uint64_t* size) { - Status s; - struct stat sbuf; - if (stat(fname.c_str(), &sbuf) != 0) { - *size = 0; - s = IOError(fname, errno); - } else { - *size = sbuf.st_size; - } - return s; - } - - virtual Status RenameFile(const std::string& src, const std::string& target) { - Status result; - if (rename(src.c_str(), target.c_str()) != 0) { - result = IOError(src, errno); - } - return result; - } - - virtual Status LockFile(const std::string& fname, FileLock** lock) { - *lock = NULL; - Status result; - int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); - if (fd < 0) { - result = IOError(fname, errno); - } else if (!locks_.Insert(fname)) { - close(fd); - result = Status::IOError("lock " + fname, "already held by process"); - } else if (LockOrUnlock(fd, true) == -1) { - result = IOError("lock " + fname, errno); - close(fd); - locks_.Remove(fname); - } else { - PosixFileLock* my_lock = new PosixFileLock; - my_lock->fd_ = fd; - my_lock->name_ = fname; - *lock = my_lock; - } - return result; - } - - virtual Status UnlockFile(FileLock* lock) { - PosixFileLock* my_lock = reinterpret_cast(lock); - Status result; - if (LockOrUnlock(my_lock->fd_, false) == -1) { - result = IOError("unlock", errno); - } - locks_.Remove(my_lock->name_); - close(my_lock->fd_); - delete my_lock; - return result; - } - - virtual void Schedule(void (*function)(void*), void* arg); - - virtual void StartThread(void (*function)(void* arg), void* arg); - - virtual Status GetTestDirectory(std::string* result) { - const char* env = getenv("TEST_TMPDIR"); - if (env && env[0] != '\0') { - *result = env; - } else { - char buf[100]; - snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); - *result = buf; - } - // Directory may already exist - CreateDir(*result); - return Status::OK(); - } - - static uint64_t gettid() { - pthread_t tid = pthread_self(); - uint64_t thread_id = 0; - memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); - return thread_id; - } - - virtual Status NewLogger(const std::string& fname, Logger** result) { - FILE* f = fopen(fname.c_str(), "w"); - if (f == NULL) { - *result = NULL; - return IOError(fname, errno); - } else { - *result = new PosixLogger(f, &PosixEnv::gettid); - return Status::OK(); - } - } - - virtual uint64_t NowMicros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; - } - - virtual void SleepForMicroseconds(int micros) { - usleep(micros); - } - - private: - void PthreadCall(const char* label, int result) { - if (result != 0) { - fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - abort(); - } - } - - // BGThread() is the body of the background thread - void BGThread(); - static void* BGThreadWrapper(void* arg) { - reinterpret_cast(arg)->BGThread(); - return NULL; - } - - pthread_mutex_t mu_; - pthread_cond_t bgsignal_; - pthread_t bgthread_; - bool started_bgthread_; - - // Entry per Schedule() call - struct BGItem { void* arg; void (*function)(void*); }; - typedef std::deque BGQueue; - BGQueue queue_; - - PosixLockTable locks_; - MmapLimiter mmap_limit_; -}; - -PosixEnv::PosixEnv() : started_bgthread_(false) { - PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); - PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); -} - -void PosixEnv::Schedule(void (*function)(void*), void* arg) { - PthreadCall("lock", pthread_mutex_lock(&mu_)); - - // Start background thread if necessary - if (!started_bgthread_) { - started_bgthread_ = true; - PthreadCall( - "create thread", - pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); - } - - // If the queue is currently empty, the background thread may currently be - // waiting. - if (queue_.empty()) { - PthreadCall("signal", pthread_cond_signal(&bgsignal_)); - } - - // Add to priority queue - queue_.push_back(BGItem()); - queue_.back().function = function; - queue_.back().arg = arg; - - PthreadCall("unlock", pthread_mutex_unlock(&mu_)); -} - -void PosixEnv::BGThread() { - while (true) { - // Wait until there is an item that is ready to run - PthreadCall("lock", pthread_mutex_lock(&mu_)); - while (queue_.empty()) { - PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); - } - - void (*function)(void*) = queue_.front().function; - void* arg = queue_.front().arg; - queue_.pop_front(); - - PthreadCall("unlock", pthread_mutex_unlock(&mu_)); - (*function)(arg); - } -} - -namespace { -struct StartThreadState { - void (*user_function)(void*); - void* arg; -}; -} -static void* StartThreadWrapper(void* arg) { - StartThreadState* state = reinterpret_cast(arg); - state->user_function(state->arg); - delete state; - return NULL; -} - -void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { - pthread_t t; - StartThreadState* state = new StartThreadState; - state->user_function = function; - state->arg = arg; - PthreadCall("start thread", - pthread_create(&t, NULL, &StartThreadWrapper, state)); -} - -} // namespace - -static pthread_once_t once = PTHREAD_ONCE_INIT; -static Env* default_env; -static void InitDefaultEnv() { default_env = new PosixEnv; } - -Env* Env::Default() { - pthread_once(&once, InitDefaultEnv); - return default_env; -} - -} // namespace leveldb - -#endif diff --git a/src/leveldb/util/env_posix_test.cc b/src/leveldb/util/env_posix_test.cc deleted file mode 100644 index 295f8ae440..0000000000 --- a/src/leveldb/util/env_posix_test.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/env.h" - -#include "port/port.h" -#include "util/testharness.h" -#include "util/env_posix_test_helper.h" - -namespace leveldb { - -static const int kDelayMicros = 100000; -static const int kReadOnlyFileLimit = 4; -static const int kMMapLimit = 4; - -class EnvPosixTest { - public: - Env* env_; - EnvPosixTest() : env_(Env::Default()) { } - - static void SetFileLimits(int read_only_file_limit, int mmap_limit) { - EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit); - EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit); - } -}; - -TEST(EnvPosixTest, TestOpenOnRead) { - // Write some test data to a single file that will be opened |n| times. - std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); - std::string test_file = test_dir + "/open_on_read.txt"; - - FILE* f = fopen(test_file.c_str(), "w"); - ASSERT_TRUE(f != NULL); - const char kFileData[] = "abcdefghijklmnopqrstuvwxyz"; - fputs(kFileData, f); - fclose(f); - - // Open test file some number above the sum of the two limits to force - // open-on-read behavior of POSIX Env leveldb::RandomAccessFile. - const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5; - leveldb::RandomAccessFile* files[kNumFiles] = {0}; - for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i])); - } - char scratch; - Slice read_result; - for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch)); - ASSERT_EQ(kFileData[i], read_result[0]); - } - for (int i = 0; i < kNumFiles; i++) { - delete files[i]; - } - ASSERT_OK(env_->DeleteFile(test_file)); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - // All tests currently run with the same read-only file limits. - leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit, - leveldb::kMMapLimit); - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/env_posix_test_helper.h b/src/leveldb/util/env_posix_test_helper.h deleted file mode 100644 index 0386960598..0000000000 --- a/src/leveldb/util/env_posix_test_helper.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ -#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ - -namespace leveldb { - -class EnvPosixTest; - -// A helper for the POSIX Env to facilitate testing. -class EnvPosixTestHelper { - private: - friend class EnvPosixTest; - - // Set the maximum number of read-only files that will be opened. - // Must be called before creating an Env. - static void SetReadOnlyFDLimit(int limit); - - // Set the maximum number of read-only files that will be mapped via mmap. - // Must be called before creating an Env. - static void SetReadOnlyMMapLimit(int limit); -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ diff --git a/src/leveldb/util/env_test.cc b/src/leveldb/util/env_test.cc deleted file mode 100644 index b72cb44384..0000000000 --- a/src/leveldb/util/env_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/env.h" - -#include "port/port.h" -#include "util/testharness.h" - -namespace leveldb { - -static const int kDelayMicros = 100000; - -class EnvPosixTest { - private: - port::Mutex mu_; - std::string events_; - - public: - Env* env_; - EnvPosixTest() : env_(Env::Default()) { } -}; - -static void SetBool(void* ptr) { - reinterpret_cast(ptr)->NoBarrier_Store(ptr); -} - -TEST(EnvPosixTest, RunImmediately) { - port::AtomicPointer called (NULL); - env_->Schedule(&SetBool, &called); - Env::Default()->SleepForMicroseconds(kDelayMicros); - ASSERT_TRUE(called.NoBarrier_Load() != NULL); -} - -TEST(EnvPosixTest, RunMany) { - port::AtomicPointer last_id (NULL); - - struct CB { - port::AtomicPointer* last_id_ptr; // Pointer to shared slot - uintptr_t id; // Order# for the execution of this callback - - CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } - - static void Run(void* v) { - CB* cb = reinterpret_cast(v); - void* cur = cb->last_id_ptr->NoBarrier_Load(); - ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); - cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); - } - }; - - // Schedule in different order than start time - CB cb1(&last_id, 1); - CB cb2(&last_id, 2); - CB cb3(&last_id, 3); - CB cb4(&last_id, 4); - env_->Schedule(&CB::Run, &cb1); - env_->Schedule(&CB::Run, &cb2); - env_->Schedule(&CB::Run, &cb3); - env_->Schedule(&CB::Run, &cb4); - - Env::Default()->SleepForMicroseconds(kDelayMicros); - void* cur = last_id.Acquire_Load(); - ASSERT_EQ(4, reinterpret_cast(cur)); -} - -struct State { - port::Mutex mu; - int val; - int num_running; -}; - -static void ThreadBody(void* arg) { - State* s = reinterpret_cast(arg); - s->mu.Lock(); - s->val += 1; - s->num_running -= 1; - s->mu.Unlock(); -} - -TEST(EnvPosixTest, StartThread) { - State state; - state.val = 0; - state.num_running = 3; - for (int i = 0; i < 3; i++) { - env_->StartThread(&ThreadBody, &state); - } - while (true) { - state.mu.Lock(); - int num = state.num_running; - state.mu.Unlock(); - if (num == 0) { - break; - } - Env::Default()->SleepForMicroseconds(kDelayMicros); - } - ASSERT_EQ(state.val, 3); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc deleted file mode 100644 index ef2ecae830..0000000000 --- a/src/leveldb/util/env_win.cc +++ /dev/null @@ -1,1031 +0,0 @@ -// This file contains source that originates from: -// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h -// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc -// Those files dont' have any explict license headers but the -// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' -// as the license. -#if defined(LEVELDB_PLATFORM_WINDOWS) -#include - - -#include "leveldb/env.h" - -#include "port/port.h" -#include "leveldb/slice.h" -#include "util/logging.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifdef max -#undef max -#endif - -#ifndef va_copy -#define va_copy(d,s) ((d) = (s)) -#endif - -#if defined DeleteFile -#undef DeleteFile -#endif - -//Declarations -namespace leveldb -{ - -namespace Win32 -{ - -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -std::string GetCurrentDir(); -std::wstring GetCurrentDirW(); - -static const std::string CurrentDir = GetCurrentDir(); -static const std::wstring CurrentDirW = GetCurrentDirW(); - -std::string& ModifyPath(std::string& path); -std::wstring& ModifyPath(std::wstring& path); - -std::string GetLastErrSz(); -std::wstring GetLastErrSzW(); - -size_t GetPageSize(); - -typedef void (*ScheduleProc)(void*) ; - -struct WorkItemWrapper -{ - WorkItemWrapper(ScheduleProc proc_,void* content_); - ScheduleProc proc; - void* pContent; -}; - -DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); - -class Win32SequentialFile : public SequentialFile -{ -public: - friend class Win32Env; - virtual ~Win32SequentialFile(); - virtual Status Read(size_t n, Slice* result, char* scratch); - virtual Status Skip(uint64_t n); - BOOL isEnable(); -private: - BOOL _Init(); - void _CleanUp(); - Win32SequentialFile(const std::string& fname); - std::string _filename; - ::HANDLE _hFile; - DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); -}; - -class Win32RandomAccessFile : public RandomAccessFile -{ -public: - friend class Win32Env; - virtual ~Win32RandomAccessFile(); - virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; - BOOL isEnable(); -private: - BOOL _Init(LPCWSTR path); - void _CleanUp(); - Win32RandomAccessFile(const std::string& fname); - HANDLE _hFile; - const std::string _filename; - DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); -}; - -class Win32MapFile : public WritableFile -{ -public: - Win32MapFile(const std::string& fname); - - ~Win32MapFile(); - virtual Status Append(const Slice& data); - virtual Status Close(); - virtual Status Flush(); - virtual Status Sync(); - BOOL isEnable(); -private: - std::string _filename; - HANDLE _hFile; - size_t _page_size; - size_t _map_size; // How much extra memory to map at a time - char* _base; // The mapped region - HANDLE _base_handle; - char* _limit; // Limit of the mapped region - char* _dst; // Where to write next (in range [base_,limit_]) - char* _last_sync; // Where have we synced up to - uint64_t _file_offset; // Offset of base_ in file - //LARGE_INTEGER file_offset_; - // Have we done an munmap of unsynced data? - bool _pending_sync; - - // Roundup x to a multiple of y - static size_t _Roundup(size_t x, size_t y); - size_t _TruncateToPageBoundary(size_t s); - bool _UnmapCurrentRegion(); - bool _MapNewRegion(); - DISALLOW_COPY_AND_ASSIGN(Win32MapFile); - BOOL _Init(LPCWSTR Path); -}; - -class Win32FileLock : public FileLock -{ -public: - friend class Win32Env; - virtual ~Win32FileLock(); - BOOL isEnable(); -private: - BOOL _Init(LPCWSTR path); - void _CleanUp(); - Win32FileLock(const std::string& fname); - HANDLE _hFile; - std::string _filename; - DISALLOW_COPY_AND_ASSIGN(Win32FileLock); -}; - -class Win32Logger : public Logger -{ -public: - friend class Win32Env; - virtual ~Win32Logger(); - virtual void Logv(const char* format, va_list ap); -private: - explicit Win32Logger(WritableFile* pFile); - WritableFile* _pFileProxy; - DISALLOW_COPY_AND_ASSIGN(Win32Logger); -}; - -class Win32Env : public Env -{ -public: - Win32Env(); - virtual ~Win32Env(); - virtual Status NewSequentialFile(const std::string& fname, - SequentialFile** result); - - virtual Status NewRandomAccessFile(const std::string& fname, - RandomAccessFile** result); - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result); - - virtual bool FileExists(const std::string& fname); - - virtual Status GetChildren(const std::string& dir, - std::vector* result); - - virtual Status DeleteFile(const std::string& fname); - - virtual Status CreateDir(const std::string& dirname); - - virtual Status DeleteDir(const std::string& dirname); - - virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); - - virtual Status RenameFile(const std::string& src, - const std::string& target); - - virtual Status LockFile(const std::string& fname, FileLock** lock); - - virtual Status UnlockFile(FileLock* lock); - - virtual void Schedule( - void (*function)(void* arg), - void* arg); - - virtual void StartThread(void (*function)(void* arg), void* arg); - - virtual Status GetTestDirectory(std::string* path); - - //virtual void Logv(WritableFile* log, const char* format, va_list ap); - - virtual Status NewLogger(const std::string& fname, Logger** result); - - virtual uint64_t NowMicros(); - - virtual void SleepForMicroseconds(int micros); -}; - -void ToWidePath(const std::string& value, std::wstring& target) { - wchar_t buffer[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); - target = buffer; -} - -void ToNarrowPath(const std::wstring& value, std::string& target) { - char buffer[MAX_PATH]; - WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); - target = buffer; -} - -std::string GetCurrentDir() -{ - CHAR path[MAX_PATH]; - ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); - *strrchr(path,'\\') = 0; - return std::string(path); -} - -std::wstring GetCurrentDirW() -{ - WCHAR path[MAX_PATH]; - ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); - *wcsrchr(path,L'\\') = 0; - return std::wstring(path); -} - -std::string& ModifyPath(std::string& path) -{ - if(path[0] == '/' || path[0] == '\\'){ - path = CurrentDir + path; - } - std::replace(path.begin(),path.end(),'/','\\'); - - return path; -} - -std::wstring& ModifyPath(std::wstring& path) -{ - if(path[0] == L'/' || path[0] == L'\\'){ - path = CurrentDirW + path; - } - std::replace(path.begin(),path.end(),L'/',L'\\'); - return path; -} - -std::string GetLastErrSz() -{ - LPWSTR lpMsgBuf; - FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - 0, // Default language - (LPWSTR) &lpMsgBuf, - 0, - NULL - ); - std::string Err; - ToNarrowPath(lpMsgBuf, Err); - LocalFree( lpMsgBuf ); - return Err; -} - -std::wstring GetLastErrSzW() -{ - LPVOID lpMsgBuf; - FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - 0, // Default language - (LPWSTR) &lpMsgBuf, - 0, - NULL - ); - std::wstring Err = (LPCWSTR)lpMsgBuf; - LocalFree(lpMsgBuf); - return Err; -} - -WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : - proc(proc_),pContent(content_) -{ - -} - -DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) -{ - WorkItemWrapper* item = static_cast(pContent); - ScheduleProc TempProc = item->proc; - void* arg = item->pContent; - delete item; - TempProc(arg); - return 0; -} - -size_t GetPageSize() -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - return std::max(si.dwPageSize,si.dwAllocationGranularity); -} - -const size_t g_PageSize = GetPageSize(); - - -Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : - _filename(fname),_hFile(NULL) -{ - _Init(); -} - -Win32SequentialFile::~Win32SequentialFile() -{ - _CleanUp(); -} - -Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) -{ - Status sRet; - DWORD hasRead = 0; - if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ - *result = Slice(scratch,hasRead); - } else { - sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); - } - return sRet; -} - -Status Win32SequentialFile::Skip( uint64_t n ) -{ - Status sRet; - LARGE_INTEGER Move,NowPointer; - Move.QuadPart = n; - if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ - sRet = Status::IOError(_filename,Win32::GetLastErrSz()); - } - return sRet; -} - -BOOL Win32SequentialFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -BOOL Win32SequentialFile::_Init() -{ - std::wstring path; - ToWidePath(_filename, path); - _hFile = CreateFileW(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - return _hFile ? TRUE : FALSE; -} - -void Win32SequentialFile::_CleanUp() -{ - if(_hFile){ - CloseHandle(_hFile); - _hFile = NULL; - } -} - -Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : - _filename(fname),_hFile(NULL) -{ - std::wstring path; - ToWidePath(fname, path); - _Init( path.c_str() ); -} - -Win32RandomAccessFile::~Win32RandomAccessFile() -{ - _CleanUp(); -} - -Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const -{ - Status sRet; - OVERLAPPED ol = {0}; - ZeroMemory(&ol,sizeof(ol)); - ol.Offset = (DWORD)offset; - ol.OffsetHigh = (DWORD)(offset >> 32); - DWORD hasRead = 0; - if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) - sRet = Status::IOError(_filename,Win32::GetLastErrSz()); - else - *result = Slice(scratch,hasRead); - return sRet; -} - -BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) -{ - BOOL bRet = FALSE; - if(!_hFile) - _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) - _hFile = NULL; - else - bRet = TRUE; - return bRet; -} - -BOOL Win32RandomAccessFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -void Win32RandomAccessFile::_CleanUp() -{ - if(_hFile){ - ::CloseHandle(_hFile); - _hFile = NULL; - } -} - -size_t Win32MapFile::_Roundup( size_t x, size_t y ) -{ - return ((x + y - 1) / y) * y; -} - -size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) -{ - s -= (s & (_page_size - 1)); - assert((s % _page_size) == 0); - return s; -} - -bool Win32MapFile::_UnmapCurrentRegion() -{ - bool result = true; - if (_base != NULL) { - if (_last_sync < _limit) { - // Defer syncing this data until next Sync() call, if any - _pending_sync = true; - } - if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) - result = false; - _file_offset += _limit - _base; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - _last_sync = NULL; - _dst = NULL; - // Increase the amount we map the next time, but capped at 1MB - if (_map_size < (1<<20)) { - _map_size *= 2; - } - } - return result; -} - -bool Win32MapFile::_MapNewRegion() -{ - assert(_base == NULL); - //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); - //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); - DWORD off_hi = (DWORD)(_file_offset >> 32); - DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset + _map_size; - SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); - SetEndOfFile(_hFile); - - _base_handle = CreateFileMappingA( - _hFile, - NULL, - PAGE_READWRITE, - 0, - 0, - 0); - if (_base_handle != NULL) { - _base = (char*) MapViewOfFile(_base_handle, - FILE_MAP_ALL_ACCESS, - off_hi, - off_lo, - _map_size); - if (_base != NULL) { - _limit = _base + _map_size; - _dst = _base; - _last_sync = _base; - return true; - } - } - return false; -} - -Win32MapFile::Win32MapFile( const std::string& fname) : - _filename(fname), - _hFile(NULL), - _page_size(Win32::g_PageSize), - _map_size(_Roundup(65536, Win32::g_PageSize)), - _base(NULL), - _base_handle(NULL), - _limit(NULL), - _dst(NULL), - _last_sync(NULL), - _file_offset(0), - _pending_sync(false) -{ - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); - assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); -} - -Status Win32MapFile::Append( const Slice& data ) -{ - const char* src = data.data(); - size_t left = data.size(); - Status s; - while (left > 0) { - assert(_base <= _dst); - assert(_dst <= _limit); - size_t avail = _limit - _dst; - if (avail == 0) { - if (!_UnmapCurrentRegion() || - !_MapNewRegion()) { - return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); - } - } - size_t n = (left <= avail) ? left : avail; - memcpy(_dst, src, n); - _dst += n; - src += n; - left -= n; - } - return s; -} - -Status Win32MapFile::Close() -{ - Status s; - size_t unused = _limit - _dst; - if (!_UnmapCurrentRegion()) { - s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); - } else if (unused > 0) { - // Trim the extra space at the end of the file - LARGE_INTEGER newSize; - newSize.QuadPart = _file_offset - unused; - if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { - s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); - } else - SetEndOfFile(_hFile); - } - if (!CloseHandle(_hFile)) { - if (s.ok()) { - s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); - } - } - _hFile = INVALID_HANDLE_VALUE; - _base = NULL; - _base_handle = NULL; - _limit = NULL; - - return s; -} - -Status Win32MapFile::Sync() -{ - Status s; - if (_pending_sync) { - // Some unmapped data was not synced - _pending_sync = false; - if (!FlushFileBuffers(_hFile)) { - s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); - } - } - if (_dst > _last_sync) { - // Find the beginnings of the pages that contain the first and last - // bytes to be synced. - size_t p1 = _TruncateToPageBoundary(_last_sync - _base); - size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); - _last_sync = _dst; - if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { - s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); - } - } - return s; -} - -Status Win32MapFile::Flush() -{ - return Status::OK(); -} - -Win32MapFile::~Win32MapFile() -{ - if (_hFile != INVALID_HANDLE_VALUE) { - Win32MapFile::Close(); - } -} - -BOOL Win32MapFile::_Init( LPCWSTR Path ) -{ - DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; - _hFile = CreateFileW(Path, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, - NULL, - Flag, - FILE_ATTRIBUTE_NORMAL, - NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE) - return FALSE; - else - return TRUE; -} - -BOOL Win32MapFile::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -Win32FileLock::Win32FileLock( const std::string& fname ) : - _hFile(NULL),_filename(fname) -{ - std::wstring path; - ToWidePath(fname, path); - _Init(path.c_str()); -} - -Win32FileLock::~Win32FileLock() -{ - _CleanUp(); -} - -BOOL Win32FileLock::_Init( LPCWSTR path ) -{ - BOOL bRet = FALSE; - if(!_hFile) - _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ - _hFile = NULL; - } - else - bRet = TRUE; - return bRet; -} - -void Win32FileLock::_CleanUp() -{ - ::CloseHandle(_hFile); - _hFile = NULL; -} - -BOOL Win32FileLock::isEnable() -{ - return _hFile ? TRUE : FALSE; -} - -Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) -{ - assert(_pFileProxy); -} - -Win32Logger::~Win32Logger() -{ - if(_pFileProxy) - delete _pFileProxy; -} - -void Win32Logger::Logv( const char* format, va_list ap ) -{ - uint64_t thread_id = ::GetCurrentThreadId(); - - // We try twice: the first time with a fixed-size stack allocated buffer, - // and the second time with a much larger dynamically allocated buffer. - char buffer[500]; - for (int iter = 0; iter < 2; iter++) { - char* base; - int bufsize; - if (iter == 0) { - bufsize = sizeof(buffer); - base = buffer; - } else { - bufsize = 30000; - base = new char[bufsize]; - } - char* p = base; - char* limit = base + bufsize; - - SYSTEMTIME st; - GetLocalTime(&st); - p += snprintf(p, limit - p, - "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", - int(st.wYear), - int(st.wMonth), - int(st.wDay), - int(st.wHour), - int(st.wMinute), - int(st.wMinute), - int(st.wMilliseconds), - static_cast(thread_id)); - - // Print the message - if (p < limit) { - va_list backup_ap; - va_copy(backup_ap, ap); - p += vsnprintf(p, limit - p, format, backup_ap); - va_end(backup_ap); - } - - // Truncate to available space if necessary - if (p >= limit) { - if (iter == 0) { - continue; // Try again with larger buffer - } else { - p = limit - 1; - } - } - - // Add newline if necessary - if (p == base || p[-1] != '\n') { - *p++ = '\n'; - } - - assert(p <= limit); - DWORD hasWritten = 0; - if(_pFileProxy){ - _pFileProxy->Append(Slice(base, p - base)); - _pFileProxy->Flush(); - } - if (base != buffer) { - delete[] base; - } - break; - } -} - -bool Win32Env::FileExists(const std::string& fname) -{ - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - return ::PathFileExistsW(wpath.c_str()) ? true : false; -} - -Status Win32Env::GetChildren(const std::string& dir, std::vector* result) -{ - Status sRet; - ::WIN32_FIND_DATAW wfd; - std::string path = dir; - ModifyPath(path); - path += "\\*.*"; - std::wstring wpath; - ToWidePath(path, wpath); - - ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); - if(hFind && hFind != INVALID_HANDLE_VALUE){ - BOOL hasNext = TRUE; - std::string child; - while(hasNext){ - ToNarrowPath(wfd.cFileName, child); - if(child != ".." && child != ".") { - result->push_back(child); - } - hasNext = ::FindNextFileW(hFind,&wfd); - } - ::FindClose(hFind); - } - else - sRet = Status::IOError(dir,"Could not get children."); - return sRet; -} - -void Win32Env::SleepForMicroseconds( int micros ) -{ - ::Sleep((micros + 999) /1000); -} - - -Status Win32Env::DeleteFile( const std::string& fname ) -{ - Status sRet; - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - - if(!::DeleteFileW(wpath.c_str())) { - sRet = Status::IOError(path, "Could not delete file."); - } - return sRet; -} - -Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) -{ - Status sRet; - std::string path = fname; - std::wstring wpath; - ToWidePath(ModifyPath(path), wpath); - - HANDLE file = ::CreateFileW(wpath.c_str(), - GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - LARGE_INTEGER li; - if(::GetFileSizeEx(file,&li)){ - *file_size = (uint64_t)li.QuadPart; - }else - sRet = Status::IOError(path,"Could not get the file size."); - CloseHandle(file); - return sRet; -} - -Status Win32Env::RenameFile( const std::string& src, const std::string& target ) -{ - Status sRet; - std::string src_path = src; - std::wstring wsrc_path; - ToWidePath(ModifyPath(src_path), wsrc_path); - std::string target_path = target; - std::wstring wtarget_path; - ToWidePath(ModifyPath(target_path), wtarget_path); - - if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ - DWORD err = GetLastError(); - if(err == 0x000000b7){ - if(!::DeleteFileW(wtarget_path.c_str() ) ) - sRet = Status::IOError(src, "Could not rename file."); - else if(!::MoveFileW(wsrc_path.c_str(), - wtarget_path.c_str() ) ) - sRet = Status::IOError(src, "Could not rename file."); - } - } - return sRet; -} - -Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) -{ - Status sRet; - std::string path = fname; - ModifyPath(path); - Win32FileLock* _lock = new Win32FileLock(path); - if(!_lock->isEnable()){ - delete _lock; - *lock = NULL; - sRet = Status::IOError(path, "Could not lock file."); - } - else - *lock = _lock; - return sRet; -} - -Status Win32Env::UnlockFile( FileLock* lock ) -{ - Status sRet; - delete lock; - return sRet; -} - -void Win32Env::Schedule( void (*function)(void* arg), void* arg ) -{ - QueueUserWorkItem(Win32::WorkItemWrapperProc, - new Win32::WorkItemWrapper(function,arg), - WT_EXECUTEDEFAULT); -} - -void Win32Env::StartThread( void (*function)(void* arg), void* arg ) -{ - ::_beginthread(function,0,arg); -} - -Status Win32Env::GetTestDirectory( std::string* path ) -{ - Status sRet; - WCHAR TempPath[MAX_PATH]; - ::GetTempPathW(MAX_PATH,TempPath); - ToNarrowPath(TempPath, *path); - path->append("leveldb\\test\\"); - ModifyPath(*path); - return sRet; -} - -uint64_t Win32Env::NowMicros() -{ -#ifndef USE_VISTA_API -#define GetTickCount64 GetTickCount -#endif - return (uint64_t)(GetTickCount64()*1000); -} - -static Status CreateDirInner( const std::string& dirname ) -{ - Status sRet; - DWORD attr = ::GetFileAttributes(dirname.c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: - std::size_t slash = dirname.find_last_of("\\"); - if (slash != std::string::npos){ - sRet = CreateDirInner(dirname.substr(0, slash)); - if (!sRet.ok()) return sRet; - } - BOOL result = ::CreateDirectory(dirname.c_str(), NULL); - if (result == FALSE) { - sRet = Status::IOError(dirname, "Could not create directory."); - return sRet; - } - } - return sRet; -} - -Status Win32Env::CreateDir( const std::string& dirname ) -{ - std::string path = dirname; - if(path[path.length() - 1] != '\\'){ - path += '\\'; - } - ModifyPath(path); - - return CreateDirInner(path); -} - -Status Win32Env::DeleteDir( const std::string& dirname ) -{ - Status sRet; - std::wstring path; - ToWidePath(dirname, path); - ModifyPath(path); - if(!::RemoveDirectoryW( path.c_str() ) ){ - sRet = Status::IOError(dirname, "Could not delete directory."); - } - return sRet; -} - -Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) -{ - Status sRet; - std::string path = fname; - ModifyPath(path); - Win32SequentialFile* pFile = new Win32SequentialFile(path); - if(pFile->isEnable()){ - *result = pFile; - }else { - delete pFile; - sRet = Status::IOError(path, Win32::GetLastErrSz()); - } - return sRet; -} - -Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) -{ - Status sRet; - std::string path = fname; - Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); - if(!pFile->isEnable()){ - delete pFile; - *result = NULL; - sRet = Status::IOError(path, Win32::GetLastErrSz()); - }else - *result = pFile; - return sRet; -} - -Status Win32Env::NewLogger( const std::string& fname, Logger** result ) -{ - Status sRet; - std::string path = fname; - Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); - if(!pMapFile->isEnable()){ - delete pMapFile; - *result = NULL; - sRet = Status::IOError(path,"could not create a logger."); - }else - *result = new Win32Logger(pMapFile); - return sRet; -} - -Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) -{ - Status sRet; - std::string path = fname; - Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); - if(!pFile->isEnable()){ - *result = NULL; - sRet = Status::IOError(fname,Win32::GetLastErrSz()); - }else - *result = pFile; - return sRet; -} - -Win32Env::Win32Env() -{ - -} - -Win32Env::~Win32Env() -{ - -} - - -} // Win32 namespace - -static port::OnceType once = LEVELDB_ONCE_INIT; -static Env* default_env; -static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } - -Env* Env::Default() { - port::InitOnce(&once, InitDefaultEnv); - return default_env; -} - -} // namespace leveldb - -#endif // defined(LEVELDB_PLATFORM_WINDOWS) diff --git a/src/leveldb/util/filter_policy.cc b/src/leveldb/util/filter_policy.cc deleted file mode 100644 index 7b045c8c91..0000000000 --- a/src/leveldb/util/filter_policy.cc +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2012 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/filter_policy.h" - -namespace leveldb { - -FilterPolicy::~FilterPolicy() { } - -} // namespace leveldb diff --git a/src/leveldb/util/hash.cc b/src/leveldb/util/hash.cc deleted file mode 100644 index ed439ce7a2..0000000000 --- a/src/leveldb/util/hash.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "util/coding.h" -#include "util/hash.h" - -// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through -// between switch labels. The real definition should be provided externally. -// This one is a fallback version for unsupported compilers. -#ifndef FALLTHROUGH_INTENDED -#define FALLTHROUGH_INTENDED do { } while (0) -#endif - -namespace leveldb { - -uint32_t Hash(const char* data, size_t n, uint32_t seed) { - // Similar to murmur hash - const uint32_t m = 0xc6a4a793; - const uint32_t r = 24; - const char* limit = data + n; - uint32_t h = seed ^ (n * m); - - // Pick up four bytes at a time - while (data + 4 <= limit) { - uint32_t w = DecodeFixed32(data); - data += 4; - h += w; - h *= m; - h ^= (h >> 16); - } - - // Pick up remaining bytes - switch (limit - data) { - case 3: - h += static_cast(data[2]) << 16; - FALLTHROUGH_INTENDED; - case 2: - h += static_cast(data[1]) << 8; - FALLTHROUGH_INTENDED; - case 1: - h += static_cast(data[0]); - h *= m; - h ^= (h >> r); - break; - } - return h; -} - - -} // namespace leveldb diff --git a/src/leveldb/util/hash.h b/src/leveldb/util/hash.h deleted file mode 100644 index 8889d56be8..0000000000 --- a/src/leveldb/util/hash.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Simple hash function used for internal data structures - -#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ -#define STORAGE_LEVELDB_UTIL_HASH_H_ - -#include -#include - -namespace leveldb { - -extern uint32_t Hash(const char* data, size_t n, uint32_t seed); - -} - -#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/src/leveldb/util/hash_test.cc b/src/leveldb/util/hash_test.cc deleted file mode 100644 index eaa1c92c23..0000000000 --- a/src/leveldb/util/hash_test.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/hash.h" -#include "util/testharness.h" - -namespace leveldb { - -class HASH { }; - -TEST(HASH, SignedUnsignedIssue) { - const unsigned char data1[1] = {0x62}; - const unsigned char data2[2] = {0xc3, 0x97}; - const unsigned char data3[3] = {0xe2, 0x99, 0xa5}; - const unsigned char data4[4] = {0xe1, 0x80, 0xb9, 0x32}; - const unsigned char data5[48] = { - 0x01, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x18, - 0x28, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - - ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34); - ASSERT_EQ( - Hash(reinterpret_cast(data1), sizeof(data1), 0xbc9f1d34), - 0xef1345c4); - ASSERT_EQ( - Hash(reinterpret_cast(data2), sizeof(data2), 0xbc9f1d34), - 0x5b663814); - ASSERT_EQ( - Hash(reinterpret_cast(data3), sizeof(data3), 0xbc9f1d34), - 0x323c078f); - ASSERT_EQ( - Hash(reinterpret_cast(data4), sizeof(data4), 0xbc9f1d34), - 0xed21633a); - ASSERT_EQ( - Hash(reinterpret_cast(data5), sizeof(data5), 0x12345678), - 0xf333dabb); -} - -} // namespace leveldb - -int main(int argc, char** argv) { - return leveldb::test::RunAllTests(); -} diff --git a/src/leveldb/util/histogram.cc b/src/leveldb/util/histogram.cc deleted file mode 100644 index bb95f583ea..0000000000 --- a/src/leveldb/util/histogram.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include -#include "port/port.h" -#include "util/histogram.h" - -namespace leveldb { - -const double Histogram::kBucketLimit[kNumBuckets] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, - 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, - 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, - 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, - 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, - 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, - 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, - 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, - 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, - 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, - 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, - 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, - 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, - 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, - 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, - 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, - 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, - 1e200, -}; - -void Histogram::Clear() { - min_ = kBucketLimit[kNumBuckets-1]; - max_ = 0; - num_ = 0; - sum_ = 0; - sum_squares_ = 0; - for (int i = 0; i < kNumBuckets; i++) { - buckets_[i] = 0; - } -} - -void Histogram::Add(double value) { - // Linear search is fast enough for our usage in db_bench - int b = 0; - while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { - b++; - } - buckets_[b] += 1.0; - if (min_ > value) min_ = value; - if (max_ < value) max_ = value; - num_++; - sum_ += value; - sum_squares_ += (value * value); -} - -void Histogram::Merge(const Histogram& other) { - if (other.min_ < min_) min_ = other.min_; - if (other.max_ > max_) max_ = other.max_; - num_ += other.num_; - sum_ += other.sum_; - sum_squares_ += other.sum_squares_; - for (int b = 0; b < kNumBuckets; b++) { - buckets_[b] += other.buckets_[b]; - } -} - -double Histogram::Median() const { - return Percentile(50.0); -} - -double Histogram::Percentile(double p) const { - double threshold = num_ * (p / 100.0); - double sum = 0; - for (int b = 0; b < kNumBuckets; b++) { - sum += buckets_[b]; - if (sum >= threshold) { - // Scale linearly within this bucket - double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; - double right_point = kBucketLimit[b]; - double left_sum = sum - buckets_[b]; - double right_sum = sum; - double pos = (threshold - left_sum) / (right_sum - left_sum); - double r = left_point + (right_point - left_point) * pos; - if (r < min_) r = min_; - if (r > max_) r = max_; - return r; - } - } - return max_; -} - -double Histogram::Average() const { - if (num_ == 0.0) return 0; - return sum_ / num_; -} - -double Histogram::StandardDeviation() const { - if (num_ == 0.0) return 0; - double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); - return sqrt(variance); -} - -std::string Histogram::ToString() const { - std::string r; - char buf[200]; - snprintf(buf, sizeof(buf), - "Count: %.0f Average: %.4f StdDev: %.2f\n", - num_, Average(), StandardDeviation()); - r.append(buf); - snprintf(buf, sizeof(buf), - "Min: %.4f Median: %.4f Max: %.4f\n", - (num_ == 0.0 ? 0.0 : min_), Median(), max_); - r.append(buf); - r.append("------------------------------------------------------\n"); - const double mult = 100.0 / num_; - double sum = 0; - for (int b = 0; b < kNumBuckets; b++) { - if (buckets_[b] <= 0.0) continue; - sum += buckets_[b]; - snprintf(buf, sizeof(buf), - "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", - ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left - kBucketLimit[b], // right - buckets_[b], // count - mult * buckets_[b], // percentage - mult * sum); // cumulative percentage - r.append(buf); - - // Add hash marks based on percentage; 20 marks for 100%. - int marks = static_cast(20*(buckets_[b] / num_) + 0.5); - r.append(marks, '#'); - r.push_back('\n'); - } - return r; -} - -} // namespace leveldb diff --git a/src/leveldb/util/histogram.h b/src/leveldb/util/histogram.h deleted file mode 100644 index 1ef9f3c8ab..0000000000 --- a/src/leveldb/util/histogram.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ -#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ - -#include - -namespace leveldb { - -class Histogram { - public: - Histogram() { } - ~Histogram() { } - - void Clear(); - void Add(double value); - void Merge(const Histogram& other); - - std::string ToString() const; - - private: - double min_; - double max_; - double num_; - double sum_; - double sum_squares_; - - enum { kNumBuckets = 154 }; - static const double kBucketLimit[kNumBuckets]; - double buckets_[kNumBuckets]; - - double Median() const; - double Percentile(double p) const; - double Average() const; - double StandardDeviation() const; -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc deleted file mode 100644 index 2a1028a2c2..0000000000 --- a/src/leveldb/util/logging.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/logging.h" - -#include -#include -#include -#include -#include "leveldb/env.h" -#include "leveldb/slice.h" - -namespace leveldb { - -void AppendNumberTo(std::string* str, uint64_t num) { - char buf[30]; - snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); - str->append(buf); -} - -void AppendEscapedStringTo(std::string* str, const Slice& value) { - for (size_t i = 0; i < value.size(); i++) { - char c = value[i]; - if (c >= ' ' && c <= '~') { - str->push_back(c); - } else { - char buf[10]; - snprintf(buf, sizeof(buf), "\\x%02x", - static_cast(c) & 0xff); - str->append(buf); - } - } -} - -std::string NumberToString(uint64_t num) { - std::string r; - AppendNumberTo(&r, num); - return r; -} - -std::string EscapeString(const Slice& value) { - std::string r; - AppendEscapedStringTo(&r, value); - return r; -} - -bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { - uint64_t v = 0; - int digits = 0; - while (!in->empty()) { - char c = (*in)[0]; - if (c >= '0' && c <= '9') { - ++digits; - const int delta = (c - '0'); - static const uint64_t kMaxUint64 = ~static_cast(0); - if (v > kMaxUint64/10 || - (v == kMaxUint64/10 && (uint64_t)delta > kMaxUint64%10)) { - // Overflow - return false; - } - v = (v * 10) + delta; - in->remove_prefix(1); - } else { - break; - } - } - *val = v; - return (digits > 0); -} - -} // namespace leveldb diff --git a/src/leveldb/util/logging.h b/src/leveldb/util/logging.h deleted file mode 100644 index 1b450d2480..0000000000 --- a/src/leveldb/util/logging.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Must not be included from any .h files to avoid polluting the namespace -// with macros. - -#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ -#define STORAGE_LEVELDB_UTIL_LOGGING_H_ - -#include -#include -#include -#include "port/port.h" - -namespace leveldb { - -class Slice; -class WritableFile; - -// Append a human-readable printout of "num" to *str -extern void AppendNumberTo(std::string* str, uint64_t num); - -// Append a human-readable printout of "value" to *str. -// Escapes any non-printable characters found in "value". -extern void AppendEscapedStringTo(std::string* str, const Slice& value); - -// Return a human-readable printout of "num" -extern std::string NumberToString(uint64_t num); - -// Return a human-readable version of "value". -// Escapes any non-printable characters found in "value". -extern std::string EscapeString(const Slice& value); - -// Parse a human-readable number from "*in" into *value. On success, -// advances "*in" past the consumed number and sets "*val" to the -// numeric value. Otherwise, returns false and leaves *in in an -// unspecified state. -extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/src/leveldb/util/mutexlock.h b/src/leveldb/util/mutexlock.h deleted file mode 100644 index 1ff5a9efa1..0000000000 --- a/src/leveldb/util/mutexlock.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ -#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ - -#include "port/port.h" -#include "port/thread_annotations.h" - -namespace leveldb { - -// Helper class that locks a mutex on construction and unlocks the mutex when -// the destructor of the MutexLock object is invoked. -// -// Typical usage: -// -// void MyClass::MyMethod() { -// MutexLock l(&mu_); // mu_ is an instance variable -// ... some complex code, possibly with multiple return paths ... -// } - -class SCOPED_LOCKABLE MutexLock { - public: - explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) - : mu_(mu) { - this->mu_->Lock(); - } - ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } - - private: - port::Mutex *const mu_; - // No copying allowed - MutexLock(const MutexLock&); - void operator=(const MutexLock&); -}; - -} // namespace leveldb - - -#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/src/leveldb/util/options.cc b/src/leveldb/util/options.cc deleted file mode 100644 index 76af5b9302..0000000000 --- a/src/leveldb/util/options.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "leveldb/options.h" - -#include "leveldb/comparator.h" -#include "leveldb/env.h" - -namespace leveldb { - -Options::Options() - : comparator(BytewiseComparator()), - create_if_missing(false), - error_if_exists(false), - paranoid_checks(false), - env(Env::Default()), - info_log(NULL), - write_buffer_size(4<<20), - max_open_files(1000), - block_cache(NULL), - block_size(4096), - block_restart_interval(16), - compression(kSnappyCompression), - filter_policy(NULL) { -} - - -} // namespace leveldb diff --git a/src/leveldb/util/posix_logger.h b/src/leveldb/util/posix_logger.h deleted file mode 100644 index c063c2b7cb..0000000000 --- a/src/leveldb/util/posix_logger.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// Logger implementation that can be shared by all environments -// where enough Posix functionality is available. - -#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ -#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ - -#include -#include -#include -#include -#include "leveldb/env.h" - -namespace leveldb { - -class PosixLogger : public Logger { - private: - FILE* file_; - uint64_t (*gettid_)(); // Return the thread id for the current thread - public: - PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } - virtual ~PosixLogger() { - fclose(file_); - } - virtual void Logv(const char* format, va_list ap) { - const uint64_t thread_id = (*gettid_)(); - - // We try twice: the first time with a fixed-size stack allocated buffer, - // and the second time with a much larger dynamically allocated buffer. - char buffer[500]; - for (int iter = 0; iter < 2; iter++) { - char* base; - int bufsize; - if (iter == 0) { - bufsize = sizeof(buffer); - base = buffer; - } else { - bufsize = 30000; - base = new char[bufsize]; - } - char* p = base; - char* limit = base + bufsize; - - struct timeval now_tv; - gettimeofday(&now_tv, NULL); - const time_t seconds = now_tv.tv_sec; - struct tm t; - localtime_r(&seconds, &t); - p += snprintf(p, limit - p, - "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", - t.tm_year + 1900, - t.tm_mon + 1, - t.tm_mday, - t.tm_hour, - t.tm_min, - t.tm_sec, - static_cast(now_tv.tv_usec), - static_cast(thread_id)); - - // Print the message - if (p < limit) { - va_list backup_ap; - va_copy(backup_ap, ap); - p += vsnprintf(p, limit - p, format, backup_ap); - va_end(backup_ap); - } - - // Truncate to available space if necessary - if (p >= limit) { - if (iter == 0) { - continue; // Try again with larger buffer - } else { - p = limit - 1; - } - } - - // Add newline if necessary - if (p == base || p[-1] != '\n') { - *p++ = '\n'; - } - - assert(p <= limit); - fwrite(base, 1, p - base, file_); - fflush(file_); - if (base != buffer) { - delete[] base; - } - break; - } - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/src/leveldb/util/random.h b/src/leveldb/util/random.h deleted file mode 100644 index ddd51b1c7b..0000000000 --- a/src/leveldb/util/random.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ -#define STORAGE_LEVELDB_UTIL_RANDOM_H_ - -#include - -namespace leveldb { - -// A very simple random number generator. Not especially good at -// generating truly random bits, but good enough for our needs in this -// package. -class Random { - private: - uint32_t seed_; - public: - explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { - // Avoid bad seeds. - if (seed_ == 0 || seed_ == 2147483647L) { - seed_ = 1; - } - } - uint32_t Next() { - static const uint32_t M = 2147483647L; // 2^31-1 - static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 - // We are computing - // seed_ = (seed_ * A) % M, where M = 2^31-1 - // - // seed_ must not be zero or M, or else all subsequent computed values - // will be zero or M respectively. For all other values, seed_ will end - // up cycling through every number in [1,M-1] - uint64_t product = seed_ * A; - - // Compute (product % M) using the fact that ((x << 31) % M) == x. - seed_ = static_cast((product >> 31) + (product & M)); - // The first reduction may overflow by 1 bit, so we may need to - // repeat. mod == M is not possible; using > allows the faster - // sign-bit-based test. - if (seed_ > M) { - seed_ -= M; - } - return seed_; - } - // Returns a uniformly distributed value in the range [0..n-1] - // REQUIRES: n > 0 - uint32_t Uniform(int n) { return Next() % n; } - - // Randomly returns true ~"1/n" of the time, and false otherwise. - // REQUIRES: n > 0 - bool OneIn(int n) { return (Next() % n) == 0; } - - // Skewed: pick "base" uniformly from range [0,max_log] and then - // return "base" random bits. The effect is to pick a number in the - // range [0,2^max_log-1] with exponential bias towards smaller numbers. - uint32_t Skewed(int max_log) { - return Uniform(1 << Uniform(max_log + 1)); - } -}; - -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/src/leveldb/util/status.cc b/src/leveldb/util/status.cc deleted file mode 100644 index a44f35b314..0000000000 --- a/src/leveldb/util/status.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include -#include "port/port.h" -#include "leveldb/status.h" - -namespace leveldb { - -const char* Status::CopyState(const char* state) { - uint32_t size; - memcpy(&size, state, sizeof(size)); - char* result = new char[size + 5]; - memcpy(result, state, size + 5); - return result; -} - -Status::Status(Code code, const Slice& msg, const Slice& msg2) { - assert(code != kOk); - const uint32_t len1 = msg.size(); - const uint32_t len2 = msg2.size(); - const uint32_t size = len1 + (len2 ? (2 + len2) : 0); - char* result = new char[size + 5]; - memcpy(result, &size, sizeof(size)); - result[4] = static_cast(code); - memcpy(result + 5, msg.data(), len1); - if (len2) { - result[5 + len1] = ':'; - result[6 + len1] = ' '; - memcpy(result + 7 + len1, msg2.data(), len2); - } - state_ = result; -} - -std::string Status::ToString() const { - if (state_ == NULL) { - return "OK"; - } else { - char tmp[30]; - const char* type; - switch (code()) { - case kOk: - type = "OK"; - break; - case kNotFound: - type = "NotFound: "; - break; - case kCorruption: - type = "Corruption: "; - break; - case kNotSupported: - type = "Not implemented: "; - break; - case kInvalidArgument: - type = "Invalid argument: "; - break; - case kIOError: - type = "IO error: "; - break; - default: - snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", - static_cast(code())); - type = tmp; - break; - } - std::string result(type); - uint32_t length; - memcpy(&length, state_, sizeof(length)); - result.append(state_ + 5, length); - return result; - } -} - -} // namespace leveldb diff --git a/src/leveldb/util/testharness.cc b/src/leveldb/util/testharness.cc deleted file mode 100644 index 402fab34d7..0000000000 --- a/src/leveldb/util/testharness.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/testharness.h" - -#include -#include -#include -#include - -namespace leveldb { -namespace test { - -namespace { -struct Test { - const char* base; - const char* name; - void (*func)(); -}; -std::vector* tests; -} - -bool RegisterTest(const char* base, const char* name, void (*func)()) { - if (tests == NULL) { - tests = new std::vector; - } - Test t; - t.base = base; - t.name = name; - t.func = func; - tests->push_back(t); - return true; -} - -int RunAllTests() { - const char* matcher = getenv("LEVELDB_TESTS"); - - int num = 0; - if (tests != NULL) { - for (size_t i = 0; i < tests->size(); i++) { - const Test& t = (*tests)[i]; - if (matcher != NULL) { - std::string name = t.base; - name.push_back('.'); - name.append(t.name); - if (strstr(name.c_str(), matcher) == NULL) { - continue; - } - } - fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); - (*t.func)(); - ++num; - } - } - fprintf(stderr, "==== PASSED %d tests\n", num); - return 0; -} - -std::string TmpDir() { - std::string dir; - Status s = Env::Default()->GetTestDirectory(&dir); - ASSERT_TRUE(s.ok()) << s.ToString(); - return dir; -} - -int RandomSeed() { - const char* env = getenv("TEST_RANDOM_SEED"); - int result = (env != NULL ? atoi(env) : 301); - if (result <= 0) { - result = 301; - } - return result; -} - -} // namespace test -} // namespace leveldb diff --git a/src/leveldb/util/testharness.h b/src/leveldb/util/testharness.h deleted file mode 100644 index da4fe68bb4..0000000000 --- a/src/leveldb/util/testharness.h +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ -#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ - -#include -#include -#include -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "util/random.h" - -namespace leveldb { -namespace test { - -// Run some of the tests registered by the TEST() macro. If the -// environment variable "LEVELDB_TESTS" is not set, runs all tests. -// Otherwise, runs only the tests whose name contains the value of -// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: -// TEST(Foo, Hello) { ... } -// TEST(Foo, World) { ... } -// LEVELDB_TESTS=Hello will run the first test -// LEVELDB_TESTS=o will run both tests -// LEVELDB_TESTS=Junk will run no tests -// -// Returns 0 if all tests pass. -// Dies or returns a non-zero value if some test fails. -extern int RunAllTests(); - -// Return the directory to use for temporary storage. -extern std::string TmpDir(); - -// Return a randomization seed for this run. Typically returns the -// same number on repeated invocations of this binary, but automated -// runs may be able to vary the seed. -extern int RandomSeed(); - -// An instance of Tester is allocated to hold temporary state during -// the execution of an assertion. -class Tester { - private: - bool ok_; - const char* fname_; - int line_; - std::stringstream ss_; - - public: - Tester(const char* f, int l) - : ok_(true), fname_(f), line_(l) { - } - - ~Tester() { - if (!ok_) { - fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); - exit(1); - } - } - - Tester& Is(bool b, const char* msg) { - if (!b) { - ss_ << " Assertion failure " << msg; - ok_ = false; - } - return *this; - } - - Tester& IsOk(const Status& s) { - if (!s.ok()) { - ss_ << " " << s.ToString(); - ok_ = false; - } - return *this; - } - -#define BINARY_OP(name,op) \ - template \ - Tester& name(const X& x, const Y& y) { \ - if (! (x op y)) { \ - ss_ << " failed: " << x << (" " #op " ") << y; \ - ok_ = false; \ - } \ - return *this; \ - } - - BINARY_OP(IsEq, ==) - BINARY_OP(IsNe, !=) - BINARY_OP(IsGe, >=) - BINARY_OP(IsGt, >) - BINARY_OP(IsLe, <=) - BINARY_OP(IsLt, <) -#undef BINARY_OP - - // Attach the specified value to the error message if an error has occurred - template - Tester& operator<<(const V& value) { - if (!ok_) { - ss_ << " " << value; - } - return *this; - } -}; - -#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) -#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) -#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) -#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) -#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) -#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) -#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) -#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) - -#define TCONCAT(a,b) TCONCAT1(a,b) -#define TCONCAT1(a,b) a##b - -#define TEST(base,name) \ -class TCONCAT(_Test_,name) : public base { \ - public: \ - void _Run(); \ - static void _RunIt() { \ - TCONCAT(_Test_,name) t; \ - t._Run(); \ - } \ -}; \ -bool TCONCAT(_Test_ignored_,name) = \ - ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ -void TCONCAT(_Test_,name)::_Run() - -// Register the specified test. Typically not used directly, but -// invoked via the macro expansion of TEST. -extern bool RegisterTest(const char* base, const char* name, void (*func)()); - - -} // namespace test -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/src/leveldb/util/testutil.cc b/src/leveldb/util/testutil.cc deleted file mode 100644 index bee56bf75f..0000000000 --- a/src/leveldb/util/testutil.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "util/testutil.h" - -#include "util/random.h" - -namespace leveldb { -namespace test { - -Slice RandomString(Random* rnd, int len, std::string* dst) { - dst->resize(len); - for (int i = 0; i < len; i++) { - (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' - } - return Slice(*dst); -} - -std::string RandomKey(Random* rnd, int len) { - // Make sure to generate a wide variety of characters so we - // test the boundary conditions for short-key optimizations. - static const char kTestChars[] = { - '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' - }; - std::string result; - for (int i = 0; i < len; i++) { - result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; - } - return result; -} - - -extern Slice CompressibleString(Random* rnd, double compressed_fraction, - size_t len, std::string* dst) { - int raw = static_cast(len * compressed_fraction); - if (raw < 1) raw = 1; - std::string raw_data; - RandomString(rnd, raw, &raw_data); - - // Duplicate the random data until we have filled "len" bytes - dst->clear(); - while (dst->size() < len) { - dst->append(raw_data); - } - dst->resize(len); - return Slice(*dst); -} - -} // namespace test -} // namespace leveldb diff --git a/src/leveldb/util/testutil.h b/src/leveldb/util/testutil.h deleted file mode 100644 index adad3fc1ea..0000000000 --- a/src/leveldb/util/testutil.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ -#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ - -#include "leveldb/env.h" -#include "leveldb/slice.h" -#include "util/random.h" - -namespace leveldb { -namespace test { - -// Store in *dst a random string of length "len" and return a Slice that -// references the generated data. -extern Slice RandomString(Random* rnd, int len, std::string* dst); - -// Return a random key with the specified length that may contain interesting -// characters (e.g. \x00, \xff, etc.). -extern std::string RandomKey(Random* rnd, int len); - -// Store in *dst a string of length "len" that will compress to -// "N*compressed_fraction" bytes and return a Slice that references -// the generated data. -extern Slice CompressibleString(Random* rnd, double compressed_fraction, - size_t len, std::string* dst); - -// A wrapper that allows injection of errors. -class ErrorEnv : public EnvWrapper { - public: - bool writable_file_error_; - int num_writable_file_errors_; - - ErrorEnv() : EnvWrapper(Env::Default()), - writable_file_error_(false), - num_writable_file_errors_(0) { } - - virtual Status NewWritableFile(const std::string& fname, - WritableFile** result) { - if (writable_file_error_) { - ++num_writable_file_errors_; - *result = NULL; - return Status::IOError(fname, "fake error"); - } - return target()->NewWritableFile(fname, result); - } -}; - -} // namespace test -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ From 68cc8ecd51309dbd32b8246b01e15d033570e644 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Nov 2020 12:49:19 -0500 Subject: [PATCH 0513/1888] Squashed 'src/leveldb/' content from commit 64052c7 git-subtree-dir: src/leveldb git-subtree-split: 64052c76c567cff3dad32d1db0ef969d97b5882f --- .gitignore | 13 + .travis.yml | 13 + AUTHORS | 12 + CONTRIBUTING.md | 36 + LICENSE | 27 + Makefile | 424 ++++++ NEWS | 17 + README.md | 174 +++ TODO | 14 + WINDOWS.md | 39 + build_detect_platform | 259 ++++ db/autocompact_test.cc | 118 ++ db/builder.cc | 88 ++ db/builder.h | 34 + db/c.cc | 595 +++++++++ db/c_test.c | 390 ++++++ db/corruption_test.cc | 374 ++++++ db/db_bench.cc | 1020 +++++++++++++++ db/db_impl.cc | 1568 ++++++++++++++++++++++ db/db_impl.h | 211 +++ db/db_iter.cc | 317 +++++ db/db_iter.h | 28 + db/db_test.cc | 2158 +++++++++++++++++++++++++++++++ db/dbformat.cc | 140 ++ db/dbformat.h | 230 ++++ db/dbformat_test.cc | 112 ++ db/dumpfile.cc | 225 ++++ db/fault_injection_test.cc | 554 ++++++++ db/filename.cc | 144 +++ db/filename.h | 85 ++ db/filename_test.cc | 123 ++ db/leveldbutil.cc | 65 + db/log_format.h | 35 + db/log_reader.cc | 284 ++++ db/log_reader.h | 113 ++ db/log_test.cc | 591 +++++++++ db/log_writer.cc | 112 ++ db/log_writer.h | 54 + db/memtable.cc | 145 +++ db/memtable.h | 88 ++ db/recovery_test.cc | 324 +++++ db/repair.cc | 461 +++++++ db/skiplist.h | 384 ++++++ db/skiplist_test.cc | 378 ++++++ db/snapshot.h | 67 + db/table_cache.cc | 127 ++ db/table_cache.h | 61 + db/version_edit.cc | 266 ++++ db/version_edit.h | 107 ++ db/version_edit_test.cc | 46 + db/version_set.cc | 1535 ++++++++++++++++++++++ db/version_set.h | 398 ++++++ db/version_set_test.cc | 179 +++ db/write_batch.cc | 147 +++ db/write_batch_internal.h | 50 + db/write_batch_test.cc | 120 ++ doc/bench/db_bench_sqlite3.cc | 718 ++++++++++ doc/bench/db_bench_tree_db.cc | 528 ++++++++ doc/benchmark.html | 459 +++++++ doc/impl.md | 170 +++ doc/index.md | 523 ++++++++ doc/log_format.md | 75 ++ doc/table_format.md | 107 ++ helpers/memenv/memenv.cc | 401 ++++++ helpers/memenv/memenv.h | 20 + helpers/memenv/memenv_test.cc | 241 ++++ include/leveldb/c.h | 290 +++++ include/leveldb/cache.h | 110 ++ include/leveldb/comparator.h | 63 + include/leveldb/db.h | 163 +++ include/leveldb/dumpfile.h | 25 + include/leveldb/env.h | 360 ++++++ include/leveldb/filter_policy.h | 70 + include/leveldb/iterator.h | 100 ++ include/leveldb/options.h | 213 +++ include/leveldb/slice.h | 109 ++ include/leveldb/status.h | 112 ++ include/leveldb/table.h | 85 ++ include/leveldb/table_builder.h | 92 ++ include/leveldb/write_batch.h | 64 + issues/issue178_test.cc | 92 ++ issues/issue200_test.cc | 59 + port/README | 10 + port/atomic_pointer.h | 245 ++++ port/port.h | 21 + port/port_example.h | 145 +++ port/port_posix.cc | 67 + port/port_posix.h | 161 +++ port/port_posix_sse.cc | 110 ++ port/port_win.cc | 158 +++ port/port_win.h | 177 +++ port/thread_annotations.h | 60 + port/win/stdint.h | 24 + table/block.cc | 268 ++++ table/block.h | 44 + table/block_builder.cc | 109 ++ table/block_builder.h | 57 + table/filter_block.cc | 111 ++ table/filter_block.h | 68 + table/filter_block_test.cc | 128 ++ table/format.cc | 144 +++ table/format.h | 108 ++ table/iterator.cc | 67 + table/iterator_wrapper.h | 66 + table/merger.cc | 197 +++ table/merger.h | 26 + table/table.cc | 285 ++++ table/table_builder.cc | 270 ++++ table/table_test.cc | 876 +++++++++++++ table/two_level_iterator.cc | 182 +++ table/two_level_iterator.h | 34 + util/arena.cc | 68 + util/arena.h | 68 + util/arena_test.cc | 68 + util/bloom.cc | 95 ++ util/bloom_test.cc | 162 +++ util/cache.cc | 405 ++++++ util/cache_test.cc | 226 ++++ util/coding.cc | 194 +++ util/coding.h | 104 ++ util/coding_test.cc | 196 +++ util/comparator.cc | 81 ++ util/crc32c.cc | 354 +++++ util/crc32c.h | 45 + util/crc32c_test.cc | 72 ++ util/env.cc | 100 ++ util/env_posix.cc | 706 ++++++++++ util/env_posix_test.cc | 66 + util/env_posix_test_helper.h | 28 + util/env_test.cc | 106 ++ util/env_win.cc | 901 +++++++++++++ util/filter_policy.cc | 11 + util/hash.cc | 52 + util/hash.h | 19 + util/hash_test.cc | 54 + util/histogram.cc | 139 ++ util/histogram.h | 42 + util/logging.cc | 72 ++ util/logging.h | 43 + util/mutexlock.h | 41 + util/options.cc | 30 + util/posix_logger.h | 98 ++ util/random.h | 64 + util/status.cc | 75 ++ util/testharness.cc | 77 ++ util/testharness.h | 138 ++ util/testutil.cc | 51 + util/testutil.h | 63 + 148 files changed, 30260 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README.md create mode 100644 TODO create mode 100644 WINDOWS.md create mode 100755 build_detect_platform create mode 100644 db/autocompact_test.cc create mode 100644 db/builder.cc create mode 100644 db/builder.h create mode 100644 db/c.cc create mode 100644 db/c_test.c create mode 100644 db/corruption_test.cc create mode 100644 db/db_bench.cc create mode 100644 db/db_impl.cc create mode 100644 db/db_impl.h create mode 100644 db/db_iter.cc create mode 100644 db/db_iter.h create mode 100644 db/db_test.cc create mode 100644 db/dbformat.cc create mode 100644 db/dbformat.h create mode 100644 db/dbformat_test.cc create mode 100644 db/dumpfile.cc create mode 100644 db/fault_injection_test.cc create mode 100644 db/filename.cc create mode 100644 db/filename.h create mode 100644 db/filename_test.cc create mode 100644 db/leveldbutil.cc create mode 100644 db/log_format.h create mode 100644 db/log_reader.cc create mode 100644 db/log_reader.h create mode 100644 db/log_test.cc create mode 100644 db/log_writer.cc create mode 100644 db/log_writer.h create mode 100644 db/memtable.cc create mode 100644 db/memtable.h create mode 100644 db/recovery_test.cc create mode 100644 db/repair.cc create mode 100644 db/skiplist.h create mode 100644 db/skiplist_test.cc create mode 100644 db/snapshot.h create mode 100644 db/table_cache.cc create mode 100644 db/table_cache.h create mode 100644 db/version_edit.cc create mode 100644 db/version_edit.h create mode 100644 db/version_edit_test.cc create mode 100644 db/version_set.cc create mode 100644 db/version_set.h create mode 100644 db/version_set_test.cc create mode 100644 db/write_batch.cc create mode 100644 db/write_batch_internal.h create mode 100644 db/write_batch_test.cc create mode 100644 doc/bench/db_bench_sqlite3.cc create mode 100644 doc/bench/db_bench_tree_db.cc create mode 100644 doc/benchmark.html create mode 100644 doc/impl.md create mode 100644 doc/index.md create mode 100644 doc/log_format.md create mode 100644 doc/table_format.md create mode 100644 helpers/memenv/memenv.cc create mode 100644 helpers/memenv/memenv.h create mode 100644 helpers/memenv/memenv_test.cc create mode 100644 include/leveldb/c.h create mode 100644 include/leveldb/cache.h create mode 100644 include/leveldb/comparator.h create mode 100644 include/leveldb/db.h create mode 100644 include/leveldb/dumpfile.h create mode 100644 include/leveldb/env.h create mode 100644 include/leveldb/filter_policy.h create mode 100644 include/leveldb/iterator.h create mode 100644 include/leveldb/options.h create mode 100644 include/leveldb/slice.h create mode 100644 include/leveldb/status.h create mode 100644 include/leveldb/table.h create mode 100644 include/leveldb/table_builder.h create mode 100644 include/leveldb/write_batch.h create mode 100644 issues/issue178_test.cc create mode 100644 issues/issue200_test.cc create mode 100644 port/README create mode 100644 port/atomic_pointer.h create mode 100644 port/port.h create mode 100644 port/port_example.h create mode 100644 port/port_posix.cc create mode 100644 port/port_posix.h create mode 100644 port/port_posix_sse.cc create mode 100644 port/port_win.cc create mode 100644 port/port_win.h create mode 100644 port/thread_annotations.h create mode 100644 port/win/stdint.h create mode 100644 table/block.cc create mode 100644 table/block.h create mode 100644 table/block_builder.cc create mode 100644 table/block_builder.h create mode 100644 table/filter_block.cc create mode 100644 table/filter_block.h create mode 100644 table/filter_block_test.cc create mode 100644 table/format.cc create mode 100644 table/format.h create mode 100644 table/iterator.cc create mode 100644 table/iterator_wrapper.h create mode 100644 table/merger.cc create mode 100644 table/merger.h create mode 100644 table/table.cc create mode 100644 table/table_builder.cc create mode 100644 table/table_test.cc create mode 100644 table/two_level_iterator.cc create mode 100644 table/two_level_iterator.h create mode 100644 util/arena.cc create mode 100644 util/arena.h create mode 100644 util/arena_test.cc create mode 100644 util/bloom.cc create mode 100644 util/bloom_test.cc create mode 100644 util/cache.cc create mode 100644 util/cache_test.cc create mode 100644 util/coding.cc create mode 100644 util/coding.h create mode 100644 util/coding_test.cc create mode 100644 util/comparator.cc create mode 100644 util/crc32c.cc create mode 100644 util/crc32c.h create mode 100644 util/crc32c_test.cc create mode 100644 util/env.cc create mode 100644 util/env_posix.cc create mode 100644 util/env_posix_test.cc create mode 100644 util/env_posix_test_helper.h create mode 100644 util/env_test.cc create mode 100644 util/env_win.cc create mode 100644 util/filter_policy.cc create mode 100644 util/hash.cc create mode 100644 util/hash.h create mode 100644 util/hash_test.cc create mode 100644 util/histogram.cc create mode 100644 util/histogram.h create mode 100644 util/logging.cc create mode 100644 util/logging.h create mode 100644 util/mutexlock.h create mode 100644 util/options.cc create mode 100644 util/posix_logger.h create mode 100644 util/random.h create mode 100644 util/status.cc create mode 100644 util/testharness.cc create mode 100644 util/testharness.h create mode 100644 util/testutil.cc create mode 100644 util/testutil.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..71d87a4eeb --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +build_config.mk +*.a +*.o +*.dylib* +*.so +*.so.* +*_test +db_bench +leveldbutil +Release +Debug +Benchmark +vs2010.* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..f5bd74c454 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: cpp +compiler: +- clang +- gcc +os: +- linux +- osx +sudo: false +before_install: +- echo $LANG +- echo $LC_ALL +script: +- make -j 4 check diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..2439d7a452 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,12 @@ +# Names should be added to this file like so: +# Name or Organization + +Google Inc. + +# Initial version authors: +Jeffrey Dean +Sanjay Ghemawat + +# Partial list of contributors: +Kevin Regan +Johan Bilien diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..cd600ff46b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing + +We'd love to accept your code patches! However, before we can take them, we +have to jump a couple of legal hurdles. + +## Contributor License Agreements + +Please fill out either the individual or corporate Contributor License +Agreement as appropriate. + +* If you are an individual writing original source code and you're sure you +own the intellectual property, then sign an [individual CLA](https://developers.google.com/open-source/cla/individual). +* If you work for a company that wants to allow you to contribute your work, +then sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. + +## Submitting a Patch + +1. Sign the contributors license agreement above. +2. Decide which code you want to submit. A submission should be a set of changes +that addresses one issue in the [issue tracker](https://github.com/google/leveldb/issues). +Please don't mix more than one logical change per submission, because it makes +the history hard to follow. If you want to make a change +(e.g. add a sample or feature) that doesn't have a corresponding issue in the +issue tracker, please create one. +3. **Submitting**: When you are ready to submit, send us a Pull Request. Be +sure to include the issue number you fixed and the name you used to sign +the CLA. + +## Writing Code ## + +If your contribution contains code, please make sure that it follows +[the style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). +Otherwise we will have to ask you to make changes, and that's no fun for anyone. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..8e80208cd7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The LevelDB Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..f7cc7d736c --- /dev/null +++ b/Makefile @@ -0,0 +1,424 @@ +# Copyright (c) 2011 The LevelDB Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. See the AUTHORS file for names of contributors. + +#----------------------------------------------- +# Uncomment exactly one of the lines labelled (A), (B), and (C) below +# to switch between compilation modes. + +# (A) Production use (optimized mode) +OPT ?= -O2 -DNDEBUG +# (B) Debug mode, w/ full line-level debugging symbols +# OPT ?= -g2 +# (C) Profiling mode: opt, but w/debugging symbols +# OPT ?= -O2 -g2 -DNDEBUG +#----------------------------------------------- + +# detect what platform we're building on +$(shell CC="$(CC)" CXX="$(CXX)" TARGET_OS="$(TARGET_OS)" \ + ./build_detect_platform build_config.mk ./) +# this file is generated by the previous line to set build flags and sources +include build_config.mk + +TESTS = \ + db/autocompact_test \ + db/c_test \ + db/corruption_test \ + db/db_test \ + db/dbformat_test \ + db/fault_injection_test \ + db/filename_test \ + db/log_test \ + db/recovery_test \ + db/skiplist_test \ + db/version_edit_test \ + db/version_set_test \ + db/write_batch_test \ + helpers/memenv/memenv_test \ + issues/issue178_test \ + issues/issue200_test \ + table/filter_block_test \ + table/table_test \ + util/arena_test \ + util/bloom_test \ + util/cache_test \ + util/coding_test \ + util/crc32c_test \ + util/env_posix_test \ + util/env_test \ + util/hash_test + +UTILS = \ + db/db_bench \ + db/leveldbutil + +# Put the object files in a subdirectory, but the application at the top of the object dir. +PROGNAMES := $(notdir $(TESTS) $(UTILS)) + +# On Linux may need libkyotocabinet-dev for dependency. +BENCHMARKS = \ + doc/bench/db_bench_sqlite3 \ + doc/bench/db_bench_tree_db + +CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) +CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) + +LDFLAGS += $(PLATFORM_LDFLAGS) +LIBS += $(PLATFORM_LIBS) + +SIMULATOR_OUTDIR=out-ios-x86 +DEVICE_OUTDIR=out-ios-arm + +ifeq ($(PLATFORM), IOS) +# Note: iOS should probably be using libtool, not ar. +AR=xcrun ar +SIMULATORSDK=$(shell xcrun -sdk iphonesimulator --show-sdk-path) +DEVICESDK=$(shell xcrun -sdk iphoneos --show-sdk-path) +DEVICE_CFLAGS = -isysroot "$(DEVICESDK)" -arch armv6 -arch armv7 -arch armv7s -arch arm64 +SIMULATOR_CFLAGS = -isysroot "$(SIMULATORSDK)" -arch i686 -arch x86_64 +STATIC_OUTDIR=out-ios-universal +else +STATIC_OUTDIR=out-static +SHARED_OUTDIR=out-shared +STATIC_PROGRAMS := $(addprefix $(STATIC_OUTDIR)/, $(PROGNAMES)) +SHARED_PROGRAMS := $(addprefix $(SHARED_OUTDIR)/, db_bench) +endif + +STATIC_LIBOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(SOURCES:.cc=.o)) +STATIC_MEMENVOBJECTS := $(addprefix $(STATIC_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +DEVICE_LIBOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(SOURCES:.cc=.o)) +DEVICE_MEMENVOBJECTS := $(addprefix $(DEVICE_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +SIMULATOR_LIBOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(SOURCES:.cc=.o)) +SIMULATOR_MEMENVOBJECTS := $(addprefix $(SIMULATOR_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +SHARED_LIBOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(SOURCES:.cc=.o)) +SHARED_MEMENVOBJECTS := $(addprefix $(SHARED_OUTDIR)/, $(MEMENV_SOURCES:.cc=.o)) + +TESTUTIL := $(STATIC_OUTDIR)/util/testutil.o +TESTHARNESS := $(STATIC_OUTDIR)/util/testharness.o $(TESTUTIL) + +STATIC_TESTOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(TESTS))) +STATIC_UTILOBJS := $(addprefix $(STATIC_OUTDIR)/, $(addsuffix .o, $(UTILS))) +STATIC_ALLOBJS := $(STATIC_LIBOBJECTS) $(STATIC_MEMENVOBJECTS) $(STATIC_TESTOBJS) $(STATIC_UTILOBJS) $(TESTHARNESS) +DEVICE_ALLOBJS := $(DEVICE_LIBOBJECTS) $(DEVICE_MEMENVOBJECTS) +SIMULATOR_ALLOBJS := $(SIMULATOR_LIBOBJECTS) $(SIMULATOR_MEMENVOBJECTS) + +default: all + +# Should we build shared libraries? +ifneq ($(PLATFORM_SHARED_EXT),) + +# Many leveldb test apps use non-exported API's. Only build a subset for testing. +SHARED_ALLOBJS := $(SHARED_LIBOBJECTS) $(SHARED_MEMENVOBJECTS) $(TESTHARNESS) + +ifneq ($(PLATFORM_SHARED_VERSIONED),true) +SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED_LIB2 = $(SHARED_LIB1) +SHARED_LIB3 = $(SHARED_LIB1) +SHARED_LIBS = $(SHARED_LIB1) +SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a +else +# Update db.h if you change these. +SHARED_VERSION_MAJOR = 1 +SHARED_VERSION_MINOR = 20 +SHARED_LIB1 = libleveldb.$(PLATFORM_SHARED_EXT) +SHARED_LIB2 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR) +SHARED_LIB3 = $(SHARED_LIB1).$(SHARED_VERSION_MAJOR).$(SHARED_VERSION_MINOR) +SHARED_LIBS = $(SHARED_OUTDIR)/$(SHARED_LIB1) $(SHARED_OUTDIR)/$(SHARED_LIB2) $(SHARED_OUTDIR)/$(SHARED_LIB3) +$(SHARED_OUTDIR)/$(SHARED_LIB1): $(SHARED_OUTDIR)/$(SHARED_LIB3) + ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB1) +$(SHARED_OUTDIR)/$(SHARED_LIB2): $(SHARED_OUTDIR)/$(SHARED_LIB3) + ln -fs $(SHARED_LIB3) $(SHARED_OUTDIR)/$(SHARED_LIB2) +SHARED_MEMENVLIB = $(SHARED_OUTDIR)/libmemenv.a +endif + +$(SHARED_OUTDIR)/$(SHARED_LIB3): $(SHARED_LIBOBJECTS) + $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED_LIB2) $(SHARED_LIBOBJECTS) -o $(SHARED_OUTDIR)/$(SHARED_LIB3) $(LIBS) + +endif # PLATFORM_SHARED_EXT + +all: $(SHARED_LIBS) $(SHARED_PROGRAMS) $(STATIC_OUTDIR)/libleveldb.a $(STATIC_OUTDIR)/libmemenv.a $(STATIC_PROGRAMS) + +check: $(STATIC_PROGRAMS) + for t in $(notdir $(TESTS)); do echo "***** Running $$t"; $(STATIC_OUTDIR)/$$t || exit 1; done + +clean: + -rm -rf out-static out-shared out-ios-x86 out-ios-arm out-ios-universal + -rm -f build_config.mk + -rm -rf ios-x86 ios-arm + +$(STATIC_OUTDIR): + mkdir $@ + +$(STATIC_OUTDIR)/db: | $(STATIC_OUTDIR) + mkdir $@ + +$(STATIC_OUTDIR)/helpers/memenv: | $(STATIC_OUTDIR) + mkdir -p $@ + +$(STATIC_OUTDIR)/port: | $(STATIC_OUTDIR) + mkdir $@ + +$(STATIC_OUTDIR)/table: | $(STATIC_OUTDIR) + mkdir $@ + +$(STATIC_OUTDIR)/util: | $(STATIC_OUTDIR) + mkdir $@ + +.PHONY: STATIC_OBJDIRS +STATIC_OBJDIRS: \ + $(STATIC_OUTDIR)/db \ + $(STATIC_OUTDIR)/port \ + $(STATIC_OUTDIR)/table \ + $(STATIC_OUTDIR)/util \ + $(STATIC_OUTDIR)/helpers/memenv + +$(SHARED_OUTDIR): + mkdir $@ + +$(SHARED_OUTDIR)/db: | $(SHARED_OUTDIR) + mkdir $@ + +$(SHARED_OUTDIR)/helpers/memenv: | $(SHARED_OUTDIR) + mkdir -p $@ + +$(SHARED_OUTDIR)/port: | $(SHARED_OUTDIR) + mkdir $@ + +$(SHARED_OUTDIR)/table: | $(SHARED_OUTDIR) + mkdir $@ + +$(SHARED_OUTDIR)/util: | $(SHARED_OUTDIR) + mkdir $@ + +.PHONY: SHARED_OBJDIRS +SHARED_OBJDIRS: \ + $(SHARED_OUTDIR)/db \ + $(SHARED_OUTDIR)/port \ + $(SHARED_OUTDIR)/table \ + $(SHARED_OUTDIR)/util \ + $(SHARED_OUTDIR)/helpers/memenv + +$(DEVICE_OUTDIR): + mkdir $@ + +$(DEVICE_OUTDIR)/db: | $(DEVICE_OUTDIR) + mkdir $@ + +$(DEVICE_OUTDIR)/helpers/memenv: | $(DEVICE_OUTDIR) + mkdir -p $@ + +$(DEVICE_OUTDIR)/port: | $(DEVICE_OUTDIR) + mkdir $@ + +$(DEVICE_OUTDIR)/table: | $(DEVICE_OUTDIR) + mkdir $@ + +$(DEVICE_OUTDIR)/util: | $(DEVICE_OUTDIR) + mkdir $@ + +.PHONY: DEVICE_OBJDIRS +DEVICE_OBJDIRS: \ + $(DEVICE_OUTDIR)/db \ + $(DEVICE_OUTDIR)/port \ + $(DEVICE_OUTDIR)/table \ + $(DEVICE_OUTDIR)/util \ + $(DEVICE_OUTDIR)/helpers/memenv + +$(SIMULATOR_OUTDIR): + mkdir $@ + +$(SIMULATOR_OUTDIR)/db: | $(SIMULATOR_OUTDIR) + mkdir $@ + +$(SIMULATOR_OUTDIR)/helpers/memenv: | $(SIMULATOR_OUTDIR) + mkdir -p $@ + +$(SIMULATOR_OUTDIR)/port: | $(SIMULATOR_OUTDIR) + mkdir $@ + +$(SIMULATOR_OUTDIR)/table: | $(SIMULATOR_OUTDIR) + mkdir $@ + +$(SIMULATOR_OUTDIR)/util: | $(SIMULATOR_OUTDIR) + mkdir $@ + +.PHONY: SIMULATOR_OBJDIRS +SIMULATOR_OBJDIRS: \ + $(SIMULATOR_OUTDIR)/db \ + $(SIMULATOR_OUTDIR)/port \ + $(SIMULATOR_OUTDIR)/table \ + $(SIMULATOR_OUTDIR)/util \ + $(SIMULATOR_OUTDIR)/helpers/memenv + +$(STATIC_ALLOBJS): | STATIC_OBJDIRS +$(DEVICE_ALLOBJS): | DEVICE_OBJDIRS +$(SIMULATOR_ALLOBJS): | SIMULATOR_OBJDIRS +$(SHARED_ALLOBJS): | SHARED_OBJDIRS + +ifeq ($(PLATFORM), IOS) +$(DEVICE_OUTDIR)/libleveldb.a: $(DEVICE_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(DEVICE_LIBOBJECTS) + +$(SIMULATOR_OUTDIR)/libleveldb.a: $(SIMULATOR_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SIMULATOR_LIBOBJECTS) + +$(DEVICE_OUTDIR)/libmemenv.a: $(DEVICE_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(DEVICE_MEMENVOBJECTS) + +$(SIMULATOR_OUTDIR)/libmemenv.a: $(SIMULATOR_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SIMULATOR_MEMENVOBJECTS) + +# For iOS, create universal object libraries to be used on both the simulator and +# a device. +$(STATIC_OUTDIR)/libleveldb.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a + lipo -create $(DEVICE_OUTDIR)/libleveldb.a $(SIMULATOR_OUTDIR)/libleveldb.a -output $@ + +$(STATIC_OUTDIR)/libmemenv.a: $(STATIC_OUTDIR) $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a + lipo -create $(DEVICE_OUTDIR)/libmemenv.a $(SIMULATOR_OUTDIR)/libmemenv.a -output $@ +else +$(STATIC_OUTDIR)/libleveldb.a:$(STATIC_LIBOBJECTS) + rm -f $@ + $(AR) -rs $@ $(STATIC_LIBOBJECTS) + +$(STATIC_OUTDIR)/libmemenv.a:$(STATIC_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(STATIC_MEMENVOBJECTS) +endif + +$(SHARED_MEMENVLIB):$(SHARED_MEMENVOBJECTS) + rm -f $@ + $(AR) -rs $@ $(SHARED_MEMENVOBJECTS) + +$(STATIC_OUTDIR)/db_bench:db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_bench.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/db_bench_sqlite3:doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_sqlite3.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS) + +$(STATIC_OUTDIR)/db_bench_tree_db:doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) + $(CXX) $(LDFLAGS) $(CXXFLAGS) doc/bench/db_bench_tree_db.cc $(STATIC_LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS) + +$(STATIC_OUTDIR)/leveldbutil:db/leveldbutil.cc $(STATIC_LIBOBJECTS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/leveldbutil.cc $(STATIC_LIBOBJECTS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/arena_test:util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/arena_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/autocompact_test:db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/autocompact_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/bloom_test:util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/bloom_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/c_test:$(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/db/c_test.o $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/cache_test:util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/cache_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/coding_test:util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/coding_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/corruption_test:db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/corruption_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/crc32c_test:util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/crc32c_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/db_test:db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/db_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/dbformat_test:db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/dbformat_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/env_posix_test:util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_posix_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/env_test:util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/env_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/fault_injection_test:db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/fault_injection_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/filename_test:db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/filename_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/filter_block_test:table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) table/filter_block_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/hash_test:util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) util/hash_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/issue178_test:issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue178_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/issue200_test:issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) issues/issue200_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/log_test:db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/log_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/recovery_test:db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/recovery_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/table_test:table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) table/table_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/skiplist_test:db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/skiplist_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/version_edit_test:db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_edit_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/version_set_test:db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/version_set_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/write_batch_test:db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) + $(CXX) $(LDFLAGS) $(CXXFLAGS) db/write_batch_test.cc $(STATIC_LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS) + +$(STATIC_OUTDIR)/memenv_test:$(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS) + $(XCRUN) $(CXX) $(LDFLAGS) $(STATIC_OUTDIR)/helpers/memenv/memenv_test.o $(STATIC_OUTDIR)/libmemenv.a $(STATIC_OUTDIR)/libleveldb.a $(TESTHARNESS) -o $@ $(LIBS) + +$(SHARED_OUTDIR)/db_bench:$(SHARED_OUTDIR)/db/db_bench.o $(SHARED_LIBS) $(TESTUTIL) + $(XCRUN) $(CXX) $(LDFLAGS) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SHARED_OUTDIR)/db/db_bench.o $(TESTUTIL) $(SHARED_OUTDIR)/$(SHARED_LIB3) -o $@ $(LIBS) + +.PHONY: run-shared +run-shared: $(SHARED_OUTDIR)/db_bench + LD_LIBRARY_PATH=$(SHARED_OUTDIR) $(SHARED_OUTDIR)/db_bench + +$(SIMULATOR_OUTDIR)/%.o: %.cc + xcrun -sdk iphonesimulator $(CXX) $(CXXFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@ + +$(DEVICE_OUTDIR)/%.o: %.cc + xcrun -sdk iphoneos $(CXX) $(CXXFLAGS) $(DEVICE_CFLAGS) -c $< -o $@ + +$(SIMULATOR_OUTDIR)/%.o: %.c + xcrun -sdk iphonesimulator $(CC) $(CFLAGS) $(SIMULATOR_CFLAGS) -c $< -o $@ + +$(DEVICE_OUTDIR)/%.o: %.c + xcrun -sdk iphoneos $(CC) $(CFLAGS) $(DEVICE_CFLAGS) -c $< -o $@ + +$(STATIC_OUTDIR)/%.o: %.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ + +$(STATIC_OUTDIR)/%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(SHARED_OUTDIR)/%.o: %.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@ + +$(SHARED_OUTDIR)/%.o: %.c + $(CC) $(CFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@ + +$(STATIC_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@ + +$(SHARED_OUTDIR)/port/port_posix_sse.o: port/port_posix_sse.cc + $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(PLATFORM_SSEFLAGS) -c $< -o $@ diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..3fd99242d7 --- /dev/null +++ b/NEWS @@ -0,0 +1,17 @@ +Release 1.2 2011-05-16 +---------------------- + +Fixes for larger databases (tested up to one billion 100-byte entries, +i.e., ~100GB). + +(1) Place hard limit on number of level-0 files. This fixes errors +of the form "too many open files". + +(2) Fixed memtable management. Before the fix, a heavy write burst +could cause unbounded memory usage. + +A fix for a logging bug where the reader would incorrectly complain +about corruption. + +Allow public access to WriteBatch contents so that users can easily +wrap a DB. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..a010c50858 --- /dev/null +++ b/README.md @@ -0,0 +1,174 @@ +**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.** + +[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb) + +Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) + +# Features + * Keys and values are arbitrary byte arrays. + * Data is stored sorted by key. + * Callers can provide a custom comparison function to override the sort order. + * The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`. + * Multiple changes can be made in one atomic batch. + * Users can create a transient snapshot to get a consistent view of data. + * Forward and backward iteration is supported over the data. + * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/). + * External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions. + +# Documentation + [LevelDB library documentation](https://github.com/google/leveldb/blob/master/doc/index.md) is online and bundled with the source code. + + +# Limitations + * This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes. + * Only a single process (possibly multi-threaded) can access a particular database at a time. + * There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library. + +# Contributing to the leveldb Project +The leveldb project welcomes contributions. leveldb's primary goal is to be +a reliable and fast key/value store. Changes that are in line with the +features/limitations outlined above, and meet the requirements below, +will be considered. + +Contribution requirements: + +1. **POSIX only**. We _generally_ will only accept changes that are both + compiled, and tested on a POSIX platform - usually Linux. Very small + changes will sometimes be accepted, but consider that more of an + exception than the rule. + +2. **Stable API**. We strive very hard to maintain a stable API. Changes that + require changes for projects using leveldb _might_ be rejected without + sufficient benefit to the project. + +3. **Tests**: All changes must be accompanied by a new (or changed) test, or + a sufficient explanation as to why a new (or changed) test is not required. + +## Submitting a Pull Request +Before any pull request will be accepted the author must first sign a +Contributor License Agreement (CLA) at https://cla.developers.google.com/. + +In order to keep the commit timeline linear +[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits) +your changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase) +on google/leveldb/master. This keeps the commit timeline linear and more easily sync'ed +with the internal repository at Google. More information at GitHub's +[About Git rebase](https://help.github.com/articles/about-git-rebase/) page. + +# Performance + +Here is a performance report (with explanations) from the run of the +included db_bench program. The results are somewhat noisy, but should +be enough to get a ballpark performance estimate. + +## Setup + +We use a database with a million entries. Each entry has a 16 byte +key, and a 100 byte value. Values used by the benchmark compress to +about half their original size. + + LevelDB: version 1.1 + Date: Sun May 1 12:11:26 2011 + CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz + CPUCache: 4096 KB + Keys: 16 bytes each + Values: 100 bytes each (50 bytes after compression) + Entries: 1000000 + Raw Size: 110.6 MB (estimated) + File Size: 62.9 MB (estimated) + +## Write performance + +The "fill" benchmarks create a brand new database, in either +sequential, or random order. The "fillsync" benchmark flushes data +from the operating system to the disk after every operation; the other +write operations leave the data sitting in the operating system buffer +cache for a while. The "overwrite" benchmark does random writes that +update existing keys in the database. + + fillseq : 1.765 micros/op; 62.7 MB/s + fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops) + fillrandom : 2.460 micros/op; 45.0 MB/s + overwrite : 2.380 micros/op; 46.5 MB/s + +Each "op" above corresponds to a write of a single key/value pair. +I.e., a random write benchmark goes at approximately 400,000 writes per second. + +Each "fillsync" operation costs much less (0.3 millisecond) +than a disk seek (typically 10 milliseconds). We suspect that this is +because the hard disk itself is buffering the update in its memory and +responding before the data has been written to the platter. This may +or may not be safe based on whether or not the hard disk has enough +power to save its memory in the event of a power failure. + +## Read performance + +We list the performance of reading sequentially in both the forward +and reverse direction, and also the performance of a random lookup. +Note that the database created by the benchmark is quite small. +Therefore the report characterizes the performance of leveldb when the +working set fits in memory. The cost of reading a piece of data that +is not present in the operating system buffer cache will be dominated +by the one or two disk seeks needed to fetch the data from disk. +Write performance will be mostly unaffected by whether or not the +working set fits in memory. + + readrandom : 16.677 micros/op; (approximately 60,000 reads per second) + readseq : 0.476 micros/op; 232.3 MB/s + readreverse : 0.724 micros/op; 152.9 MB/s + +LevelDB compacts its underlying storage data in the background to +improve read performance. The results listed above were done +immediately after a lot of random writes. The results after +compactions (which are usually triggered automatically) are better. + + readrandom : 11.602 micros/op; (approximately 85,000 reads per second) + readseq : 0.423 micros/op; 261.8 MB/s + readreverse : 0.663 micros/op; 166.9 MB/s + +Some of the high cost of reads comes from repeated decompression of blocks +read from disk. If we supply enough cache to the leveldb so it can hold the +uncompressed blocks in memory, the read performance improves again: + + readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction) + readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction) + +## Repository contents + +See [doc/index.md](doc/index.md) for more explanation. See +[doc/impl.md](doc/impl.md) for a brief overview of the implementation. + +The public interface is in include/*.h. Callers should not include or +rely on the details of any other header files in this package. Those +internal APIs may be changed without warning. + +Guide to header files: + +* **include/db.h**: Main interface to the DB: Start here + +* **include/options.h**: Control over the behavior of an entire database, +and also control over the behavior of individual reads and writes. + +* **include/comparator.h**: Abstraction for user-specified comparison function. +If you want just bytewise comparison of keys, you can use the default +comparator, but clients can write their own comparator implementations if they +want custom ordering (e.g. to handle different character encodings, etc.) + +* **include/iterator.h**: Interface for iterating over data. You can get +an iterator from a DB object. + +* **include/write_batch.h**: Interface for atomically applying multiple +updates to a database. + +* **include/slice.h**: A simple module for maintaining a pointer and a +length into some other byte array. + +* **include/status.h**: Status is returned from many of the public interfaces +and is used to report success and various kinds of errors. + +* **include/env.h**: +Abstraction of the OS environment. A posix implementation of this interface is +in util/env_posix.cc + +* **include/table.h, include/table_builder.h**: Lower-level modules that most +clients probably won't use directly diff --git a/TODO b/TODO new file mode 100644 index 0000000000..e603c07137 --- /dev/null +++ b/TODO @@ -0,0 +1,14 @@ +ss +- Stats + +db +- Maybe implement DB::BulkDeleteForRange(start_key, end_key) + that would blow away files whose ranges are entirely contained + within [start_key..end_key]? For Chrome, deletion of obsolete + object stores, etc. can be done in the background anyway, so + probably not that important. +- There have been requests for MultiGet. + +After a range is completely deleted, what gets rid of the +corresponding files if we do no future changes to that range. Make +the conditions for triggering compactions fire in more situations? diff --git a/WINDOWS.md b/WINDOWS.md new file mode 100644 index 0000000000..5b76c2448f --- /dev/null +++ b/WINDOWS.md @@ -0,0 +1,39 @@ +# Building LevelDB On Windows + +## Prereqs + +Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b). + +Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz) + +1. Open the "Windows SDK 7.1 Command Prompt" : + Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt" +2. Change the directory to the leveldb project + +## Building the Static lib + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + + +## Building and Running the Benchmark app + +* 32 bit Version + + setenv /x86 + msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5 + Benchmark\leveldb.exe + +* 64 bit Version + + setenv /x64 + msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5 + x64\Benchmark\leveldb.exe + diff --git a/build_detect_platform b/build_detect_platform new file mode 100755 index 0000000000..4a94715900 --- /dev/null +++ b/build_detect_platform @@ -0,0 +1,259 @@ +#!/bin/sh +# +# Detects OS we're compiling on and outputs a file specified by the first +# argument, which in turn gets read while processing Makefile. +# +# The output will set the following variables: +# CC C Compiler path +# CXX C++ Compiler path +# PLATFORM_LDFLAGS Linker flags +# PLATFORM_LIBS Libraries flags +# PLATFORM_SHARED_EXT Extension for shared libraries +# PLATFORM_SHARED_LDFLAGS Flags for building shared library +# This flag is embedded just before the name +# of the shared library without intervening spaces +# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library +# PLATFORM_CCFLAGS C compiler flags +# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: +# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned +# shared libraries, empty otherwise. +# +# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: +# +# -DLEVELDB_ATOMIC_PRESENT if is present +# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms +# -DSNAPPY if the Snappy library is present +# + +OUTPUT=$1 +PREFIX=$2 +if test -z "$OUTPUT" || test -z "$PREFIX"; then + echo "usage: $0 " >&2 + exit 1 +fi + +# Delete existing output, if it exists +rm -f $OUTPUT +touch $OUTPUT + +if test -z "$CC"; then + CC=cc +fi + +if test -z "$CXX"; then + CXX=g++ +fi + +if test -z "$TMPDIR"; then + TMPDIR=/tmp +fi + +# Detect OS +if test -z "$TARGET_OS"; then + TARGET_OS=`uname -s` +fi + +COMMON_FLAGS= +CROSS_COMPILE= +PLATFORM_CCFLAGS= +PLATFORM_CXXFLAGS= +PLATFORM_LDFLAGS= +PLATFORM_LIBS= +PLATFORM_SHARED_EXT="so" +PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," +PLATFORM_SHARED_CFLAGS="-fPIC" +PLATFORM_SHARED_VERSIONED=true +PLATFORM_SSEFLAGS= + +MEMCMP_FLAG= +if [ "$CXX" = "g++" ]; then + # Use libc's memcmp instead of GCC's memcmp. This results in ~40% + # performance improvement on readrandom under gcc 4.4.3 on Linux/x86. + MEMCMP_FLAG="-fno-builtin-memcmp" +fi + +case "$TARGET_OS" in + CYGWIN_*) + PLATFORM=OS_LINUX + COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN" + PLATFORM_LDFLAGS="-lpthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + Darwin) + PLATFORM=OS_MACOSX + COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" + PLATFORM_SHARED_EXT=dylib + [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` + PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + Linux) + PLATFORM=OS_LINUX + COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + SunOS) + PLATFORM=OS_SOLARIS + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS" + PLATFORM_LIBS="-lpthread -lrt" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + FreeBSD) + PLATFORM=OS_FREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + GNU/kFreeBSD) + PLATFORM=OS_KFREEBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_KFREEBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + ;; + NetBSD) + PLATFORM=OS_NETBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD" + PLATFORM_LIBS="-lpthread -lgcc_s" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + OpenBSD) + PLATFORM=OS_OPENBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + DragonFly) + PLATFORM=OS_DRAGONFLYBSD + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD" + PLATFORM_LIBS="-lpthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + ;; + OS_ANDROID_CROSSCOMPILE) + PLATFORM=OS_ANDROID + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" + PLATFORM_LDFLAGS="" # All pthread features are in the Android C library + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + CROSS_COMPILE=true + ;; + HP-UX) + PLATFORM=OS_HPUX + COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX" + PLATFORM_LDFLAGS="-pthread" + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + # man ld: +h internal_name + PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl," + ;; + IOS) + PLATFORM=IOS + COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX" + [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd` + PORT_FILE=port/port_posix.cc + PORT_SSE_FILE=port/port_posix_sse.cc + PLATFORM_SHARED_EXT= + PLATFORM_SHARED_LDFLAGS= + PLATFORM_SHARED_CFLAGS= + PLATFORM_SHARED_VERSIONED= + ;; + OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) + PLATFORM=OS_WINDOWS + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" + PLATFORM_SOURCES="util/env_win.cc" + PLATFORM_LIBS="-lshlwapi" + PORT_FILE=port/port_win.cc + CROSS_COMPILE=true + ;; + *) + echo "Unknown platform!" >&2 + exit 1 +esac + +# We want to make a list of all cc files within util, db, table, and helpers +# except for the test and benchmark files. By default, find will output a list +# of all files matching either rule, so we need to append -print to make the +# prune take effect. +DIRS="$PREFIX/db $PREFIX/util $PREFIX/table" + +set -f # temporarily disable globbing so that our patterns aren't expanded +PRUNE_TEST="-name *test*.cc -prune" +PRUNE_BENCH="-name *_bench.cc -prune" +PRUNE_TOOL="-name leveldbutil.cc -prune" +PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "` + +set +f # re-enable globbing + +# The sources consist of the portable files, plus the platform-specific port +# file. +echo "SOURCES=$PORTABLE_FILES $PORT_FILE $PORT_SSE_FILE" >> $OUTPUT +echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT + +if [ "$CROSS_COMPILE" = "true" ]; then + # Cross-compiling; do not try any compilation tests. + true +else + CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$" + + # If -std=c++0x works, use as fallback for when memory barriers + # are not available. + $CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null < + int main() {} +EOF + if [ "$?" = 0 ]; then + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_ATOMIC_PRESENT" + PLATFORM_CXXFLAGS="-std=c++0x" + else + COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" + fi + + # Test whether tcmalloc is available + $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -ltcmalloc 2>/dev/null </dev/null + + # Test if gcc SSE 4.2 is supported + $CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -msse4.2 2>/dev/null </dev/null +fi + +# Use the SSE 4.2 CRC32C intrinsics iff runtime checks indicate compiler supports them. +if [ -n "$PLATFORM_SSEFLAGS" ]; then + PLATFORM_SSEFLAGS="$PLATFORM_SSEFLAGS -DLEVELDB_PLATFORM_POSIX_SSE" +fi + +PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" +PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS" + +echo "CC=$CC" >> $OUTPUT +echo "CXX=$CXX" >> $OUTPUT +echo "PLATFORM=$PLATFORM" >> $OUTPUT +echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT +echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT +echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT +echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT +echo "PLATFORM_SSEFLAGS=$PLATFORM_SSEFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT +echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT +echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT diff --git a/db/autocompact_test.cc b/db/autocompact_test.cc new file mode 100644 index 0000000000..d20a2362c3 --- /dev/null +++ b/db/autocompact_test.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "db/db_impl.h" +#include "leveldb/cache.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class AutoCompactTest { + public: + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + AutoCompactTest() { + dbname_ = test::TmpDir() + "/autocompact_test"; + tiny_cache_ = NewLRUCache(100); + options_.block_cache = tiny_cache_; + DestroyDB(dbname_, options_); + options_.create_if_missing = true; + options_.compression = kNoCompression; + ASSERT_OK(DB::Open(options_, dbname_, &db_)); + } + + ~AutoCompactTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void DoReads(int n); +}; + +static const int kValueSize = 200 * 1024; +static const int kTotalSize = 100 * 1024 * 1024; +static const int kCount = kTotalSize / kValueSize; + +// Read through the first n keys repeatedly and check that they get +// compacted (verified by checking the size of the key space). +void AutoCompactTest::DoReads(int n) { + std::string value(kValueSize, 'x'); + DBImpl* dbi = reinterpret_cast(db_); + + // Fill database + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Put(WriteOptions(), Key(i), value)); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Delete everything + for (int i = 0; i < kCount; i++) { + ASSERT_OK(db_->Delete(WriteOptions(), Key(i))); + } + ASSERT_OK(dbi->TEST_CompactMemTable()); + + // Get initial measurement of the space we will be reading. + const int64_t initial_size = Size(Key(0), Key(n)); + const int64_t initial_other_size = Size(Key(n), Key(kCount)); + + // Read until size drops significantly. + std::string limit_key = Key(n); + for (int read = 0; true; read++) { + ASSERT_LT(read, 100) << "Taking too long to compact"; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); + iter->Valid() && iter->key().ToString() < limit_key; + iter->Next()) { + // Drop data + } + delete iter; + // Wait a little bit to allow any triggered compactions to complete. + Env::Default()->SleepForMicroseconds(1000000); + uint64_t size = Size(Key(0), Key(n)); + fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", + read+1, size/1048576.0, Size(Key(n), Key(kCount))/1048576.0); + if (size <= initial_size/10) { + break; + } + } + + // Verify that the size of the key space not touched by the reads + // is pretty much unchanged. + const int64_t final_other_size = Size(Key(n), Key(kCount)); + ASSERT_LE(final_other_size, initial_other_size + 1048576); + ASSERT_GE(final_other_size, initial_other_size/5 - 1048576); +} + +TEST(AutoCompactTest, ReadAll) { + DoReads(kCount); +} + +TEST(AutoCompactTest, ReadHalf) { + DoReads(kCount/2); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/builder.cc b/db/builder.cc new file mode 100644 index 0000000000..f419882197 --- /dev/null +++ b/db/builder.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/builder.h" + +#include "db/filename.h" +#include "db/dbformat.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" + +namespace leveldb { + +Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta) { + Status s; + meta->file_size = 0; + iter->SeekToFirst(); + + std::string fname = TableFileName(dbname, meta->number); + if (iter->Valid()) { + WritableFile* file; + s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + + TableBuilder* builder = new TableBuilder(options, file); + meta->smallest.DecodeFrom(iter->key()); + for (; iter->Valid(); iter->Next()) { + Slice key = iter->key(); + meta->largest.DecodeFrom(key); + builder->Add(key, iter->value()); + } + + // Finish and check for builder errors + if (s.ok()) { + s = builder->Finish(); + if (s.ok()) { + meta->file_size = builder->FileSize(); + assert(meta->file_size > 0); + } + } else { + builder->Abandon(); + } + delete builder; + + // Finish and check for file errors + if (s.ok()) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (s.ok()) { + // Verify that the table is usable + Iterator* it = table_cache->NewIterator(ReadOptions(), + meta->number, + meta->file_size); + s = it->status(); + delete it; + } + } + + // Check for input iterator errors + if (!iter->status().ok()) { + s = iter->status(); + } + + if (s.ok() && meta->file_size > 0) { + // Keep it + } else { + env->DeleteFile(fname); + } + return s; +} + +} // namespace leveldb diff --git a/db/builder.h b/db/builder.h new file mode 100644 index 0000000000..62431fcf44 --- /dev/null +++ b/db/builder.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ +#define STORAGE_LEVELDB_DB_BUILDER_H_ + +#include "leveldb/status.h" + +namespace leveldb { + +struct Options; +struct FileMetaData; + +class Env; +class Iterator; +class TableCache; +class VersionEdit; + +// Build a Table file from the contents of *iter. The generated file +// will be named according to meta->number. On success, the rest of +// *meta will be filled with metadata about the generated table. +// If no data is present in *iter, meta->file_size will be set to +// zero, and no Table file will be produced. +extern Status BuildTable(const std::string& dbname, + Env* env, + const Options& options, + TableCache* table_cache, + Iterator* iter, + FileMetaData* meta); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_BUILDER_H_ diff --git a/db/c.cc b/db/c.cc new file mode 100644 index 0000000000..08ff0ad90a --- /dev/null +++ b/db/c.cc @@ -0,0 +1,595 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/c.h" + +#include +#include +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/write_batch.h" + +using leveldb::Cache; +using leveldb::Comparator; +using leveldb::CompressionType; +using leveldb::DB; +using leveldb::Env; +using leveldb::FileLock; +using leveldb::FilterPolicy; +using leveldb::Iterator; +using leveldb::kMajorVersion; +using leveldb::kMinorVersion; +using leveldb::Logger; +using leveldb::NewBloomFilterPolicy; +using leveldb::NewLRUCache; +using leveldb::Options; +using leveldb::RandomAccessFile; +using leveldb::Range; +using leveldb::ReadOptions; +using leveldb::SequentialFile; +using leveldb::Slice; +using leveldb::Snapshot; +using leveldb::Status; +using leveldb::WritableFile; +using leveldb::WriteBatch; +using leveldb::WriteOptions; + +extern "C" { + +struct leveldb_t { DB* rep; }; +struct leveldb_iterator_t { Iterator* rep; }; +struct leveldb_writebatch_t { WriteBatch rep; }; +struct leveldb_snapshot_t { const Snapshot* rep; }; +struct leveldb_readoptions_t { ReadOptions rep; }; +struct leveldb_writeoptions_t { WriteOptions rep; }; +struct leveldb_options_t { Options rep; }; +struct leveldb_cache_t { Cache* rep; }; +struct leveldb_seqfile_t { SequentialFile* rep; }; +struct leveldb_randomfile_t { RandomAccessFile* rep; }; +struct leveldb_writablefile_t { WritableFile* rep; }; +struct leveldb_logger_t { Logger* rep; }; +struct leveldb_filelock_t { FileLock* rep; }; + +struct leveldb_comparator_t : public Comparator { + void* state_; + void (*destructor_)(void*); + int (*compare_)( + void*, + const char* a, size_t alen, + const char* b, size_t blen); + const char* (*name_)(void*); + + virtual ~leveldb_comparator_t() { + (*destructor_)(state_); + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + // No-ops since the C binding does not support key shortening methods. + virtual void FindShortestSeparator(std::string*, const Slice&) const { } + virtual void FindShortSuccessor(std::string* key) const { } +}; + +struct leveldb_filterpolicy_t : public FilterPolicy { + void* state_; + void (*destructor_)(void*); + const char* (*name_)(void*); + char* (*create_)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length); + unsigned char (*key_match_)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length); + + virtual ~leveldb_filterpolicy_t() { + (*destructor_)(state_); + } + + virtual const char* Name() const { + return (*name_)(state_); + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + std::vector key_pointers(n); + std::vector key_sizes(n); + for (int i = 0; i < n; i++) { + key_pointers[i] = keys[i].data(); + key_sizes[i] = keys[i].size(); + } + size_t len; + char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); + dst->append(filter, len); + free(filter); + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return (*key_match_)(state_, key.data(), key.size(), + filter.data(), filter.size()); + } +}; + +struct leveldb_env_t { + Env* rep; + bool is_default; +}; + +static bool SaveError(char** errptr, const Status& s) { + assert(errptr != NULL); + if (s.ok()) { + return false; + } else if (*errptr == NULL) { + *errptr = strdup(s.ToString().c_str()); + } else { + // TODO(sanjay): Merge with existing error? + free(*errptr); + *errptr = strdup(s.ToString().c_str()); + } + return true; +} + +static char* CopyString(const std::string& str) { + char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); + memcpy(result, str.data(), sizeof(char) * str.size()); + return result; +} + +leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr) { + DB* db; + if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { + return NULL; + } + leveldb_t* result = new leveldb_t; + result->rep = db; + return result; +} + +void leveldb_close(leveldb_t* db) { + delete db->rep; + delete db; +} + +void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr) { + SaveError(errptr, + db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); +} + +void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr) { + SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); +} + + +void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr) { + SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); +} + +char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr) { + char* result = NULL; + std::string tmp; + Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); + if (s.ok()) { + *vallen = tmp.size(); + result = CopyString(tmp); + } else { + *vallen = 0; + if (!s.IsNotFound()) { + SaveError(errptr, s); + } + } + return result; +} + +leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options) { + leveldb_iterator_t* result = new leveldb_iterator_t; + result->rep = db->rep->NewIterator(options->rep); + return result; +} + +const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db) { + leveldb_snapshot_t* result = new leveldb_snapshot_t; + result->rep = db->rep->GetSnapshot(); + return result; +} + +void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot) { + db->rep->ReleaseSnapshot(snapshot->rep); + delete snapshot; +} + +char* leveldb_property_value( + leveldb_t* db, + const char* propname) { + std::string tmp; + if (db->rep->GetProperty(Slice(propname), &tmp)) { + // We use strdup() since we expect human readable output. + return strdup(tmp.c_str()); + } else { + return NULL; + } +} + +void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes) { + Range* ranges = new Range[num_ranges]; + for (int i = 0; i < num_ranges; i++) { + ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); + ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); + } + db->rep->GetApproximateSizes(ranges, num_ranges, sizes); + delete[] ranges; +} + +void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len) { + Slice a, b; + db->rep->CompactRange( + // Pass NULL Slice if corresponding "const char*" is NULL + (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), + (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); +} + +void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, DestroyDB(name, options->rep)); +} + +void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr) { + SaveError(errptr, RepairDB(name, options->rep)); +} + +void leveldb_iter_destroy(leveldb_iterator_t* iter) { + delete iter->rep; + delete iter; +} + +unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { + return iter->rep->Valid(); +} + +void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { + iter->rep->SeekToFirst(); +} + +void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { + iter->rep->SeekToLast(); +} + +void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { + iter->rep->Seek(Slice(k, klen)); +} + +void leveldb_iter_next(leveldb_iterator_t* iter) { + iter->rep->Next(); +} + +void leveldb_iter_prev(leveldb_iterator_t* iter) { + iter->rep->Prev(); +} + +const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { + Slice s = iter->rep->key(); + *klen = s.size(); + return s.data(); +} + +const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { + Slice s = iter->rep->value(); + *vlen = s.size(); + return s.data(); +} + +void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { + SaveError(errptr, iter->rep->status()); +} + +leveldb_writebatch_t* leveldb_writebatch_create() { + return new leveldb_writebatch_t; +} + +void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { + delete b; +} + +void leveldb_writebatch_clear(leveldb_writebatch_t* b) { + b->rep.Clear(); +} + +void leveldb_writebatch_put( + leveldb_writebatch_t* b, + const char* key, size_t klen, + const char* val, size_t vlen) { + b->rep.Put(Slice(key, klen), Slice(val, vlen)); +} + +void leveldb_writebatch_delete( + leveldb_writebatch_t* b, + const char* key, size_t klen) { + b->rep.Delete(Slice(key, klen)); +} + +void leveldb_writebatch_iterate( + leveldb_writebatch_t* b, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)) { + class H : public WriteBatch::Handler { + public: + void* state_; + void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); + void (*deleted_)(void*, const char* k, size_t klen); + virtual void Put(const Slice& key, const Slice& value) { + (*put_)(state_, key.data(), key.size(), value.data(), value.size()); + } + virtual void Delete(const Slice& key) { + (*deleted_)(state_, key.data(), key.size()); + } + }; + H handler; + handler.state_ = state; + handler.put_ = put; + handler.deleted_ = deleted; + b->rep.Iterate(&handler); +} + +leveldb_options_t* leveldb_options_create() { + return new leveldb_options_t; +} + +void leveldb_options_destroy(leveldb_options_t* options) { + delete options; +} + +void leveldb_options_set_comparator( + leveldb_options_t* opt, + leveldb_comparator_t* cmp) { + opt->rep.comparator = cmp; +} + +void leveldb_options_set_filter_policy( + leveldb_options_t* opt, + leveldb_filterpolicy_t* policy) { + opt->rep.filter_policy = policy; +} + +void leveldb_options_set_create_if_missing( + leveldb_options_t* opt, unsigned char v) { + opt->rep.create_if_missing = v; +} + +void leveldb_options_set_error_if_exists( + leveldb_options_t* opt, unsigned char v) { + opt->rep.error_if_exists = v; +} + +void leveldb_options_set_paranoid_checks( + leveldb_options_t* opt, unsigned char v) { + opt->rep.paranoid_checks = v; +} + +void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { + opt->rep.env = (env ? env->rep : NULL); +} + +void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { + opt->rep.info_log = (l ? l->rep : NULL); +} + +void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { + opt->rep.write_buffer_size = s; +} + +void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { + opt->rep.max_open_files = n; +} + +void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { + opt->rep.block_cache = c->rep; +} + +void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { + opt->rep.block_size = s; +} + +void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { + opt->rep.block_restart_interval = n; +} + +void leveldb_options_set_compression(leveldb_options_t* opt, int t) { + opt->rep.compression = static_cast(t); +} + +leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)) { + leveldb_comparator_t* result = new leveldb_comparator_t; + result->state_ = state; + result->destructor_ = destructor; + result->compare_ = compare; + result->name_ = name; + return result; +} + +void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { + delete cmp; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)) { + leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; + result->state_ = state; + result->destructor_ = destructor; + result->create_ = create_filter; + result->key_match_ = key_may_match; + result->name_ = name; + return result; +} + +void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { + delete filter; +} + +leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { + // Make a leveldb_filterpolicy_t, but override all of its methods so + // they delegate to a NewBloomFilterPolicy() instead of user + // supplied C functions. + struct Wrapper : public leveldb_filterpolicy_t { + const FilterPolicy* rep_; + ~Wrapper() { delete rep_; } + const char* Name() const { return rep_->Name(); } + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + return rep_->CreateFilter(keys, n, dst); + } + bool KeyMayMatch(const Slice& key, const Slice& filter) const { + return rep_->KeyMayMatch(key, filter); + } + static void DoNothing(void*) { } + }; + Wrapper* wrapper = new Wrapper; + wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); + wrapper->state_ = NULL; + wrapper->destructor_ = &Wrapper::DoNothing; + return wrapper; +} + +leveldb_readoptions_t* leveldb_readoptions_create() { + return new leveldb_readoptions_t; +} + +void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { + delete opt; +} + +void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t* opt, + unsigned char v) { + opt->rep.verify_checksums = v; +} + +void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t* opt, unsigned char v) { + opt->rep.fill_cache = v; +} + +void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t* opt, + const leveldb_snapshot_t* snap) { + opt->rep.snapshot = (snap ? snap->rep : NULL); +} + +leveldb_writeoptions_t* leveldb_writeoptions_create() { + return new leveldb_writeoptions_t; +} + +void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { + delete opt; +} + +void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t* opt, unsigned char v) { + opt->rep.sync = v; +} + +leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { + leveldb_cache_t* c = new leveldb_cache_t; + c->rep = NewLRUCache(capacity); + return c; +} + +void leveldb_cache_destroy(leveldb_cache_t* cache) { + delete cache->rep; + delete cache; +} + +leveldb_env_t* leveldb_create_default_env() { + leveldb_env_t* result = new leveldb_env_t; + result->rep = Env::Default(); + result->is_default = true; + return result; +} + +void leveldb_env_destroy(leveldb_env_t* env) { + if (!env->is_default) delete env->rep; + delete env; +} + +void leveldb_free(void* ptr) { + free(ptr); +} + +int leveldb_major_version() { + return kMajorVersion; +} + +int leveldb_minor_version() { + return kMinorVersion; +} + +} // end extern "C" diff --git a/db/c_test.c b/db/c_test.c new file mode 100644 index 0000000000..7cd5ee0207 --- /dev/null +++ b/db/c_test.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. */ + +#include "leveldb/c.h" + +#include +#include +#include +#include +#include +#include + +const char* phase = ""; +static char dbname[200]; + +static void StartPhase(const char* name) { + fprintf(stderr, "=== Test %s\n", name); + phase = name; +} + +static const char* GetTempDir(void) { + const char* ret = getenv("TEST_TMPDIR"); + if (ret == NULL || ret[0] == '\0') + ret = "/tmp"; + return ret; +} + +#define CheckNoError(err) \ + if ((err) != NULL) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ + abort(); \ + } + +#define CheckCondition(cond) \ + if (!(cond)) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ + abort(); \ + } + +static void CheckEqual(const char* expected, const char* v, size_t n) { + if (expected == NULL && v == NULL) { + // ok + } else if (expected != NULL && v != NULL && n == strlen(expected) && + memcmp(expected, v, n) == 0) { + // ok + return; + } else { + fprintf(stderr, "%s: expected '%s', got '%s'\n", + phase, + (expected ? expected : "(null)"), + (v ? v : "(null")); + abort(); + } +} + +static void Free(char** ptr) { + if (*ptr) { + free(*ptr); + *ptr = NULL; + } +} + +static void CheckGet( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, + const char* expected) { + char* err = NULL; + size_t val_len; + char* val; + val = leveldb_get(db, options, key, strlen(key), &val_len, &err); + CheckNoError(err); + CheckEqual(expected, val, val_len); + Free(&val); +} + +static void CheckIter(leveldb_iterator_t* iter, + const char* key, const char* val) { + size_t len; + const char* str; + str = leveldb_iter_key(iter, &len); + CheckEqual(key, str, len); + str = leveldb_iter_value(iter, &len); + CheckEqual(val, str, len); +} + +// Callback from leveldb_writebatch_iterate() +static void CheckPut(void* ptr, + const char* k, size_t klen, + const char* v, size_t vlen) { + int* state = (int*) ptr; + CheckCondition(*state < 2); + switch (*state) { + case 0: + CheckEqual("bar", k, klen); + CheckEqual("b", v, vlen); + break; + case 1: + CheckEqual("box", k, klen); + CheckEqual("c", v, vlen); + break; + } + (*state)++; +} + +// Callback from leveldb_writebatch_iterate() +static void CheckDel(void* ptr, const char* k, size_t klen) { + int* state = (int*) ptr; + CheckCondition(*state == 2); + CheckEqual("bar", k, klen); + (*state)++; +} + +static void CmpDestroy(void* arg) { } + +static int CmpCompare(void* arg, const char* a, size_t alen, + const char* b, size_t blen) { + int n = (alen < blen) ? alen : blen; + int r = memcmp(a, b, n); + if (r == 0) { + if (alen < blen) r = -1; + else if (alen > blen) r = +1; + } + return r; +} + +static const char* CmpName(void* arg) { + return "foo"; +} + +// Custom filter policy +static unsigned char fake_filter_result = 1; +static void FilterDestroy(void* arg) { } +static const char* FilterName(void* arg) { + return "TestFilter"; +} +static char* FilterCreate( + void* arg, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length) { + *filter_length = 4; + char* result = malloc(4); + memcpy(result, "fake", 4); + return result; +} +unsigned char FilterKeyMatch( + void* arg, + const char* key, size_t length, + const char* filter, size_t filter_length) { + CheckCondition(filter_length == 4); + CheckCondition(memcmp(filter, "fake", 4) == 0); + return fake_filter_result; +} + +int main(int argc, char** argv) { + leveldb_t* db; + leveldb_comparator_t* cmp; + leveldb_cache_t* cache; + leveldb_env_t* env; + leveldb_options_t* options; + leveldb_readoptions_t* roptions; + leveldb_writeoptions_t* woptions; + char* err = NULL; + int run = -1; + + CheckCondition(leveldb_major_version() >= 1); + CheckCondition(leveldb_minor_version() >= 1); + + snprintf(dbname, sizeof(dbname), + "%s/leveldb_c_test-%d", + GetTempDir(), + ((int) geteuid())); + + StartPhase("create_objects"); + cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); + env = leveldb_create_default_env(); + cache = leveldb_cache_create_lru(100000); + + options = leveldb_options_create(); + leveldb_options_set_comparator(options, cmp); + leveldb_options_set_error_if_exists(options, 1); + leveldb_options_set_cache(options, cache); + leveldb_options_set_env(options, env); + leveldb_options_set_info_log(options, NULL); + leveldb_options_set_write_buffer_size(options, 100000); + leveldb_options_set_paranoid_checks(options, 1); + leveldb_options_set_max_open_files(options, 10); + leveldb_options_set_block_size(options, 1024); + leveldb_options_set_block_restart_interval(options, 8); + leveldb_options_set_compression(options, leveldb_no_compression); + + roptions = leveldb_readoptions_create(); + leveldb_readoptions_set_verify_checksums(roptions, 1); + leveldb_readoptions_set_fill_cache(roptions, 0); + + woptions = leveldb_writeoptions_create(); + leveldb_writeoptions_set_sync(woptions, 1); + + StartPhase("destroy"); + leveldb_destroy_db(options, dbname, &err); + Free(&err); + + StartPhase("open_error"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + Free(&err); + + StartPhase("leveldb_free"); + db = leveldb_open(options, dbname, &err); + CheckCondition(err != NULL); + leveldb_free(err); + err = NULL; + + StartPhase("open"); + leveldb_options_set_create_if_missing(options, 1); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + + StartPhase("put"); + leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactall"); + leveldb_compact_range(db, NULL, 0, NULL, 0); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("compactrange"); + leveldb_compact_range(db, "a", 1, "z", 1); + CheckGet(db, roptions, "foo", "hello"); + + StartPhase("writebatch"); + { + leveldb_writebatch_t* wb = leveldb_writebatch_create(); + leveldb_writebatch_put(wb, "foo", 3, "a", 1); + leveldb_writebatch_clear(wb); + leveldb_writebatch_put(wb, "bar", 3, "b", 1); + leveldb_writebatch_put(wb, "box", 3, "c", 1); + leveldb_writebatch_delete(wb, "bar", 3); + leveldb_write(db, woptions, wb, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", "hello"); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + int pos = 0; + leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); + CheckCondition(pos == 3); + leveldb_writebatch_destroy(wb); + } + + StartPhase("iter"); + { + leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_first(iter); + CheckCondition(leveldb_iter_valid(iter)); + CheckIter(iter, "box", "c"); + leveldb_iter_next(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_prev(iter); + CheckIter(iter, "box", "c"); + leveldb_iter_prev(iter); + CheckCondition(!leveldb_iter_valid(iter)); + leveldb_iter_seek_to_last(iter); + CheckIter(iter, "foo", "hello"); + leveldb_iter_seek(iter, "b", 1); + CheckIter(iter, "box", "c"); + leveldb_iter_get_error(iter, &err); + CheckNoError(err); + leveldb_iter_destroy(iter); + } + + StartPhase("approximate_sizes"); + { + int i; + int n = 20000; + char keybuf[100]; + char valbuf[100]; + uint64_t sizes[2]; + const char* start[2] = { "a", "k00000000000000010000" }; + size_t start_len[2] = { 1, 21 }; + const char* limit[2] = { "k00000000000000010000", "z" }; + size_t limit_len[2] = { 21, 1 }; + leveldb_writeoptions_set_sync(woptions, 0); + for (i = 0; i < n; i++) { + snprintf(keybuf, sizeof(keybuf), "k%020d", i); + snprintf(valbuf, sizeof(valbuf), "v%020d", i); + leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf), + &err); + CheckNoError(err); + } + leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes); + CheckCondition(sizes[0] > 0); + CheckCondition(sizes[1] > 0); + } + + StartPhase("property"); + { + char* prop = leveldb_property_value(db, "nosuchprop"); + CheckCondition(prop == NULL); + prop = leveldb_property_value(db, "leveldb.stats"); + CheckCondition(prop != NULL); + Free(&prop); + } + + StartPhase("snapshot"); + { + const leveldb_snapshot_t* snap; + snap = leveldb_create_snapshot(db); + leveldb_delete(db, woptions, "foo", 3, &err); + CheckNoError(err); + leveldb_readoptions_set_snapshot(roptions, snap); + CheckGet(db, roptions, "foo", "hello"); + leveldb_readoptions_set_snapshot(roptions, NULL); + CheckGet(db, roptions, "foo", NULL); + leveldb_release_snapshot(db, snap); + } + + StartPhase("repair"); + { + leveldb_close(db); + leveldb_options_set_create_if_missing(options, 0); + leveldb_options_set_error_if_exists(options, 0); + leveldb_repair_db(options, dbname, &err); + CheckNoError(err); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + CheckGet(db, roptions, "box", "c"); + leveldb_options_set_create_if_missing(options, 1); + leveldb_options_set_error_if_exists(options, 1); + } + + StartPhase("filter"); + for (run = 0; run < 2; run++) { + // First run uses custom filter, second run uses bloom filter + CheckNoError(err); + leveldb_filterpolicy_t* policy; + if (run == 0) { + policy = leveldb_filterpolicy_create( + NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName); + } else { + policy = leveldb_filterpolicy_create_bloom(10); + } + + // Create new database + leveldb_close(db); + leveldb_destroy_db(options, dbname, &err); + leveldb_options_set_filter_policy(options, policy); + db = leveldb_open(options, dbname, &err); + CheckNoError(err); + leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err); + CheckNoError(err); + leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err); + CheckNoError(err); + leveldb_compact_range(db, NULL, 0, NULL, 0); + + fake_filter_result = 1; + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + if (phase == 0) { + // Must not find value when custom filter returns false + fake_filter_result = 0; + CheckGet(db, roptions, "foo", NULL); + CheckGet(db, roptions, "bar", NULL); + fake_filter_result = 1; + + CheckGet(db, roptions, "foo", "foovalue"); + CheckGet(db, roptions, "bar", "barvalue"); + } + leveldb_options_set_filter_policy(options, NULL); + leveldb_filterpolicy_destroy(policy); + } + + StartPhase("cleanup"); + leveldb_close(db); + leveldb_options_destroy(options); + leveldb_readoptions_destroy(roptions); + leveldb_writeoptions_destroy(woptions); + leveldb_cache_destroy(cache); + leveldb_comparator_destroy(cmp); + leveldb_env_destroy(env); + + fprintf(stderr, "PASS\n"); + return 0; +} diff --git a/db/corruption_test.cc b/db/corruption_test.cc new file mode 100644 index 0000000000..37a484d25f --- /dev/null +++ b/db/corruption_test.cc @@ -0,0 +1,374 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include +#include +#include +#include +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; + +class CorruptionTest { + public: + test::ErrorEnv env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + CorruptionTest() { + tiny_cache_ = NewLRUCache(100); + options_.env = &env_; + options_.block_cache = tiny_cache_; + dbname_ = test::TmpDir() + "/corruption_test"; + DestroyDB(dbname_, options_); + + db_ = NULL; + options_.create_if_missing = true; + Reopen(); + options_.create_if_missing = false; + } + + ~CorruptionTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete tiny_cache_; + } + + Status TryReopen() { + delete db_; + db_ = NULL; + return DB::Open(options_, dbname_, &db_); + } + + void Reopen() { + ASSERT_OK(TryReopen()); + } + + void RepairDB() { + delete db_; + db_ = NULL; + ASSERT_OK(::leveldb::RepairDB(dbname_, options_)); + } + + void Build(int n) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = 0; i < n; i++) { + //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n); + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + WriteOptions options; + // Corrupt() doesn't work without this sync on windows; stat reports 0 for + // the file size. + if (i == n - 1) { + options.sync = true; + } + ASSERT_OK(db_->Write(options, &batch)); + } + } + + void Check(int min_expected, int max_expected) { + int next_expected = 0; + int missed = 0; + int bad_keys = 0; + int bad_values = 0; + int correct = 0; + std::string value_space; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + uint64_t key; + Slice in(iter->key()); + if (in == "" || in == "~") { + // Ignore boundary keys. + continue; + } + if (!ConsumeDecimalNumber(&in, &key) || + !in.empty() || + key < next_expected) { + bad_keys++; + continue; + } + missed += (key - next_expected); + next_expected = key + 1; + if (iter->value() != Value(key, &value_space)) { + bad_values++; + } else { + correct++; + } + } + delete iter; + + fprintf(stderr, + "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n", + min_expected, max_expected, correct, bad_keys, bad_values, missed); + ASSERT_LE(min_expected, correct); + ASSERT_GE(max_expected, correct); + } + + void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) { + // Pick file to corrupt + std::vector filenames; + ASSERT_OK(env_.GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + std::string fname; + int picked_number = -1; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type == filetype && + int(number) > picked_number) { // Pick latest file + fname = dbname_ + "/" + filenames[i]; + picked_number = number; + } + } + ASSERT_TRUE(!fname.empty()) << filetype; + + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + const char* msg = strerror(errno); + ASSERT_TRUE(false) << fname << ": " << msg; + } + + if (offset < 0) { + // Relative to end of file; make it absolute + if (-offset > sbuf.st_size) { + offset = 0; + } else { + offset = sbuf.st_size + offset; + } + } + if (offset > sbuf.st_size) { + offset = sbuf.st_size; + } + if (offset + bytes_to_corrupt > sbuf.st_size) { + bytes_to_corrupt = sbuf.st_size - offset; + } + + // Do it + std::string contents; + Status s = ReadFileToString(Env::Default(), fname, &contents); + ASSERT_TRUE(s.ok()) << s.ToString(); + for (int i = 0; i < bytes_to_corrupt; i++) { + contents[i + offset] ^= 0x80; + } + s = WriteStringToFile(Env::Default(), contents, fname); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + int Property(const std::string& name) { + std::string property; + int result; + if (db_->GetProperty(name, &property) && + sscanf(property.c_str(), "%d", &result) == 1) { + return result; + } else { + return -1; + } + } + + // Return the ith key + Slice Key(int i, std::string* storage) { + char buf[100]; + snprintf(buf, sizeof(buf), "%016d", i); + storage->assign(buf, strlen(buf)); + return Slice(*storage); + } + + // Return the value to associate with the specified key + Slice Value(int k, std::string* storage) { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } +}; + +TEST(CorruptionTest, Recovery) { + Build(100); + Check(100, 100); + Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record + Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block + Reopen(); + + // The 64 records in the first two log blocks are completely lost. + Check(36, 36); +} + +TEST(CorruptionTest, RecoverWriteError) { + env_.writable_file_error_ = true; + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); +} + +TEST(CorruptionTest, NewFileErrorDuringWrite) { + // Do enough writing to force minor compaction + env_.writable_file_error_ = true; + const int num = 3 + (Options().write_buffer_size / kValueSize); + std::string value_storage; + Status s; + for (int i = 0; s.ok() && i < num; i++) { + WriteBatch batch; + batch.Put("a", Value(100, &value_storage)); + s = db_->Write(WriteOptions(), &batch); + } + ASSERT_TRUE(!s.ok()); + ASSERT_GE(env_.num_writable_file_errors_, 1); + env_.writable_file_error_ = false; + Reopen(); +} + +TEST(CorruptionTest, TableFile) { + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + Check(90, 99); +} + +TEST(CorruptionTest, TableFileRepair) { + options_.block_size = 2 * kValueSize; // Limit scope of corruption + options_.paranoid_checks = true; + Reopen(); + Build(100); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + dbi->TEST_CompactRange(1, NULL, NULL); + + Corrupt(kTableFile, 100, 1); + RepairDB(); + Reopen(); + Check(95, 99); +} + +TEST(CorruptionTest, TableFileIndexData) { + Build(10000); // Enough to build multiple Tables + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + + Corrupt(kTableFile, -2000, 500); + Reopen(); + Check(5000, 9999); +} + +TEST(CorruptionTest, MissingDescriptor) { + Build(1000); + RepairDB(); + Reopen(); + Check(1000, 1000); +} + +TEST(CorruptionTest, SequenceNumberRecovery) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5")); + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v5", v); + // Write something. If sequence number was not recovered properly, + // it will be hidden by an earlier write. + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6")); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); + Reopen(); + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("v6", v); +} + +TEST(CorruptionTest, CorruptedDescriptor) { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello")); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + dbi->TEST_CompactRange(0, NULL, NULL); + + Corrupt(kDescriptorFile, 0, 1000); + Status s = TryReopen(); + ASSERT_TRUE(!s.ok()); + + RepairDB(); + Reopen(); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), "foo", &v)); + ASSERT_EQ("hello", v); +} + +TEST(CorruptionTest, CompactionInputError) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last))); + + Corrupt(kTableFile, 100, 1); + Check(5, 9); + + // Force compactions by writing lots of values + Build(10000); + Check(10000, 10000); +} + +TEST(CorruptionTest, CompactionInputErrorParanoid) { + options_.paranoid_checks = true; + options_.write_buffer_size = 512 << 10; + Reopen(); + DBImpl* dbi = reinterpret_cast(db_); + + // Make multiple inputs so we need to compact. + for (int i = 0; i < 2; i++) { + Build(10); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + env_.SleepForMicroseconds(100000); + } + dbi->CompactRange(NULL, NULL); + + // Write must fail because of corrupted table + std::string tmp1, tmp2; + Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2)); + ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db"; +} + +TEST(CorruptionTest, UnrelatedKeys) { + Build(10); + DBImpl* dbi = reinterpret_cast(db_); + dbi->TEST_CompactMemTable(); + Corrupt(kTableFile, 100, 1); + + std::string tmp1, tmp2; + ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2))); + std::string v; + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); + dbi->TEST_CompactMemTable(); + ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v)); + ASSERT_EQ(Value(1000, &tmp2).ToString(), v); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/db_bench.cc b/db/db_bench.cc new file mode 100644 index 0000000000..3ad19a512b --- /dev/null +++ b/db/db_bench.cc @@ -0,0 +1,1020 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "db/db_impl.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "port/port.h" +#include "util/crc32c.h" +#include "util/histogram.h" +#include "util/mutexlock.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillsync -- write N/100 values in random key order in sync mode +// fill100K -- write N/1000 100K values in random order in async mode +// deleteseq -- delete N keys in sequential order +// deleterandom -- delete N keys in random order +// readseq -- read N times sequentially +// readreverse -- read N times in reverse order +// readrandom -- read N times in random order +// readmissing -- read N missing keys in random order +// readhot -- read N times in random order from 1% section of DB +// seekrandom -- N random seeks +// open -- cost of opening a DB +// crc32c -- repeated crc32c of 4K of data +// acquireload -- load N*1000 times +// Meta operations: +// compact -- Compact the entire DB +// stats -- Print DB stats +// sstables -- Print sstable info +// heapprofile -- Dump a heap profile (if supported by this port) +static const char* FLAGS_benchmarks = + "fillseq," + "fillsync," + "fillrandom," + "overwrite," + "readrandom," + "readrandom," // Extra run to allow previous compactions to quiesce + "readseq," + "readreverse," + "compact," + "readrandom," + "readseq," + "readreverse," + "fill100K," + "crc32c," + "snappycomp," + "snappyuncomp," + "acquireload," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Number of concurrent threads to run. +static int FLAGS_threads = 1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Number of bytes to buffer in memtable before compacting +// (initialized to default value by "main") +static int FLAGS_write_buffer_size = 0; + +// Number of bytes written to each file. +// (initialized to default value by "main") +static int FLAGS_max_file_size = 0; + +// Approximate size of user data packed per block (before compression. +// (initialized to default value by "main") +static int FLAGS_block_size = 0; + +// Number of bytes to use as a cache of uncompressed data. +// Negative means use default settings. +static int FLAGS_cache_size = -1; + +// Maximum number of files to keep open at the same time (use default if == 0) +static int FLAGS_open_files = 0; + +// Bloom filter bits per key. +// Negative means use default settings. +static int FLAGS_bloom_bits = -1; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// If true, reuse existing log/MANIFEST files when re-opening a database. +static bool FLAGS_reuse_logs = false; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +namespace leveldb { + +namespace { +leveldb::Env* g_env = NULL; + +// Helper for quickly generating random data. +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(size_t len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +#if defined(__linux) +static Slice TrimSpace(Slice s) { + size_t start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + size_t limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} +#endif + +static void AppendWithSpace(std::string* str, Slice msg) { + if (msg.empty()) return; + if (!str->empty()) { + str->push_back(' '); + } + str->append(msg.data(), msg.size()); +} + +class Stats { + private: + double start_; + double finish_; + double seconds_; + int done_; + int next_report_; + int64_t bytes_; + double last_op_finish_; + Histogram hist_; + std::string message_; + + public: + Stats() { Start(); } + + void Start() { + next_report_ = 100; + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + bytes_ = 0; + seconds_ = 0; + start_ = g_env->NowMicros(); + finish_ = start_; + message_.clear(); + } + + void Merge(const Stats& other) { + hist_.Merge(other.hist_); + done_ += other.done_; + bytes_ += other.bytes_; + seconds_ += other.seconds_; + if (other.start_ < start_) start_ = other.start_; + if (other.finish_ > finish_) finish_ = other.finish_; + + // Just keep the messages from one thread + if (message_.empty()) message_ = other.message_; + } + + void Stop() { + finish_ = g_env->NowMicros(); + seconds_ = (finish_ - start_) * 1e-6; + } + + void AddMessage(Slice msg) { + AppendWithSpace(&message_, msg); + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = g_env->NowMicros(); + double micros = now - last_op_finish_; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void AddBytes(int64_t n) { + bytes_ += n; + } + + void Report(const Slice& name) { + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + std::string extra; + if (bytes_ > 0) { + // Rate is computed on actual elapsed time, not the sum of per-thread + // elapsed times. + double elapsed = (finish_ - start_) * 1e-6; + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / elapsed); + extra = rate; + } + AppendWithSpace(&extra, message_); + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + seconds_ * 1e6 / done_, + (extra.empty() ? "" : " "), + extra.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } +}; + +// State shared by all concurrent executions of the same benchmark. +struct SharedState { + port::Mutex mu; + port::CondVar cv; + int total; + + // Each thread goes through the following states: + // (1) initializing + // (2) waiting for others to be initialized + // (3) running + // (4) done + + int num_initialized; + int num_done; + bool start; + + SharedState() : cv(&mu) { } +}; + +// Per-thread state for concurrent executions of the same benchmark. +struct ThreadState { + int tid; // 0..n-1 when running in n threads + Random rand; // Has different seeds for different threads + Stats stats; + SharedState* shared; + + ThreadState(int index) + : tid(index), + rand(1000 + index) { + } +}; + +} // namespace + +class Benchmark { + private: + Cache* cache_; + const FilterPolicy* filter_policy_; + DB* db_; + int num_; + int value_size_; + int entries_per_batch_; + WriteOptions write_options_; + int reads_; + int heap_counter_; + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + + // See if snappy is working by attempting to compress a compressible string + const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + std::string compressed; + if (!port::Snappy_Compress(text, sizeof(text), &compressed)) { + fprintf(stdout, "WARNING: Snappy compression is not enabled\n"); + } else if (compressed.size() >= sizeof(text)) { + fprintf(stdout, "WARNING: Snappy compression is not effective\n"); + } + } + + void PrintEnvironment() { + fprintf(stderr, "LevelDB: version %d.%d\n", + kMajorVersion, kMinorVersion); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + public: + Benchmark() + : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL), + filter_policy_(FLAGS_bloom_bits >= 0 + ? NewBloomFilterPolicy(FLAGS_bloom_bits) + : NULL), + db_(NULL), + num_(FLAGS_num), + value_size_(FLAGS_value_size), + entries_per_batch_(1), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + heap_counter_(0) { + std::vector files; + g_env->GetChildren(FLAGS_db, &files); + for (size_t i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("heap-")) { + g_env->DeleteFile(std::string(FLAGS_db) + "/" + files[i]); + } + } + if (!FLAGS_use_existing_db) { + DestroyDB(FLAGS_db, Options()); + } + } + + ~Benchmark() { + delete db_; + delete cache_; + delete filter_policy_; + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + // Reset parameters that may be overridden below + num_ = FLAGS_num; + reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads); + value_size_ = FLAGS_value_size; + entries_per_batch_ = 1; + write_options_ = WriteOptions(); + + void (Benchmark::*method)(ThreadState*) = NULL; + bool fresh_db = false; + int num_threads = FLAGS_threads; + + if (name == Slice("open")) { + method = &Benchmark::OpenBench; + num_ /= 10000; + if (num_ < 1) num_ = 1; + } else if (name == Slice("fillseq")) { + fresh_db = true; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillbatch")) { + fresh_db = true; + entries_per_batch_ = 1000; + method = &Benchmark::WriteSeq; + } else if (name == Slice("fillrandom")) { + fresh_db = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("overwrite")) { + fresh_db = false; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fillsync")) { + fresh_db = true; + num_ /= 1000; + write_options_.sync = true; + method = &Benchmark::WriteRandom; + } else if (name == Slice("fill100K")) { + fresh_db = true; + num_ /= 1000; + value_size_ = 100 * 1000; + method = &Benchmark::WriteRandom; + } else if (name == Slice("readseq")) { + method = &Benchmark::ReadSequential; + } else if (name == Slice("readreverse")) { + method = &Benchmark::ReadReverse; + } else if (name == Slice("readrandom")) { + method = &Benchmark::ReadRandom; + } else if (name == Slice("readmissing")) { + method = &Benchmark::ReadMissing; + } else if (name == Slice("seekrandom")) { + method = &Benchmark::SeekRandom; + } else if (name == Slice("readhot")) { + method = &Benchmark::ReadHot; + } else if (name == Slice("readrandomsmall")) { + reads_ /= 1000; + method = &Benchmark::ReadRandom; + } else if (name == Slice("deleteseq")) { + method = &Benchmark::DeleteSeq; + } else if (name == Slice("deleterandom")) { + method = &Benchmark::DeleteRandom; + } else if (name == Slice("readwhilewriting")) { + num_threads++; // Add extra thread for writing + method = &Benchmark::ReadWhileWriting; + } else if (name == Slice("compact")) { + method = &Benchmark::Compact; + } else if (name == Slice("crc32c")) { + method = &Benchmark::Crc32c; + } else if (name == Slice("acquireload")) { + method = &Benchmark::AcquireLoad; + } else if (name == Slice("snappycomp")) { + method = &Benchmark::SnappyCompress; + } else if (name == Slice("snappyuncomp")) { + method = &Benchmark::SnappyUncompress; + } else if (name == Slice("heapprofile")) { + HeapProfile(); + } else if (name == Slice("stats")) { + PrintStats("leveldb.stats"); + } else if (name == Slice("sstables")) { + PrintStats("leveldb.sstables"); + } else { + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + + if (fresh_db) { + if (FLAGS_use_existing_db) { + fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n", + name.ToString().c_str()); + method = NULL; + } else { + delete db_; + db_ = NULL; + DestroyDB(FLAGS_db, Options()); + Open(); + } + } + + if (method != NULL) { + RunBenchmark(num_threads, name, method); + } + } + } + + private: + struct ThreadArg { + Benchmark* bm; + SharedState* shared; + ThreadState* thread; + void (Benchmark::*method)(ThreadState*); + }; + + static void ThreadBody(void* v) { + ThreadArg* arg = reinterpret_cast(v); + SharedState* shared = arg->shared; + ThreadState* thread = arg->thread; + { + MutexLock l(&shared->mu); + shared->num_initialized++; + if (shared->num_initialized >= shared->total) { + shared->cv.SignalAll(); + } + while (!shared->start) { + shared->cv.Wait(); + } + } + + thread->stats.Start(); + (arg->bm->*(arg->method))(thread); + thread->stats.Stop(); + + { + MutexLock l(&shared->mu); + shared->num_done++; + if (shared->num_done >= shared->total) { + shared->cv.SignalAll(); + } + } + } + + void RunBenchmark(int n, Slice name, + void (Benchmark::*method)(ThreadState*)) { + SharedState shared; + shared.total = n; + shared.num_initialized = 0; + shared.num_done = 0; + shared.start = false; + + ThreadArg* arg = new ThreadArg[n]; + for (int i = 0; i < n; i++) { + arg[i].bm = this; + arg[i].method = method; + arg[i].shared = &shared; + arg[i].thread = new ThreadState(i); + arg[i].thread->shared = &shared; + g_env->StartThread(ThreadBody, &arg[i]); + } + + shared.mu.Lock(); + while (shared.num_initialized < n) { + shared.cv.Wait(); + } + + shared.start = true; + shared.cv.SignalAll(); + while (shared.num_done < n) { + shared.cv.Wait(); + } + shared.mu.Unlock(); + + for (int i = 1; i < n; i++) { + arg[0].thread->stats.Merge(arg[i].thread->stats); + } + arg[0].thread->stats.Report(name); + + for (int i = 0; i < n; i++) { + delete arg[i].thread; + } + delete[] arg; + } + + void Crc32c(ThreadState* thread) { + // Checksum about 500MB of data total + const int size = 4096; + const char* label = "(4K per op)"; + std::string data(size, 'x'); + int64_t bytes = 0; + uint32_t crc = 0; + while (bytes < 500 * 1048576) { + crc = crc32c::Value(data.data(), size); + thread->stats.FinishedSingleOp(); + bytes += size; + } + // Print so result is not dead + fprintf(stderr, "... crc=0x%x\r", static_cast(crc)); + + thread->stats.AddBytes(bytes); + thread->stats.AddMessage(label); + } + + void AcquireLoad(ThreadState* thread) { + int dummy; + port::AtomicPointer ap(&dummy); + int count = 0; + void *ptr = NULL; + thread->stats.AddMessage("(each op is 1000 loads)"); + while (count < 100000) { + for (int i = 0; i < 1000; i++) { + ptr = ap.Acquire_Load(); + } + count++; + thread->stats.FinishedSingleOp(); + } + if (ptr == NULL) exit(1); // Disable unused variable warning. + } + + void SnappyCompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + int64_t bytes = 0; + int64_t produced = 0; + bool ok = true; + std::string compressed; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + produced += compressed.size(); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "(output: %.1f%%)", + (produced * 100.0) / bytes); + thread->stats.AddMessage(buf); + thread->stats.AddBytes(bytes); + } + } + + void SnappyUncompress(ThreadState* thread) { + RandomGenerator gen; + Slice input = gen.Generate(Options().block_size); + std::string compressed; + bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed); + int64_t bytes = 0; + char* uncompressed = new char[input.size()]; + while (ok && bytes < 1024 * 1048576) { // Compress 1G + ok = port::Snappy_Uncompress(compressed.data(), compressed.size(), + uncompressed); + bytes += input.size(); + thread->stats.FinishedSingleOp(); + } + delete[] uncompressed; + + if (!ok) { + thread->stats.AddMessage("(snappy failure)"); + } else { + thread->stats.AddBytes(bytes); + } + } + + void Open() { + assert(db_ == NULL); + Options options; + options.env = g_env; + options.create_if_missing = !FLAGS_use_existing_db; + options.block_cache = cache_; + options.write_buffer_size = FLAGS_write_buffer_size; + options.max_file_size = FLAGS_max_file_size; + options.block_size = FLAGS_block_size; + options.max_open_files = FLAGS_open_files; + options.filter_policy = filter_policy_; + options.reuse_logs = FLAGS_reuse_logs; + Status s = DB::Open(options, FLAGS_db, &db_); + if (!s.ok()) { + fprintf(stderr, "open error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + void OpenBench(ThreadState* thread) { + for (int i = 0; i < num_; i++) { + delete db_; + Open(); + thread->stats.FinishedSingleOp(); + } + } + + void WriteSeq(ThreadState* thread) { + DoWrite(thread, true); + } + + void WriteRandom(ThreadState* thread) { + DoWrite(thread, false); + } + + void DoWrite(ThreadState* thread, bool seq) { + if (num_ != FLAGS_num) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_); + thread->stats.AddMessage(msg); + } + + RandomGenerator gen; + WriteBatch batch; + Status s; + int64_t bytes = 0; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Put(key, gen.Generate(value_size_)); + bytes += value_size_ + strlen(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + thread->stats.AddBytes(bytes); + } + + void ReadSequential(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadReverse(ThreadState* thread) { + Iterator* iter = db_->NewIterator(ReadOptions()); + int i = 0; + int64_t bytes = 0; + for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) { + bytes += iter->key().size() + iter->value().size(); + thread->stats.FinishedSingleOp(); + ++i; + } + delete iter; + thread->stats.AddBytes(bytes); + } + + void ReadRandom(ThreadState* thread) { + ReadOptions options; + std::string value; + int found = 0; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + if (db_->Get(options, key, &value).ok()) { + found++; + } + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void ReadMissing(ThreadState* thread) { + ReadOptions options; + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d.", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void ReadHot(ThreadState* thread) { + ReadOptions options; + std::string value; + const int range = (FLAGS_num + 99) / 100; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = thread->rand.Next() % range; + snprintf(key, sizeof(key), "%016d", k); + db_->Get(options, key, &value); + thread->stats.FinishedSingleOp(); + } + } + + void SeekRandom(ThreadState* thread) { + ReadOptions options; + int found = 0; + for (int i = 0; i < reads_; i++) { + Iterator* iter = db_->NewIterator(options); + char key[100]; + const int k = thread->rand.Next() % FLAGS_num; + snprintf(key, sizeof(key), "%016d", k); + iter->Seek(key); + if (iter->Valid() && iter->key() == key) found++; + delete iter; + thread->stats.FinishedSingleOp(); + } + char msg[100]; + snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_); + thread->stats.AddMessage(msg); + } + + void DoDelete(ThreadState* thread, bool seq) { + RandomGenerator gen; + WriteBatch batch; + Status s; + for (int i = 0; i < num_; i += entries_per_batch_) { + batch.Clear(); + for (int j = 0; j < entries_per_batch_; j++) { + const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + batch.Delete(key); + thread->stats.FinishedSingleOp(); + } + s = db_->Write(write_options_, &batch); + if (!s.ok()) { + fprintf(stderr, "del error: %s\n", s.ToString().c_str()); + exit(1); + } + } + } + + void DeleteSeq(ThreadState* thread) { + DoDelete(thread, true); + } + + void DeleteRandom(ThreadState* thread) { + DoDelete(thread, false); + } + + void ReadWhileWriting(ThreadState* thread) { + if (thread->tid > 0) { + ReadRandom(thread); + } else { + // Special thread that keeps writing until other threads are done. + RandomGenerator gen; + while (true) { + { + MutexLock l(&thread->shared->mu); + if (thread->shared->num_done + 1 >= thread->shared->num_initialized) { + // Other threads have finished + break; + } + } + + const int k = thread->rand.Next() % FLAGS_num; + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + Status s = db_->Put(write_options_, key, gen.Generate(value_size_)); + if (!s.ok()) { + fprintf(stderr, "put error: %s\n", s.ToString().c_str()); + exit(1); + } + } + + // Do not count any of the preceding work/delay in stats. + thread->stats.Start(); + } + } + + void Compact(ThreadState* thread) { + db_->CompactRange(NULL, NULL); + } + + void PrintStats(const char* key) { + std::string stats; + if (!db_->GetProperty(key, &stats)) { + stats = "(failed)"; + } + fprintf(stdout, "\n%s\n", stats.c_str()); + } + + static void WriteToFile(void* arg, const char* buf, int n) { + reinterpret_cast(arg)->Append(Slice(buf, n)); + } + + void HeapProfile() { + char fname[100]; + snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_); + WritableFile* file; + Status s = g_env->NewWritableFile(fname, &file); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + return; + } + bool ok = port::GetHeapProfile(WriteToFile, file); + delete file; + if (!ok) { + fprintf(stderr, "heap profiling not supported\n"); + g_env->DeleteFile(fname); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + FLAGS_write_buffer_size = leveldb::Options().write_buffer_size; + FLAGS_max_file_size = leveldb::Options().max_file_size; + FLAGS_block_size = leveldb::Options().block_size; + FLAGS_open_files = leveldb::Options().max_open_files; + std::string default_db_path; + + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--reuse_logs=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_reuse_logs = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) { + FLAGS_threads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) { + FLAGS_write_buffer_size = n; + } else if (sscanf(argv[i], "--max_file_size=%d%c", &n, &junk) == 1) { + FLAGS_max_file_size = n; + } else if (sscanf(argv[i], "--block_size=%d%c", &n, &junk) == 1) { + FLAGS_block_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) { + FLAGS_bloom_bits = n; + } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) { + FLAGS_open_files = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + leveldb::g_env = leveldb::Env::Default(); + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::g_env->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/db/db_impl.cc b/db/db_impl.cc new file mode 100644 index 0000000000..3bb58e560a --- /dev/null +++ b/db/db_impl.cc @@ -0,0 +1,1568 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" + +#include +#include +#include +#include +#include +#include +#include "db/builder.h" +#include "db/db_iter.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/table_builder.h" +#include "port/port.h" +#include "table/block.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" +#include "util/mutexlock.h" + +namespace leveldb { + +const int kNumNonTableCacheFiles = 10; + +// Information kept for every waiting writer +struct DBImpl::Writer { + Status status; + WriteBatch* batch; + bool sync; + bool done; + port::CondVar cv; + + explicit Writer(port::Mutex* mu) : cv(mu) { } +}; + +struct DBImpl::CompactionState { + Compaction* const compaction; + + // Sequence numbers < smallest_snapshot are not significant since we + // will never have to service a snapshot below smallest_snapshot. + // Therefore if we have seen a sequence number S <= smallest_snapshot, + // we can drop all entries for the same key with sequence numbers < S. + SequenceNumber smallest_snapshot; + + // Files produced by compaction + struct Output { + uint64_t number; + uint64_t file_size; + InternalKey smallest, largest; + }; + std::vector outputs; + + // State kept for output being generated + WritableFile* outfile; + TableBuilder* builder; + + uint64_t total_bytes; + + Output* current_output() { return &outputs[outputs.size()-1]; } + + explicit CompactionState(Compaction* c) + : compaction(c), + outfile(NULL), + builder(NULL), + total_bytes(0) { + } +}; + +// Fix user-supplied options to be reasonable +template +static void ClipToRange(T* ptr, V minvalue, V maxvalue) { + if (static_cast(*ptr) > maxvalue) *ptr = maxvalue; + if (static_cast(*ptr) < minvalue) *ptr = minvalue; +} +Options SanitizeOptions(const std::string& dbname, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src) { + Options result = src; + result.comparator = icmp; + result.filter_policy = (src.filter_policy != NULL) ? ipolicy : NULL; + ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000); + ClipToRange(&result.write_buffer_size, 64<<10, 1<<30); + ClipToRange(&result.max_file_size, 1<<20, 1<<30); + ClipToRange(&result.block_size, 1<<10, 4<<20); + if (result.info_log == NULL) { + // Open a log file in the same directory as the db + src.env->CreateDir(dbname); // In case it does not exist + src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname)); + Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log); + if (!s.ok()) { + // No place suitable for logging + result.info_log = NULL; + } + } + if (result.block_cache == NULL) { + result.block_cache = NewLRUCache(8 << 20); + } + return result; +} + +DBImpl::DBImpl(const Options& raw_options, const std::string& dbname) + : env_(raw_options.env), + internal_comparator_(raw_options.comparator), + internal_filter_policy_(raw_options.filter_policy), + options_(SanitizeOptions(dbname, &internal_comparator_, + &internal_filter_policy_, raw_options)), + owns_info_log_(options_.info_log != raw_options.info_log), + owns_cache_(options_.block_cache != raw_options.block_cache), + dbname_(dbname), + db_lock_(NULL), + shutting_down_(NULL), + bg_cv_(&mutex_), + mem_(NULL), + imm_(NULL), + logfile_(NULL), + logfile_number_(0), + log_(NULL), + seed_(0), + tmp_batch_(new WriteBatch), + bg_compaction_scheduled_(false), + manual_compaction_(NULL) { + has_imm_.Release_Store(NULL); + + // Reserve ten files or so for other uses and give the rest to TableCache. + const int table_cache_size = options_.max_open_files - kNumNonTableCacheFiles; + table_cache_ = new TableCache(dbname_, &options_, table_cache_size); + + versions_ = new VersionSet(dbname_, &options_, table_cache_, + &internal_comparator_); +} + +DBImpl::~DBImpl() { + // Wait for background work to finish + mutex_.Lock(); + shutting_down_.Release_Store(this); // Any non-NULL value is ok + while (bg_compaction_scheduled_) { + bg_cv_.Wait(); + } + mutex_.Unlock(); + + if (db_lock_ != NULL) { + env_->UnlockFile(db_lock_); + } + + delete versions_; + if (mem_ != NULL) mem_->Unref(); + if (imm_ != NULL) imm_->Unref(); + delete tmp_batch_; + delete log_; + delete logfile_; + delete table_cache_; + + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } +} + +Status DBImpl::NewDB() { + VersionEdit new_db; + new_db.SetComparatorName(user_comparator()->Name()); + new_db.SetLogNumber(0); + new_db.SetNextFile(2); + new_db.SetLastSequence(0); + + const std::string manifest = DescriptorFileName(dbname_, 1); + WritableFile* file; + Status s = env_->NewWritableFile(manifest, &file); + if (!s.ok()) { + return s; + } + { + log::Writer log(file); + std::string record; + new_db.EncodeTo(&record); + s = log.AddRecord(record); + if (s.ok()) { + s = file->Close(); + } + } + delete file; + if (s.ok()) { + // Make "CURRENT" file that points to the new manifest file. + s = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(manifest); + } + return s; +} + +void DBImpl::MaybeIgnoreError(Status* s) const { + if (s->ok() || options_.paranoid_checks) { + // No change needed + } else { + Log(options_.info_log, "Ignoring error %s", s->ToString().c_str()); + *s = Status::OK(); + } +} + +void DBImpl::DeleteObsoleteFiles() { + if (!bg_error_.ok()) { + // After a background error, we don't know whether a new version may + // or may not have been committed, so we cannot safely garbage collect. + return; + } + + // Make a set of all of the live files + std::set live = pending_outputs_; + versions_->AddLiveFiles(&live); + + std::vector filenames; + env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + bool keep = true; + switch (type) { + case kLogFile: + keep = ((number >= versions_->LogNumber()) || + (number == versions_->PrevLogNumber())); + break; + case kDescriptorFile: + // Keep my manifest file, and any newer incarnations' + // (in case there is a race that allows other incarnations) + keep = (number >= versions_->ManifestFileNumber()); + break; + case kTableFile: + keep = (live.find(number) != live.end()); + break; + case kTempFile: + // Any temp files that are currently being written to must + // be recorded in pending_outputs_, which is inserted into "live" + keep = (live.find(number) != live.end()); + break; + case kCurrentFile: + case kDBLockFile: + case kInfoLogFile: + keep = true; + break; + } + + if (!keep) { + if (type == kTableFile) { + table_cache_->Evict(number); + } + Log(options_.info_log, "Delete type=%d #%lld\n", + int(type), + static_cast(number)); + env_->DeleteFile(dbname_ + "/" + filenames[i]); + } + } + } +} + +Status DBImpl::Recover(VersionEdit* edit, bool *save_manifest) { + mutex_.AssertHeld(); + + // Ignore error from CreateDir since the creation of the DB is + // committed only when the descriptor is created, and this directory + // may already exist from a previous failed creation attempt. + env_->CreateDir(dbname_); + assert(db_lock_ == NULL); + Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); + if (!s.ok()) { + return s; + } + + if (!env_->FileExists(CurrentFileName(dbname_))) { + if (options_.create_if_missing) { + s = NewDB(); + if (!s.ok()) { + return s; + } + } else { + return Status::InvalidArgument( + dbname_, "does not exist (create_if_missing is false)"); + } + } else { + if (options_.error_if_exists) { + return Status::InvalidArgument( + dbname_, "exists (error_if_exists is true)"); + } + } + + s = versions_->Recover(save_manifest); + if (!s.ok()) { + return s; + } + SequenceNumber max_sequence(0); + + // Recover from all newer log files than the ones named in the + // descriptor (new log files may have been added by the previous + // incarnation without registering them in the descriptor). + // + // Note that PrevLogNumber() is no longer used, but we pay + // attention to it in case we are recovering a database + // produced by an older version of leveldb. + const uint64_t min_log = versions_->LogNumber(); + const uint64_t prev_log = versions_->PrevLogNumber(); + std::vector filenames; + s = env_->GetChildren(dbname_, &filenames); + if (!s.ok()) { + return s; + } + std::set expected; + versions_->AddLiveFiles(&expected); + uint64_t number; + FileType type; + std::vector logs; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + expected.erase(number); + if (type == kLogFile && ((number >= min_log) || (number == prev_log))) + logs.push_back(number); + } + } + if (!expected.empty()) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d missing files; e.g.", + static_cast(expected.size())); + return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin()))); + } + + // Recover in the order in which the logs were generated + std::sort(logs.begin(), logs.end()); + for (size_t i = 0; i < logs.size(); i++) { + s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit, + &max_sequence); + if (!s.ok()) { + return s; + } + + // The previous incarnation may not have written any MANIFEST + // records after allocating this log number. So we manually + // update the file number allocation counter in VersionSet. + versions_->MarkFileNumberUsed(logs[i]); + } + + if (versions_->LastSequence() < max_sequence) { + versions_->SetLastSequence(max_sequence); + } + + return Status::OK(); +} + +Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log, + bool* save_manifest, VersionEdit* edit, + SequenceNumber* max_sequence) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + const char* fname; + Status* status; // NULL if options_.paranoid_checks==false + virtual void Corruption(size_t bytes, const Status& s) { + Log(info_log, "%s%s: dropping %d bytes; %s", + (this->status == NULL ? "(ignoring error) " : ""), + fname, static_cast(bytes), s.ToString().c_str()); + if (this->status != NULL && this->status->ok()) *this->status = s; + } + }; + + mutex_.AssertHeld(); + + // Open the log file + std::string fname = LogFileName(dbname_, log_number); + SequentialFile* file; + Status status = env_->NewSequentialFile(fname, &file); + if (!status.ok()) { + MaybeIgnoreError(&status); + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.fname = fname.c_str(); + reporter.status = (options_.paranoid_checks ? &status : NULL); + // We intentionally make log::Reader do checksumming even if + // paranoid_checks==false so that corruptions cause entire commits + // to be skipped instead of propagating bad information (like overly + // large sequence numbers). + log::Reader reader(file, &reporter, true/*checksum*/, + 0/*initial_offset*/); + Log(options_.info_log, "Recovering log #%llu", + (unsigned long long) log_number); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + int compactions = 0; + MemTable* mem = NULL; + while (reader.ReadRecord(&record, &scratch) && + status.ok()) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small", fname)); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + + if (mem == NULL) { + mem = new MemTable(internal_comparator_); + mem->Ref(); + } + status = WriteBatchInternal::InsertInto(&batch, mem); + MaybeIgnoreError(&status); + if (!status.ok()) { + break; + } + const SequenceNumber last_seq = + WriteBatchInternal::Sequence(&batch) + + WriteBatchInternal::Count(&batch) - 1; + if (last_seq > *max_sequence) { + *max_sequence = last_seq; + } + + if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) { + compactions++; + *save_manifest = true; + status = WriteLevel0Table(mem, edit, NULL); + mem->Unref(); + mem = NULL; + if (!status.ok()) { + // Reflect errors immediately so that conditions like full + // file-systems cause the DB::Open() to fail. + break; + } + } + } + + delete file; + + // See if we should keep reusing the last log file. + if (status.ok() && options_.reuse_logs && last_log && compactions == 0) { + assert(logfile_ == NULL); + assert(log_ == NULL); + assert(mem_ == NULL); + uint64_t lfile_size; + if (env_->GetFileSize(fname, &lfile_size).ok() && + env_->NewAppendableFile(fname, &logfile_).ok()) { + Log(options_.info_log, "Reusing old log %s \n", fname.c_str()); + log_ = new log::Writer(logfile_, lfile_size); + logfile_number_ = log_number; + if (mem != NULL) { + mem_ = mem; + mem = NULL; + } else { + // mem can be NULL if lognum exists but was empty. + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + } + } + } + + if (mem != NULL) { + // mem did not get reused; compact it. + if (status.ok()) { + *save_manifest = true; + status = WriteLevel0Table(mem, edit, NULL); + } + mem->Unref(); + } + + return status; +} + +Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit, + Version* base) { + mutex_.AssertHeld(); + const uint64_t start_micros = env_->NowMicros(); + FileMetaData meta; + meta.number = versions_->NewFileNumber(); + pending_outputs_.insert(meta.number); + Iterator* iter = mem->NewIterator(); + Log(options_.info_log, "Level-0 table #%llu: started", + (unsigned long long) meta.number); + + Status s; + { + mutex_.Unlock(); + s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + mutex_.Lock(); + } + + Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s", + (unsigned long long) meta.number, + (unsigned long long) meta.file_size, + s.ToString().c_str()); + delete iter; + pending_outputs_.erase(meta.number); + + + // Note that if file_size is zero, the file has been deleted and + // should not be added to the manifest. + int level = 0; + if (s.ok() && meta.file_size > 0) { + const Slice min_user_key = meta.smallest.user_key(); + const Slice max_user_key = meta.largest.user_key(); + if (base != NULL) { + level = base->PickLevelForMemTableOutput(min_user_key, max_user_key); + } + edit->AddFile(level, meta.number, meta.file_size, + meta.smallest, meta.largest); + } + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros; + stats.bytes_written = meta.file_size; + stats_[level].Add(stats); + return s; +} + +void DBImpl::CompactMemTable() { + mutex_.AssertHeld(); + assert(imm_ != NULL); + + // Save the contents of the memtable as a new Table + VersionEdit edit; + Version* base = versions_->current(); + base->Ref(); + Status s = WriteLevel0Table(imm_, &edit, base); + base->Unref(); + + if (s.ok() && shutting_down_.Acquire_Load()) { + s = Status::IOError("Deleting DB during memtable compaction"); + } + + // Replace immutable memtable with the generated Table + if (s.ok()) { + edit.SetPrevLogNumber(0); + edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed + s = versions_->LogAndApply(&edit, &mutex_); + } + + if (s.ok()) { + // Commit to the new state + imm_->Unref(); + imm_ = NULL; + has_imm_.Release_Store(NULL); + DeleteObsoleteFiles(); + } else { + RecordBackgroundError(s); + } +} + +void DBImpl::CompactRange(const Slice* begin, const Slice* end) { + int max_level_with_files = 1; + { + MutexLock l(&mutex_); + Version* base = versions_->current(); + for (int level = 1; level < config::kNumLevels; level++) { + if (base->OverlapInLevel(level, begin, end)) { + max_level_with_files = level; + } + } + } + TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap + for (int level = 0; level < max_level_with_files; level++) { + TEST_CompactRange(level, begin, end); + } +} + +void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) { + assert(level >= 0); + assert(level + 1 < config::kNumLevels); + + InternalKey begin_storage, end_storage; + + ManualCompaction manual; + manual.level = level; + manual.done = false; + if (begin == NULL) { + manual.begin = NULL; + } else { + begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek); + manual.begin = &begin_storage; + } + if (end == NULL) { + manual.end = NULL; + } else { + end_storage = InternalKey(*end, 0, static_cast(0)); + manual.end = &end_storage; + } + + MutexLock l(&mutex_); + while (!manual.done && !shutting_down_.Acquire_Load() && bg_error_.ok()) { + if (manual_compaction_ == NULL) { // Idle + manual_compaction_ = &manual; + MaybeScheduleCompaction(); + } else { // Running either my compaction or another compaction. + bg_cv_.Wait(); + } + } + if (manual_compaction_ == &manual) { + // Cancel my manual compaction since we aborted early for some reason. + manual_compaction_ = NULL; + } +} + +Status DBImpl::TEST_CompactMemTable() { + // NULL batch means just wait for earlier writes to be done + Status s = Write(WriteOptions(), NULL); + if (s.ok()) { + // Wait until the compaction completes + MutexLock l(&mutex_); + while (imm_ != NULL && bg_error_.ok()) { + bg_cv_.Wait(); + } + if (imm_ != NULL) { + s = bg_error_; + } + } + return s; +} + +void DBImpl::RecordBackgroundError(const Status& s) { + mutex_.AssertHeld(); + if (bg_error_.ok()) { + bg_error_ = s; + bg_cv_.SignalAll(); + } +} + +void DBImpl::MaybeScheduleCompaction() { + mutex_.AssertHeld(); + if (bg_compaction_scheduled_) { + // Already scheduled + } else if (shutting_down_.Acquire_Load()) { + // DB is being deleted; no more background compactions + } else if (!bg_error_.ok()) { + // Already got an error; no more changes + } else if (imm_ == NULL && + manual_compaction_ == NULL && + !versions_->NeedsCompaction()) { + // No work to be done + } else { + bg_compaction_scheduled_ = true; + env_->Schedule(&DBImpl::BGWork, this); + } +} + +void DBImpl::BGWork(void* db) { + reinterpret_cast(db)->BackgroundCall(); +} + +void DBImpl::BackgroundCall() { + MutexLock l(&mutex_); + assert(bg_compaction_scheduled_); + if (shutting_down_.Acquire_Load()) { + // No more background work when shutting down. + } else if (!bg_error_.ok()) { + // No more background work after a background error. + } else { + BackgroundCompaction(); + } + + bg_compaction_scheduled_ = false; + + // Previous compaction may have produced too many files in a level, + // so reschedule another compaction if needed. + MaybeScheduleCompaction(); + bg_cv_.SignalAll(); +} + +void DBImpl::BackgroundCompaction() { + mutex_.AssertHeld(); + + if (imm_ != NULL) { + CompactMemTable(); + return; + } + + Compaction* c; + bool is_manual = (manual_compaction_ != NULL); + InternalKey manual_end; + if (is_manual) { + ManualCompaction* m = manual_compaction_; + c = versions_->CompactRange(m->level, m->begin, m->end); + m->done = (c == NULL); + if (c != NULL) { + manual_end = c->input(0, c->num_input_files(0) - 1)->largest; + } + Log(options_.info_log, + "Manual compaction at level-%d from %s .. %s; will stop at %s\n", + m->level, + (m->begin ? m->begin->DebugString().c_str() : "(begin)"), + (m->end ? m->end->DebugString().c_str() : "(end)"), + (m->done ? "(end)" : manual_end.DebugString().c_str())); + } else { + c = versions_->PickCompaction(); + } + + Status status; + if (c == NULL) { + // Nothing to do + } else if (!is_manual && c->IsTrivialMove()) { + // Move file to next level + assert(c->num_input_files(0) == 1); + FileMetaData* f = c->input(0, 0); + c->edit()->DeleteFile(c->level(), f->number); + c->edit()->AddFile(c->level() + 1, f->number, f->file_size, + f->smallest, f->largest); + status = versions_->LogAndApply(c->edit(), &mutex_); + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n", + static_cast(f->number), + c->level() + 1, + static_cast(f->file_size), + status.ToString().c_str(), + versions_->LevelSummary(&tmp)); + } else { + CompactionState* compact = new CompactionState(c); + status = DoCompactionWork(compact); + if (!status.ok()) { + RecordBackgroundError(status); + } + CleanupCompaction(compact); + c->ReleaseInputs(); + DeleteObsoleteFiles(); + } + delete c; + + if (status.ok()) { + // Done + } else if (shutting_down_.Acquire_Load()) { + // Ignore compaction errors found during shutting down + } else { + Log(options_.info_log, + "Compaction error: %s", status.ToString().c_str()); + } + + if (is_manual) { + ManualCompaction* m = manual_compaction_; + if (!status.ok()) { + m->done = true; + } + if (!m->done) { + // We only compacted part of the requested range. Update *m + // to the range that is left to be compacted. + m->tmp_storage = manual_end; + m->begin = &m->tmp_storage; + } + manual_compaction_ = NULL; + } +} + +void DBImpl::CleanupCompaction(CompactionState* compact) { + mutex_.AssertHeld(); + if (compact->builder != NULL) { + // May happen if we get a shutdown call in the middle of compaction + compact->builder->Abandon(); + delete compact->builder; + } else { + assert(compact->outfile == NULL); + } + delete compact->outfile; + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + pending_outputs_.erase(out.number); + } + delete compact; +} + +Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) { + assert(compact != NULL); + assert(compact->builder == NULL); + uint64_t file_number; + { + mutex_.Lock(); + file_number = versions_->NewFileNumber(); + pending_outputs_.insert(file_number); + CompactionState::Output out; + out.number = file_number; + out.smallest.Clear(); + out.largest.Clear(); + compact->outputs.push_back(out); + mutex_.Unlock(); + } + + // Make the output file + std::string fname = TableFileName(dbname_, file_number); + Status s = env_->NewWritableFile(fname, &compact->outfile); + if (s.ok()) { + compact->builder = new TableBuilder(options_, compact->outfile); + } + return s; +} + +Status DBImpl::FinishCompactionOutputFile(CompactionState* compact, + Iterator* input) { + assert(compact != NULL); + assert(compact->outfile != NULL); + assert(compact->builder != NULL); + + const uint64_t output_number = compact->current_output()->number; + assert(output_number != 0); + + // Check for iterator errors + Status s = input->status(); + const uint64_t current_entries = compact->builder->NumEntries(); + if (s.ok()) { + s = compact->builder->Finish(); + } else { + compact->builder->Abandon(); + } + const uint64_t current_bytes = compact->builder->FileSize(); + compact->current_output()->file_size = current_bytes; + compact->total_bytes += current_bytes; + delete compact->builder; + compact->builder = NULL; + + // Finish and check for file errors + if (s.ok()) { + s = compact->outfile->Sync(); + } + if (s.ok()) { + s = compact->outfile->Close(); + } + delete compact->outfile; + compact->outfile = NULL; + + if (s.ok() && current_entries > 0) { + // Verify that the table is usable + Iterator* iter = table_cache_->NewIterator(ReadOptions(), + output_number, + current_bytes); + s = iter->status(); + delete iter; + if (s.ok()) { + Log(options_.info_log, + "Generated table #%llu@%d: %lld keys, %lld bytes", + (unsigned long long) output_number, + compact->compaction->level(), + (unsigned long long) current_entries, + (unsigned long long) current_bytes); + } + } + return s; +} + + +Status DBImpl::InstallCompactionResults(CompactionState* compact) { + mutex_.AssertHeld(); + Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1, + static_cast(compact->total_bytes)); + + // Add compaction outputs + compact->compaction->AddInputDeletions(compact->compaction->edit()); + const int level = compact->compaction->level(); + for (size_t i = 0; i < compact->outputs.size(); i++) { + const CompactionState::Output& out = compact->outputs[i]; + compact->compaction->edit()->AddFile( + level + 1, + out.number, out.file_size, out.smallest, out.largest); + } + return versions_->LogAndApply(compact->compaction->edit(), &mutex_); +} + +Status DBImpl::DoCompactionWork(CompactionState* compact) { + const uint64_t start_micros = env_->NowMicros(); + int64_t imm_micros = 0; // Micros spent doing imm_ compactions + + Log(options_.info_log, "Compacting %d@%d + %d@%d files", + compact->compaction->num_input_files(0), + compact->compaction->level(), + compact->compaction->num_input_files(1), + compact->compaction->level() + 1); + + assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); + assert(compact->builder == NULL); + assert(compact->outfile == NULL); + if (snapshots_.empty()) { + compact->smallest_snapshot = versions_->LastSequence(); + } else { + compact->smallest_snapshot = snapshots_.oldest()->number_; + } + + // Release mutex while we're actually doing the compaction work + mutex_.Unlock(); + + Iterator* input = versions_->MakeInputIterator(compact->compaction); + input->SeekToFirst(); + Status status; + ParsedInternalKey ikey; + std::string current_user_key; + bool has_current_user_key = false; + SequenceNumber last_sequence_for_key = kMaxSequenceNumber; + for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { + // Prioritize immutable compaction work + if (has_imm_.NoBarrier_Load() != NULL) { + const uint64_t imm_start = env_->NowMicros(); + mutex_.Lock(); + if (imm_ != NULL) { + CompactMemTable(); + bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary + } + mutex_.Unlock(); + imm_micros += (env_->NowMicros() - imm_start); + } + + Slice key = input->key(); + if (compact->compaction->ShouldStopBefore(key) && + compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + + // Handle key/value, add to state, etc. + bool drop = false; + if (!ParseInternalKey(key, &ikey)) { + // Do not hide error keys + current_user_key.clear(); + has_current_user_key = false; + last_sequence_for_key = kMaxSequenceNumber; + } else { + if (!has_current_user_key || + user_comparator()->Compare(ikey.user_key, + Slice(current_user_key)) != 0) { + // First occurrence of this user key + current_user_key.assign(ikey.user_key.data(), ikey.user_key.size()); + has_current_user_key = true; + last_sequence_for_key = kMaxSequenceNumber; + } + + if (last_sequence_for_key <= compact->smallest_snapshot) { + // Hidden by an newer entry for same user key + drop = true; // (A) + } else if (ikey.type == kTypeDeletion && + ikey.sequence <= compact->smallest_snapshot && + compact->compaction->IsBaseLevelForKey(ikey.user_key)) { + // For this user key: + // (1) there is no data in higher levels + // (2) data in lower levels will have larger sequence numbers + // (3) data in layers that are being compacted here and have + // smaller sequence numbers will be dropped in the next + // few iterations of this loop (by rule (A) above). + // Therefore this deletion marker is obsolete and can be dropped. + drop = true; + } + + last_sequence_for_key = ikey.sequence; + } +#if 0 + Log(options_.info_log, + " Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, " + "%d smallest_snapshot: %d", + ikey.user_key.ToString().c_str(), + (int)ikey.sequence, ikey.type, kTypeValue, drop, + compact->compaction->IsBaseLevelForKey(ikey.user_key), + (int)last_sequence_for_key, (int)compact->smallest_snapshot); +#endif + + if (!drop) { + // Open output file if necessary + if (compact->builder == NULL) { + status = OpenCompactionOutputFile(compact); + if (!status.ok()) { + break; + } + } + if (compact->builder->NumEntries() == 0) { + compact->current_output()->smallest.DecodeFrom(key); + } + compact->current_output()->largest.DecodeFrom(key); + compact->builder->Add(key, input->value()); + + // Close output file if it is big enough + if (compact->builder->FileSize() >= + compact->compaction->MaxOutputFileSize()) { + status = FinishCompactionOutputFile(compact, input); + if (!status.ok()) { + break; + } + } + } + + input->Next(); + } + + if (status.ok() && shutting_down_.Acquire_Load()) { + status = Status::IOError("Deleting DB during compaction"); + } + if (status.ok() && compact->builder != NULL) { + status = FinishCompactionOutputFile(compact, input); + } + if (status.ok()) { + status = input->status(); + } + delete input; + input = NULL; + + CompactionStats stats; + stats.micros = env_->NowMicros() - start_micros - imm_micros; + for (int which = 0; which < 2; which++) { + for (int i = 0; i < compact->compaction->num_input_files(which); i++) { + stats.bytes_read += compact->compaction->input(which, i)->file_size; + } + } + for (size_t i = 0; i < compact->outputs.size(); i++) { + stats.bytes_written += compact->outputs[i].file_size; + } + + mutex_.Lock(); + stats_[compact->compaction->level() + 1].Add(stats); + + if (status.ok()) { + status = InstallCompactionResults(compact); + } + if (!status.ok()) { + RecordBackgroundError(status); + } + VersionSet::LevelSummaryStorage tmp; + Log(options_.info_log, + "compacted to: %s", versions_->LevelSummary(&tmp)); + return status; +} + +namespace { +struct IterState { + port::Mutex* mu; + Version* version; + MemTable* mem; + MemTable* imm; +}; + +static void CleanupIteratorState(void* arg1, void* arg2) { + IterState* state = reinterpret_cast(arg1); + state->mu->Lock(); + state->mem->Unref(); + if (state->imm != NULL) state->imm->Unref(); + state->version->Unref(); + state->mu->Unlock(); + delete state; +} +} // namespace + +Iterator* DBImpl::NewInternalIterator(const ReadOptions& options, + SequenceNumber* latest_snapshot, + uint32_t* seed) { + IterState* cleanup = new IterState; + mutex_.Lock(); + *latest_snapshot = versions_->LastSequence(); + + // Collect together all needed child iterators + std::vector list; + list.push_back(mem_->NewIterator()); + mem_->Ref(); + if (imm_ != NULL) { + list.push_back(imm_->NewIterator()); + imm_->Ref(); + } + versions_->current()->AddIterators(options, &list); + Iterator* internal_iter = + NewMergingIterator(&internal_comparator_, &list[0], list.size()); + versions_->current()->Ref(); + + cleanup->mu = &mutex_; + cleanup->mem = mem_; + cleanup->imm = imm_; + cleanup->version = versions_->current(); + internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL); + + *seed = ++seed_; + mutex_.Unlock(); + return internal_iter; +} + +Iterator* DBImpl::TEST_NewInternalIterator() { + SequenceNumber ignored; + uint32_t ignored_seed; + return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed); +} + +int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() { + MutexLock l(&mutex_); + return versions_->MaxNextLevelOverlappingBytes(); +} + +Status DBImpl::Get(const ReadOptions& options, + const Slice& key, + std::string* value) { + Status s; + MutexLock l(&mutex_); + SequenceNumber snapshot; + if (options.snapshot != NULL) { + snapshot = reinterpret_cast(options.snapshot)->number_; + } else { + snapshot = versions_->LastSequence(); + } + + MemTable* mem = mem_; + MemTable* imm = imm_; + Version* current = versions_->current(); + mem->Ref(); + if (imm != NULL) imm->Ref(); + current->Ref(); + + bool have_stat_update = false; + Version::GetStats stats; + + // Unlock while reading from files and memtables + { + mutex_.Unlock(); + // First look in the memtable, then in the immutable memtable (if any). + LookupKey lkey(key, snapshot); + if (mem->Get(lkey, value, &s)) { + // Done + } else if (imm != NULL && imm->Get(lkey, value, &s)) { + // Done + } else { + s = current->Get(options, lkey, value, &stats); + have_stat_update = true; + } + mutex_.Lock(); + } + + if (have_stat_update && current->UpdateStats(stats)) { + MaybeScheduleCompaction(); + } + mem->Unref(); + if (imm != NULL) imm->Unref(); + current->Unref(); + return s; +} + +Iterator* DBImpl::NewIterator(const ReadOptions& options) { + SequenceNumber latest_snapshot; + uint32_t seed; + Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed); + return NewDBIterator( + this, user_comparator(), iter, + (options.snapshot != NULL + ? reinterpret_cast(options.snapshot)->number_ + : latest_snapshot), + seed); +} + +void DBImpl::RecordReadSample(Slice key) { + MutexLock l(&mutex_); + if (versions_->current()->RecordReadSample(key)) { + MaybeScheduleCompaction(); + } +} + +const Snapshot* DBImpl::GetSnapshot() { + MutexLock l(&mutex_); + return snapshots_.New(versions_->LastSequence()); +} + +void DBImpl::ReleaseSnapshot(const Snapshot* s) { + MutexLock l(&mutex_); + snapshots_.Delete(reinterpret_cast(s)); +} + +// Convenience methods +Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { + return DB::Put(o, key, val); +} + +Status DBImpl::Delete(const WriteOptions& options, const Slice& key) { + return DB::Delete(options, key); +} + +Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) { + Writer w(&mutex_); + w.batch = my_batch; + w.sync = options.sync; + w.done = false; + + MutexLock l(&mutex_); + writers_.push_back(&w); + while (!w.done && &w != writers_.front()) { + w.cv.Wait(); + } + if (w.done) { + return w.status; + } + + // May temporarily unlock and wait. + Status status = MakeRoomForWrite(my_batch == NULL); + uint64_t last_sequence = versions_->LastSequence(); + Writer* last_writer = &w; + if (status.ok() && my_batch != NULL) { // NULL batch is for compactions + WriteBatch* updates = BuildBatchGroup(&last_writer); + WriteBatchInternal::SetSequence(updates, last_sequence + 1); + last_sequence += WriteBatchInternal::Count(updates); + + // Add to log and apply to memtable. We can release the lock + // during this phase since &w is currently responsible for logging + // and protects against concurrent loggers and concurrent writes + // into mem_. + { + mutex_.Unlock(); + status = log_->AddRecord(WriteBatchInternal::Contents(updates)); + bool sync_error = false; + if (status.ok() && options.sync) { + status = logfile_->Sync(); + if (!status.ok()) { + sync_error = true; + } + } + if (status.ok()) { + status = WriteBatchInternal::InsertInto(updates, mem_); + } + mutex_.Lock(); + if (sync_error) { + // The state of the log file is indeterminate: the log record we + // just added may or may not show up when the DB is re-opened. + // So we force the DB into a mode where all future writes fail. + RecordBackgroundError(status); + } + } + if (updates == tmp_batch_) tmp_batch_->Clear(); + + versions_->SetLastSequence(last_sequence); + } + + while (true) { + Writer* ready = writers_.front(); + writers_.pop_front(); + if (ready != &w) { + ready->status = status; + ready->done = true; + ready->cv.Signal(); + } + if (ready == last_writer) break; + } + + // Notify new head of write queue + if (!writers_.empty()) { + writers_.front()->cv.Signal(); + } + + return status; +} + +// REQUIRES: Writer list must be non-empty +// REQUIRES: First writer must have a non-NULL batch +WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) { + assert(!writers_.empty()); + Writer* first = writers_.front(); + WriteBatch* result = first->batch; + assert(result != NULL); + + size_t size = WriteBatchInternal::ByteSize(first->batch); + + // Allow the group to grow up to a maximum size, but if the + // original write is small, limit the growth so we do not slow + // down the small write too much. + size_t max_size = 1 << 20; + if (size <= (128<<10)) { + max_size = size + (128<<10); + } + + *last_writer = first; + std::deque::iterator iter = writers_.begin(); + ++iter; // Advance past "first" + for (; iter != writers_.end(); ++iter) { + Writer* w = *iter; + if (w->sync && !first->sync) { + // Do not include a sync write into a batch handled by a non-sync write. + break; + } + + if (w->batch != NULL) { + size += WriteBatchInternal::ByteSize(w->batch); + if (size > max_size) { + // Do not make batch too big + break; + } + + // Append to *result + if (result == first->batch) { + // Switch to temporary batch instead of disturbing caller's batch + result = tmp_batch_; + assert(WriteBatchInternal::Count(result) == 0); + WriteBatchInternal::Append(result, first->batch); + } + WriteBatchInternal::Append(result, w->batch); + } + *last_writer = w; + } + return result; +} + +// REQUIRES: mutex_ is held +// REQUIRES: this thread is currently at the front of the writer queue +Status DBImpl::MakeRoomForWrite(bool force) { + mutex_.AssertHeld(); + assert(!writers_.empty()); + bool allow_delay = !force; + Status s; + while (true) { + if (!bg_error_.ok()) { + // Yield previous error + s = bg_error_; + break; + } else if ( + allow_delay && + versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) { + // We are getting close to hitting a hard limit on the number of + // L0 files. Rather than delaying a single write by several + // seconds when we hit the hard limit, start delaying each + // individual write by 1ms to reduce latency variance. Also, + // this delay hands over some CPU to the compaction thread in + // case it is sharing the same core as the writer. + mutex_.Unlock(); + env_->SleepForMicroseconds(1000); + allow_delay = false; // Do not delay a single write more than once + mutex_.Lock(); + } else if (!force && + (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) { + // There is room in current memtable + break; + } else if (imm_ != NULL) { + // We have filled up the current memtable, but the previous + // one is still being compacted, so we wait. + Log(options_.info_log, "Current memtable full; waiting...\n"); + bg_cv_.Wait(); + } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) { + // There are too many level-0 files. + Log(options_.info_log, "Too many L0 files; waiting...\n"); + bg_cv_.Wait(); + } else { + // Attempt to switch to a new memtable and trigger compaction of old + assert(versions_->PrevLogNumber() == 0); + uint64_t new_log_number = versions_->NewFileNumber(); + WritableFile* lfile = NULL; + s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile); + if (!s.ok()) { + // Avoid chewing through file number space in a tight loop. + versions_->ReuseFileNumber(new_log_number); + break; + } + delete log_; + delete logfile_; + logfile_ = lfile; + logfile_number_ = new_log_number; + log_ = new log::Writer(lfile); + imm_ = mem_; + has_imm_.Release_Store(imm_); + mem_ = new MemTable(internal_comparator_); + mem_->Ref(); + force = false; // Do not force another compaction if have room + MaybeScheduleCompaction(); + } + } + return s; +} + +bool DBImpl::GetProperty(const Slice& property, std::string* value) { + value->clear(); + + MutexLock l(&mutex_); + Slice in = property; + Slice prefix("leveldb."); + if (!in.starts_with(prefix)) return false; + in.remove_prefix(prefix.size()); + + if (in.starts_with("num-files-at-level")) { + in.remove_prefix(strlen("num-files-at-level")); + uint64_t level; + bool ok = ConsumeDecimalNumber(&in, &level) && in.empty(); + if (!ok || level >= config::kNumLevels) { + return false; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "%d", + versions_->NumLevelFiles(static_cast(level))); + *value = buf; + return true; + } + } else if (in == "stats") { + char buf[200]; + snprintf(buf, sizeof(buf), + " Compactions\n" + "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n" + "--------------------------------------------------\n" + ); + value->append(buf); + for (int level = 0; level < config::kNumLevels; level++) { + int files = versions_->NumLevelFiles(level); + if (stats_[level].micros > 0 || files > 0) { + snprintf( + buf, sizeof(buf), + "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", + level, + files, + versions_->NumLevelBytes(level) / 1048576.0, + stats_[level].micros / 1e6, + stats_[level].bytes_read / 1048576.0, + stats_[level].bytes_written / 1048576.0); + value->append(buf); + } + } + return true; + } else if (in == "sstables") { + *value = versions_->current()->DebugString(); + return true; + } else if (in == "approximate-memory-usage") { + size_t total_usage = options_.block_cache->TotalCharge(); + if (mem_) { + total_usage += mem_->ApproximateMemoryUsage(); + } + if (imm_) { + total_usage += imm_->ApproximateMemoryUsage(); + } + char buf[50]; + snprintf(buf, sizeof(buf), "%llu", + static_cast(total_usage)); + value->append(buf); + return true; + } + + return false; +} + +void DBImpl::GetApproximateSizes( + const Range* range, int n, + uint64_t* sizes) { + // TODO(opt): better implementation + Version* v; + { + MutexLock l(&mutex_); + versions_->current()->Ref(); + v = versions_->current(); + } + + for (int i = 0; i < n; i++) { + // Convert user_key into a corresponding internal key. + InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek); + uint64_t start = versions_->ApproximateOffsetOf(v, k1); + uint64_t limit = versions_->ApproximateOffsetOf(v, k2); + sizes[i] = (limit >= start ? limit - start : 0); + } + + { + MutexLock l(&mutex_); + v->Unref(); + } +} + +// Default implementations of convenience methods that subclasses of DB +// can call if they wish +Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { + WriteBatch batch; + batch.Put(key, value); + return Write(opt, &batch); +} + +Status DB::Delete(const WriteOptions& opt, const Slice& key) { + WriteBatch batch; + batch.Delete(key); + return Write(opt, &batch); +} + +DB::~DB() { } + +Status DB::Open(const Options& options, const std::string& dbname, + DB** dbptr) { + *dbptr = NULL; + + DBImpl* impl = new DBImpl(options, dbname); + impl->mutex_.Lock(); + VersionEdit edit; + // Recover handles create_if_missing, error_if_exists + bool save_manifest = false; + Status s = impl->Recover(&edit, &save_manifest); + if (s.ok() && impl->mem_ == NULL) { + // Create new log and a corresponding memtable. + uint64_t new_log_number = impl->versions_->NewFileNumber(); + WritableFile* lfile; + s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), + &lfile); + if (s.ok()) { + edit.SetLogNumber(new_log_number); + impl->logfile_ = lfile; + impl->logfile_number_ = new_log_number; + impl->log_ = new log::Writer(lfile); + impl->mem_ = new MemTable(impl->internal_comparator_); + impl->mem_->Ref(); + } + } + if (s.ok() && save_manifest) { + edit.SetPrevLogNumber(0); // No older logs needed after recovery. + edit.SetLogNumber(impl->logfile_number_); + s = impl->versions_->LogAndApply(&edit, &impl->mutex_); + } + if (s.ok()) { + impl->DeleteObsoleteFiles(); + impl->MaybeScheduleCompaction(); + } + impl->mutex_.Unlock(); + if (s.ok()) { + assert(impl->mem_ != NULL); + *dbptr = impl; + } else { + delete impl; + } + return s; +} + +Snapshot::~Snapshot() { +} + +Status DestroyDB(const std::string& dbname, const Options& options) { + Env* env = options.env; + std::vector filenames; + // Ignore error in case directory does not exist + env->GetChildren(dbname, &filenames); + if (filenames.empty()) { + return Status::OK(); + } + + FileLock* lock; + const std::string lockname = LockFileName(dbname); + Status result = env->LockFile(lockname, &lock); + if (result.ok()) { + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && + type != kDBLockFile) { // Lock file will be deleted at end + Status del = env->DeleteFile(dbname + "/" + filenames[i]); + if (result.ok() && !del.ok()) { + result = del; + } + } + } + env->UnlockFile(lock); // Ignore error since state is already gone + env->DeleteFile(lockname); + env->DeleteDir(dbname); // Ignore error in case dir contains other files + } + return result; +} + +} // namespace leveldb diff --git a/db/db_impl.h b/db/db_impl.h new file mode 100644 index 0000000000..8ff323e728 --- /dev/null +++ b/db/db_impl.h @@ -0,0 +1,211 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_ +#define STORAGE_LEVELDB_DB_DB_IMPL_H_ + +#include +#include +#include "db/dbformat.h" +#include "db/log_writer.h" +#include "db/snapshot.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +class MemTable; +class TableCache; +class Version; +class VersionEdit; +class VersionSet; + +class DBImpl : public DB { + public: + DBImpl(const Options& options, const std::string& dbname); + virtual ~DBImpl(); + + // Implementations of the DB interface + virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value); + virtual Status Delete(const WriteOptions&, const Slice& key); + virtual Status Write(const WriteOptions& options, WriteBatch* updates); + virtual Status Get(const ReadOptions& options, + const Slice& key, + std::string* value); + virtual Iterator* NewIterator(const ReadOptions&); + virtual const Snapshot* GetSnapshot(); + virtual void ReleaseSnapshot(const Snapshot* snapshot); + virtual bool GetProperty(const Slice& property, std::string* value); + virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes); + virtual void CompactRange(const Slice* begin, const Slice* end); + + // Extra methods (for testing) that are not in the public DB interface + + // Compact any files in the named level that overlap [*begin,*end] + void TEST_CompactRange(int level, const Slice* begin, const Slice* end); + + // Force current memtable contents to be compacted. + Status TEST_CompactMemTable(); + + // Return an internal iterator over the current state of the database. + // The keys of this iterator are internal keys (see format.h). + // The returned iterator should be deleted when no longer needed. + Iterator* TEST_NewInternalIterator(); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t TEST_MaxNextLevelOverlappingBytes(); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. + void RecordReadSample(Slice key); + + private: + friend class DB; + struct CompactionState; + struct Writer; + + Iterator* NewInternalIterator(const ReadOptions&, + SequenceNumber* latest_snapshot, + uint32_t* seed); + + Status NewDB(); + + // Recover the descriptor from persistent storage. May do a significant + // amount of work to recover recently logged updates. Any changes to + // be made to the descriptor are added to *edit. + Status Recover(VersionEdit* edit, bool* save_manifest) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void MaybeIgnoreError(Status* s) const; + + // Delete any unneeded files and stale in-memory entries. + void DeleteObsoleteFiles(); + + // Compact the in-memory write buffer to disk. Switches to a new + // log-file/memtable and writes a new descriptor iff successful. + // Errors are recorded in bg_error_. + void CompactMemTable() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status RecoverLogFile(uint64_t log_number, bool last_log, bool* save_manifest, + VersionEdit* edit, SequenceNumber* max_sequence) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status MakeRoomForWrite(bool force /* compact even if there is room? */) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + WriteBatch* BuildBatchGroup(Writer** last_writer); + + void RecordBackgroundError(const Status& s); + + void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + static void BGWork(void* db); + void BackgroundCall(); + void BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_); + void CleanupCompaction(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + Status DoCompactionWork(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + Status OpenCompactionOutputFile(CompactionState* compact); + Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input); + Status InstallCompactionResults(CompactionState* compact) + EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + // Constant after construction + Env* const env_; + const InternalKeyComparator internal_comparator_; + const InternalFilterPolicy internal_filter_policy_; + const Options options_; // options_.comparator == &internal_comparator_ + bool owns_info_log_; + bool owns_cache_; + const std::string dbname_; + + // table_cache_ provides its own synchronization + TableCache* table_cache_; + + // Lock over the persistent DB state. Non-NULL iff successfully acquired. + FileLock* db_lock_; + + // State below is protected by mutex_ + port::Mutex mutex_; + port::AtomicPointer shutting_down_; + port::CondVar bg_cv_; // Signalled when background work finishes + MemTable* mem_; + MemTable* imm_; // Memtable being compacted + port::AtomicPointer has_imm_; // So bg thread can detect non-NULL imm_ + WritableFile* logfile_; + uint64_t logfile_number_; + log::Writer* log_; + uint32_t seed_; // For sampling. + + // Queue of writers. + std::deque writers_; + WriteBatch* tmp_batch_; + + SnapshotList snapshots_; + + // Set of table files to protect from deletion because they are + // part of ongoing compactions. + std::set pending_outputs_; + + // Has a background compaction been scheduled or is running? + bool bg_compaction_scheduled_; + + // Information for a manual compaction + struct ManualCompaction { + int level; + bool done; + const InternalKey* begin; // NULL means beginning of key range + const InternalKey* end; // NULL means end of key range + InternalKey tmp_storage; // Used to keep track of compaction progress + }; + ManualCompaction* manual_compaction_; + + VersionSet* versions_; + + // Have we encountered a background error in paranoid mode? + Status bg_error_; + + // Per level compaction stats. stats_[level] stores the stats for + // compactions that produced data for the specified "level". + struct CompactionStats { + int64_t micros; + int64_t bytes_read; + int64_t bytes_written; + + CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { } + + void Add(const CompactionStats& c) { + this->micros += c.micros; + this->bytes_read += c.bytes_read; + this->bytes_written += c.bytes_written; + } + }; + CompactionStats stats_[config::kNumLevels]; + + // No copying allowed + DBImpl(const DBImpl&); + void operator=(const DBImpl&); + + const Comparator* user_comparator() const { + return internal_comparator_.user_comparator(); + } +}; + +// Sanitize db options. The caller should delete result.info_log if +// it is not equal to src.info_log. +extern Options SanitizeOptions(const std::string& db, + const InternalKeyComparator* icmp, + const InternalFilterPolicy* ipolicy, + const Options& src); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_ diff --git a/db/db_iter.cc b/db/db_iter.cc new file mode 100644 index 0000000000..3b2035e9e3 --- /dev/null +++ b/db/db_iter.cc @@ -0,0 +1,317 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_iter.h" + +#include "db/filename.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/random.h" + +namespace leveldb { + +#if 0 +static void DumpInternalIter(Iterator* iter) { + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey k; + if (!ParseInternalKey(iter->key(), &k)) { + fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str()); + } else { + fprintf(stderr, "@ '%s'\n", k.DebugString().c_str()); + } + } +} +#endif + +namespace { + +// Memtables and sstables that make the DB representation contain +// (userkey,seq,type) => uservalue entries. DBIter +// combines multiple entries for the same userkey found in the DB +// representation into a single entry while accounting for sequence +// numbers, deletion markers, overwrites, etc. +class DBIter: public Iterator { + public: + // Which direction is the iterator currently moving? + // (1) When moving forward, the internal iterator is positioned at + // the exact entry that yields this->key(), this->value() + // (2) When moving backwards, the internal iterator is positioned + // just before all entries whose user key == this->key(). + enum Direction { + kForward, + kReverse + }; + + DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNumber s, + uint32_t seed) + : db_(db), + user_comparator_(cmp), + iter_(iter), + sequence_(s), + direction_(kForward), + valid_(false), + rnd_(seed), + bytes_counter_(RandomPeriod()) { + } + virtual ~DBIter() { + delete iter_; + } + virtual bool Valid() const { return valid_; } + virtual Slice key() const { + assert(valid_); + return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_; + } + virtual Slice value() const { + assert(valid_); + return (direction_ == kForward) ? iter_->value() : saved_value_; + } + virtual Status status() const { + if (status_.ok()) { + return iter_->status(); + } else { + return status_; + } + } + + virtual void Next(); + virtual void Prev(); + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + + private: + void FindNextUserEntry(bool skipping, std::string* skip); + void FindPrevUserEntry(); + bool ParseKey(ParsedInternalKey* key); + + inline void SaveKey(const Slice& k, std::string* dst) { + dst->assign(k.data(), k.size()); + } + + inline void ClearSavedValue() { + if (saved_value_.capacity() > 1048576) { + std::string empty; + swap(empty, saved_value_); + } else { + saved_value_.clear(); + } + } + + // Pick next gap with average value of config::kReadBytesPeriod. + ssize_t RandomPeriod() { + return rnd_.Uniform(2*config::kReadBytesPeriod); + } + + DBImpl* db_; + const Comparator* const user_comparator_; + Iterator* const iter_; + SequenceNumber const sequence_; + + Status status_; + std::string saved_key_; // == current key when direction_==kReverse + std::string saved_value_; // == current raw value when direction_==kReverse + Direction direction_; + bool valid_; + + Random rnd_; + ssize_t bytes_counter_; + + // No copying allowed + DBIter(const DBIter&); + void operator=(const DBIter&); +}; + +inline bool DBIter::ParseKey(ParsedInternalKey* ikey) { + Slice k = iter_->key(); + ssize_t n = k.size() + iter_->value().size(); + bytes_counter_ -= n; + while (bytes_counter_ < 0) { + bytes_counter_ += RandomPeriod(); + db_->RecordReadSample(k); + } + if (!ParseInternalKey(k, ikey)) { + status_ = Status::Corruption("corrupted internal key in DBIter"); + return false; + } else { + return true; + } +} + +void DBIter::Next() { + assert(valid_); + + if (direction_ == kReverse) { // Switch directions? + direction_ = kForward; + // iter_ is pointing just before the entries for this->key(), + // so advance into the range of entries for this->key() and then + // use the normal skipping code below. + if (!iter_->Valid()) { + iter_->SeekToFirst(); + } else { + iter_->Next(); + } + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + return; + } + // saved_key_ already contains the key to skip past. + } else { + // Store in saved_key_ the current key so we skip it below. + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + } + + FindNextUserEntry(true, &saved_key_); +} + +void DBIter::FindNextUserEntry(bool skipping, std::string* skip) { + // Loop until we hit an acceptable entry to yield + assert(iter_->Valid()); + assert(direction_ == kForward); + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + switch (ikey.type) { + case kTypeDeletion: + // Arrange to skip all upcoming entries for this key since + // they are hidden by this deletion. + SaveKey(ikey.user_key, skip); + skipping = true; + break; + case kTypeValue: + if (skipping && + user_comparator_->Compare(ikey.user_key, *skip) <= 0) { + // Entry hidden + } else { + valid_ = true; + saved_key_.clear(); + return; + } + break; + } + } + iter_->Next(); + } while (iter_->Valid()); + saved_key_.clear(); + valid_ = false; +} + +void DBIter::Prev() { + assert(valid_); + + if (direction_ == kForward) { // Switch directions? + // iter_ is pointing at the current entry. Scan backwards until + // the key changes so we can use the normal reverse scanning code. + assert(iter_->Valid()); // Otherwise valid_ would have been false + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + while (true) { + iter_->Prev(); + if (!iter_->Valid()) { + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + return; + } + if (user_comparator_->Compare(ExtractUserKey(iter_->key()), + saved_key_) < 0) { + break; + } + } + direction_ = kReverse; + } + + FindPrevUserEntry(); +} + +void DBIter::FindPrevUserEntry() { + assert(direction_ == kReverse); + + ValueType value_type = kTypeDeletion; + if (iter_->Valid()) { + do { + ParsedInternalKey ikey; + if (ParseKey(&ikey) && ikey.sequence <= sequence_) { + if ((value_type != kTypeDeletion) && + user_comparator_->Compare(ikey.user_key, saved_key_) < 0) { + // We encountered a non-deleted value in entries for previous keys, + break; + } + value_type = ikey.type; + if (value_type == kTypeDeletion) { + saved_key_.clear(); + ClearSavedValue(); + } else { + Slice raw_value = iter_->value(); + if (saved_value_.capacity() > raw_value.size() + 1048576) { + std::string empty; + swap(empty, saved_value_); + } + SaveKey(ExtractUserKey(iter_->key()), &saved_key_); + saved_value_.assign(raw_value.data(), raw_value.size()); + } + } + iter_->Prev(); + } while (iter_->Valid()); + } + + if (value_type == kTypeDeletion) { + // End + valid_ = false; + saved_key_.clear(); + ClearSavedValue(); + direction_ = kForward; + } else { + valid_ = true; + } +} + +void DBIter::Seek(const Slice& target) { + direction_ = kForward; + ClearSavedValue(); + saved_key_.clear(); + AppendInternalKey( + &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek)); + iter_->Seek(saved_key_); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToFirst() { + direction_ = kForward; + ClearSavedValue(); + iter_->SeekToFirst(); + if (iter_->Valid()) { + FindNextUserEntry(false, &saved_key_ /* temporary storage */); + } else { + valid_ = false; + } +} + +void DBIter::SeekToLast() { + direction_ = kReverse; + ClearSavedValue(); + iter_->SeekToLast(); + FindPrevUserEntry(); +} + +} // anonymous namespace + +Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed) { + return new DBIter(db, user_key_comparator, internal_iter, sequence, seed); +} + +} // namespace leveldb diff --git a/db/db_iter.h b/db/db_iter.h new file mode 100644 index 0000000000..04927e937b --- /dev/null +++ b/db/db_iter.h @@ -0,0 +1,28 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_ +#define STORAGE_LEVELDB_DB_DB_ITER_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" + +namespace leveldb { + +class DBImpl; + +// Return a new iterator that converts internal keys (yielded by +// "*internal_iter") that were live at the specified "sequence" number +// into appropriate user keys. +extern Iterator* NewDBIterator( + DBImpl* db, + const Comparator* user_key_comparator, + Iterator* internal_iter, + SequenceNumber sequence, + uint32_t seed); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DB_ITER_H_ diff --git a/db/db_test.cc b/db/db_test.cc new file mode 100644 index 0000000000..a0b08bc19c --- /dev/null +++ b/db/db_test.cc @@ -0,0 +1,2158 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static std::string RandomString(Random* rnd, int len) { + std::string r; + test::RandomString(rnd, len, &r); + return r; +} + +namespace { +class AtomicCounter { + private: + port::Mutex mu_; + int count_; + public: + AtomicCounter() : count_(0) { } + void Increment() { + IncrementBy(1); + } + void IncrementBy(int count) { + MutexLock l(&mu_); + count_ += count; + } + int Read() { + MutexLock l(&mu_); + return count_; + } + void Reset() { + MutexLock l(&mu_); + count_ = 0; + } +}; + +void DelayMilliseconds(int millis) { + Env::Default()->SleepForMicroseconds(millis * 1000); +} +} + +// Special Env used to delay background operations +class SpecialEnv : public EnvWrapper { + public: + // sstable/log Sync() calls are blocked while this pointer is non-NULL. + port::AtomicPointer delay_data_sync_; + + // sstable/log Sync() calls return an error. + port::AtomicPointer data_sync_error_; + + // Simulate no-space errors while this pointer is non-NULL. + port::AtomicPointer no_space_; + + // Simulate non-writable file system while this pointer is non-NULL + port::AtomicPointer non_writable_; + + // Force sync of manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_sync_error_; + + // Force write to manifest files to fail while this pointer is non-NULL + port::AtomicPointer manifest_write_error_; + + bool count_random_reads_; + AtomicCounter random_read_counter_; + + explicit SpecialEnv(Env* base) : EnvWrapper(base) { + delay_data_sync_.Release_Store(NULL); + data_sync_error_.Release_Store(NULL); + no_space_.Release_Store(NULL); + non_writable_.Release_Store(NULL); + count_random_reads_ = false; + manifest_sync_error_.Release_Store(NULL); + manifest_write_error_.Release_Store(NULL); + } + + Status NewWritableFile(const std::string& f, WritableFile** r) { + class DataFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + + public: + DataFile(SpecialEnv* env, WritableFile* base) + : env_(env), + base_(base) { + } + ~DataFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->no_space_.Acquire_Load() != NULL) { + // Drop writes on the floor + return Status::OK(); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->data_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated data sync error"); + } + while (env_->delay_data_sync_.Acquire_Load() != NULL) { + DelayMilliseconds(100); + } + return base_->Sync(); + } + }; + class ManifestFile : public WritableFile { + private: + SpecialEnv* env_; + WritableFile* base_; + public: + ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { } + ~ManifestFile() { delete base_; } + Status Append(const Slice& data) { + if (env_->manifest_write_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated writer error"); + } else { + return base_->Append(data); + } + } + Status Close() { return base_->Close(); } + Status Flush() { return base_->Flush(); } + Status Sync() { + if (env_->manifest_sync_error_.Acquire_Load() != NULL) { + return Status::IOError("simulated sync error"); + } else { + return base_->Sync(); + } + } + }; + + if (non_writable_.Acquire_Load() != NULL) { + return Status::IOError("simulated write error"); + } + + Status s = target()->NewWritableFile(f, r); + if (s.ok()) { + if (strstr(f.c_str(), ".ldb") != NULL || + strstr(f.c_str(), ".log") != NULL) { + *r = new DataFile(this, *r); + } else if (strstr(f.c_str(), "MANIFEST") != NULL) { + *r = new ManifestFile(this, *r); + } + } + return s; + } + + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + class CountingFile : public RandomAccessFile { + private: + RandomAccessFile* target_; + AtomicCounter* counter_; + public: + CountingFile(RandomAccessFile* target, AtomicCounter* counter) + : target_(target), counter_(counter) { + } + virtual ~CountingFile() { delete target_; } + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + counter_->Increment(); + return target_->Read(offset, n, result, scratch); + } + }; + + Status s = target()->NewRandomAccessFile(f, r); + if (s.ok() && count_random_reads_) { + *r = new CountingFile(*r, &random_read_counter_); + } + return s; + } +}; + +class DBTest { + private: + const FilterPolicy* filter_policy_; + + // Sequence of option configurations to try + enum OptionConfig { + kDefault, + kReuse, + kFilter, + kUncompressed, + kEnd + }; + int option_config_; + + public: + std::string dbname_; + SpecialEnv* env_; + DB* db_; + + Options last_options_; + + DBTest() : option_config_(kDefault), + env_(new SpecialEnv(Env::Default())) { + filter_policy_ = NewBloomFilterPolicy(10); + dbname_ = test::TmpDir() + "/db_test"; + DestroyDB(dbname_, Options()); + db_ = NULL; + Reopen(); + } + + ~DBTest() { + delete db_; + DestroyDB(dbname_, Options()); + delete env_; + delete filter_policy_; + } + + // Switch to a fresh database with the next option configuration to + // test. Return false if there are no more configurations to test. + bool ChangeOptions() { + option_config_++; + if (option_config_ >= kEnd) { + return false; + } else { + DestroyAndReopen(); + return true; + } + } + + // Return the current option configuration. + Options CurrentOptions() { + Options options; + options.reuse_logs = false; + switch (option_config_) { + case kReuse: + options.reuse_logs = true; + break; + case kFilter: + options.filter_policy = filter_policy_; + break; + case kUncompressed: + options.compression = kNoCompression; + break; + default: + break; + } + return options; + } + + DBImpl* dbfull() { + return reinterpret_cast(db_); + } + + void Reopen(Options* options = NULL) { + ASSERT_OK(TryReopen(options)); + } + + void Close() { + delete db_; + db_ = NULL; + } + + void DestroyAndReopen(Options* options = NULL) { + delete db_; + db_ = NULL; + DestroyDB(dbname_, Options()); + ASSERT_OK(TryReopen(options)); + } + + Status TryReopen(Options* options) { + delete db_; + db_ = NULL; + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts = CurrentOptions(); + opts.create_if_missing = true; + } + last_options_ = opts; + + return DB::Open(opts, dbname_, &db_); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + Status Delete(const std::string& k) { + return db_->Delete(WriteOptions(), k); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + ReadOptions options; + options.snapshot = snapshot; + std::string result; + Status s = db_->Get(options, k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + // Return a string that contains all key,value pairs in order, + // formatted like "(k1->v1)(k2->v2)". + std::string Contents() { + std::vector forward; + std::string result; + Iterator* iter = db_->NewIterator(ReadOptions()); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + std::string s = IterStatus(iter); + result.push_back('('); + result.append(s); + result.push_back(')'); + forward.push_back(s); + } + + // Check reverse iteration results are the reverse of forward results + size_t matched = 0; + for (iter->SeekToLast(); iter->Valid(); iter->Prev()) { + ASSERT_LT(matched, forward.size()); + ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]); + matched++; + } + ASSERT_EQ(matched, forward.size()); + + delete iter; + return result; + } + + std::string AllEntriesFor(const Slice& user_key) { + Iterator* iter = dbfull()->TEST_NewInternalIterator(); + InternalKey target(user_key, kMaxSequenceNumber, kTypeValue); + iter->Seek(target.Encode()); + std::string result; + if (!iter->status().ok()) { + result = iter->status().ToString(); + } else { + result = "[ "; + bool first = true; + while (iter->Valid()) { + ParsedInternalKey ikey; + if (!ParseInternalKey(iter->key(), &ikey)) { + result += "CORRUPTED"; + } else { + if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) { + break; + } + if (!first) { + result += ", "; + } + first = false; + switch (ikey.type) { + case kTypeValue: + result += iter->value().ToString(); + break; + case kTypeDeletion: + result += "DEL"; + break; + } + } + iter->Next(); + } + if (!first) { + result += " "; + } + result += "]"; + } + delete iter; + return result; + } + + int NumTableFilesAtLevel(int level) { + std::string property; + ASSERT_TRUE( + db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level), + &property)); + return atoi(property.c_str()); + } + + int TotalTableFiles() { + int result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + result += NumTableFilesAtLevel(level); + } + return result; + } + + // Return spread of files per level + std::string FilesPerLevel() { + std::string result; + int last_non_zero_offset = 0; + for (int level = 0; level < config::kNumLevels; level++) { + int f = NumTableFilesAtLevel(level); + char buf[100]; + snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f); + result += buf; + if (f > 0) { + last_non_zero_offset = result.size(); + } + } + result.resize(last_non_zero_offset); + return result; + } + + int CountFiles() { + std::vector files; + env_->GetChildren(dbname_, &files); + return static_cast(files.size()); + } + + uint64_t Size(const Slice& start, const Slice& limit) { + Range r(start, limit); + uint64_t size; + db_->GetApproximateSizes(&r, 1, &size); + return size; + } + + void Compact(const Slice& start, const Slice& limit) { + db_->CompactRange(&start, &limit); + } + + // Do n memtable compactions, each of which produces an sstable + // covering the range [small,large]. + void MakeTables(int n, const std::string& small, const std::string& large) { + for (int i = 0; i < n; i++) { + Put(small, "begin"); + Put(large, "end"); + dbfull()->TEST_CompactMemTable(); + } + } + + // Prevent pushing of new sstables into deeper levels by adding + // tables that cover a specified range to all levels. + void FillLevels(const std::string& smallest, const std::string& largest) { + MakeTables(config::kNumLevels, smallest, largest); + } + + void DumpFileCounts(const char* label) { + fprintf(stderr, "---\n%s:\n", label); + fprintf(stderr, "maxoverlap: %lld\n", + static_cast( + dbfull()->TEST_MaxNextLevelOverlappingBytes())); + for (int level = 0; level < config::kNumLevels; level++) { + int num = NumTableFilesAtLevel(level); + if (num > 0) { + fprintf(stderr, " level %3d : %d files\n", level, num); + } + } + } + + std::string DumpSSTableList() { + std::string property; + db_->GetProperty("leveldb.sstables", &property); + return property; + } + + std::string IterStatus(Iterator* iter) { + std::string result; + if (iter->Valid()) { + result = iter->key().ToString() + "->" + iter->value().ToString(); + } else { + result = "(invalid)"; + } + return result; + } + + bool DeleteAnSSTFile() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number))); + return true; + } + } + return false; + } + + // Returns number of files renamed. + int RenameLDBToSST() { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + uint64_t number; + FileType type; + int files_renamed = 0; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) { + const std::string from = TableFileName(dbname_, number); + const std::string to = SSTTableFileName(dbname_, number); + ASSERT_OK(env_->RenameFile(from, to)); + files_renamed++; + } + } + return files_renamed; + } +}; + +TEST(DBTest, Empty) { + do { + ASSERT_TRUE(db_ != NULL); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, ReadWrite) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + ASSERT_EQ("v3", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + } while (ChangeOptions()); +} + +TEST(DBTest, PutDeleteGet) { + do { + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + ASSERT_OK(db_->Delete(WriteOptions(), "foo")); + ASSERT_EQ("NOT_FOUND", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromImmutableLayer) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + + env_->delay_data_sync_.Release_Store(env_); // Block sync calls + Put("k1", std::string(100000, 'x')); // Fill memtable + Put("k2", std::string(100000, 'y')); // Trigger compaction + ASSERT_EQ("v1", Get("foo")); + env_->delay_data_sync_.Release_Store(NULL); // Release sync calls + } while (ChangeOptions()); +} + +TEST(DBTest, GetFromVersions) { + do { + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v1", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetMemUsage) { + do { + ASSERT_OK(Put("foo", "v1")); + std::string val; + ASSERT_TRUE(db_->GetProperty("leveldb.approximate-memory-usage", &val)); + int mem_usage = atoi(val.c_str()); + ASSERT_GT(mem_usage, 0); + ASSERT_LT(mem_usage, 5*1024*1024); + } while (ChangeOptions()); +} + +TEST(DBTest, GetSnapshot) { + do { + // Try with both a short key and a long key + for (int i = 0; i < 2; i++) { + std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x'); + ASSERT_OK(Put(key, "v1")); + const Snapshot* s1 = db_->GetSnapshot(); + ASSERT_OK(Put(key, "v2")); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get(key)); + ASSERT_EQ("v1", Get(key, s1)); + db_->ReleaseSnapshot(s1); + } + } while (ChangeOptions()); +} + +TEST(DBTest, GetLevel0Ordering) { + do { + // Check that we process level-0 files in correct order. The code + // below generates two level-0 files where the earlier one comes + // before the later one in the level-0 file list since the earlier + // one has a smaller "smallest" key. + ASSERT_OK(Put("bar", "b")); + ASSERT_OK(Put("foo", "v1")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("foo", "v2")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetOrderedByLevels) { + do { + ASSERT_OK(Put("foo", "v1")); + Compact("a", "z"); + ASSERT_EQ("v1", Get("foo")); + ASSERT_OK(Put("foo", "v2")); + ASSERT_EQ("v2", Get("foo")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("v2", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetPicksCorrectFile) { + do { + // Arrange to have multiple files in a non-level-0 level. + ASSERT_OK(Put("a", "va")); + Compact("a", "b"); + ASSERT_OK(Put("x", "vx")); + Compact("x", "y"); + ASSERT_OK(Put("f", "vf")); + Compact("f", "g"); + ASSERT_EQ("va", Get("a")); + ASSERT_EQ("vf", Get("f")); + ASSERT_EQ("vx", Get("x")); + } while (ChangeOptions()); +} + +TEST(DBTest, GetEncountersEmptyLevel) { + do { + // Arrange for the following to happen: + // * sstable A in level 0 + // * nothing in level 1 + // * sstable B in level 2 + // Then do enough Get() calls to arrange for an automatic compaction + // of sstable A. A bug would cause the compaction to be marked as + // occurring at level 1 (instead of the correct level 0). + + // Step 1: First place sstables in levels 0 and 2 + int compaction_count = 0; + while (NumTableFilesAtLevel(0) == 0 || + NumTableFilesAtLevel(2) == 0) { + ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2"; + compaction_count++; + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + } + + // Step 2: clear level 1 if necessary. + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_EQ(NumTableFilesAtLevel(0), 1); + ASSERT_EQ(NumTableFilesAtLevel(1), 0); + ASSERT_EQ(NumTableFilesAtLevel(2), 1); + + // Step 3: read a bunch of times + for (int i = 0; i < 1000; i++) { + ASSERT_EQ("NOT_FOUND", Get("missing")); + } + + // Step 4: Wait for compaction to finish + DelayMilliseconds(1000); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } while (ChangeOptions()); +} + +TEST(DBTest, IterEmpty) { + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("foo"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSingle) { + ASSERT_OK(Put("a", "va")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMulti) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->Seek(""); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("a"); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Seek("ax"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("b"); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Seek("z"); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + // Switch from reverse to forward + iter->SeekToLast(); + iter->Prev(); + iter->Prev(); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Switch from forward to reverse + iter->SeekToFirst(); + iter->Next(); + iter->Next(); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + + // Make sure iter stays at snapshot + ASSERT_OK(Put("a", "va2")); + ASSERT_OK(Put("a2", "va3")); + ASSERT_OK(Put("b", "vb2")); + ASSERT_OK(Put("c", "vc2")); + ASSERT_OK(Delete("b")); + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->vb"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterSmallAndLargeMix) { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", std::string(100000, 'b'))); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Put("d", std::string(100000, 'd'))); + ASSERT_OK(Put("e", std::string(100000, 'e'))); + + Iterator* iter = db_->NewIterator(ReadOptions()); + + iter->SeekToFirst(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Next(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + iter->SeekToLast(); + ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b')); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "(invalid)"); + + delete iter; +} + +TEST(DBTest, IterMultiWithDelete) { + do { + ASSERT_OK(Put("a", "va")); + ASSERT_OK(Put("b", "vb")); + ASSERT_OK(Put("c", "vc")); + ASSERT_OK(Delete("b")); + ASSERT_EQ("NOT_FOUND", Get("b")); + + Iterator* iter = db_->NewIterator(ReadOptions()); + iter->Seek("c"); + ASSERT_EQ(IterStatus(iter), "c->vc"); + iter->Prev(); + ASSERT_EQ(IterStatus(iter), "a->va"); + delete iter; + } while (ChangeOptions()); +} + +TEST(DBTest, Recover) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("baz", "v5")); + + Reopen(); + ASSERT_EQ("v1", Get("foo")); + + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v5", Get("baz")); + ASSERT_OK(Put("bar", "v2")); + ASSERT_OK(Put("foo", "v3")); + + Reopen(); + ASSERT_EQ("v3", Get("foo")); + ASSERT_OK(Put("foo", "v4")); + ASSERT_EQ("v4", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ("v5", Get("baz")); + } while (ChangeOptions()); +} + +TEST(DBTest, RecoveryWithEmptyLog) { + do { + ASSERT_OK(Put("foo", "v1")); + ASSERT_OK(Put("foo", "v2")); + Reopen(); + Reopen(); + ASSERT_OK(Put("foo", "v3")); + Reopen(); + ASSERT_EQ("v3", Get("foo")); + } while (ChangeOptions()); +} + +// Check that writes done during a memtable compaction are recovered +// if the database is shutdown during the memtable compaction. +TEST(DBTest, RecoverDuringMemtableCompaction) { + do { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 1000000; + Reopen(&options); + + // Trigger a long memtable compaction and reopen the database during it + ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file + ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable + ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction + ASSERT_OK(Put("bar", "v2")); // Goes to new log file + + Reopen(&options); + ASSERT_EQ("v1", Get("foo")); + ASSERT_EQ("v2", Get("bar")); + ASSERT_EQ(std::string(10000000, 'x'), Get("big1")); + ASSERT_EQ(std::string(1000, 'y'), Get("big2")); + } while (ChangeOptions()); +} + +static std::string Key(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "key%06d", i); + return std::string(buf); +} + +TEST(DBTest, MinorCompactionsHappen) { + Options options = CurrentOptions(); + options.write_buffer_size = 10000; + Reopen(&options); + + const int N = 500; + + int starting_num_tables = TotalTableFiles(); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v'))); + } + int ending_num_tables = TotalTableFiles(); + ASSERT_GT(ending_num_tables, starting_num_tables); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } + + Reopen(); + + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i))); + } +} + +TEST(DBTest, RecoverWithLargeLog) { + { + Options options = CurrentOptions(); + Reopen(&options); + ASSERT_OK(Put("big1", std::string(200000, '1'))); + ASSERT_OK(Put("big2", std::string(200000, '2'))); + ASSERT_OK(Put("small3", std::string(10, '3'))); + ASSERT_OK(Put("small4", std::string(10, '4'))); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + } + + // Make sure that if we re-open with a small write buffer size that + // we flush table files in the middle of a large log file. + Options options = CurrentOptions(); + options.write_buffer_size = 100000; + Reopen(&options); + ASSERT_EQ(NumTableFilesAtLevel(0), 3); + ASSERT_EQ(std::string(200000, '1'), Get("big1")); + ASSERT_EQ(std::string(200000, '2'), Get("big2")); + ASSERT_EQ(std::string(10, '3'), Get("small3")); + ASSERT_EQ(std::string(10, '4'), Get("small4")); + ASSERT_GT(NumTableFilesAtLevel(0), 1); +} + +TEST(DBTest, CompactionsGenerateMultipleFiles) { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + Reopen(&options); + + Random rnd(301); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + std::vector values; + for (int i = 0; i < 80; i++) { + values.push_back(RandomString(&rnd, 100000)); + ASSERT_OK(Put(Key(i), values[i])); + } + + // Reopening moves updates to level-0 + Reopen(&options); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 1); + for (int i = 0; i < 80; i++) { + ASSERT_EQ(Get(Key(i)), values[i]); + } +} + +TEST(DBTest, RepeatedWritesToSameKey) { + Options options = CurrentOptions(); + options.env = env_; + options.write_buffer_size = 100000; // Small write buffer + Reopen(&options); + + // We must have at most one file per level except for level-0, + // which may have up to kL0_StopWritesTrigger files. + const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger; + + Random rnd(301); + std::string value = RandomString(&rnd, 2 * options.write_buffer_size); + for (int i = 0; i < 5 * kMaxFiles; i++) { + Put("key", value); + ASSERT_LE(TotalTableFiles(), kMaxFiles); + fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles()); + } +} + +TEST(DBTest, SparseMerge) { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(&options); + + FillLevels("A", "Z"); + + // Suppose there is: + // small amount of data with prefix A + // large amount of data with prefix B + // small amount of data with prefix C + // and that recent updates have made small changes to all three prefixes. + // Check that we do not do a compaction that merges all of B in one shot. + const std::string value(1000, 'x'); + Put("A", "va"); + // Write approximately 100MB of "B" values + for (int i = 0; i < 100000; i++) { + char key[100]; + snprintf(key, sizeof(key), "B%010d", i); + Put(key, value); + } + Put("C", "vc"); + dbfull()->TEST_CompactMemTable(); + dbfull()->TEST_CompactRange(0, NULL, NULL); + + // Make sparse update + Put("A", "va2"); + Put("B100", "bvalue2"); + Put("C", "vc2"); + dbfull()->TEST_CompactMemTable(); + + // Compactions should not cause us to create a situation where + // a file overlaps too much data at the next level. + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(0, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); + dbfull()->TEST_CompactRange(1, NULL, NULL); + ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +TEST(DBTest, ApproximateSizes) { + do { + Options options = CurrentOptions(); + options.write_buffer_size = 100000000; // Large write buffer + options.compression = kNoCompression; + DestroyAndReopen(); + + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + Reopen(&options); + ASSERT_TRUE(Between(Size("", "xyz"), 0, 0)); + + // Write 8MB (80 values, each 100K) + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + const int N = 80; + static const int S1 = 100000; + static const int S2 = 105000; // Allow some expansion from metadata + Random rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), RandomString(&rnd, S1))); + } + + // 0 because GetApproximateSizes() does not account for memtable space + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + + if (options.reuse_logs) { + // Recovery will reuse memtable, and GetApproximateSizes() does not + // account for memtable usage; + Reopen(&options); + ASSERT_TRUE(Between(Size("", Key(50)), 0, 0)); + continue; + } + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + for (int compact_start = 0; compact_start < N; compact_start += 10) { + for (int i = 0; i < N; i += 10) { + ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i)); + ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1))); + ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10)); + } + ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50)); + ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50)); + + std::string cstart_str = Key(compact_start); + std::string cend_str = Key(compact_start + 9); + Slice cstart = cstart_str; + Slice cend = cend_str; + dbfull()->TEST_CompactRange(0, &cstart, &cend); + } + + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GT(NumTableFilesAtLevel(1), 0); + } + } while (ChangeOptions()); +} + +TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) { + do { + Options options = CurrentOptions(); + options.compression = kNoCompression; + Reopen(); + + Random rnd(301); + std::string big1 = RandomString(&rnd, 100000); + ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(2), big1)); + ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(4), big1)); + ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000))); + ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000))); + ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000))); + + if (options.reuse_logs) { + // Need to force a memtable compaction since recovery does not do so. + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + } + + // Check sizes across recovery by reopening a few times + for (int run = 0; run < 3; run++) { + Reopen(&options); + + ASSERT_TRUE(Between(Size("", Key(0)), 0, 0)); + ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000)); + ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000)); + ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000)); + ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000)); + ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000)); + ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000)); + ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000)); + ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000)); + + ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000)); + + dbfull()->TEST_CompactRange(0, NULL, NULL); + } + } while (ChangeOptions()); +} + +TEST(DBTest, IteratorPinsRef) { + Put("foo", "hello"); + + // Get iterator that will yield the current contents of the DB. + Iterator* iter = db_->NewIterator(ReadOptions()); + + // Write to force compactions + Put("foo", "newvalue1"); + for (int i = 0; i < 100; i++) { + ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values + } + Put("foo", "newvalue2"); + + iter->SeekToFirst(); + ASSERT_TRUE(iter->Valid()); + ASSERT_EQ("foo", iter->key().ToString()); + ASSERT_EQ("hello", iter->value().ToString()); + iter->Next(); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +TEST(DBTest, Snapshot) { + do { + Put("foo", "v1"); + const Snapshot* s1 = db_->GetSnapshot(); + Put("foo", "v2"); + const Snapshot* s2 = db_->GetSnapshot(); + Put("foo", "v3"); + const Snapshot* s3 = db_->GetSnapshot(); + + Put("foo", "v4"); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v3", Get("foo", s3)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s3); + ASSERT_EQ("v1", Get("foo", s1)); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s1); + ASSERT_EQ("v2", Get("foo", s2)); + ASSERT_EQ("v4", Get("foo")); + + db_->ReleaseSnapshot(s2); + ASSERT_EQ("v4", Get("foo")); + } while (ChangeOptions()); +} + +TEST(DBTest, HiddenValuesAreRemoved) { + do { + Random rnd(301); + FillLevels("a", "z"); + + std::string big = RandomString(&rnd, 50000); + Put("foo", big); + Put("pastfoo", "v"); + const Snapshot* snapshot = db_->GetSnapshot(); + Put("foo", "tiny"); + Put("pastfoo2", "v2"); // Advance sequence number one more + + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + ASSERT_GT(NumTableFilesAtLevel(0), 0); + + ASSERT_EQ(big, Get("foo", snapshot)); + ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000)); + db_->ReleaseSnapshot(snapshot); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]"); + Slice x("x"); + dbfull()->TEST_CompactRange(0, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + ASSERT_EQ(NumTableFilesAtLevel(0), 0); + ASSERT_GE(NumTableFilesAtLevel(1), 1); + dbfull()->TEST_CompactRange(1, NULL, &x); + ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]"); + + ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000)); + } while (ChangeOptions()); +} + +TEST(DBTest, DeletionMarkers1) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + Put("foo", "v2"); + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]"); + Slice z("z"); + dbfull()->TEST_CompactRange(last-2, NULL, &z); + // DEL eliminated, but v1 remains because we aren't compacting that level + // (DEL can be eliminated because v2 hides v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]"); +} + +TEST(DBTest, DeletionMarkers2) { + Put("foo", "v1"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level + + // Place a table at level last-1 to prevent merging with preceding mutation + Put("a", "begin"); + Put("z", "end"); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ(NumTableFilesAtLevel(last), 1); + ASSERT_EQ(NumTableFilesAtLevel(last-1), 1); + + Delete("foo"); + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2 + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-2, NULL, NULL); + // DEL kept: "last" file overlaps + ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]"); + dbfull()->TEST_CompactRange(last-1, NULL, NULL); + // Merging last-1 w/ last, so we are the base level for "foo", so + // DEL is removed. (as is v1). + ASSERT_EQ(AllEntriesFor("foo"), "[ ]"); +} + +TEST(DBTest, OverlapInLevel0) { + do { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config"; + + // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0. + ASSERT_OK(Put("100", "v100")); + ASSERT_OK(Put("999", "v999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Delete("100")); + ASSERT_OK(Delete("999")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("0,1,1", FilesPerLevel()); + + // Make files spanning the following ranges in level-0: + // files[0] 200 .. 900 + // files[1] 300 .. 500 + // Note that files are sorted by smallest key. + ASSERT_OK(Put("300", "v300")); + ASSERT_OK(Put("500", "v500")); + dbfull()->TEST_CompactMemTable(); + ASSERT_OK(Put("200", "v200")); + ASSERT_OK(Put("600", "v600")); + ASSERT_OK(Put("900", "v900")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("2,1,1", FilesPerLevel()); + + // Compact away the placeholder files we created initially + dbfull()->TEST_CompactRange(1, NULL, NULL); + dbfull()->TEST_CompactRange(2, NULL, NULL); + ASSERT_EQ("2", FilesPerLevel()); + + // Do a memtable compaction. Before bug-fix, the compaction would + // not detect the overlap with level-0 files and would incorrectly place + // the deletion in a deeper level. + ASSERT_OK(Delete("600")); + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("3", FilesPerLevel()); + ASSERT_EQ("NOT_FOUND", Get("600")); + } while (ChangeOptions()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_a) { + Reopen(); + ASSERT_OK(Put("b", "v")); + Reopen(); + ASSERT_OK(Delete("b")); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Delete("a")); + Reopen(); + ASSERT_OK(Put("a", "v")); + Reopen(); + Reopen(); + ASSERT_EQ("(a->v)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(a->v)", Contents()); +} + +TEST(DBTest, L0_CompactionBug_Issue44_b) { + Reopen(); + Put("",""); + Reopen(); + Delete("e"); + Put("",""); + Reopen(); + Put("c", "cv"); + Reopen(); + Put("",""); + Reopen(); + Put("",""); + DelayMilliseconds(1000); // Wait for compaction to finish + Reopen(); + Put("d","dv"); + Reopen(); + Put("",""); + Reopen(); + Delete("d"); + Delete("b"); + Reopen(); + ASSERT_EQ("(->)(c->cv)", Contents()); + DelayMilliseconds(1000); // Wait for compaction to finish + ASSERT_EQ("(->)(c->cv)", Contents()); +} + +TEST(DBTest, ComparatorCheck) { + class NewComparator : public Comparator { + public: + virtual const char* Name() const { return "leveldb.NewComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(a, b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + BytewiseComparator()->FindShortestSeparator(s, l); + } + virtual void FindShortSuccessor(std::string* key) const { + BytewiseComparator()->FindShortSuccessor(key); + } + }; + NewComparator cmp; + Options new_options = CurrentOptions(); + new_options.comparator = &cmp; + Status s = TryReopen(&new_options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, CustomComparator) { + class NumberComparator : public Comparator { + public: + virtual const char* Name() const { return "test.NumberComparator"; } + virtual int Compare(const Slice& a, const Slice& b) const { + return ToNumber(a) - ToNumber(b); + } + virtual void FindShortestSeparator(std::string* s, const Slice& l) const { + ToNumber(*s); // Check format + ToNumber(l); // Check format + } + virtual void FindShortSuccessor(std::string* key) const { + ToNumber(*key); // Check format + } + private: + static int ToNumber(const Slice& x) { + // Check that there are no extra characters. + ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']') + << EscapeString(x); + int val; + char ignored; + ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1) + << EscapeString(x); + return val; + } + }; + NumberComparator cmp; + Options new_options = CurrentOptions(); + new_options.create_if_missing = true; + new_options.comparator = &cmp; + new_options.filter_policy = NULL; // Cannot use bloom filters + new_options.write_buffer_size = 1000; // Compact more often + DestroyAndReopen(&new_options); + ASSERT_OK(Put("[10]", "ten")); + ASSERT_OK(Put("[0x14]", "twenty")); + for (int i = 0; i < 2; i++) { + ASSERT_EQ("ten", Get("[10]")); + ASSERT_EQ("ten", Get("[0xa]")); + ASSERT_EQ("twenty", Get("[20]")); + ASSERT_EQ("twenty", Get("[0x14]")); + ASSERT_EQ("NOT_FOUND", Get("[15]")); + ASSERT_EQ("NOT_FOUND", Get("[0xf]")); + Compact("[0]", "[9999]"); + } + + for (int run = 0; run < 2; run++) { + for (int i = 0; i < 1000; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "[%d]", i*10); + ASSERT_OK(Put(buf, buf)); + } + Compact("[0]", "[1000000]"); + } +} + +TEST(DBTest, ManualCompaction) { + ASSERT_EQ(config::kMaxMemCompactLevel, 2) + << "Need to update this test to match kMaxMemCompactLevel"; + + MakeTables(3, "p", "q"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls before files + Compact("", "c"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range falls after files + Compact("r", "z"); + ASSERT_EQ("1,1,1", FilesPerLevel()); + + // Compaction range overlaps files + Compact("p1", "p9"); + ASSERT_EQ("0,0,1", FilesPerLevel()); + + // Populate a different range + MakeTables(3, "c", "e"); + ASSERT_EQ("1,1,2", FilesPerLevel()); + + // Compact just the new range + Compact("b", "f"); + ASSERT_EQ("0,0,2", FilesPerLevel()); + + // Compact all + MakeTables(1, "a", "z"); + ASSERT_EQ("0,1,2", FilesPerLevel()); + db_->CompactRange(NULL, NULL); + ASSERT_EQ("0,0,1", FilesPerLevel()); +} + +TEST(DBTest, DBOpen_Options) { + std::string dbname = test::TmpDir() + "/db_options_test"; + DestroyDB(dbname, Options()); + + // Does not exist, and create_if_missing == false: error + DB* db = NULL; + Options opts; + opts.create_if_missing = false; + Status s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL); + ASSERT_TRUE(db == NULL); + + // Does not exist, and create_if_missing == true: OK + opts.create_if_missing = true; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + // Does exist, and error_if_exists == true: error + opts.create_if_missing = false; + opts.error_if_exists = true; + s = DB::Open(opts, dbname, &db); + ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL); + ASSERT_TRUE(db == NULL); + + // Does exist, and error_if_exists == false: OK + opts.create_if_missing = true; + opts.error_if_exists = false; + s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; +} + +TEST(DBTest, Locking) { + DB* db2 = NULL; + Status s = DB::Open(CurrentOptions(), dbname_, &db2); + ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db"; +} + +// Check that number of files does not grow when we are out of space +TEST(DBTest, NoSpace) { + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + + ASSERT_OK(Put("foo", "v1")); + ASSERT_EQ("v1", Get("foo")); + Compact("a", "z"); + const int num_files = CountFiles(); + env_->no_space_.Release_Store(env_); // Force out-of-space errors + for (int i = 0; i < 10; i++) { + for (int level = 0; level < config::kNumLevels-1; level++) { + dbfull()->TEST_CompactRange(level, NULL, NULL); + } + } + env_->no_space_.Release_Store(NULL); + ASSERT_LT(CountFiles(), num_files + 3); +} + +TEST(DBTest, NonWritableFileSystem) { + Options options = CurrentOptions(); + options.write_buffer_size = 1000; + options.env = env_; + Reopen(&options); + ASSERT_OK(Put("foo", "v1")); + env_->non_writable_.Release_Store(env_); // Force errors for new files + std::string big(100000, 'x'); + int errors = 0; + for (int i = 0; i < 20; i++) { + fprintf(stderr, "iter %d; errors %d\n", i, errors); + if (!Put("foo", big).ok()) { + errors++; + DelayMilliseconds(100); + } + } + ASSERT_GT(errors, 0); + env_->non_writable_.Release_Store(NULL); +} + +TEST(DBTest, WriteSyncError) { + // Check that log sync errors cause the DB to disallow future writes. + + // (a) Cause log sync calls to fail + Options options = CurrentOptions(); + options.env = env_; + Reopen(&options); + env_->data_sync_error_.Release_Store(env_); + + // (b) Normal write should succeed + WriteOptions w; + ASSERT_OK(db_->Put(w, "k1", "v1")); + ASSERT_EQ("v1", Get("k1")); + + // (c) Do a sync write; should fail + w.sync = true; + ASSERT_TRUE(!db_->Put(w, "k2", "v2").ok()); + ASSERT_EQ("v1", Get("k1")); + ASSERT_EQ("NOT_FOUND", Get("k2")); + + // (d) make sync behave normally + env_->data_sync_error_.Release_Store(NULL); + + // (e) Do a non-sync write; should fail + w.sync = false; + ASSERT_TRUE(!db_->Put(w, "k3", "v3").ok()); + ASSERT_EQ("v1", Get("k1")); + ASSERT_EQ("NOT_FOUND", Get("k2")); + ASSERT_EQ("NOT_FOUND", Get("k3")); +} + +TEST(DBTest, ManifestWriteError) { + // Test for the following problem: + // (a) Compaction produces file F + // (b) Log record containing F is written to MANIFEST file, but Sync() fails + // (c) GC deletes F + // (d) After reopening DB, reads fail since deleted F is named in log record + + // We iterate twice. In the second iteration, everything is the + // same except the log record never makes it to the MANIFEST file. + for (int iter = 0; iter < 2; iter++) { + port::AtomicPointer* error_type = (iter == 0) + ? &env_->manifest_sync_error_ + : &env_->manifest_write_error_; + + // Insert foo=>bar mapping + Options options = CurrentOptions(); + options.env = env_; + options.create_if_missing = true; + options.error_if_exists = false; + DestroyAndReopen(&options); + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Memtable compaction (will succeed) + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + const int last = config::kMaxMemCompactLevel; + ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo=>bar is now in last level + + // Merging compaction (will fail) + error_type->Release_Store(env_); + dbfull()->TEST_CompactRange(last, NULL, NULL); // Should fail + ASSERT_EQ("bar", Get("foo")); + + // Recovery: should not lose data + error_type->Release_Store(NULL); + Reopen(&options); + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(DBTest, MissingSSTFile) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + + Close(); + ASSERT_TRUE(DeleteAnSSTFile()); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); + ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) + << s.ToString(); +} + +TEST(DBTest, StillReadSST) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ("bar", Get("foo")); + + // Dump the memtable to disk. + dbfull()->TEST_CompactMemTable(); + ASSERT_EQ("bar", Get("foo")); + Close(); + ASSERT_GT(RenameLDBToSST(), 0); + Options options = CurrentOptions(); + options.paranoid_checks = true; + Status s = TryReopen(&options); + ASSERT_TRUE(s.ok()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(DBTest, FilesDeletedAfterCompaction) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + const int num_files = CountFiles(); + for (int i = 0; i < 10; i++) { + ASSERT_OK(Put("foo", "v2")); + Compact("a", "z"); + } + ASSERT_EQ(CountFiles(), num_files); +} + +TEST(DBTest, BloomFilter) { + env_->count_random_reads_ = true; + Options options = CurrentOptions(); + options.env = env_; + options.block_cache = NewLRUCache(0); // Prevent cache hits + options.filter_policy = NewBloomFilterPolicy(10); + Reopen(&options); + + // Populate multiple layers + const int N = 10000; + for (int i = 0; i < N; i++) { + ASSERT_OK(Put(Key(i), Key(i))); + } + Compact("a", "z"); + for (int i = 0; i < N; i += 100) { + ASSERT_OK(Put(Key(i), Key(i))); + } + dbfull()->TEST_CompactMemTable(); + + // Prevent auto compactions triggered by seeks + env_->delay_data_sync_.Release_Store(env_); + + // Lookup present keys. Should rarely read from small sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ(Key(i), Get(Key(i))); + } + int reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d present => %d reads\n", N, reads); + ASSERT_GE(reads, N); + ASSERT_LE(reads, N + 2*N/100); + + // Lookup present keys. Should rarely read from either sstable. + env_->random_read_counter_.Reset(); + for (int i = 0; i < N; i++) { + ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing")); + } + reads = env_->random_read_counter_.Read(); + fprintf(stderr, "%d missing => %d reads\n", N, reads); + ASSERT_LE(reads, 3*N/100); + + env_->delay_data_sync_.Release_Store(NULL); + Close(); + delete options.block_cache; + delete options.filter_policy; +} + +// Multi-threaded test: +namespace { + +static const int kNumThreads = 4; +static const int kTestSeconds = 10; +static const int kNumKeys = 1000; + +struct MTState { + DBTest* test; + port::AtomicPointer stop; + port::AtomicPointer counter[kNumThreads]; + port::AtomicPointer thread_done[kNumThreads]; +}; + +struct MTThread { + MTState* state; + int id; +}; + +static void MTThreadBody(void* arg) { + MTThread* t = reinterpret_cast(arg); + int id = t->id; + DB* db = t->state->test->db_; + uintptr_t counter = 0; + fprintf(stderr, "... starting thread %d\n", id); + Random rnd(1000 + id); + std::string value; + char valbuf[1500]; + while (t->state->stop.Acquire_Load() == NULL) { + t->state->counter[id].Release_Store(reinterpret_cast(counter)); + + int key = rnd.Uniform(kNumKeys); + char keybuf[20]; + snprintf(keybuf, sizeof(keybuf), "%016d", key); + + if (rnd.OneIn(2)) { + // Write values of the form . + // We add some padding for force compactions. + snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", + key, id, static_cast(counter)); + ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf))); + } else { + // Read a value and verify that it matches the pattern written above. + Status s = db->Get(ReadOptions(), Slice(keybuf), &value); + if (s.IsNotFound()) { + // Key has not yet been written + } else { + // Check that the writer thread counter is >= the counter in the value + ASSERT_OK(s); + int k, w, c; + ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value; + ASSERT_EQ(k, key); + ASSERT_GE(w, 0); + ASSERT_LT(w, kNumThreads); + ASSERT_LE(static_cast(c), reinterpret_cast( + t->state->counter[w].Acquire_Load())); + } + } + counter++; + } + t->state->thread_done[id].Release_Store(t); + fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter)); +} + +} // namespace + +TEST(DBTest, MultiThreaded) { + do { + // Initialize state + MTState mt; + mt.test = this; + mt.stop.Release_Store(0); + for (int id = 0; id < kNumThreads; id++) { + mt.counter[id].Release_Store(0); + mt.thread_done[id].Release_Store(0); + } + + // Start threads + MTThread thread[kNumThreads]; + for (int id = 0; id < kNumThreads; id++) { + thread[id].state = &mt; + thread[id].id = id; + env_->StartThread(MTThreadBody, &thread[id]); + } + + // Let them run for a while + DelayMilliseconds(kTestSeconds * 1000); + + // Stop the threads and wait for them to finish + mt.stop.Release_Store(&mt); + for (int id = 0; id < kNumThreads; id++) { + while (mt.thread_done[id].Acquire_Load() == NULL) { + DelayMilliseconds(100); + } + } + } while (ChangeOptions()); +} + +namespace { +typedef std::map KVMap; +} + +class ModelDB: public DB { + public: + class ModelSnapshot : public Snapshot { + public: + KVMap map_; + }; + + explicit ModelDB(const Options& options): options_(options) { } + ~ModelDB() { } + virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) { + return DB::Put(o, k, v); + } + virtual Status Delete(const WriteOptions& o, const Slice& key) { + return DB::Delete(o, key); + } + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) { + assert(false); // Not implemented + return Status::NotFound(key); + } + virtual Iterator* NewIterator(const ReadOptions& options) { + if (options.snapshot == NULL) { + KVMap* saved = new KVMap; + *saved = map_; + return new ModelIter(saved, true); + } else { + const KVMap* snapshot_state = + &(reinterpret_cast(options.snapshot)->map_); + return new ModelIter(snapshot_state, false); + } + } + virtual const Snapshot* GetSnapshot() { + ModelSnapshot* snapshot = new ModelSnapshot; + snapshot->map_ = map_; + return snapshot; + } + + virtual void ReleaseSnapshot(const Snapshot* snapshot) { + delete reinterpret_cast(snapshot); + } + virtual Status Write(const WriteOptions& options, WriteBatch* batch) { + class Handler : public WriteBatch::Handler { + public: + KVMap* map_; + virtual void Put(const Slice& key, const Slice& value) { + (*map_)[key.ToString()] = value.ToString(); + } + virtual void Delete(const Slice& key) { + map_->erase(key.ToString()); + } + }; + Handler handler; + handler.map_ = &map_; + return batch->Iterate(&handler); + } + + virtual bool GetProperty(const Slice& property, std::string* value) { + return false; + } + virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) { + for (int i = 0; i < n; i++) { + sizes[i] = 0; + } + } + virtual void CompactRange(const Slice* start, const Slice* end) { + } + + private: + class ModelIter: public Iterator { + public: + ModelIter(const KVMap* map, bool owned) + : map_(map), owned_(owned), iter_(map_->end()) { + } + ~ModelIter() { + if (owned_) delete map_; + } + virtual bool Valid() const { return iter_ != map_->end(); } + virtual void SeekToFirst() { iter_ = map_->begin(); } + virtual void SeekToLast() { + if (map_->empty()) { + iter_ = map_->end(); + } else { + iter_ = map_->find(map_->rbegin()->first); + } + } + virtual void Seek(const Slice& k) { + iter_ = map_->lower_bound(k.ToString()); + } + virtual void Next() { ++iter_; } + virtual void Prev() { --iter_; } + virtual Slice key() const { return iter_->first; } + virtual Slice value() const { return iter_->second; } + virtual Status status() const { return Status::OK(); } + private: + const KVMap* const map_; + const bool owned_; // Do we own map_ + KVMap::const_iterator iter_; + }; + const Options options_; + KVMap map_; +}; + +static std::string RandomKey(Random* rnd) { + int len = (rnd->OneIn(3) + ? 1 // Short sometimes to encourage collisions + : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10))); + return test::RandomKey(rnd, len); +} + +static bool CompareIterators(int step, + DB* model, + DB* db, + const Snapshot* model_snap, + const Snapshot* db_snap) { + ReadOptions options; + options.snapshot = model_snap; + Iterator* miter = model->NewIterator(options); + options.snapshot = db_snap; + Iterator* dbiter = db->NewIterator(options); + bool ok = true; + int count = 0; + for (miter->SeekToFirst(), dbiter->SeekToFirst(); + ok && miter->Valid() && dbiter->Valid(); + miter->Next(), dbiter->Next()) { + count++; + if (miter->key().compare(dbiter->key()) != 0) { + fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(dbiter->key()).c_str()); + ok = false; + break; + } + + if (miter->value().compare(dbiter->value()) != 0) { + fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n", + step, + EscapeString(miter->key()).c_str(), + EscapeString(miter->value()).c_str(), + EscapeString(miter->value()).c_str()); + ok = false; + } + } + + if (ok) { + if (miter->Valid() != dbiter->Valid()) { + fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n", + step, miter->Valid(), dbiter->Valid()); + ok = false; + } + } + fprintf(stderr, "%d entries compared: ok=%d\n", count, ok); + delete miter; + delete dbiter; + return ok; +} + +TEST(DBTest, Randomized) { + Random rnd(test::RandomSeed()); + do { + ModelDB model(CurrentOptions()); + const int N = 10000; + const Snapshot* model_snap = NULL; + const Snapshot* db_snap = NULL; + std::string k, v; + for (int step = 0; step < N; step++) { + if (step % 100 == 0) { + fprintf(stderr, "Step %d of %d\n", step, N); + } + // TODO(sanjay): Test Get() works + int p = rnd.Uniform(100); + if (p < 45) { // Put + k = RandomKey(&rnd); + v = RandomString(&rnd, + rnd.OneIn(20) + ? 100 + rnd.Uniform(100) + : rnd.Uniform(8)); + ASSERT_OK(model.Put(WriteOptions(), k, v)); + ASSERT_OK(db_->Put(WriteOptions(), k, v)); + + } else if (p < 90) { // Delete + k = RandomKey(&rnd); + ASSERT_OK(model.Delete(WriteOptions(), k)); + ASSERT_OK(db_->Delete(WriteOptions(), k)); + + + } else { // Multi-element batch + WriteBatch b; + const int num = rnd.Uniform(8); + for (int i = 0; i < num; i++) { + if (i == 0 || !rnd.OneIn(10)) { + k = RandomKey(&rnd); + } else { + // Periodically re-use the same key from the previous iter, so + // we have multiple entries in the write batch for the same key + } + if (rnd.OneIn(2)) { + v = RandomString(&rnd, rnd.Uniform(10)); + b.Put(k, v); + } else { + b.Delete(k); + } + } + ASSERT_OK(model.Write(WriteOptions(), &b)); + ASSERT_OK(db_->Write(WriteOptions(), &b)); + } + + if ((step % 100) == 0) { + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap)); + // Save a snapshot from each DB this time that we'll use next + // time we compare things, to make sure the current state is + // preserved with the snapshot + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + + Reopen(); + ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL)); + + model_snap = model.GetSnapshot(); + db_snap = db_->GetSnapshot(); + } + } + if (model_snap != NULL) model.ReleaseSnapshot(model_snap); + if (db_snap != NULL) db_->ReleaseSnapshot(db_snap); + } while (ChangeOptions()); +} + +std::string MakeKey(unsigned int num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%016u", num); + return std::string(buf); +} + +void BM_LogAndApply(int iters, int num_base_files) { + std::string dbname = test::TmpDir() + "/leveldb_test_benchmark"; + DestroyDB(dbname, Options()); + + DB* db = NULL; + Options opts; + opts.create_if_missing = true; + Status s = DB::Open(opts, dbname, &db); + ASSERT_OK(s); + ASSERT_TRUE(db != NULL); + + delete db; + db = NULL; + + Env* env = Env::Default(); + + port::Mutex mu; + MutexLock l(&mu); + + InternalKeyComparator cmp(BytewiseComparator()); + Options options; + VersionSet vset(dbname, &options, NULL, &cmp); + bool save_manifest; + ASSERT_OK(vset.Recover(&save_manifest)); + VersionEdit vbase; + uint64_t fnum = 1; + for (int i = 0; i < num_base_files; i++) { + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vbase.AddFile(2, fnum++, 1 /* file size */, start, limit); + } + ASSERT_OK(vset.LogAndApply(&vbase, &mu)); + + uint64_t start_micros = env->NowMicros(); + + for (int i = 0; i < iters; i++) { + VersionEdit vedit; + vedit.DeleteFile(2, fnum); + InternalKey start(MakeKey(2*fnum), 1, kTypeValue); + InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion); + vedit.AddFile(2, fnum++, 1 /* file size */, start, limit); + vset.LogAndApply(&vedit, &mu); + } + uint64_t stop_micros = env->NowMicros(); + unsigned int us = stop_micros - start_micros; + char buf[16]; + snprintf(buf, sizeof(buf), "%d", num_base_files); + fprintf(stderr, + "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", + buf, iters, us, ((float)us) / iters); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + if (argc > 1 && std::string(argv[1]) == "--benchmark") { + leveldb::BM_LogAndApply(1000, 1); + leveldb::BM_LogAndApply(1000, 100); + leveldb::BM_LogAndApply(1000, 10000); + leveldb::BM_LogAndApply(100, 100000); + return 0; + } + + return leveldb::test::RunAllTests(); +} diff --git a/db/dbformat.cc b/db/dbformat.cc new file mode 100644 index 0000000000..20a7ca4462 --- /dev/null +++ b/db/dbformat.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { + +static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { + assert(seq <= kMaxSequenceNumber); + assert(t <= kValueTypeForSeek); + return (seq << 8) | t; +} + +void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { + result->append(key.user_key.data(), key.user_key.size()); + PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); +} + +std::string ParsedInternalKey::DebugString() const { + char buf[50]; + snprintf(buf, sizeof(buf), "' @ %llu : %d", + (unsigned long long) sequence, + int(type)); + std::string result = "'"; + result += EscapeString(user_key.ToString()); + result += buf; + return result; +} + +std::string InternalKey::DebugString() const { + std::string result; + ParsedInternalKey parsed; + if (ParseInternalKey(rep_, &parsed)) { + result = parsed.DebugString(); + } else { + result = "(bad)"; + result.append(EscapeString(rep_)); + } + return result; +} + +const char* InternalKeyComparator::Name() const { + return "leveldb.InternalKeyComparator"; +} + +int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { + // Order by: + // increasing user key (according to user-supplied comparator) + // decreasing sequence number + // decreasing type (though sequence# should be enough to disambiguate) + int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); + if (r == 0) { + const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); + const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); + if (anum > bnum) { + r = -1; + } else if (anum < bnum) { + r = +1; + } + } + return r; +} + +void InternalKeyComparator::FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Attempt to shorten the user portion of the key + Slice user_start = ExtractUserKey(*start); + Slice user_limit = ExtractUserKey(limit); + std::string tmp(user_start.data(), user_start.size()); + user_comparator_->FindShortestSeparator(&tmp, user_limit); + if (tmp.size() < user_start.size() && + user_comparator_->Compare(user_start, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*start, tmp) < 0); + assert(this->Compare(tmp, limit) < 0); + start->swap(tmp); + } +} + +void InternalKeyComparator::FindShortSuccessor(std::string* key) const { + Slice user_key = ExtractUserKey(*key); + std::string tmp(user_key.data(), user_key.size()); + user_comparator_->FindShortSuccessor(&tmp); + if (tmp.size() < user_key.size() && + user_comparator_->Compare(user_key, tmp) < 0) { + // User key has become shorter physically, but larger logically. + // Tack on the earliest possible number to the shortened user key. + PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek)); + assert(this->Compare(*key, tmp) < 0); + key->swap(tmp); + } +} + +const char* InternalFilterPolicy::Name() const { + return user_policy_->Name(); +} + +void InternalFilterPolicy::CreateFilter(const Slice* keys, int n, + std::string* dst) const { + // We rely on the fact that the code in table.cc does not mind us + // adjusting keys[]. + Slice* mkey = const_cast(keys); + for (int i = 0; i < n; i++) { + mkey[i] = ExtractUserKey(keys[i]); + // TODO(sanjay): Suppress dups? + } + user_policy_->CreateFilter(keys, n, dst); +} + +bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const { + return user_policy_->KeyMayMatch(ExtractUserKey(key), f); +} + +LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) { + size_t usize = user_key.size(); + size_t needed = usize + 13; // A conservative estimate + char* dst; + if (needed <= sizeof(space_)) { + dst = space_; + } else { + dst = new char[needed]; + } + start_ = dst; + dst = EncodeVarint32(dst, usize + 8); + kstart_ = dst; + memcpy(dst, user_key.data(), usize); + dst += usize; + EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); + dst += 8; + end_ = dst; +} + +} // namespace leveldb diff --git a/db/dbformat.h b/db/dbformat.h new file mode 100644 index 0000000000..ea897b13c0 --- /dev/null +++ b/db/dbformat.h @@ -0,0 +1,230 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_DBFORMAT_H_ +#define STORAGE_LEVELDB_DB_DBFORMAT_H_ + +#include +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/filter_policy.h" +#include "leveldb/slice.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +// Grouping of constants. We may want to make some of these +// parameters set via options. +namespace config { +static const int kNumLevels = 7; + +// Level-0 compaction is started when we hit this many files. +static const int kL0_CompactionTrigger = 4; + +// Soft limit on number of level-0 files. We slow down writes at this point. +static const int kL0_SlowdownWritesTrigger = 8; + +// Maximum number of level-0 files. We stop writes at this point. +static const int kL0_StopWritesTrigger = 12; + +// Maximum level to which a new compacted memtable is pushed if it +// does not create overlap. We try to push to level 2 to avoid the +// relatively expensive level 0=>1 compactions and to avoid some +// expensive manifest file operations. We do not push all the way to +// the largest level since that can generate a lot of wasted disk +// space if the same key space is being repeatedly overwritten. +static const int kMaxMemCompactLevel = 2; + +// Approximate gap in bytes between samples of data read during iteration. +static const int kReadBytesPeriod = 1048576; + +} // namespace config + +class InternalKey; + +// Value types encoded as the last component of internal keys. +// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk +// data structures. +enum ValueType { + kTypeDeletion = 0x0, + kTypeValue = 0x1 +}; +// kValueTypeForSeek defines the ValueType that should be passed when +// constructing a ParsedInternalKey object for seeking to a particular +// sequence number (since we sort sequence numbers in decreasing order +// and the value type is embedded as the low 8 bits in the sequence +// number in internal keys, we need to use the highest-numbered +// ValueType, not the lowest). +static const ValueType kValueTypeForSeek = kTypeValue; + +typedef uint64_t SequenceNumber; + +// We leave eight bits empty at the bottom so a type and sequence# +// can be packed together into 64-bits. +static const SequenceNumber kMaxSequenceNumber = + ((0x1ull << 56) - 1); + +struct ParsedInternalKey { + Slice user_key; + SequenceNumber sequence; + ValueType type; + + ParsedInternalKey() { } // Intentionally left uninitialized (for speed) + ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t) + : user_key(u), sequence(seq), type(t) { } + std::string DebugString() const; +}; + +// Return the length of the encoding of "key". +inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) { + return key.user_key.size() + 8; +} + +// Append the serialization of "key" to *result. +extern void AppendInternalKey(std::string* result, + const ParsedInternalKey& key); + +// Attempt to parse an internal key from "internal_key". On success, +// stores the parsed data in "*result", and returns true. +// +// On error, returns false, leaves "*result" in an undefined state. +extern bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result); + +// Returns the user key portion of an internal key. +inline Slice ExtractUserKey(const Slice& internal_key) { + assert(internal_key.size() >= 8); + return Slice(internal_key.data(), internal_key.size() - 8); +} + +inline ValueType ExtractValueType(const Slice& internal_key) { + assert(internal_key.size() >= 8); + const size_t n = internal_key.size(); + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + return static_cast(c); +} + +// A comparator for internal keys that uses a specified comparator for +// the user key portion and breaks ties by decreasing sequence number. +class InternalKeyComparator : public Comparator { + private: + const Comparator* user_comparator_; + public: + explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { } + virtual const char* Name() const; + virtual int Compare(const Slice& a, const Slice& b) const; + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const; + virtual void FindShortSuccessor(std::string* key) const; + + const Comparator* user_comparator() const { return user_comparator_; } + + int Compare(const InternalKey& a, const InternalKey& b) const; +}; + +// Filter policy wrapper that converts from internal keys to user keys +class InternalFilterPolicy : public FilterPolicy { + private: + const FilterPolicy* const user_policy_; + public: + explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) { } + virtual const char* Name() const; + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const; + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const; +}; + +// Modules in this directory should keep internal keys wrapped inside +// the following class instead of plain strings so that we do not +// incorrectly use string comparisons instead of an InternalKeyComparator. +class InternalKey { + private: + std::string rep_; + public: + InternalKey() { } // Leave rep_ as empty to indicate it is invalid + InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) { + AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t)); + } + + void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); } + Slice Encode() const { + assert(!rep_.empty()); + return rep_; + } + + Slice user_key() const { return ExtractUserKey(rep_); } + + void SetFrom(const ParsedInternalKey& p) { + rep_.clear(); + AppendInternalKey(&rep_, p); + } + + void Clear() { rep_.clear(); } + + std::string DebugString() const; +}; + +inline int InternalKeyComparator::Compare( + const InternalKey& a, const InternalKey& b) const { + return Compare(a.Encode(), b.Encode()); +} + +inline bool ParseInternalKey(const Slice& internal_key, + ParsedInternalKey* result) { + const size_t n = internal_key.size(); + if (n < 8) return false; + uint64_t num = DecodeFixed64(internal_key.data() + n - 8); + unsigned char c = num & 0xff; + result->sequence = num >> 8; + result->type = static_cast(c); + result->user_key = Slice(internal_key.data(), n - 8); + return (c <= static_cast(kTypeValue)); +} + +// A helper class useful for DBImpl::Get() +class LookupKey { + public: + // Initialize *this for looking up user_key at a snapshot with + // the specified sequence number. + LookupKey(const Slice& user_key, SequenceNumber sequence); + + ~LookupKey(); + + // Return a key suitable for lookup in a MemTable. + Slice memtable_key() const { return Slice(start_, end_ - start_); } + + // Return an internal key (suitable for passing to an internal iterator) + Slice internal_key() const { return Slice(kstart_, end_ - kstart_); } + + // Return the user key + Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); } + + private: + // We construct a char array of the form: + // klength varint32 <-- start_ + // userkey char[klength] <-- kstart_ + // tag uint64 + // <-- end_ + // The array is a suitable MemTable key. + // The suffix starting with "userkey" can be used as an InternalKey. + const char* start_; + const char* kstart_; + const char* end_; + char space_[200]; // Avoid allocation for short keys + + // No copying allowed + LookupKey(const LookupKey&); + void operator=(const LookupKey&); +}; + +inline LookupKey::~LookupKey() { + if (start_ != space_) delete[] start_; +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_DBFORMAT_H_ diff --git a/db/dbformat_test.cc b/db/dbformat_test.cc new file mode 100644 index 0000000000..5d82f5d313 --- /dev/null +++ b/db/dbformat_test.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/dbformat.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string IKey(const std::string& user_key, + uint64_t seq, + ValueType vt) { + std::string encoded; + AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt)); + return encoded; +} + +static std::string Shorten(const std::string& s, const std::string& l) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l); + return result; +} + +static std::string ShortSuccessor(const std::string& s) { + std::string result = s; + InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result); + return result; +} + +static void TestKey(const std::string& key, + uint64_t seq, + ValueType vt) { + std::string encoded = IKey(key, seq, vt); + + Slice in(encoded); + ParsedInternalKey decoded("", 0, kTypeValue); + + ASSERT_TRUE(ParseInternalKey(in, &decoded)); + ASSERT_EQ(key, decoded.user_key.ToString()); + ASSERT_EQ(seq, decoded.sequence); + ASSERT_EQ(vt, decoded.type); + + ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded)); +} + +class FormatTest { }; + +TEST(FormatTest, InternalKey_EncodeDecode) { + const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" }; + const uint64_t seq[] = { + 1, 2, 3, + (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1, + (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1, + (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1 + }; + for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) { + for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) { + TestKey(keys[k], seq[s], kTypeValue); + TestKey("hello", 1, kTypeDeletion); + } + } +} + +TEST(FormatTest, InternalKeyShortSeparator) { + // When user keys are same + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 99, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 101, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foo", 100, kTypeDeletion))); + + // When user keys are misordered + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("bar", 99, kTypeValue))); + + // When user keys are different, but correctly ordered + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + Shorten(IKey("foo", 100, kTypeValue), + IKey("hello", 200, kTypeValue))); + + // When start user key is prefix of limit user key + ASSERT_EQ(IKey("foo", 100, kTypeValue), + Shorten(IKey("foo", 100, kTypeValue), + IKey("foobar", 200, kTypeValue))); + + // When limit user key is prefix of start user key + ASSERT_EQ(IKey("foobar", 100, kTypeValue), + Shorten(IKey("foobar", 100, kTypeValue), + IKey("foo", 200, kTypeValue))); +} + +TEST(FormatTest, InternalKeyShortestSuccessor) { + ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek), + ShortSuccessor(IKey("foo", 100, kTypeValue))); + ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue), + ShortSuccessor(IKey("\xff\xff", 100, kTypeValue))); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/dumpfile.cc b/db/dumpfile.cc new file mode 100644 index 0000000000..61c47c2ff9 --- /dev/null +++ b/db/dumpfile.cc @@ -0,0 +1,225 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" + +namespace leveldb { + +namespace { + +bool GuessType(const std::string& fname, FileType* type) { + size_t pos = fname.rfind('/'); + std::string basename; + if (pos == std::string::npos) { + basename = fname; + } else { + basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1); + } + uint64_t ignored; + return ParseFileName(basename, &ignored, type); +} + +// Notified when log reader encounters corruption. +class CorruptionReporter : public log::Reader::Reporter { + public: + WritableFile* dst_; + virtual void Corruption(size_t bytes, const Status& status) { + std::string r = "corruption: "; + AppendNumberTo(&r, bytes); + r += " bytes; "; + r += status.ToString(); + r.push_back('\n'); + dst_->Append(r); + } +}; + +// Print contents of a log file. (*func)() is called on every record. +Status PrintLogContents(Env* env, const std::string& fname, + void (*func)(uint64_t, Slice, WritableFile*), + WritableFile* dst) { + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + CorruptionReporter reporter; + reporter.dst_ = dst; + log::Reader reader(file, &reporter, true, 0); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch)) { + (*func)(reader.LastRecordOffset(), record, dst); + } + delete file; + return Status::OK(); +} + +// Called on every item found in a WriteBatch. +class WriteBatchItemPrinter : public WriteBatch::Handler { + public: + WritableFile* dst_; + virtual void Put(const Slice& key, const Slice& value) { + std::string r = " put '"; + AppendEscapedStringTo(&r, key); + r += "' '"; + AppendEscapedStringTo(&r, value); + r += "'\n"; + dst_->Append(r); + } + virtual void Delete(const Slice& key) { + std::string r = " del '"; + AppendEscapedStringTo(&r, key); + r += "'\n"; + dst_->Append(r); + } +}; + + +// Called on every log record (each one of which is a WriteBatch) +// found in a kLogFile. +static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + if (record.size() < 12) { + r += "log record length "; + AppendNumberTo(&r, record.size()); + r += " is too small\n"; + dst->Append(r); + return; + } + WriteBatch batch; + WriteBatchInternal::SetContents(&batch, record); + r += "sequence "; + AppendNumberTo(&r, WriteBatchInternal::Sequence(&batch)); + r.push_back('\n'); + dst->Append(r); + WriteBatchItemPrinter batch_item_printer; + batch_item_printer.dst_ = dst; + Status s = batch.Iterate(&batch_item_printer); + if (!s.ok()) { + dst->Append(" error: " + s.ToString() + "\n"); + } +} + +Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, WriteBatchPrinter, dst); +} + +// Called on every log record (each one of which is a WriteBatch) +// found in a kDescriptorFile. +static void VersionEditPrinter(uint64_t pos, Slice record, WritableFile* dst) { + std::string r = "--- offset "; + AppendNumberTo(&r, pos); + r += "; "; + VersionEdit edit; + Status s = edit.DecodeFrom(record); + if (!s.ok()) { + r += s.ToString(); + r.push_back('\n'); + } else { + r += edit.DebugString(); + } + dst->Append(r); +} + +Status DumpDescriptor(Env* env, const std::string& fname, WritableFile* dst) { + return PrintLogContents(env, fname, VersionEditPrinter, dst); +} + +Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) { + uint64_t file_size; + RandomAccessFile* file = NULL; + Table* table = NULL; + Status s = env->GetFileSize(fname, &file_size); + if (s.ok()) { + s = env->NewRandomAccessFile(fname, &file); + } + if (s.ok()) { + // We use the default comparator, which may or may not match the + // comparator used in this database. However this should not cause + // problems since we only use Table operations that do not require + // any comparisons. In particular, we do not call Seek or Prev. + s = Table::Open(Options(), file, file_size, &table); + } + if (!s.ok()) { + delete table; + delete file; + return s; + } + + ReadOptions ro; + ro.fill_cache = false; + Iterator* iter = table->NewIterator(ro); + std::string r; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + r.clear(); + ParsedInternalKey key; + if (!ParseInternalKey(iter->key(), &key)) { + r = "badkey '"; + AppendEscapedStringTo(&r, iter->key()); + r += "' => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } else { + r = "'"; + AppendEscapedStringTo(&r, key.user_key); + r += "' @ "; + AppendNumberTo(&r, key.sequence); + r += " : "; + if (key.type == kTypeDeletion) { + r += "del"; + } else if (key.type == kTypeValue) { + r += "val"; + } else { + AppendNumberTo(&r, key.type); + } + r += " => '"; + AppendEscapedStringTo(&r, iter->value()); + r += "'\n"; + dst->Append(r); + } + } + s = iter->status(); + if (!s.ok()) { + dst->Append("iterator error: " + s.ToString() + "\n"); + } + + delete iter; + delete table; + delete file; + return Status::OK(); +} + +} // namespace + +Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) { + FileType ftype; + if (!GuessType(fname, &ftype)) { + return Status::InvalidArgument(fname + ": unknown file type"); + } + switch (ftype) { + case kLogFile: return DumpLog(env, fname, dst); + case kDescriptorFile: return DumpDescriptor(env, fname, dst); + case kTableFile: return DumpTable(env, fname, dst); + default: + break; + } + return Status::InvalidArgument(fname + ": not a dump-able file type"); +} + +} // namespace leveldb diff --git a/db/fault_injection_test.cc b/db/fault_injection_test.cc new file mode 100644 index 0000000000..875dfe81ee --- /dev/null +++ b/db/fault_injection_test.cc @@ -0,0 +1,554 @@ +// Copyright 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// This test uses a custom Env to keep track of the state of a filesystem as of +// the last "sync". It then checks for data loss errors by purposely dropping +// file data (or entire files) not protected by a "sync". + +#include "leveldb/db.h" + +#include +#include +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/log_format.h" +#include "db/version_set.h" +#include "leveldb/cache.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kValueSize = 1000; +static const int kMaxNumValues = 2000; +static const size_t kNumIterations = 3; + +class FaultInjectionTestEnv; + +namespace { + +// Assume a filename, and not a directory name like "/foo/bar/" +static std::string GetDirName(const std::string filename) { + size_t found = filename.find_last_of("/\\"); + if (found == std::string::npos) { + return ""; + } else { + return filename.substr(0, found); + } +} + +Status SyncDir(const std::string& dir) { + // As this is a test it isn't required to *actually* sync this directory. + return Status::OK(); +} + +// A basic file truncation function suitable for this test. +Status Truncate(const std::string& filename, uint64_t length) { + leveldb::Env* env = leveldb::Env::Default(); + + SequentialFile* orig_file; + Status s = env->NewSequentialFile(filename, &orig_file); + if (!s.ok()) + return s; + + char* scratch = new char[length]; + leveldb::Slice result; + s = orig_file->Read(length, &result, scratch); + delete orig_file; + if (s.ok()) { + std::string tmp_name = GetDirName(filename) + "/truncate.tmp"; + WritableFile* tmp_file; + s = env->NewWritableFile(tmp_name, &tmp_file); + if (s.ok()) { + s = tmp_file->Append(result); + delete tmp_file; + if (s.ok()) { + s = env->RenameFile(tmp_name, filename); + } else { + env->DeleteFile(tmp_name); + } + } + } + + delete[] scratch; + + return s; +} + +struct FileState { + std::string filename_; + ssize_t pos_; + ssize_t pos_at_last_sync_; + ssize_t pos_at_last_flush_; + + FileState(const std::string& filename) + : filename_(filename), + pos_(-1), + pos_at_last_sync_(-1), + pos_at_last_flush_(-1) { } + + FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1) {} + + bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; } + + Status DropUnsyncedData() const; +}; + +} // anonymous namespace + +// A wrapper around WritableFile which informs another Env whenever this file +// is written to or sync'ed. +class TestWritableFile : public WritableFile { + public: + TestWritableFile(const FileState& state, + WritableFile* f, + FaultInjectionTestEnv* env); + virtual ~TestWritableFile(); + virtual Status Append(const Slice& data); + virtual Status Close(); + virtual Status Flush(); + virtual Status Sync(); + + private: + FileState state_; + WritableFile* target_; + bool writable_file_opened_; + FaultInjectionTestEnv* env_; + + Status SyncParent(); +}; + +class FaultInjectionTestEnv : public EnvWrapper { + public: + FaultInjectionTestEnv() : EnvWrapper(Env::Default()), filesystem_active_(true) {} + virtual ~FaultInjectionTestEnv() { } + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result); + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + virtual Status DeleteFile(const std::string& f); + virtual Status RenameFile(const std::string& s, const std::string& t); + + void WritableFileClosed(const FileState& state); + Status DropUnsyncedFileData(); + Status DeleteFilesCreatedAfterLastDirSync(); + void DirWasSynced(); + bool IsFileCreatedSinceLastDirSync(const std::string& filename); + void ResetState(); + void UntrackFile(const std::string& f); + // Setting the filesystem to inactive is the test equivalent to simulating a + // system reset. Setting to inactive will freeze our saved filesystem state so + // that it will stop being recorded. It can then be reset back to the state at + // the time of the reset. + bool IsFilesystemActive() const { return filesystem_active_; } + void SetFilesystemActive(bool active) { filesystem_active_ = active; } + + private: + port::Mutex mutex_; + std::map db_file_state_; + std::set new_files_since_last_dir_sync_; + bool filesystem_active_; // Record flushes, syncs, writes +}; + +TestWritableFile::TestWritableFile(const FileState& state, + WritableFile* f, + FaultInjectionTestEnv* env) + : state_(state), + target_(f), + writable_file_opened_(true), + env_(env) { + assert(f != NULL); +} + +TestWritableFile::~TestWritableFile() { + if (writable_file_opened_) { + Close(); + } + delete target_; +} + +Status TestWritableFile::Append(const Slice& data) { + Status s = target_->Append(data); + if (s.ok() && env_->IsFilesystemActive()) { + state_.pos_ += data.size(); + } + return s; +} + +Status TestWritableFile::Close() { + writable_file_opened_ = false; + Status s = target_->Close(); + if (s.ok()) { + env_->WritableFileClosed(state_); + } + return s; +} + +Status TestWritableFile::Flush() { + Status s = target_->Flush(); + if (s.ok() && env_->IsFilesystemActive()) { + state_.pos_at_last_flush_ = state_.pos_; + } + return s; +} + +Status TestWritableFile::SyncParent() { + Status s = SyncDir(GetDirName(state_.filename_)); + if (s.ok()) { + env_->DirWasSynced(); + } + return s; +} + +Status TestWritableFile::Sync() { + if (!env_->IsFilesystemActive()) { + return Status::OK(); + } + // Ensure new files referred to by the manifest are in the filesystem. + Status s = target_->Sync(); + if (s.ok()) { + state_.pos_at_last_sync_ = state_.pos_; + } + if (env_->IsFileCreatedSinceLastDirSync(state_.filename_)) { + Status ps = SyncParent(); + if (s.ok() && !ps.ok()) { + s = ps; + } + } + return s; +} + +Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname, + WritableFile** result) { + WritableFile* actual_writable_file; + Status s = target()->NewWritableFile(fname, &actual_writable_file); + if (s.ok()) { + FileState state(fname); + state.pos_ = 0; + *result = new TestWritableFile(state, actual_writable_file, this); + // NewWritableFile doesn't append to files, so if the same file is + // opened again then it will be truncated - so forget our saved + // state. + UntrackFile(fname); + MutexLock l(&mutex_); + new_files_since_last_dir_sync_.insert(fname); + } + return s; +} + +Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname, + WritableFile** result) { + WritableFile* actual_writable_file; + Status s = target()->NewAppendableFile(fname, &actual_writable_file); + if (s.ok()) { + FileState state(fname); + state.pos_ = 0; + { + MutexLock l(&mutex_); + if (db_file_state_.count(fname) == 0) { + new_files_since_last_dir_sync_.insert(fname); + } else { + state = db_file_state_[fname]; + } + } + *result = new TestWritableFile(state, actual_writable_file, this); + } + return s; +} + +Status FaultInjectionTestEnv::DropUnsyncedFileData() { + Status s; + MutexLock l(&mutex_); + for (std::map::const_iterator it = + db_file_state_.begin(); + s.ok() && it != db_file_state_.end(); ++it) { + const FileState& state = it->second; + if (!state.IsFullySynced()) { + s = state.DropUnsyncedData(); + } + } + return s; +} + +void FaultInjectionTestEnv::DirWasSynced() { + MutexLock l(&mutex_); + new_files_since_last_dir_sync_.clear(); +} + +bool FaultInjectionTestEnv::IsFileCreatedSinceLastDirSync( + const std::string& filename) { + MutexLock l(&mutex_); + return new_files_since_last_dir_sync_.find(filename) != + new_files_since_last_dir_sync_.end(); +} + +void FaultInjectionTestEnv::UntrackFile(const std::string& f) { + MutexLock l(&mutex_); + db_file_state_.erase(f); + new_files_since_last_dir_sync_.erase(f); +} + +Status FaultInjectionTestEnv::DeleteFile(const std::string& f) { + Status s = EnvWrapper::DeleteFile(f); + ASSERT_OK(s); + if (s.ok()) { + UntrackFile(f); + } + return s; +} + +Status FaultInjectionTestEnv::RenameFile(const std::string& s, + const std::string& t) { + Status ret = EnvWrapper::RenameFile(s, t); + + if (ret.ok()) { + MutexLock l(&mutex_); + if (db_file_state_.find(s) != db_file_state_.end()) { + db_file_state_[t] = db_file_state_[s]; + db_file_state_.erase(s); + } + + if (new_files_since_last_dir_sync_.erase(s) != 0) { + assert(new_files_since_last_dir_sync_.find(t) == + new_files_since_last_dir_sync_.end()); + new_files_since_last_dir_sync_.insert(t); + } + } + + return ret; +} + +void FaultInjectionTestEnv::ResetState() { + // Since we are not destroying the database, the existing files + // should keep their recorded synced/flushed state. Therefore + // we do not reset db_file_state_ and new_files_since_last_dir_sync_. + MutexLock l(&mutex_); + SetFilesystemActive(true); +} + +Status FaultInjectionTestEnv::DeleteFilesCreatedAfterLastDirSync() { + // Because DeleteFile access this container make a copy to avoid deadlock + mutex_.Lock(); + std::set new_files(new_files_since_last_dir_sync_.begin(), + new_files_since_last_dir_sync_.end()); + mutex_.Unlock(); + Status s; + std::set::const_iterator it; + for (it = new_files.begin(); s.ok() && it != new_files.end(); ++it) { + s = DeleteFile(*it); + } + return s; +} + +void FaultInjectionTestEnv::WritableFileClosed(const FileState& state) { + MutexLock l(&mutex_); + db_file_state_[state.filename_] = state; +} + +Status FileState::DropUnsyncedData() const { + ssize_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_; + return Truncate(filename_, sync_pos); +} + +class FaultInjectionTest { + public: + enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR }; + enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_FILES }; + + FaultInjectionTestEnv* env_; + std::string dbname_; + Cache* tiny_cache_; + Options options_; + DB* db_; + + FaultInjectionTest() + : env_(new FaultInjectionTestEnv), + tiny_cache_(NewLRUCache(100)), + db_(NULL) { + dbname_ = test::TmpDir() + "/fault_test"; + DestroyDB(dbname_, Options()); // Destroy any db from earlier run + options_.reuse_logs = true; + options_.env = env_; + options_.paranoid_checks = true; + options_.block_cache = tiny_cache_; + options_.create_if_missing = true; + } + + ~FaultInjectionTest() { + CloseDB(); + DestroyDB(dbname_, Options()); + delete tiny_cache_; + delete env_; + } + + void ReuseLogs(bool reuse) { + options_.reuse_logs = reuse; + } + + void Build(int start_idx, int num_vals) { + std::string key_space, value_space; + WriteBatch batch; + for (int i = start_idx; i < start_idx + num_vals; i++) { + Slice key = Key(i, &key_space); + batch.Clear(); + batch.Put(key, Value(i, &value_space)); + WriteOptions options; + ASSERT_OK(db_->Write(options, &batch)); + } + } + + Status ReadValue(int i, std::string* val) const { + std::string key_space, value_space; + Slice key = Key(i, &key_space); + Value(i, &value_space); + ReadOptions options; + return db_->Get(options, key, val); + } + + Status Verify(int start_idx, int num_vals, + ExpectedVerifResult expected) const { + std::string val; + std::string value_space; + Status s; + for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) { + Value(i, &value_space); + s = ReadValue(i, &val); + if (expected == VAL_EXPECT_NO_ERROR) { + if (s.ok()) { + ASSERT_EQ(value_space, val); + } + } else if (s.ok()) { + fprintf(stderr, "Expected an error at %d, but was OK\n", i); + s = Status::IOError(dbname_, "Expected value error:"); + } else { + s = Status::OK(); // An expected error + } + } + return s; + } + + // Return the ith key + Slice Key(int i, std::string* storage) const { + char buf[100]; + snprintf(buf, sizeof(buf), "%016d", i); + storage->assign(buf, strlen(buf)); + return Slice(*storage); + } + + // Return the value to associate with the specified key + Slice Value(int k, std::string* storage) const { + Random r(k); + return test::RandomString(&r, kValueSize, storage); + } + + Status OpenDB() { + delete db_; + db_ = NULL; + env_->ResetState(); + return DB::Open(options_, dbname_, &db_); + } + + void CloseDB() { + delete db_; + db_ = NULL; + } + + void DeleteAllData() { + Iterator* iter = db_->NewIterator(ReadOptions()); + WriteOptions options; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ASSERT_OK(db_->Delete(WriteOptions(), iter->key())); + } + + delete iter; + } + + void ResetDBState(ResetMethod reset_method) { + switch (reset_method) { + case RESET_DROP_UNSYNCED_DATA: + ASSERT_OK(env_->DropUnsyncedFileData()); + break; + case RESET_DELETE_UNSYNCED_FILES: + ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync()); + break; + default: + assert(false); + } + } + + void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) { + DeleteAllData(); + Build(0, num_pre_sync); + db_->CompactRange(NULL, NULL); + Build(num_pre_sync, num_post_sync); + } + + void PartialCompactTestReopenWithFault(ResetMethod reset_method, + int num_pre_sync, + int num_post_sync) { + env_->SetFilesystemActive(false); + CloseDB(); + ResetDBState(reset_method); + ASSERT_OK(OpenDB()); + ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::VAL_EXPECT_NO_ERROR)); + ASSERT_OK(Verify(num_pre_sync, num_post_sync, FaultInjectionTest::VAL_EXPECT_ERROR)); + } + + void NoWriteTestPreFault() { + } + + void NoWriteTestReopenWithFault(ResetMethod reset_method) { + CloseDB(); + ResetDBState(reset_method); + ASSERT_OK(OpenDB()); + } + + void DoTest() { + Random rnd(0); + ASSERT_OK(OpenDB()); + for (size_t idx = 0; idx < kNumIterations; idx++) { + int num_pre_sync = rnd.Uniform(kMaxNumValues); + int num_post_sync = rnd.Uniform(kMaxNumValues); + + PartialCompactTestPreFault(num_pre_sync, num_post_sync); + PartialCompactTestReopenWithFault(RESET_DROP_UNSYNCED_DATA, + num_pre_sync, + num_post_sync); + + NoWriteTestPreFault(); + NoWriteTestReopenWithFault(RESET_DROP_UNSYNCED_DATA); + + PartialCompactTestPreFault(num_pre_sync, num_post_sync); + // No new files created so we expect all values since no files will be + // dropped. + PartialCompactTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES, + num_pre_sync + num_post_sync, + 0); + + NoWriteTestPreFault(); + NoWriteTestReopenWithFault(RESET_DELETE_UNSYNCED_FILES); + } + } +}; + +TEST(FaultInjectionTest, FaultTestNoLogReuse) { + ReuseLogs(false); + DoTest(); +} + +TEST(FaultInjectionTest, FaultTestWithLogReuse) { + ReuseLogs(true); + DoTest(); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/filename.cc b/db/filename.cc new file mode 100644 index 0000000000..da32946d99 --- /dev/null +++ b/db/filename.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "db/filename.h" +#include "db/dbformat.h" +#include "leveldb/env.h" +#include "util/logging.h" + +namespace leveldb { + +// A utility routine: write "data" to the named file and Sync() it. +extern Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname); + +static std::string MakeFileName(const std::string& name, uint64_t number, + const char* suffix) { + char buf[100]; + snprintf(buf, sizeof(buf), "/%06llu.%s", + static_cast(number), + suffix); + return name + buf; +} + +std::string LogFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "log"); +} + +std::string TableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "ldb"); +} + +std::string SSTTableFileName(const std::string& name, uint64_t number) { + assert(number > 0); + return MakeFileName(name, number, "sst"); +} + +std::string DescriptorFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + char buf[100]; + snprintf(buf, sizeof(buf), "/MANIFEST-%06llu", + static_cast(number)); + return dbname + buf; +} + +std::string CurrentFileName(const std::string& dbname) { + return dbname + "/CURRENT"; +} + +std::string LockFileName(const std::string& dbname) { + return dbname + "/LOCK"; +} + +std::string TempFileName(const std::string& dbname, uint64_t number) { + assert(number > 0); + return MakeFileName(dbname, number, "dbtmp"); +} + +std::string InfoLogFileName(const std::string& dbname) { + return dbname + "/LOG"; +} + +// Return the name of the old info log file for "dbname". +std::string OldInfoLogFileName(const std::string& dbname) { + return dbname + "/LOG.old"; +} + + +// Owned filenames have the form: +// dbname/CURRENT +// dbname/LOCK +// dbname/LOG +// dbname/LOG.old +// dbname/MANIFEST-[0-9]+ +// dbname/[0-9]+.(log|sst|ldb) +bool ParseFileName(const std::string& fname, + uint64_t* number, + FileType* type) { + Slice rest(fname); + if (rest == "CURRENT") { + *number = 0; + *type = kCurrentFile; + } else if (rest == "LOCK") { + *number = 0; + *type = kDBLockFile; + } else if (rest == "LOG" || rest == "LOG.old") { + *number = 0; + *type = kInfoLogFile; + } else if (rest.starts_with("MANIFEST-")) { + rest.remove_prefix(strlen("MANIFEST-")); + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + if (!rest.empty()) { + return false; + } + *type = kDescriptorFile; + *number = num; + } else { + // Avoid strtoull() to keep filename format independent of the + // current locale + uint64_t num; + if (!ConsumeDecimalNumber(&rest, &num)) { + return false; + } + Slice suffix = rest; + if (suffix == Slice(".log")) { + *type = kLogFile; + } else if (suffix == Slice(".sst") || suffix == Slice(".ldb")) { + *type = kTableFile; + } else if (suffix == Slice(".dbtmp")) { + *type = kTempFile; + } else { + return false; + } + *number = num; + } + return true; +} + +Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number) { + // Remove leading "dbname/" and add newline to manifest file name + std::string manifest = DescriptorFileName(dbname, descriptor_number); + Slice contents = manifest; + assert(contents.starts_with(dbname + "/")); + contents.remove_prefix(dbname.size() + 1); + std::string tmp = TempFileName(dbname, descriptor_number); + Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp); + if (s.ok()) { + s = env->RenameFile(tmp, CurrentFileName(dbname)); + } + if (!s.ok()) { + env->DeleteFile(tmp); + } + return s; +} + +} // namespace leveldb diff --git a/db/filename.h b/db/filename.h new file mode 100644 index 0000000000..87a752605d --- /dev/null +++ b/db/filename.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// File names used by DB code + +#ifndef STORAGE_LEVELDB_DB_FILENAME_H_ +#define STORAGE_LEVELDB_DB_FILENAME_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +enum FileType { + kLogFile, + kDBLockFile, + kTableFile, + kDescriptorFile, + kCurrentFile, + kTempFile, + kInfoLogFile // Either the current one, or an old one +}; + +// Return the name of the log file with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string LogFileName(const std::string& dbname, uint64_t number); + +// Return the name of the sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string TableFileName(const std::string& dbname, uint64_t number); + +// Return the legacy file name for an sstable with the specified number +// in the db named by "dbname". The result will be prefixed with +// "dbname". +extern std::string SSTTableFileName(const std::string& dbname, uint64_t number); + +// Return the name of the descriptor file for the db named by +// "dbname" and the specified incarnation number. The result will be +// prefixed with "dbname". +extern std::string DescriptorFileName(const std::string& dbname, + uint64_t number); + +// Return the name of the current file. This file contains the name +// of the current manifest file. The result will be prefixed with +// "dbname". +extern std::string CurrentFileName(const std::string& dbname); + +// Return the name of the lock file for the db named by +// "dbname". The result will be prefixed with "dbname". +extern std::string LockFileName(const std::string& dbname); + +// Return the name of a temporary file owned by the db named "dbname". +// The result will be prefixed with "dbname". +extern std::string TempFileName(const std::string& dbname, uint64_t number); + +// Return the name of the info log file for "dbname". +extern std::string InfoLogFileName(const std::string& dbname); + +// Return the name of the old info log file for "dbname". +extern std::string OldInfoLogFileName(const std::string& dbname); + +// If filename is a leveldb file, store the type of the file in *type. +// The number encoded in the filename is stored in *number. If the +// filename was successfully parsed, returns true. Else return false. +extern bool ParseFileName(const std::string& filename, + uint64_t* number, + FileType* type); + +// Make the CURRENT file point to the descriptor file with the +// specified number. +extern Status SetCurrentFile(Env* env, const std::string& dbname, + uint64_t descriptor_number); + + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_FILENAME_H_ diff --git a/db/filename_test.cc b/db/filename_test.cc new file mode 100644 index 0000000000..a32556deaf --- /dev/null +++ b/db/filename_test.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/filename.h" + +#include "db/dbformat.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +class FileNameTest { }; + +TEST(FileNameTest, Parse) { + Slice db; + FileType type; + uint64_t number; + + // Successful parses + static struct { + const char* fname; + uint64_t number; + FileType type; + } cases[] = { + { "100.log", 100, kLogFile }, + { "0.log", 0, kLogFile }, + { "0.sst", 0, kTableFile }, + { "0.ldb", 0, kTableFile }, + { "CURRENT", 0, kCurrentFile }, + { "LOCK", 0, kDBLockFile }, + { "MANIFEST-2", 2, kDescriptorFile }, + { "MANIFEST-7", 7, kDescriptorFile }, + { "LOG", 0, kInfoLogFile }, + { "LOG.old", 0, kInfoLogFile }, + { "18446744073709551615.log", 18446744073709551615ull, kLogFile }, + }; + for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + std::string f = cases[i].fname; + ASSERT_TRUE(ParseFileName(f, &number, &type)) << f; + ASSERT_EQ(cases[i].type, type) << f; + ASSERT_EQ(cases[i].number, number) << f; + } + + // Errors + static const char* errors[] = { + "", + "foo", + "foo-dx-100.log", + ".log", + "", + "manifest", + "CURREN", + "CURRENTX", + "MANIFES", + "MANIFEST", + "MANIFEST-", + "XMANIFEST-3", + "MANIFEST-3x", + "LOC", + "LOCKx", + "LO", + "LOGx", + "18446744073709551616.log", + "184467440737095516150.log", + "100", + "100.", + "100.lop" + }; + for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) { + std::string f = errors[i]; + ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f; + } +} + +TEST(FileNameTest, Construction) { + uint64_t number; + FileType type; + std::string fname; + + fname = CurrentFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kCurrentFile, type); + + fname = LockFileName("foo"); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(0, number); + ASSERT_EQ(kDBLockFile, type); + + fname = LogFileName("foo", 192); + ASSERT_EQ("foo/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(192, number); + ASSERT_EQ(kLogFile, type); + + fname = TableFileName("bar", 200); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(200, number); + ASSERT_EQ(kTableFile, type); + + fname = DescriptorFileName("bar", 100); + ASSERT_EQ("bar/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(100, number); + ASSERT_EQ(kDescriptorFile, type); + + fname = TempFileName("tmp", 999); + ASSERT_EQ("tmp/", std::string(fname.data(), 4)); + ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type)); + ASSERT_EQ(999, number); + ASSERT_EQ(kTempFile, type); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/leveldbutil.cc b/db/leveldbutil.cc new file mode 100644 index 0000000000..d06d64d640 --- /dev/null +++ b/db/leveldbutil.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "leveldb/dumpfile.h" +#include "leveldb/env.h" +#include "leveldb/status.h" + +namespace leveldb { +namespace { + +class StdoutPrinter : public WritableFile { + public: + virtual Status Append(const Slice& data) { + fwrite(data.data(), 1, data.size(), stdout); + return Status::OK(); + } + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + virtual std::string GetName() const { return "[stdout]"; } +}; + +bool HandleDumpCommand(Env* env, char** files, int num) { + StdoutPrinter printer; + bool ok = true; + for (int i = 0; i < num; i++) { + Status s = DumpFile(env, files[i], &printer); + if (!s.ok()) { + fprintf(stderr, "%s\n", s.ToString().c_str()); + ok = false; + } + } + return ok; +} + +} // namespace +} // namespace leveldb + +static void Usage() { + fprintf( + stderr, + "Usage: leveldbutil command...\n" + " dump files... -- dump contents of specified files\n" + ); +} + +int main(int argc, char** argv) { + leveldb::Env* env = leveldb::Env::Default(); + bool ok = true; + if (argc < 2) { + Usage(); + ok = false; + } else { + std::string command = argv[1]; + if (command == "dump") { + ok = leveldb::HandleDumpCommand(env, argv+2, argc-2); + } else { + Usage(); + ok = false; + } + } + return (ok ? 0 : 1); +} diff --git a/db/log_format.h b/db/log_format.h new file mode 100644 index 0000000000..356e69fca2 --- /dev/null +++ b/db/log_format.h @@ -0,0 +1,35 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Log format information shared by reader and writer. +// See ../doc/log_format.md for more detail. + +#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_ +#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_ + +namespace leveldb { +namespace log { + +enum RecordType { + // Zero is reserved for preallocated files + kZeroType = 0, + + kFullType = 1, + + // For fragments + kFirstType = 2, + kMiddleType = 3, + kLastType = 4 +}; +static const int kMaxRecordType = kLastType; + +static const int kBlockSize = 32768; + +// Header is checksum (4 bytes), length (2 bytes), type (1 byte). +static const int kHeaderSize = 4 + 2 + 1; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_ diff --git a/db/log_reader.cc b/db/log_reader.cc new file mode 100644 index 0000000000..8b6ad136d7 --- /dev/null +++ b/db/log_reader.cc @@ -0,0 +1,284 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Reader::Reporter::~Reporter() { +} + +Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset) + : file_(file), + reporter_(reporter), + checksum_(checksum), + backing_store_(new char[kBlockSize]), + buffer_(), + eof_(false), + last_record_offset_(0), + end_of_buffer_offset_(0), + initial_offset_(initial_offset), + resyncing_(initial_offset > 0) { +} + +Reader::~Reader() { + delete[] backing_store_; +} + +bool Reader::SkipToInitialBlock() { + size_t offset_in_block = initial_offset_ % kBlockSize; + uint64_t block_start_location = initial_offset_ - offset_in_block; + + // Don't search a block if we'd be in the trailer + if (offset_in_block > kBlockSize - 6) { + offset_in_block = 0; + block_start_location += kBlockSize; + } + + end_of_buffer_offset_ = block_start_location; + + // Skip to start of first block that can contain the initial record + if (block_start_location > 0) { + Status skip_status = file_->Skip(block_start_location); + if (!skip_status.ok()) { + ReportDrop(block_start_location, skip_status); + return false; + } + } + + return true; +} + +bool Reader::ReadRecord(Slice* record, std::string* scratch) { + if (last_record_offset_ < initial_offset_) { + if (!SkipToInitialBlock()) { + return false; + } + } + + scratch->clear(); + record->clear(); + bool in_fragmented_record = false; + // Record offset of the logical record that we're reading + // 0 is a dummy value to make compilers happy + uint64_t prospective_record_offset = 0; + + Slice fragment; + while (true) { + const unsigned int record_type = ReadPhysicalRecord(&fragment); + + // ReadPhysicalRecord may have only had an empty trailer remaining in its + // internal buffer. Calculate the offset of the next physical record now + // that it has returned, properly accounting for its header size. + uint64_t physical_record_offset = + end_of_buffer_offset_ - buffer_.size() - kHeaderSize - fragment.size(); + + if (resyncing_) { + if (record_type == kMiddleType) { + continue; + } else if (record_type == kLastType) { + resyncing_ = false; + continue; + } else { + resyncing_ = false; + } + } + + switch (record_type) { + case kFullType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(1)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->clear(); + *record = fragment; + last_record_offset_ = prospective_record_offset; + return true; + + case kFirstType: + if (in_fragmented_record) { + // Handle bug in earlier versions of log::Writer where + // it could emit an empty kFirstType record at the tail end + // of a block followed by a kFullType or kFirstType record + // at the beginning of the next block. + if (scratch->empty()) { + in_fragmented_record = false; + } else { + ReportCorruption(scratch->size(), "partial record without end(2)"); + } + } + prospective_record_offset = physical_record_offset; + scratch->assign(fragment.data(), fragment.size()); + in_fragmented_record = true; + break; + + case kMiddleType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(1)"); + } else { + scratch->append(fragment.data(), fragment.size()); + } + break; + + case kLastType: + if (!in_fragmented_record) { + ReportCorruption(fragment.size(), + "missing start of fragmented record(2)"); + } else { + scratch->append(fragment.data(), fragment.size()); + *record = Slice(*scratch); + last_record_offset_ = prospective_record_offset; + return true; + } + break; + + case kEof: + if (in_fragmented_record) { + // This can be caused by the writer dying immediately after + // writing a physical record but before completing the next; don't + // treat it as a corruption, just ignore the entire logical record. + scratch->clear(); + } + return false; + + case kBadRecord: + if (in_fragmented_record) { + ReportCorruption(scratch->size(), "error in middle of record"); + in_fragmented_record = false; + scratch->clear(); + } + break; + + default: { + char buf[40]; + snprintf(buf, sizeof(buf), "unknown record type %u", record_type); + ReportCorruption( + (fragment.size() + (in_fragmented_record ? scratch->size() : 0)), + buf); + in_fragmented_record = false; + scratch->clear(); + break; + } + } + } + return false; +} + +uint64_t Reader::LastRecordOffset() { + return last_record_offset_; +} + +void Reader::ReportCorruption(uint64_t bytes, const char* reason) { + ReportDrop(bytes, Status::Corruption(reason, file_->GetName())); +} + +void Reader::ReportDrop(uint64_t bytes, const Status& reason) { + if (reporter_ != NULL && + end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) { + reporter_->Corruption(static_cast(bytes), reason); + } +} + +unsigned int Reader::ReadPhysicalRecord(Slice* result) { + while (true) { + if (buffer_.size() < kHeaderSize) { + if (!eof_) { + // Last read was a full read, so this is a trailer to skip + buffer_.clear(); + Status status = file_->Read(kBlockSize, &buffer_, backing_store_); + end_of_buffer_offset_ += buffer_.size(); + if (!status.ok()) { + buffer_.clear(); + ReportDrop(kBlockSize, status); + eof_ = true; + return kEof; + } else if (buffer_.size() < kBlockSize) { + eof_ = true; + } + continue; + } else { + // Note that if buffer_ is non-empty, we have a truncated header at the + // end of the file, which can be caused by the writer crashing in the + // middle of writing the header. Instead of considering this an error, + // just report EOF. + buffer_.clear(); + return kEof; + } + } + + // Parse the header + const char* header = buffer_.data(); + const uint32_t a = static_cast(header[4]) & 0xff; + const uint32_t b = static_cast(header[5]) & 0xff; + const unsigned int type = header[6]; + const uint32_t length = a | (b << 8); + if (kHeaderSize + length > buffer_.size()) { + size_t drop_size = buffer_.size(); + buffer_.clear(); + if (!eof_) { + ReportCorruption(drop_size, "bad record length"); + return kBadRecord; + } + // If the end of the file has been reached without reading |length| bytes + // of payload, assume the writer died in the middle of writing the record. + // Don't report a corruption. + return kEof; + } + + if (type == kZeroType && length == 0) { + // Skip zero length record without reporting any drops since + // such records are produced by the mmap based writing code in + // env_posix.cc that preallocates file regions. + buffer_.clear(); + return kBadRecord; + } + + // Check crc + if (checksum_) { + uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header)); + uint32_t actual_crc = crc32c::Value(header + 6, 1 + length); + if (actual_crc != expected_crc) { + // Drop the rest of the buffer since "length" itself may have + // been corrupted and if we trust it, we could find some + // fragment of a real log record that just happens to look + // like a valid log record. + size_t drop_size = buffer_.size(); + buffer_.clear(); + ReportCorruption(drop_size, "checksum mismatch"); + return kBadRecord; + } + } + + buffer_.remove_prefix(kHeaderSize + length); + + // Skip physical record that started before initial_offset_ + if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length < + initial_offset_) { + result->clear(); + return kBadRecord; + } + + *result = Slice(header + kHeaderSize, length); + return type; + } +} + +} // namespace log +} // namespace leveldb diff --git a/db/log_reader.h b/db/log_reader.h new file mode 100644 index 0000000000..8389d61f8f --- /dev/null +++ b/db/log_reader.h @@ -0,0 +1,113 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_ +#define STORAGE_LEVELDB_DB_LOG_READER_H_ + +#include + +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class SequentialFile; + +namespace log { + +class Reader { + public: + // Interface for reporting errors. + class Reporter { + public: + virtual ~Reporter(); + + // Some corruption was detected. "size" is the approximate number + // of bytes dropped due to the corruption. + virtual void Corruption(size_t bytes, const Status& status) = 0; + }; + + // Create a reader that will return log records from "*file". + // "*file" must remain live while this Reader is in use. + // + // If "reporter" is non-NULL, it is notified whenever some data is + // dropped due to a detected corruption. "*reporter" must remain + // live while this Reader is in use. + // + // If "checksum" is true, verify checksums if available. + // + // The Reader will start reading at the first record located at physical + // position >= initial_offset within the file. + Reader(SequentialFile* file, Reporter* reporter, bool checksum, + uint64_t initial_offset); + + ~Reader(); + + // Read the next record into *record. Returns true if read + // successfully, false if we hit end of the input. May use + // "*scratch" as temporary storage. The contents filled in *record + // will only be valid until the next mutating operation on this + // reader or the next mutation to *scratch. + bool ReadRecord(Slice* record, std::string* scratch); + + // Returns the physical offset of the last record returned by ReadRecord. + // + // Undefined before the first call to ReadRecord. + uint64_t LastRecordOffset(); + + private: + SequentialFile* const file_; + Reporter* const reporter_; + bool const checksum_; + char* const backing_store_; + Slice buffer_; + bool eof_; // Last Read() indicated EOF by returning < kBlockSize + + // Offset of the last record returned by ReadRecord. + uint64_t last_record_offset_; + // Offset of the first location past the end of buffer_. + uint64_t end_of_buffer_offset_; + + // Offset at which to start looking for the first record to return + uint64_t const initial_offset_; + + // True if we are resynchronizing after a seek (initial_offset_ > 0). In + // particular, a run of kMiddleType and kLastType records can be silently + // skipped in this mode + bool resyncing_; + + // Extend record types with the following special values + enum { + kEof = kMaxRecordType + 1, + // Returned whenever we find an invalid physical record. + // Currently there are three situations in which this happens: + // * The record has an invalid CRC (ReadPhysicalRecord reports a drop) + // * The record is a 0-length record (No drop is reported) + // * The record is below constructor's initial_offset (No drop is reported) + kBadRecord = kMaxRecordType + 2 + }; + + // Skips all blocks that are completely before "initial_offset_". + // + // Returns true on success. Handles reporting. + bool SkipToInitialBlock(); + + // Return type, or one of the preceding special values + unsigned int ReadPhysicalRecord(Slice* result); + + // Reports dropped bytes to the reporter. + // buffer_ must be updated to remove the dropped bytes prior to invocation. + void ReportCorruption(uint64_t bytes, const char* reason); + void ReportDrop(uint64_t bytes, const Status& reason); + + // No copying allowed + Reader(const Reader&); + void operator=(const Reader&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_READER_H_ diff --git a/db/log_test.cc b/db/log_test.cc new file mode 100644 index 0000000000..48a5928657 --- /dev/null +++ b/db/log_test.cc @@ -0,0 +1,591 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { +namespace log { + +// Construct a string of the specified length made out of the supplied +// partial string. +static std::string BigString(const std::string& partial_string, size_t n) { + std::string result; + while (result.size() < n) { + result.append(partial_string); + } + result.resize(n); + return result; +} + +// Construct a string from a number +static std::string NumberString(int n) { + char buf[50]; + snprintf(buf, sizeof(buf), "%d.", n); + return std::string(buf); +} + +// Return a skewed potentially long string +static std::string RandomSkewedString(int i, Random* rnd) { + return BigString(NumberString(i), rnd->Skewed(17)); +} + +class LogTest { + private: + class StringDest : public WritableFile { + public: + std::string contents_; + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + virtual Status Append(const Slice& slice) { + contents_.append(slice.data(), slice.size()); + return Status::OK(); + } + }; + + class StringSource : public SequentialFile { + public: + Slice contents_; + bool force_error_; + bool returned_partial_; + StringSource() : force_error_(false), returned_partial_(false) { } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error"; + + if (force_error_) { + force_error_ = false; + returned_partial_ = true; + return Status::Corruption("read error"); + } + + if (contents_.size() < n) { + n = contents_.size(); + returned_partial_ = true; + } + *result = Slice(contents_.data(), n); + contents_.remove_prefix(n); + return Status::OK(); + } + + virtual Status Skip(uint64_t n) { + if (n > contents_.size()) { + contents_.clear(); + return Status::NotFound("in-memory file skipped past end"); + } + + contents_.remove_prefix(n); + + return Status::OK(); + } + }; + + class ReportCollector : public Reader::Reporter { + public: + size_t dropped_bytes_; + std::string message_; + + ReportCollector() : dropped_bytes_(0) { } + virtual void Corruption(size_t bytes, const Status& status) { + dropped_bytes_ += bytes; + message_.append(status.ToString()); + } + }; + + StringDest dest_; + StringSource source_; + ReportCollector report_; + bool reading_; + Writer* writer_; + Reader* reader_; + + // Record metadata for testing initial offset functionality + static size_t initial_offset_record_sizes_[]; + static uint64_t initial_offset_last_record_offsets_[]; + static int num_initial_offset_records_; + + public: + LogTest() : reading_(false), + writer_(new Writer(&dest_)), + reader_(new Reader(&source_, &report_, true/*checksum*/, + 0/*initial_offset*/)) { + } + + ~LogTest() { + delete writer_; + delete reader_; + } + + void ReopenForAppend() { + delete writer_; + writer_ = new Writer(&dest_, dest_.contents_.size()); + } + + void Write(const std::string& msg) { + ASSERT_TRUE(!reading_) << "Write() after starting to read"; + writer_->AddRecord(Slice(msg)); + } + + size_t WrittenBytes() const { + return dest_.contents_.size(); + } + + std::string Read() { + if (!reading_) { + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + } + std::string scratch; + Slice record; + if (reader_->ReadRecord(&record, &scratch)) { + return record.ToString(); + } else { + return "EOF"; + } + } + + void IncrementByte(int offset, int delta) { + dest_.contents_[offset] += delta; + } + + void SetByte(int offset, char new_byte) { + dest_.contents_[offset] = new_byte; + } + + void ShrinkSize(int bytes) { + dest_.contents_.resize(dest_.contents_.size() - bytes); + } + + void FixChecksum(int header_offset, int len) { + // Compute crc of type/len/data + uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len); + crc = crc32c::Mask(crc); + EncodeFixed32(&dest_.contents_[header_offset], crc); + } + + void ForceError() { + source_.force_error_ = true; + } + + size_t DroppedBytes() const { + return report_.dropped_bytes_; + } + + std::string ReportMessage() const { + return report_.message_; + } + + // Returns OK iff recorded error message contains "msg" + std::string MatchError(const std::string& msg) const { + if (report_.message_.find(msg) == std::string::npos) { + return report_.message_; + } else { + return "OK"; + } + } + + void WriteInitialOffsetLog() { + for (int i = 0; i < num_initial_offset_records_; i++) { + std::string record(initial_offset_record_sizes_[i], + static_cast('a' + i)); + Write(record); + } + } + + void StartReadingAt(uint64_t initial_offset) { + delete reader_; + reader_ = new Reader(&source_, &report_, true/*checksum*/, initial_offset); + } + + void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + WrittenBytes() + offset_past_end); + Slice record; + std::string scratch; + ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch)); + delete offset_reader; + } + + void CheckInitialOffsetRecord(uint64_t initial_offset, + int expected_record_offset) { + WriteInitialOffsetLog(); + reading_ = true; + source_.contents_ = Slice(dest_.contents_); + Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/, + initial_offset); + + // Read all records from expected_record_offset through the last one. + ASSERT_LT(expected_record_offset, num_initial_offset_records_); + for (; expected_record_offset < num_initial_offset_records_; + ++expected_record_offset) { + Slice record; + std::string scratch; + ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch)); + ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset], + record.size()); + ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset], + offset_reader->LastRecordOffset()); + ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]); + } + delete offset_reader; + } +}; + +size_t LogTest::initial_offset_record_sizes_[] = + {10000, // Two sizable records in first block + 10000, + 2 * log::kBlockSize - 1000, // Span three blocks + 1, + 13716, // Consume all but two bytes of block 3. + log::kBlockSize - kHeaderSize, // Consume the entirety of block 4. + }; + +uint64_t LogTest::initial_offset_last_record_offsets_[] = + {0, + kHeaderSize + 10000, + 2 * (kHeaderSize + 10000), + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 2 * (kHeaderSize + 10000) + + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize + + kHeaderSize + 1, + 3 * log::kBlockSize, + }; + +// LogTest::initial_offset_last_record_offsets_ must be defined before this. +int LogTest::num_initial_offset_records_ = + sizeof(LogTest::initial_offset_last_record_offsets_)/sizeof(uint64_t); + +TEST(LogTest, Empty) { + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, ReadWrite) { + Write("foo"); + Write("bar"); + Write(""); + Write("xxxx"); + ASSERT_EQ("foo", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("xxxx", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("EOF", Read()); // Make sure reads at eof work +} + +TEST(LogTest, ManyBlocks) { + for (int i = 0; i < 100000; i++) { + Write(NumberString(i)); + } + for (int i = 0; i < 100000; i++) { + ASSERT_EQ(NumberString(i), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, Fragmentation) { + Write("small"); + Write(BigString("medium", 50000)); + Write(BigString("large", 100000)); + ASSERT_EQ("small", Read()); + ASSERT_EQ(BigString("medium", 50000), Read()); + ASSERT_EQ(BigString("large", 100000), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, MarginalTrailer2) { + // Make a trailer that is exactly the same length as an empty record. + const int n = kBlockSize - 2*kHeaderSize; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes()); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ShortTrailer) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + Write(""); + Write("bar"); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("", Read()); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, AlignedEof) { + const int n = kBlockSize - 2*kHeaderSize + 4; + Write(BigString("foo", n)); + ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes()); + ASSERT_EQ(BigString("foo", n), Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, OpenForAppend) { + Write("hello"); + ReopenForAppend(); + Write("world"); + ASSERT_EQ("hello", Read()); + ASSERT_EQ("world", Read()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, RandomRead) { + const int N = 500; + Random write_rnd(301); + for (int i = 0; i < N; i++) { + Write(RandomSkewedString(i, &write_rnd)); + } + Random read_rnd(301); + for (int i = 0; i < N; i++) { + ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read()); + } + ASSERT_EQ("EOF", Read()); +} + +// Tests of all the error paths in log_reader.cc follow: + +TEST(LogTest, ReadError) { + Write("foo"); + ForceError(); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("read error")); +} + +TEST(LogTest, BadRecordType) { + Write("foo"); + // Type is stored in header[6] + IncrementByte(6, 100); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("unknown record type")); +} + +TEST(LogTest, TruncatedTrailingRecordIsIgnored) { + Write("foo"); + ShrinkSize(4); // Drop all payload as well as a header byte + ASSERT_EQ("EOF", Read()); + // Truncated last record is ignored, not treated as an error. + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, BadLength) { + const int kPayloadSize = kBlockSize - kHeaderSize; + Write(BigString("bar", kPayloadSize)); + Write("foo"); + // Least significant size byte is stored in header[4]. + IncrementByte(4, 1); + ASSERT_EQ("foo", Read()); + ASSERT_EQ(kBlockSize, DroppedBytes()); + ASSERT_EQ("OK", MatchError("bad record length")); +} + +TEST(LogTest, BadLengthAtEndIsIgnored) { + Write("foo"); + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("", ReportMessage()); +} + +TEST(LogTest, ChecksumMismatch) { + Write("foo"); + IncrementByte(0, 10); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(10, DroppedBytes()); + ASSERT_EQ("OK", MatchError("checksum mismatch")); +} + +TEST(LogTest, UnexpectedMiddleType) { + Write("foo"); + SetByte(6, kMiddleType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedLastType) { + Write("foo"); + SetByte(6, kLastType); + FixChecksum(0, 3); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("missing start")); +} + +TEST(LogTest, UnexpectedFullType) { + Write("foo"); + Write("bar"); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ("bar", Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, UnexpectedFirstType) { + Write("foo"); + Write(BigString("bar", 100000)); + SetByte(6, kFirstType); + FixChecksum(0, 3); + ASSERT_EQ(BigString("bar", 100000), Read()); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ(3, DroppedBytes()); + ASSERT_EQ("OK", MatchError("partial record without end")); +} + +TEST(LogTest, MissingLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Remove the LAST block, including header. + ShrinkSize(14); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + +TEST(LogTest, PartialLastIsIgnored) { + Write(BigString("bar", kBlockSize)); + // Cause a bad record length in the LAST block. + ShrinkSize(1); + ASSERT_EQ("EOF", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); +} + +TEST(LogTest, SkipIntoMultiRecord) { + // Consider a fragmented record: + // first(R1), middle(R1), last(R1), first(R2) + // If initial_offset points to a record after first(R1) but before first(R2) + // incomplete fragment errors are not actual errors, and must be suppressed + // until a new first or full record is encountered. + Write(BigString("foo", 3*kBlockSize)); + Write("correct"); + StartReadingAt(kBlockSize); + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("", ReportMessage()); + ASSERT_EQ(0, DroppedBytes()); + ASSERT_EQ("EOF", Read()); +} + +TEST(LogTest, ErrorJoinsRecords) { + // Consider two fragmented records: + // first(R1) last(R1) first(R2) last(R2) + // where the middle two fragments disappear. We do not want + // first(R1),last(R2) to get joined and returned as a valid record. + + // Write records that span two blocks + Write(BigString("foo", kBlockSize)); + Write(BigString("bar", kBlockSize)); + Write("correct"); + + // Wipe the middle block + for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) { + SetByte(offset, 'x'); + } + + ASSERT_EQ("correct", Read()); + ASSERT_EQ("EOF", Read()); + const size_t dropped = DroppedBytes(); + ASSERT_LE(dropped, 2*kBlockSize + 100); + ASSERT_GE(dropped, 2*kBlockSize); +} + +TEST(LogTest, ReadStart) { + CheckInitialOffsetRecord(0, 0); +} + +TEST(LogTest, ReadSecondOneOff) { + CheckInitialOffsetRecord(1, 1); +} + +TEST(LogTest, ReadSecondTenThousand) { + CheckInitialOffsetRecord(10000, 1); +} + +TEST(LogTest, ReadSecondStart) { + CheckInitialOffsetRecord(10007, 1); +} + +TEST(LogTest, ReadThirdOneOff) { + CheckInitialOffsetRecord(10008, 2); +} + +TEST(LogTest, ReadThirdStart) { + CheckInitialOffsetRecord(20014, 2); +} + +TEST(LogTest, ReadFourthOneOff) { + CheckInitialOffsetRecord(20015, 3); +} + +TEST(LogTest, ReadFourthFirstBlockTrailer) { + CheckInitialOffsetRecord(log::kBlockSize - 4, 3); +} + +TEST(LogTest, ReadFourthMiddleBlock) { + CheckInitialOffsetRecord(log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthLastBlock) { + CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3); +} + +TEST(LogTest, ReadFourthStart) { + CheckInitialOffsetRecord( + 2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize, + 3); +} + +TEST(LogTest, ReadInitialOffsetIntoBlockPadding) { + CheckInitialOffsetRecord(3 * log::kBlockSize - 3, 5); +} + +TEST(LogTest, ReadEnd) { + CheckOffsetPastEndReturnsNoRecords(0); +} + +TEST(LogTest, ReadPastEnd) { + CheckOffsetPastEndReturnsNoRecords(5); +} + +} // namespace log +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/log_writer.cc b/db/log_writer.cc new file mode 100644 index 0000000000..74a03270da --- /dev/null +++ b/db/log_writer.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include +#include "leveldb/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +static void InitTypeCrc(uint32_t* type_crc) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast(i); + type_crc[i] = crc32c::Value(&t, 1); + } +} + +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + InitTypeCrc(type_crc_); +} + +Writer::Writer(WritableFile* dest, uint64_t dest_length) + : dest_(dest), block_offset_(dest_length % kBlockSize) { + InitTypeCrc(type_crc_); +} + +Writer::~Writer() { +} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + bool begin = true; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover < kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer (literal below relies on kHeaderSize being 7) + assert(kHeaderSize == 7); + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave < kHeaderSize bytes in a block. + assert(kBlockSize - block_offset_ - kHeaderSize >= 0); + + const size_t avail = kBlockSize - block_offset_ - kHeaderSize; + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + begin = false; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { + assert(n <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + n <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast(n & 0xff); + buf[5] = static_cast(n >> 8); + buf[6] = static_cast(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, n)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + n; + return s; +} + +} // namespace log +} // namespace leveldb diff --git a/db/log_writer.h b/db/log_writer.h new file mode 100644 index 0000000000..9e7cc4705b --- /dev/null +++ b/db/log_writer.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_ +#define STORAGE_LEVELDB_DB_LOG_WRITER_H_ + +#include +#include "db/log_format.h" +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class WritableFile; + +namespace log { + +class Writer { + public: + // Create a writer that will append data to "*dest". + // "*dest" must be initially empty. + // "*dest" must remain live while this Writer is in use. + explicit Writer(WritableFile* dest); + + // Create a writer that will append data to "*dest". + // "*dest" must have initial length "dest_length". + // "*dest" must remain live while this Writer is in use. + Writer(WritableFile* dest, uint64_t dest_length); + + ~Writer(); + + Status AddRecord(const Slice& slice); + + private: + WritableFile* dest_; + int block_offset_; // Current offset in block + + // crc32c values for all supported record types. These are + // pre-computed to reduce the overhead of computing the crc of the + // record type stored in the header. + uint32_t type_crc_[kMaxRecordType + 1]; + + Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length); + + // No copying allowed + Writer(const Writer&); + void operator=(const Writer&); +}; + +} // namespace log +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_ diff --git a/db/memtable.cc b/db/memtable.cc new file mode 100644 index 0000000000..287afdbdcb --- /dev/null +++ b/db/memtable.cc @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/memtable.h" +#include "db/dbformat.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "util/coding.h" + +namespace leveldb { + +static Slice GetLengthPrefixedSlice(const char* data) { + uint32_t len; + const char* p = data; + p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted + return Slice(p, len); +} + +MemTable::MemTable(const InternalKeyComparator& cmp) + : comparator_(cmp), + refs_(0), + table_(comparator_, &arena_) { +} + +MemTable::~MemTable() { + assert(refs_ == 0); +} + +size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); } + +int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr) + const { + // Internal keys are encoded as length-prefixed strings. + Slice a = GetLengthPrefixedSlice(aptr); + Slice b = GetLengthPrefixedSlice(bptr); + return comparator.Compare(a, b); +} + +// Encode a suitable internal key target for "target" and return it. +// Uses *scratch as scratch space, and the returned pointer will point +// into this scratch space. +static const char* EncodeKey(std::string* scratch, const Slice& target) { + scratch->clear(); + PutVarint32(scratch, target.size()); + scratch->append(target.data(), target.size()); + return scratch->data(); +} + +class MemTableIterator: public Iterator { + public: + explicit MemTableIterator(MemTable::Table* table) : iter_(table) { } + + virtual bool Valid() const { return iter_.Valid(); } + virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); } + virtual void SeekToFirst() { iter_.SeekToFirst(); } + virtual void SeekToLast() { iter_.SeekToLast(); } + virtual void Next() { iter_.Next(); } + virtual void Prev() { iter_.Prev(); } + virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); } + virtual Slice value() const { + Slice key_slice = GetLengthPrefixedSlice(iter_.key()); + return GetLengthPrefixedSlice(key_slice.data() + key_slice.size()); + } + + virtual Status status() const { return Status::OK(); } + + private: + MemTable::Table::Iterator iter_; + std::string tmp_; // For passing to EncodeKey + + // No copying allowed + MemTableIterator(const MemTableIterator&); + void operator=(const MemTableIterator&); +}; + +Iterator* MemTable::NewIterator() { + return new MemTableIterator(&table_); +} + +void MemTable::Add(SequenceNumber s, ValueType type, + const Slice& key, + const Slice& value) { + // Format of an entry is concatenation of: + // key_size : varint32 of internal_key.size() + // key bytes : char[internal_key.size()] + // value_size : varint32 of value.size() + // value bytes : char[value.size()] + size_t key_size = key.size(); + size_t val_size = value.size(); + size_t internal_key_size = key_size + 8; + const size_t encoded_len = + VarintLength(internal_key_size) + internal_key_size + + VarintLength(val_size) + val_size; + char* buf = arena_.Allocate(encoded_len); + char* p = EncodeVarint32(buf, internal_key_size); + memcpy(p, key.data(), key_size); + p += key_size; + EncodeFixed64(p, (s << 8) | type); + p += 8; + p = EncodeVarint32(p, val_size); + memcpy(p, value.data(), val_size); + assert(p + val_size == buf + encoded_len); + table_.Insert(buf); +} + +bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) { + Slice memkey = key.memtable_key(); + Table::Iterator iter(&table_); + iter.Seek(memkey.data()); + if (iter.Valid()) { + // entry format is: + // klength varint32 + // userkey char[klength] + // tag uint64 + // vlength varint32 + // value char[vlength] + // Check that it belongs to same user key. We do not check the + // sequence number since the Seek() call above should have skipped + // all entries with overly large sequence numbers. + const char* entry = iter.key(); + uint32_t key_length; + const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length); + if (comparator_.comparator.user_comparator()->Compare( + Slice(key_ptr, key_length - 8), + key.user_key()) == 0) { + // Correct user key + const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8); + switch (static_cast(tag & 0xff)) { + case kTypeValue: { + Slice v = GetLengthPrefixedSlice(key_ptr + key_length); + value->assign(v.data(), v.size()); + return true; + } + case kTypeDeletion: + *s = Status::NotFound(Slice()); + return true; + } + } + } + return false; +} + +} // namespace leveldb diff --git a/db/memtable.h b/db/memtable.h new file mode 100644 index 0000000000..9f41567cde --- /dev/null +++ b/db/memtable.h @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_ +#define STORAGE_LEVELDB_DB_MEMTABLE_H_ + +#include +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/skiplist.h" +#include "util/arena.h" + +namespace leveldb { + +class InternalKeyComparator; +class Mutex; +class MemTableIterator; + +class MemTable { + public: + // MemTables are reference counted. The initial reference count + // is zero and the caller must call Ref() at least once. + explicit MemTable(const InternalKeyComparator& comparator); + + // Increase reference count. + void Ref() { ++refs_; } + + // Drop reference count. Delete if no more references exist. + void Unref() { + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + delete this; + } + } + + // Returns an estimate of the number of bytes of data in use by this + // data structure. It is safe to call when MemTable is being modified. + size_t ApproximateMemoryUsage(); + + // Return an iterator that yields the contents of the memtable. + // + // The caller must ensure that the underlying MemTable remains live + // while the returned iterator is live. The keys returned by this + // iterator are internal keys encoded by AppendInternalKey in the + // db/format.{h,cc} module. + Iterator* NewIterator(); + + // Add an entry into memtable that maps key to value at the + // specified sequence number and with the specified type. + // Typically value will be empty if type==kTypeDeletion. + void Add(SequenceNumber seq, ValueType type, + const Slice& key, + const Slice& value); + + // If memtable contains a value for key, store it in *value and return true. + // If memtable contains a deletion for key, store a NotFound() error + // in *status and return true. + // Else, return false. + bool Get(const LookupKey& key, std::string* value, Status* s); + + private: + ~MemTable(); // Private since only Unref() should be used to delete it + + struct KeyComparator { + const InternalKeyComparator comparator; + explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { } + int operator()(const char* a, const char* b) const; + }; + friend class MemTableIterator; + friend class MemTableBackwardIterator; + + typedef SkipList Table; + + KeyComparator comparator_; + int refs_; + Arena arena_; + Table table_; + + // No copying allowed + MemTable(const MemTable&); + void operator=(const MemTable&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_ diff --git a/db/recovery_test.cc b/db/recovery_test.cc new file mode 100644 index 0000000000..9596f4288a --- /dev/null +++ b/db/recovery_test.cc @@ -0,0 +1,324 @@ +// Copyright (c) 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/db_impl.h" +#include "db/filename.h" +#include "db/version_set.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/write_batch.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class RecoveryTest { + public: + RecoveryTest() : env_(Env::Default()), db_(NULL) { + dbname_ = test::TmpDir() + "/recovery_test"; + DestroyDB(dbname_, Options()); + Open(); + } + + ~RecoveryTest() { + Close(); + DestroyDB(dbname_, Options()); + } + + DBImpl* dbfull() const { return reinterpret_cast(db_); } + Env* env() const { return env_; } + + bool CanAppend() { + WritableFile* tmp; + Status s = env_->NewAppendableFile(CurrentFileName(dbname_), &tmp); + delete tmp; + if (s.IsNotSupportedError()) { + return false; + } else { + return true; + } + } + + void Close() { + delete db_; + db_ = NULL; + } + + void Open(Options* options = NULL) { + Close(); + Options opts; + if (options != NULL) { + opts = *options; + } else { + opts.reuse_logs = true; // TODO(sanjay): test both ways + opts.create_if_missing = true; + } + if (opts.env == NULL) { + opts.env = env_; + } + ASSERT_OK(DB::Open(opts, dbname_, &db_)); + ASSERT_EQ(1, NumLogs()); + } + + Status Put(const std::string& k, const std::string& v) { + return db_->Put(WriteOptions(), k, v); + } + + std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { + std::string result; + Status s = db_->Get(ReadOptions(), k, &result); + if (s.IsNotFound()) { + result = "NOT_FOUND"; + } else if (!s.ok()) { + result = s.ToString(); + } + return result; + } + + std::string ManifestFileName() { + std::string current; + ASSERT_OK(ReadFileToString(env_, CurrentFileName(dbname_), ¤t)); + size_t len = current.size(); + if (len > 0 && current[len-1] == '\n') { + current.resize(len - 1); + } + return dbname_ + "/" + current; + } + + std::string LogName(uint64_t number) { + return LogFileName(dbname_, number); + } + + size_t DeleteLogFiles() { + std::vector logs = GetFiles(kLogFile); + for (size_t i = 0; i < logs.size(); i++) { + ASSERT_OK(env_->DeleteFile(LogName(logs[i]))) << LogName(logs[i]); + } + return logs.size(); + } + + uint64_t FirstLogFile() { + return GetFiles(kLogFile)[0]; + } + + std::vector GetFiles(FileType t) { + std::vector filenames; + ASSERT_OK(env_->GetChildren(dbname_, &filenames)); + std::vector result; + for (size_t i = 0; i < filenames.size(); i++) { + uint64_t number; + FileType type; + if (ParseFileName(filenames[i], &number, &type) && type == t) { + result.push_back(number); + } + } + return result; + } + + int NumLogs() { + return GetFiles(kLogFile).size(); + } + + int NumTables() { + return GetFiles(kTableFile).size(); + } + + uint64_t FileSize(const std::string& fname) { + uint64_t result; + ASSERT_OK(env_->GetFileSize(fname, &result)) << fname; + return result; + } + + void CompactMemTable() { + dbfull()->TEST_CompactMemTable(); + } + + // Directly construct a log file that sets key to val. + void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Slice val) { + std::string fname = LogFileName(dbname_, lognum); + WritableFile* file; + ASSERT_OK(env_->NewWritableFile(fname, &file)); + log::Writer writer(file); + WriteBatch batch; + batch.Put(key, val); + WriteBatchInternal::SetSequence(&batch, seq); + ASSERT_OK(writer.AddRecord(WriteBatchInternal::Contents(&batch))); + ASSERT_OK(file->Flush()); + delete file; + } + + private: + std::string dbname_; + Env* env_; + DB* db_; +}; + +TEST(RecoveryTest, ManifestReused) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + ASSERT_OK(Put("foo", "bar")); + Close(); + std::string old_manifest = ManifestFileName(); + Open(); + ASSERT_EQ(old_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); + Open(); + ASSERT_EQ(old_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(RecoveryTest, LargeManifestCompacted) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + ASSERT_OK(Put("foo", "bar")); + Close(); + std::string old_manifest = ManifestFileName(); + + // Pad with zeroes to make manifest file very big. + { + uint64_t len = FileSize(old_manifest); + WritableFile* file; + ASSERT_OK(env()->NewAppendableFile(old_manifest, &file)); + std::string zeroes(3*1048576 - static_cast(len), 0); + ASSERT_OK(file->Append(zeroes)); + ASSERT_OK(file->Flush()); + delete file; + } + + Open(); + std::string new_manifest = ManifestFileName(); + ASSERT_NE(old_manifest, new_manifest); + ASSERT_GT(10000, FileSize(new_manifest)); + ASSERT_EQ("bar", Get("foo")); + + Open(); + ASSERT_EQ(new_manifest, ManifestFileName()); + ASSERT_EQ("bar", Get("foo")); +} + +TEST(RecoveryTest, NoLogFiles) { + ASSERT_OK(Put("foo", "bar")); + ASSERT_EQ(1, DeleteLogFiles()); + Open(); + ASSERT_EQ("NOT_FOUND", Get("foo")); + Open(); + ASSERT_EQ("NOT_FOUND", Get("foo")); +} + +TEST(RecoveryTest, LogFileReuse) { + if (!CanAppend()) { + fprintf(stderr, "skipping test because env does not support appending\n"); + return; + } + for (int i = 0; i < 2; i++) { + ASSERT_OK(Put("foo", "bar")); + if (i == 0) { + // Compact to ensure current log is empty + CompactMemTable(); + } + Close(); + ASSERT_EQ(1, NumLogs()); + uint64_t number = FirstLogFile(); + if (i == 0) { + ASSERT_EQ(0, FileSize(LogName(number))); + } else { + ASSERT_LT(0, FileSize(LogName(number))); + } + Open(); + ASSERT_EQ(1, NumLogs()); + ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; + ASSERT_EQ("bar", Get("foo")); + Open(); + ASSERT_EQ(1, NumLogs()); + ASSERT_EQ(number, FirstLogFile()) << "did not reuse log file"; + ASSERT_EQ("bar", Get("foo")); + } +} + +TEST(RecoveryTest, MultipleMemTables) { + // Make a large log. + const int kNum = 1000; + for (int i = 0; i < kNum; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "%050d", i); + ASSERT_OK(Put(buf, buf)); + } + ASSERT_EQ(0, NumTables()); + Close(); + ASSERT_EQ(0, NumTables()); + ASSERT_EQ(1, NumLogs()); + uint64_t old_log_file = FirstLogFile(); + + // Force creation of multiple memtables by reducing the write buffer size. + Options opt; + opt.reuse_logs = true; + opt.write_buffer_size = (kNum*100) / 2; + Open(&opt); + ASSERT_LE(2, NumTables()); + ASSERT_EQ(1, NumLogs()); + ASSERT_NE(old_log_file, FirstLogFile()) << "must not reuse log"; + for (int i = 0; i < kNum; i++) { + char buf[100]; + snprintf(buf, sizeof(buf), "%050d", i); + ASSERT_EQ(buf, Get(buf)); + } +} + +TEST(RecoveryTest, MultipleLogFiles) { + ASSERT_OK(Put("foo", "bar")); + Close(); + ASSERT_EQ(1, NumLogs()); + + // Make a bunch of uncompacted log files. + uint64_t old_log = FirstLogFile(); + MakeLogFile(old_log+1, 1000, "hello", "world"); + MakeLogFile(old_log+2, 1001, "hi", "there"); + MakeLogFile(old_log+3, 1002, "foo", "bar2"); + + // Recover and check that all log files were processed. + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + uint64_t new_log = FirstLogFile(); + ASSERT_LE(old_log+3, new_log); + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); + + // Test that previous recovery produced recoverable state. + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + if (CanAppend()) { + ASSERT_EQ(new_log, FirstLogFile()); + } + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); + + // Check that introducing an older log file does not cause it to be re-read. + Close(); + MakeLogFile(old_log+1, 2000, "hello", "stale write"); + Open(); + ASSERT_LE(1, NumTables()); + ASSERT_EQ(1, NumLogs()); + if (CanAppend()) { + ASSERT_EQ(new_log, FirstLogFile()); + } + ASSERT_EQ("bar2", Get("foo")); + ASSERT_EQ("world", Get("hello")); + ASSERT_EQ("there", Get("hi")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/repair.cc b/db/repair.cc new file mode 100644 index 0000000000..7281e3d345 --- /dev/null +++ b/db/repair.cc @@ -0,0 +1,461 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// We recover the contents of the descriptor from the other files we find. +// (1) Any log files are first converted to tables +// (2) We scan every table to compute +// (a) smallest/largest for the table +// (b) largest sequence number in the table +// (3) We generate descriptor contents: +// - log number is set to zero +// - next-file-number is set to 1 + largest file number we found +// - last-sequence-number is set to largest sequence# found across +// all tables (see 2c) +// - compaction pointers are cleared +// - every table file is added at level 0 +// +// Possible optimization 1: +// (a) Compute total size and use to pick appropriate max-level M +// (b) Sort tables by largest sequence# in the table +// (c) For each table: if it overlaps earlier table, place in level-0, +// else place in level-M. +// Possible optimization 2: +// Store per-table metadata (smallest, largest, largest-seq#, ...) +// in the table's meta section to speed up ScanTable. + +#include "db/builder.h" +#include "db/db_impl.h" +#include "db/dbformat.h" +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "db/version_edit.h" +#include "db/write_batch_internal.h" +#include "leveldb/comparator.h" +#include "leveldb/db.h" +#include "leveldb/env.h" + +namespace leveldb { + +namespace { + +class Repairer { + public: + Repairer(const std::string& dbname, const Options& options) + : dbname_(dbname), + env_(options.env), + icmp_(options.comparator), + ipolicy_(options.filter_policy), + options_(SanitizeOptions(dbname, &icmp_, &ipolicy_, options)), + owns_info_log_(options_.info_log != options.info_log), + owns_cache_(options_.block_cache != options.block_cache), + next_file_number_(1) { + // TableCache can be small since we expect each table to be opened once. + table_cache_ = new TableCache(dbname_, &options_, 10); + } + + ~Repairer() { + delete table_cache_; + if (owns_info_log_) { + delete options_.info_log; + } + if (owns_cache_) { + delete options_.block_cache; + } + } + + Status Run() { + Status status = FindFiles(); + if (status.ok()) { + ConvertLogFilesToTables(); + ExtractMetaData(); + status = WriteDescriptor(); + } + if (status.ok()) { + unsigned long long bytes = 0; + for (size_t i = 0; i < tables_.size(); i++) { + bytes += tables_[i].meta.file_size; + } + Log(options_.info_log, + "**** Repaired leveldb %s; " + "recovered %d files; %llu bytes. " + "Some data may have been lost. " + "****", + dbname_.c_str(), + static_cast(tables_.size()), + bytes); + } + return status; + } + + private: + struct TableInfo { + FileMetaData meta; + SequenceNumber max_sequence; + }; + + std::string const dbname_; + Env* const env_; + InternalKeyComparator const icmp_; + InternalFilterPolicy const ipolicy_; + Options const options_; + bool owns_info_log_; + bool owns_cache_; + TableCache* table_cache_; + VersionEdit edit_; + + std::vector manifests_; + std::vector table_numbers_; + std::vector logs_; + std::vector tables_; + uint64_t next_file_number_; + + Status FindFiles() { + std::vector filenames; + Status status = env_->GetChildren(dbname_, &filenames); + if (!status.ok()) { + return status; + } + if (filenames.empty()) { + return Status::IOError(dbname_, "repair found no files"); + } + + uint64_t number; + FileType type; + for (size_t i = 0; i < filenames.size(); i++) { + if (ParseFileName(filenames[i], &number, &type)) { + if (type == kDescriptorFile) { + manifests_.push_back(filenames[i]); + } else { + if (number + 1 > next_file_number_) { + next_file_number_ = number + 1; + } + if (type == kLogFile) { + logs_.push_back(number); + } else if (type == kTableFile) { + table_numbers_.push_back(number); + } else { + // Ignore other files + } + } + } + } + return status; + } + + void ConvertLogFilesToTables() { + for (size_t i = 0; i < logs_.size(); i++) { + std::string logname = LogFileName(dbname_, logs_[i]); + Status status = ConvertLogToTable(logs_[i]); + if (!status.ok()) { + Log(options_.info_log, "Log #%llu: ignoring conversion error: %s", + (unsigned long long) logs_[i], + status.ToString().c_str()); + } + ArchiveFile(logname); + } + } + + Status ConvertLogToTable(uint64_t log) { + struct LogReporter : public log::Reader::Reporter { + Env* env; + Logger* info_log; + uint64_t lognum; + virtual void Corruption(size_t bytes, const Status& s) { + // We print error messages for corruption, but continue repairing. + Log(info_log, "Log #%llu: dropping %d bytes; %s", + (unsigned long long) lognum, + static_cast(bytes), + s.ToString().c_str()); + } + }; + + // Open the log file + std::string logname = LogFileName(dbname_, log); + SequentialFile* lfile; + Status status = env_->NewSequentialFile(logname, &lfile); + if (!status.ok()) { + return status; + } + + // Create the log reader. + LogReporter reporter; + reporter.env = env_; + reporter.info_log = options_.info_log; + reporter.lognum = log; + // We intentionally make log::Reader do checksumming so that + // corruptions cause entire commits to be skipped instead of + // propagating bad information (like overly large sequence + // numbers). + log::Reader reader(lfile, &reporter, false/*do not checksum*/, + 0/*initial_offset*/); + + // Read all the records and add to a memtable + std::string scratch; + Slice record; + WriteBatch batch; + MemTable* mem = new MemTable(icmp_); + mem->Ref(); + int counter = 0; + while (reader.ReadRecord(&record, &scratch)) { + if (record.size() < 12) { + reporter.Corruption( + record.size(), Status::Corruption("log record too small", logname)); + continue; + } + WriteBatchInternal::SetContents(&batch, record); + status = WriteBatchInternal::InsertInto(&batch, mem); + if (status.ok()) { + counter += WriteBatchInternal::Count(&batch); + } else { + Log(options_.info_log, "Log #%llu: ignoring %s", + (unsigned long long) log, + status.ToString().c_str()); + status = Status::OK(); // Keep going with rest of file + } + } + delete lfile; + + // Do not record a version edit for this conversion to a Table + // since ExtractMetaData() will also generate edits. + FileMetaData meta; + meta.number = next_file_number_++; + Iterator* iter = mem->NewIterator(); + status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta); + delete iter; + mem->Unref(); + mem = NULL; + if (status.ok()) { + if (meta.file_size > 0) { + table_numbers_.push_back(meta.number); + } + } + Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s", + (unsigned long long) log, + counter, + (unsigned long long) meta.number, + status.ToString().c_str()); + return status; + } + + void ExtractMetaData() { + for (size_t i = 0; i < table_numbers_.size(); i++) { + ScanTable(table_numbers_[i]); + } + } + + Iterator* NewTableIterator(const FileMetaData& meta) { + // Same as compaction iterators: if paranoid_checks are on, turn + // on checksum verification. + ReadOptions r; + r.verify_checksums = options_.paranoid_checks; + return table_cache_->NewIterator(r, meta.number, meta.file_size); + } + + void ScanTable(uint64_t number) { + TableInfo t; + t.meta.number = number; + std::string fname = TableFileName(dbname_, number); + Status status = env_->GetFileSize(fname, &t.meta.file_size); + if (!status.ok()) { + // Try alternate file name. + fname = SSTTableFileName(dbname_, number); + Status s2 = env_->GetFileSize(fname, &t.meta.file_size); + if (s2.ok()) { + status = Status::OK(); + } + } + if (!status.ok()) { + ArchiveFile(TableFileName(dbname_, number)); + ArchiveFile(SSTTableFileName(dbname_, number)); + Log(options_.info_log, "Table #%llu: dropped: %s", + (unsigned long long) t.meta.number, + status.ToString().c_str()); + return; + } + + // Extract metadata by scanning through table. + int counter = 0; + Iterator* iter = NewTableIterator(t.meta); + bool empty = true; + ParsedInternalKey parsed; + t.max_sequence = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + Slice key = iter->key(); + if (!ParseInternalKey(key, &parsed)) { + Log(options_.info_log, "Table #%llu: unparsable key %s", + (unsigned long long) t.meta.number, + EscapeString(key).c_str()); + continue; + } + + counter++; + if (empty) { + empty = false; + t.meta.smallest.DecodeFrom(key); + } + t.meta.largest.DecodeFrom(key); + if (parsed.sequence > t.max_sequence) { + t.max_sequence = parsed.sequence; + } + } + if (!iter->status().ok()) { + status = iter->status(); + } + delete iter; + Log(options_.info_log, "Table #%llu: %d entries %s", + (unsigned long long) t.meta.number, + counter, + status.ToString().c_str()); + + if (status.ok()) { + tables_.push_back(t); + } else { + RepairTable(fname, t); // RepairTable archives input file. + } + } + + void RepairTable(const std::string& src, TableInfo t) { + // We will copy src contents to a new table and then rename the + // new table over the source. + + // Create builder. + std::string copy = TableFileName(dbname_, next_file_number_++); + WritableFile* file; + Status s = env_->NewWritableFile(copy, &file); + if (!s.ok()) { + return; + } + TableBuilder* builder = new TableBuilder(options_, file); + + // Copy data. + Iterator* iter = NewTableIterator(t.meta); + int counter = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + builder->Add(iter->key(), iter->value()); + counter++; + } + delete iter; + + ArchiveFile(src); + if (counter == 0) { + builder->Abandon(); // Nothing to save + } else { + s = builder->Finish(); + if (s.ok()) { + t.meta.file_size = builder->FileSize(); + } + } + delete builder; + builder = NULL; + + if (s.ok()) { + s = file->Close(); + } + delete file; + file = NULL; + + if (counter > 0 && s.ok()) { + std::string orig = TableFileName(dbname_, t.meta.number); + s = env_->RenameFile(copy, orig); + if (s.ok()) { + Log(options_.info_log, "Table #%llu: %d entries repaired", + (unsigned long long) t.meta.number, counter); + tables_.push_back(t); + } + } + if (!s.ok()) { + env_->DeleteFile(copy); + } + } + + Status WriteDescriptor() { + std::string tmp = TempFileName(dbname_, 1); + WritableFile* file; + Status status = env_->NewWritableFile(tmp, &file); + if (!status.ok()) { + return status; + } + + SequenceNumber max_sequence = 0; + for (size_t i = 0; i < tables_.size(); i++) { + if (max_sequence < tables_[i].max_sequence) { + max_sequence = tables_[i].max_sequence; + } + } + + edit_.SetComparatorName(icmp_.user_comparator()->Name()); + edit_.SetLogNumber(0); + edit_.SetNextFile(next_file_number_); + edit_.SetLastSequence(max_sequence); + + for (size_t i = 0; i < tables_.size(); i++) { + // TODO(opt): separate out into multiple levels + const TableInfo& t = tables_[i]; + edit_.AddFile(0, t.meta.number, t.meta.file_size, + t.meta.smallest, t.meta.largest); + } + + //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str()); + { + log::Writer log(file); + std::string record; + edit_.EncodeTo(&record); + status = log.AddRecord(record); + } + if (status.ok()) { + status = file->Close(); + } + delete file; + file = NULL; + + if (!status.ok()) { + env_->DeleteFile(tmp); + } else { + // Discard older manifests + for (size_t i = 0; i < manifests_.size(); i++) { + ArchiveFile(dbname_ + "/" + manifests_[i]); + } + + // Install new manifest + status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1)); + if (status.ok()) { + status = SetCurrentFile(env_, dbname_, 1); + } else { + env_->DeleteFile(tmp); + } + } + return status; + } + + void ArchiveFile(const std::string& fname) { + // Move into another directory. E.g., for + // dir/foo + // rename to + // dir/lost/foo + const char* slash = strrchr(fname.c_str(), '/'); + std::string new_dir; + if (slash != NULL) { + new_dir.assign(fname.data(), slash - fname.data()); + } + new_dir.append("/lost"); + env_->CreateDir(new_dir); // Ignore error + std::string new_file = new_dir; + new_file.append("/"); + new_file.append((slash == NULL) ? fname.c_str() : slash + 1); + Status s = env_->RenameFile(fname, new_file); + Log(options_.info_log, "Archiving %s: %s\n", + fname.c_str(), s.ToString().c_str()); + } +}; +} // namespace + +Status RepairDB(const std::string& dbname, const Options& options) { + Repairer repairer(dbname, options); + return repairer.Run(); +} + +} // namespace leveldb diff --git a/db/skiplist.h b/db/skiplist.h new file mode 100644 index 0000000000..8bd77764d8 --- /dev/null +++ b/db/skiplist.h @@ -0,0 +1,384 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_ +#define STORAGE_LEVELDB_DB_SKIPLIST_H_ + +// Thread safety +// ------------- +// +// Writes require external synchronization, most likely a mutex. +// Reads require a guarantee that the SkipList will not be destroyed +// while the read is in progress. Apart from that, reads progress +// without any internal locking or synchronization. +// +// Invariants: +// +// (1) Allocated nodes are never deleted until the SkipList is +// destroyed. This is trivially guaranteed by the code since we +// never delete any skip list nodes. +// +// (2) The contents of a Node except for the next/prev pointers are +// immutable after the Node has been linked into the SkipList. +// Only Insert() modifies the list, and it is careful to initialize +// a node and use release-stores to publish the nodes in one or +// more lists. +// +// ... prev vs. next pointer ordering ... + +#include +#include +#include "port/port.h" +#include "util/arena.h" +#include "util/random.h" + +namespace leveldb { + +class Arena; + +template +class SkipList { + private: + struct Node; + + public: + // Create a new SkipList object that will use "cmp" for comparing keys, + // and will allocate memory using "*arena". Objects allocated in the arena + // must remain allocated for the lifetime of the skiplist object. + explicit SkipList(Comparator cmp, Arena* arena); + + // Insert key into the list. + // REQUIRES: nothing that compares equal to key is currently in the list. + void Insert(const Key& key); + + // Returns true iff an entry that compares equal to key is in the list. + bool Contains(const Key& key) const; + + // Iteration over the contents of a skip list + class Iterator { + public: + // Initialize an iterator over the specified list. + // The returned iterator is not valid. + explicit Iterator(const SkipList* list); + + // Returns true iff the iterator is positioned at a valid node. + bool Valid() const; + + // Returns the key at the current position. + // REQUIRES: Valid() + const Key& key() const; + + // Advances to the next position. + // REQUIRES: Valid() + void Next(); + + // Advances to the previous position. + // REQUIRES: Valid() + void Prev(); + + // Advance to the first entry with a key >= target + void Seek(const Key& target); + + // Position at the first entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToFirst(); + + // Position at the last entry in list. + // Final state of iterator is Valid() iff list is not empty. + void SeekToLast(); + + private: + const SkipList* list_; + Node* node_; + // Intentionally copyable + }; + + private: + enum { kMaxHeight = 12 }; + + // Immutable after construction + Comparator const compare_; + Arena* const arena_; // Arena used for allocations of nodes + + Node* const head_; + + // Modified only by Insert(). Read racily by readers, but stale + // values are ok. + port::AtomicPointer max_height_; // Height of the entire list + + inline int GetMaxHeight() const { + return static_cast( + reinterpret_cast(max_height_.NoBarrier_Load())); + } + + // Read/written only by Insert(). + Random rnd_; + + Node* NewNode(const Key& key, int height); + int RandomHeight(); + bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } + + // Return true if key is greater than the data stored in "n" + bool KeyIsAfterNode(const Key& key, Node* n) const; + + // Return the earliest node that comes at or after key. + // Return NULL if there is no such node. + // + // If prev is non-NULL, fills prev[level] with pointer to previous + // node at "level" for every level in [0..max_height_-1]. + Node* FindGreaterOrEqual(const Key& key, Node** prev) const; + + // Return the latest node with a key < key. + // Return head_ if there is no such node. + Node* FindLessThan(const Key& key) const; + + // Return the last node in the list. + // Return head_ if list is empty. + Node* FindLast() const; + + // No copying allowed + SkipList(const SkipList&); + void operator=(const SkipList&); +}; + +// Implementation details follow +template +struct SkipList::Node { + explicit Node(const Key& k) : key(k) { } + + Key const key; + + // Accessors/mutators for links. Wrapped in methods so we can + // add the appropriate barriers as necessary. + Node* Next(int n) { + assert(n >= 0); + // Use an 'acquire load' so that we observe a fully initialized + // version of the returned Node. + return reinterpret_cast(next_[n].Acquire_Load()); + } + void SetNext(int n, Node* x) { + assert(n >= 0); + // Use a 'release store' so that anybody who reads through this + // pointer observes a fully initialized version of the inserted node. + next_[n].Release_Store(x); + } + + // No-barrier variants that can be safely used in a few locations. + Node* NoBarrier_Next(int n) { + assert(n >= 0); + return reinterpret_cast(next_[n].NoBarrier_Load()); + } + void NoBarrier_SetNext(int n, Node* x) { + assert(n >= 0); + next_[n].NoBarrier_Store(x); + } + + private: + // Array of length equal to the node height. next_[0] is lowest level link. + port::AtomicPointer next_[1]; +}; + +template +typename SkipList::Node* +SkipList::NewNode(const Key& key, int height) { + char* mem = arena_->AllocateAligned( + sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); + return new (mem) Node(key); +} + +template +inline SkipList::Iterator::Iterator(const SkipList* list) { + list_ = list; + node_ = NULL; +} + +template +inline bool SkipList::Iterator::Valid() const { + return node_ != NULL; +} + +template +inline const Key& SkipList::Iterator::key() const { + assert(Valid()); + return node_->key; +} + +template +inline void SkipList::Iterator::Next() { + assert(Valid()); + node_ = node_->Next(0); +} + +template +inline void SkipList::Iterator::Prev() { + // Instead of using explicit "prev" links, we just search for the + // last node that falls before key. + assert(Valid()); + node_ = list_->FindLessThan(node_->key); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +inline void SkipList::Iterator::Seek(const Key& target) { + node_ = list_->FindGreaterOrEqual(target, NULL); +} + +template +inline void SkipList::Iterator::SeekToFirst() { + node_ = list_->head_->Next(0); +} + +template +inline void SkipList::Iterator::SeekToLast() { + node_ = list_->FindLast(); + if (node_ == list_->head_) { + node_ = NULL; + } +} + +template +int SkipList::RandomHeight() { + // Increase height with probability 1 in kBranching + static const unsigned int kBranching = 4; + int height = 1; + while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { + height++; + } + assert(height > 0); + assert(height <= kMaxHeight); + return height; +} + +template +bool SkipList::KeyIsAfterNode(const Key& key, Node* n) const { + // NULL n is considered infinite + return (n != NULL) && (compare_(n->key, key) < 0); +} + +template +typename SkipList::Node* SkipList::FindGreaterOrEqual(const Key& key, Node** prev) + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (KeyIsAfterNode(key, next)) { + // Keep searching in this list + x = next; + } else { + if (prev != NULL) prev[level] = x; + if (level == 0) { + return next; + } else { + // Switch to next list + level--; + } + } + } +} + +template +typename SkipList::Node* +SkipList::FindLessThan(const Key& key) const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + assert(x == head_ || compare_(x->key, key) < 0); + Node* next = x->Next(level); + if (next == NULL || compare_(next->key, key) >= 0) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +typename SkipList::Node* SkipList::FindLast() + const { + Node* x = head_; + int level = GetMaxHeight() - 1; + while (true) { + Node* next = x->Next(level); + if (next == NULL) { + if (level == 0) { + return x; + } else { + // Switch to next list + level--; + } + } else { + x = next; + } + } +} + +template +SkipList::SkipList(Comparator cmp, Arena* arena) + : compare_(cmp), + arena_(arena), + head_(NewNode(0 /* any key will do */, kMaxHeight)), + max_height_(reinterpret_cast(1)), + rnd_(0xdeadbeef) { + for (int i = 0; i < kMaxHeight; i++) { + head_->SetNext(i, NULL); + } +} + +template +void SkipList::Insert(const Key& key) { + // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() + // here since Insert() is externally synchronized. + Node* prev[kMaxHeight]; + Node* x = FindGreaterOrEqual(key, prev); + + // Our data structure does not allow duplicate insertion + assert(x == NULL || !Equal(key, x->key)); + + int height = RandomHeight(); + if (height > GetMaxHeight()) { + for (int i = GetMaxHeight(); i < height; i++) { + prev[i] = head_; + } + //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); + + // It is ok to mutate max_height_ without any synchronization + // with concurrent readers. A concurrent reader that observes + // the new value of max_height_ will see either the old value of + // new level pointers from head_ (NULL), or a new value set in + // the loop below. In the former case the reader will + // immediately drop to the next level since NULL sorts after all + // keys. In the latter case the reader will use the new node. + max_height_.NoBarrier_Store(reinterpret_cast(height)); + } + + x = NewNode(key, height); + for (int i = 0; i < height; i++) { + // NoBarrier_SetNext() suffices since we will add a barrier when + // we publish a pointer to "x" in prev[i]. + x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); + prev[i]->SetNext(i, x); + } +} + +template +bool SkipList::Contains(const Key& key) const { + Node* x = FindGreaterOrEqual(key, NULL); + if (x != NULL && Equal(key, x->key)) { + return true; + } else { + return false; + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_ diff --git a/db/skiplist_test.cc b/db/skiplist_test.cc new file mode 100644 index 0000000000..aee1461e1b --- /dev/null +++ b/db/skiplist_test.cc @@ -0,0 +1,378 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/skiplist.h" +#include +#include "leveldb/env.h" +#include "util/arena.h" +#include "util/hash.h" +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +typedef uint64_t Key; + +struct Comparator { + int operator()(const Key& a, const Key& b) const { + if (a < b) { + return -1; + } else if (a > b) { + return +1; + } else { + return 0; + } + } +}; + +class SkipTest { }; + +TEST(SkipTest, Empty) { + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + ASSERT_TRUE(!list.Contains(10)); + + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToFirst(); + ASSERT_TRUE(!iter.Valid()); + iter.Seek(100); + ASSERT_TRUE(!iter.Valid()); + iter.SeekToLast(); + ASSERT_TRUE(!iter.Valid()); +} + +TEST(SkipTest, InsertAndLookup) { + const int N = 2000; + const int R = 5000; + Random rnd(1000); + std::set keys; + Arena arena; + Comparator cmp; + SkipList list(cmp, &arena); + for (int i = 0; i < N; i++) { + Key key = rnd.Next() % R; + if (keys.insert(key).second) { + list.Insert(key); + } + } + + for (int i = 0; i < R; i++) { + if (list.Contains(i)) { + ASSERT_EQ(keys.count(i), 1); + } else { + ASSERT_EQ(keys.count(i), 0); + } + } + + // Simple iterator tests + { + SkipList::Iterator iter(&list); + ASSERT_TRUE(!iter.Valid()); + + iter.Seek(0); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToFirst(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.begin()), iter.key()); + + iter.SeekToLast(); + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*(keys.rbegin()), iter.key()); + } + + // Forward iteration test + for (int i = 0; i < R; i++) { + SkipList::Iterator iter(&list); + iter.Seek(i); + + // Compare against model iterator + std::set::iterator model_iter = keys.lower_bound(i); + for (int j = 0; j < 3; j++) { + if (model_iter == keys.end()) { + ASSERT_TRUE(!iter.Valid()); + break; + } else { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + ++model_iter; + iter.Next(); + } + } + } + + // Backward iteration test + { + SkipList::Iterator iter(&list); + iter.SeekToLast(); + + // Compare against model iterator + for (std::set::reverse_iterator model_iter = keys.rbegin(); + model_iter != keys.rend(); + ++model_iter) { + ASSERT_TRUE(iter.Valid()); + ASSERT_EQ(*model_iter, iter.key()); + iter.Prev(); + } + ASSERT_TRUE(!iter.Valid()); + } +} + +// We want to make sure that with a single writer and multiple +// concurrent readers (with no synchronization other than when a +// reader's iterator is created), the reader always observes all the +// data that was present in the skip list when the iterator was +// constructor. Because insertions are happening concurrently, we may +// also observe new values that were inserted since the iterator was +// constructed, but we should never miss any values that were present +// at iterator construction time. +// +// We generate multi-part keys: +// +// where: +// key is in range [0..K-1] +// gen is a generation number for key +// hash is hash(key,gen) +// +// The insertion code picks a random key, sets gen to be 1 + the last +// generation number inserted for that key, and sets hash to Hash(key,gen). +// +// At the beginning of a read, we snapshot the last inserted +// generation number for each key. We then iterate, including random +// calls to Next() and Seek(). For every key we encounter, we +// check that it is either expected given the initial snapshot or has +// been concurrently added since the iterator started. +class ConcurrentTest { + private: + static const uint32_t K = 4; + + static uint64_t key(Key key) { return (key >> 40); } + static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; } + static uint64_t hash(Key key) { return key & 0xff; } + + static uint64_t HashNumbers(uint64_t k, uint64_t g) { + uint64_t data[2] = { k, g }; + return Hash(reinterpret_cast(data), sizeof(data), 0); + } + + static Key MakeKey(uint64_t k, uint64_t g) { + assert(sizeof(Key) == sizeof(uint64_t)); + assert(k <= K); // We sometimes pass K to seek to the end of the skiplist + assert(g <= 0xffffffffu); + return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff)); + } + + static bool IsValidKey(Key k) { + return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff); + } + + static Key RandomTarget(Random* rnd) { + switch (rnd->Next() % 10) { + case 0: + // Seek to beginning + return MakeKey(0, 0); + case 1: + // Seek to end + return MakeKey(K, 0); + default: + // Seek to middle + return MakeKey(rnd->Next() % K, 0); + } + } + + // Per-key generation + struct State { + port::AtomicPointer generation[K]; + void Set(int k, intptr_t v) { + generation[k].Release_Store(reinterpret_cast(v)); + } + intptr_t Get(int k) { + return reinterpret_cast(generation[k].Acquire_Load()); + } + + State() { + for (int k = 0; k < K; k++) { + Set(k, 0); + } + } + }; + + // Current state of the test + State current_; + + Arena arena_; + + // SkipList is not protected by mu_. We just use a single writer + // thread to modify it. + SkipList list_; + + public: + ConcurrentTest() : list_(Comparator(), &arena_) { } + + // REQUIRES: External synchronization + void WriteStep(Random* rnd) { + const uint32_t k = rnd->Next() % K; + const intptr_t g = current_.Get(k) + 1; + const Key key = MakeKey(k, g); + list_.Insert(key); + current_.Set(k, g); + } + + void ReadStep(Random* rnd) { + // Remember the initial committed state of the skiplist. + State initial_state; + for (int k = 0; k < K; k++) { + initial_state.Set(k, current_.Get(k)); + } + + Key pos = RandomTarget(rnd); + SkipList::Iterator iter(&list_); + iter.Seek(pos); + while (true) { + Key current; + if (!iter.Valid()) { + current = MakeKey(K, 0); + } else { + current = iter.key(); + ASSERT_TRUE(IsValidKey(current)) << current; + } + ASSERT_LE(pos, current) << "should not go backwards"; + + // Verify that everything in [pos,current) was not present in + // initial_state. + while (pos < current) { + ASSERT_LT(key(pos), K) << pos; + + // Note that generation 0 is never inserted, so it is ok if + // <*,0,*> is missing. + ASSERT_TRUE((gen(pos) == 0) || + (gen(pos) > static_cast(initial_state.Get(key(pos)))) + ) << "key: " << key(pos) + << "; gen: " << gen(pos) + << "; initgen: " + << initial_state.Get(key(pos)); + + // Advance to next key in the valid key space + if (key(pos) < key(current)) { + pos = MakeKey(key(pos) + 1, 0); + } else { + pos = MakeKey(key(pos), gen(pos) + 1); + } + } + + if (!iter.Valid()) { + break; + } + + if (rnd->Next() % 2) { + iter.Next(); + pos = MakeKey(key(pos), gen(pos) + 1); + } else { + Key new_target = RandomTarget(rnd); + if (new_target > pos) { + pos = new_target; + iter.Seek(new_target); + } + } + } + } +}; +const uint32_t ConcurrentTest::K; + +// Simple test that does single-threaded testing of the ConcurrentTest +// scaffolding. +TEST(SkipTest, ConcurrentWithoutThreads) { + ConcurrentTest test; + Random rnd(test::RandomSeed()); + for (int i = 0; i < 10000; i++) { + test.ReadStep(&rnd); + test.WriteStep(&rnd); + } +} + +class TestState { + public: + ConcurrentTest t_; + int seed_; + port::AtomicPointer quit_flag_; + + enum ReaderState { + STARTING, + RUNNING, + DONE + }; + + explicit TestState(int s) + : seed_(s), + quit_flag_(NULL), + state_(STARTING), + state_cv_(&mu_) {} + + void Wait(ReaderState s) { + mu_.Lock(); + while (state_ != s) { + state_cv_.Wait(); + } + mu_.Unlock(); + } + + void Change(ReaderState s) { + mu_.Lock(); + state_ = s; + state_cv_.Signal(); + mu_.Unlock(); + } + + private: + port::Mutex mu_; + ReaderState state_; + port::CondVar state_cv_; +}; + +static void ConcurrentReader(void* arg) { + TestState* state = reinterpret_cast(arg); + Random rnd(state->seed_); + int64_t reads = 0; + state->Change(TestState::RUNNING); + while (!state->quit_flag_.Acquire_Load()) { + state->t_.ReadStep(&rnd); + ++reads; + } + state->Change(TestState::DONE); +} + +static void RunConcurrent(int run) { + const int seed = test::RandomSeed() + (run * 100); + Random rnd(seed); + const int N = 1000; + const int kSize = 1000; + for (int i = 0; i < N; i++) { + if ((i % 100) == 0) { + fprintf(stderr, "Run %d of %d\n", i, N); + } + TestState state(seed + 1); + Env::Default()->Schedule(ConcurrentReader, &state); + state.Wait(TestState::RUNNING); + for (int i = 0; i < kSize; i++) { + state.t_.WriteStep(&rnd); + } + state.quit_flag_.Release_Store(&state); // Any non-NULL arg will do + state.Wait(TestState::DONE); + } +} + +TEST(SkipTest, Concurrent1) { RunConcurrent(1); } +TEST(SkipTest, Concurrent2) { RunConcurrent(2); } +TEST(SkipTest, Concurrent3) { RunConcurrent(3); } +TEST(SkipTest, Concurrent4) { RunConcurrent(4); } +TEST(SkipTest, Concurrent5) { RunConcurrent(5); } + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/snapshot.h b/db/snapshot.h new file mode 100644 index 0000000000..6ed413c42d --- /dev/null +++ b/db/snapshot.h @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_ +#define STORAGE_LEVELDB_DB_SNAPSHOT_H_ + +#include "db/dbformat.h" +#include "leveldb/db.h" + +namespace leveldb { + +class SnapshotList; + +// Snapshots are kept in a doubly-linked list in the DB. +// Each SnapshotImpl corresponds to a particular sequence number. +class SnapshotImpl : public Snapshot { + public: + SequenceNumber number_; // const after creation + + private: + friend class SnapshotList; + + // SnapshotImpl is kept in a doubly-linked circular list + SnapshotImpl* prev_; + SnapshotImpl* next_; + + SnapshotList* list_; // just for sanity checks +}; + +class SnapshotList { + public: + SnapshotList() { + list_.prev_ = &list_; + list_.next_ = &list_; + } + + bool empty() const { return list_.next_ == &list_; } + SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; } + SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; } + + const SnapshotImpl* New(SequenceNumber seq) { + SnapshotImpl* s = new SnapshotImpl; + s->number_ = seq; + s->list_ = this; + s->next_ = &list_; + s->prev_ = list_.prev_; + s->prev_->next_ = s; + s->next_->prev_ = s; + return s; + } + + void Delete(const SnapshotImpl* s) { + assert(s->list_ == this); + s->prev_->next_ = s->next_; + s->next_->prev_ = s->prev_; + delete s; + } + + private: + // Dummy head of doubly-linked list of snapshots + SnapshotImpl list_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_ diff --git a/db/table_cache.cc b/db/table_cache.cc new file mode 100644 index 0000000000..e3d82cd3ea --- /dev/null +++ b/db/table_cache.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/table_cache.h" + +#include "db/filename.h" +#include "leveldb/env.h" +#include "leveldb/table.h" +#include "util/coding.h" + +namespace leveldb { + +struct TableAndFile { + RandomAccessFile* file; + Table* table; +}; + +static void DeleteEntry(const Slice& key, void* value) { + TableAndFile* tf = reinterpret_cast(value); + delete tf->table; + delete tf->file; + delete tf; +} + +static void UnrefEntry(void* arg1, void* arg2) { + Cache* cache = reinterpret_cast(arg1); + Cache::Handle* h = reinterpret_cast(arg2); + cache->Release(h); +} + +TableCache::TableCache(const std::string& dbname, + const Options* options, + int entries) + : env_(options->env), + dbname_(dbname), + options_(options), + cache_(NewLRUCache(entries)) { +} + +TableCache::~TableCache() { + delete cache_; +} + +Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, + Cache::Handle** handle) { + Status s; + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + Slice key(buf, sizeof(buf)); + *handle = cache_->Lookup(key); + if (*handle == NULL) { + std::string fname = TableFileName(dbname_, file_number); + RandomAccessFile* file = NULL; + Table* table = NULL; + s = env_->NewRandomAccessFile(fname, &file); + if (!s.ok()) { + std::string old_fname = SSTTableFileName(dbname_, file_number); + if (env_->NewRandomAccessFile(old_fname, &file).ok()) { + s = Status::OK(); + } + } + if (s.ok()) { + s = Table::Open(*options_, file, file_size, &table); + } + + if (!s.ok()) { + assert(table == NULL); + delete file; + // We do not cache error results so that if the error is transient, + // or somebody repairs the file, we recover automatically. + } else { + TableAndFile* tf = new TableAndFile; + tf->file = file; + tf->table = table; + *handle = cache_->Insert(key, tf, 1, &DeleteEntry); + } + } + return s; +} + +Iterator* TableCache::NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr) { + if (tableptr != NULL) { + *tableptr = NULL; + } + + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (!s.ok()) { + return NewErrorIterator(s); + } + + Table* table = reinterpret_cast(cache_->Value(handle))->table; + Iterator* result = table->NewIterator(options); + result->RegisterCleanup(&UnrefEntry, cache_, handle); + if (tableptr != NULL) { + *tableptr = table; + } + return result; +} + +Status TableCache::Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Cache::Handle* handle = NULL; + Status s = FindTable(file_number, file_size, &handle); + if (s.ok()) { + Table* t = reinterpret_cast(cache_->Value(handle))->table; + s = t->InternalGet(options, k, arg, saver); + cache_->Release(handle); + } + return s; +} + +void TableCache::Evict(uint64_t file_number) { + char buf[sizeof(file_number)]; + EncodeFixed64(buf, file_number); + cache_->Erase(Slice(buf, sizeof(buf))); +} + +} // namespace leveldb diff --git a/db/table_cache.h b/db/table_cache.h new file mode 100644 index 0000000000..8cf4aaf12d --- /dev/null +++ b/db/table_cache.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Thread-safe (provides internal synchronization) + +#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_ +#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_ + +#include +#include +#include "db/dbformat.h" +#include "leveldb/cache.h" +#include "leveldb/table.h" +#include "port/port.h" + +namespace leveldb { + +class Env; + +class TableCache { + public: + TableCache(const std::string& dbname, const Options* options, int entries); + ~TableCache(); + + // Return an iterator for the specified file number (the corresponding + // file length must be exactly "file_size" bytes). If "tableptr" is + // non-NULL, also sets "*tableptr" to point to the Table object + // underlying the returned iterator, or NULL if no Table object underlies + // the returned iterator. The returned "*tableptr" object is owned by + // the cache and should not be deleted, and is valid for as long as the + // returned iterator is live. + Iterator* NewIterator(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + Table** tableptr = NULL); + + // If a seek to internal key "k" in specified file finds an entry, + // call (*handle_result)(arg, found_key, found_value). + Status Get(const ReadOptions& options, + uint64_t file_number, + uint64_t file_size, + const Slice& k, + void* arg, + void (*handle_result)(void*, const Slice&, const Slice&)); + + // Evict any entry for the specified file number + void Evict(uint64_t file_number); + + private: + Env* const env_; + const std::string dbname_; + const Options* options_; + Cache* cache_; + + Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_ diff --git a/db/version_edit.cc b/db/version_edit.cc new file mode 100644 index 0000000000..f10a2d58b2 --- /dev/null +++ b/db/version_edit.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" + +#include "db/version_set.h" +#include "util/coding.h" + +namespace leveldb { + +// Tag numbers for serialized VersionEdit. These numbers are written to +// disk and should not be changed. +enum Tag { + kComparator = 1, + kLogNumber = 2, + kNextFileNumber = 3, + kLastSequence = 4, + kCompactPointer = 5, + kDeletedFile = 6, + kNewFile = 7, + // 8 was used for large value refs + kPrevLogNumber = 9 +}; + +void VersionEdit::Clear() { + comparator_.clear(); + log_number_ = 0; + prev_log_number_ = 0; + last_sequence_ = 0; + next_file_number_ = 0; + has_comparator_ = false; + has_log_number_ = false; + has_prev_log_number_ = false; + has_next_file_number_ = false; + has_last_sequence_ = false; + deleted_files_.clear(); + new_files_.clear(); +} + +void VersionEdit::EncodeTo(std::string* dst) const { + if (has_comparator_) { + PutVarint32(dst, kComparator); + PutLengthPrefixedSlice(dst, comparator_); + } + if (has_log_number_) { + PutVarint32(dst, kLogNumber); + PutVarint64(dst, log_number_); + } + if (has_prev_log_number_) { + PutVarint32(dst, kPrevLogNumber); + PutVarint64(dst, prev_log_number_); + } + if (has_next_file_number_) { + PutVarint32(dst, kNextFileNumber); + PutVarint64(dst, next_file_number_); + } + if (has_last_sequence_) { + PutVarint32(dst, kLastSequence); + PutVarint64(dst, last_sequence_); + } + + for (size_t i = 0; i < compact_pointers_.size(); i++) { + PutVarint32(dst, kCompactPointer); + PutVarint32(dst, compact_pointers_[i].first); // level + PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode()); + } + + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + PutVarint32(dst, kDeletedFile); + PutVarint32(dst, iter->first); // level + PutVarint64(dst, iter->second); // file number + } + + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + PutVarint32(dst, kNewFile); + PutVarint32(dst, new_files_[i].first); // level + PutVarint64(dst, f.number); + PutVarint64(dst, f.file_size); + PutLengthPrefixedSlice(dst, f.smallest.Encode()); + PutLengthPrefixedSlice(dst, f.largest.Encode()); + } +} + +static bool GetInternalKey(Slice* input, InternalKey* dst) { + Slice str; + if (GetLengthPrefixedSlice(input, &str)) { + dst->DecodeFrom(str); + return true; + } else { + return false; + } +} + +static bool GetLevel(Slice* input, int* level) { + uint32_t v; + if (GetVarint32(input, &v) && + v < config::kNumLevels) { + *level = v; + return true; + } else { + return false; + } +} + +Status VersionEdit::DecodeFrom(const Slice& src) { + Clear(); + Slice input = src; + const char* msg = NULL; + uint32_t tag; + + // Temporary storage for parsing + int level; + uint64_t number; + FileMetaData f; + Slice str; + InternalKey key; + + while (msg == NULL && GetVarint32(&input, &tag)) { + switch (tag) { + case kComparator: + if (GetLengthPrefixedSlice(&input, &str)) { + comparator_ = str.ToString(); + has_comparator_ = true; + } else { + msg = "comparator name"; + } + break; + + case kLogNumber: + if (GetVarint64(&input, &log_number_)) { + has_log_number_ = true; + } else { + msg = "log number"; + } + break; + + case kPrevLogNumber: + if (GetVarint64(&input, &prev_log_number_)) { + has_prev_log_number_ = true; + } else { + msg = "previous log number"; + } + break; + + case kNextFileNumber: + if (GetVarint64(&input, &next_file_number_)) { + has_next_file_number_ = true; + } else { + msg = "next file number"; + } + break; + + case kLastSequence: + if (GetVarint64(&input, &last_sequence_)) { + has_last_sequence_ = true; + } else { + msg = "last sequence number"; + } + break; + + case kCompactPointer: + if (GetLevel(&input, &level) && + GetInternalKey(&input, &key)) { + compact_pointers_.push_back(std::make_pair(level, key)); + } else { + msg = "compaction pointer"; + } + break; + + case kDeletedFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &number)) { + deleted_files_.insert(std::make_pair(level, number)); + } else { + msg = "deleted file"; + } + break; + + case kNewFile: + if (GetLevel(&input, &level) && + GetVarint64(&input, &f.number) && + GetVarint64(&input, &f.file_size) && + GetInternalKey(&input, &f.smallest) && + GetInternalKey(&input, &f.largest)) { + new_files_.push_back(std::make_pair(level, f)); + } else { + msg = "new-file entry"; + } + break; + + default: + msg = "unknown tag"; + break; + } + } + + if (msg == NULL && !input.empty()) { + msg = "invalid tag"; + } + + Status result; + if (msg != NULL) { + result = Status::Corruption("VersionEdit", msg); + } + return result; +} + +std::string VersionEdit::DebugString() const { + std::string r; + r.append("VersionEdit {"); + if (has_comparator_) { + r.append("\n Comparator: "); + r.append(comparator_); + } + if (has_log_number_) { + r.append("\n LogNumber: "); + AppendNumberTo(&r, log_number_); + } + if (has_prev_log_number_) { + r.append("\n PrevLogNumber: "); + AppendNumberTo(&r, prev_log_number_); + } + if (has_next_file_number_) { + r.append("\n NextFile: "); + AppendNumberTo(&r, next_file_number_); + } + if (has_last_sequence_) { + r.append("\n LastSeq: "); + AppendNumberTo(&r, last_sequence_); + } + for (size_t i = 0; i < compact_pointers_.size(); i++) { + r.append("\n CompactPointer: "); + AppendNumberTo(&r, compact_pointers_[i].first); + r.append(" "); + r.append(compact_pointers_[i].second.DebugString()); + } + for (DeletedFileSet::const_iterator iter = deleted_files_.begin(); + iter != deleted_files_.end(); + ++iter) { + r.append("\n DeleteFile: "); + AppendNumberTo(&r, iter->first); + r.append(" "); + AppendNumberTo(&r, iter->second); + } + for (size_t i = 0; i < new_files_.size(); i++) { + const FileMetaData& f = new_files_[i].second; + r.append("\n AddFile: "); + AppendNumberTo(&r, new_files_[i].first); + r.append(" "); + AppendNumberTo(&r, f.number); + r.append(" "); + AppendNumberTo(&r, f.file_size); + r.append(" "); + r.append(f.smallest.DebugString()); + r.append(" .. "); + r.append(f.largest.DebugString()); + } + r.append("\n}\n"); + return r; +} + +} // namespace leveldb diff --git a/db/version_edit.h b/db/version_edit.h new file mode 100644 index 0000000000..eaef77b327 --- /dev/null +++ b/db/version_edit.h @@ -0,0 +1,107 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_ +#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_ + +#include +#include +#include +#include "db/dbformat.h" + +namespace leveldb { + +class VersionSet; + +struct FileMetaData { + int refs; + int allowed_seeks; // Seeks allowed until compaction + uint64_t number; + uint64_t file_size; // File size in bytes + InternalKey smallest; // Smallest internal key served by table + InternalKey largest; // Largest internal key served by table + + FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { } +}; + +class VersionEdit { + public: + VersionEdit() { Clear(); } + ~VersionEdit() { } + + void Clear(); + + void SetComparatorName(const Slice& name) { + has_comparator_ = true; + comparator_ = name.ToString(); + } + void SetLogNumber(uint64_t num) { + has_log_number_ = true; + log_number_ = num; + } + void SetPrevLogNumber(uint64_t num) { + has_prev_log_number_ = true; + prev_log_number_ = num; + } + void SetNextFile(uint64_t num) { + has_next_file_number_ = true; + next_file_number_ = num; + } + void SetLastSequence(SequenceNumber seq) { + has_last_sequence_ = true; + last_sequence_ = seq; + } + void SetCompactPointer(int level, const InternalKey& key) { + compact_pointers_.push_back(std::make_pair(level, key)); + } + + // Add the specified file at the specified number. + // REQUIRES: This version has not been saved (see VersionSet::SaveTo) + // REQUIRES: "smallest" and "largest" are smallest and largest keys in file + void AddFile(int level, uint64_t file, + uint64_t file_size, + const InternalKey& smallest, + const InternalKey& largest) { + FileMetaData f; + f.number = file; + f.file_size = file_size; + f.smallest = smallest; + f.largest = largest; + new_files_.push_back(std::make_pair(level, f)); + } + + // Delete the specified "file" from the specified "level". + void DeleteFile(int level, uint64_t file) { + deleted_files_.insert(std::make_pair(level, file)); + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(const Slice& src); + + std::string DebugString() const; + + private: + friend class VersionSet; + + typedef std::set< std::pair > DeletedFileSet; + + std::string comparator_; + uint64_t log_number_; + uint64_t prev_log_number_; + uint64_t next_file_number_; + SequenceNumber last_sequence_; + bool has_comparator_; + bool has_log_number_; + bool has_prev_log_number_; + bool has_next_file_number_; + bool has_last_sequence_; + + std::vector< std::pair > compact_pointers_; + DeletedFileSet deleted_files_; + std::vector< std::pair > new_files_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_ diff --git a/db/version_edit_test.cc b/db/version_edit_test.cc new file mode 100644 index 0000000000..280310b49d --- /dev/null +++ b/db/version_edit_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_edit.h" +#include "util/testharness.h" + +namespace leveldb { + +static void TestEncodeDecode(const VersionEdit& edit) { + std::string encoded, encoded2; + edit.EncodeTo(&encoded); + VersionEdit parsed; + Status s = parsed.DecodeFrom(encoded); + ASSERT_TRUE(s.ok()) << s.ToString(); + parsed.EncodeTo(&encoded2); + ASSERT_EQ(encoded, encoded2); +} + +class VersionEditTest { }; + +TEST(VersionEditTest, EncodeDecode) { + static const uint64_t kBig = 1ull << 50; + + VersionEdit edit; + for (int i = 0; i < 4; i++) { + TestEncodeDecode(edit); + edit.AddFile(3, kBig + 300 + i, kBig + 400 + i, + InternalKey("foo", kBig + 500 + i, kTypeValue), + InternalKey("zoo", kBig + 600 + i, kTypeDeletion)); + edit.DeleteFile(4, kBig + 700 + i); + edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue)); + } + + edit.SetComparatorName("foo"); + edit.SetLogNumber(kBig + 100); + edit.SetNextFile(kBig + 200); + edit.SetLastSequence(kBig + 1000); + TestEncodeDecode(edit); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/version_set.cc b/db/version_set.cc new file mode 100644 index 0000000000..2cb6d80ed3 --- /dev/null +++ b/db/version_set.cc @@ -0,0 +1,1535 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" + +#include +#include +#include "db/filename.h" +#include "db/log_reader.h" +#include "db/log_writer.h" +#include "db/memtable.h" +#include "db/table_cache.h" +#include "leveldb/env.h" +#include "leveldb/table_builder.h" +#include "table/merger.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +static size_t TargetFileSize(const Options* options) { + return options->max_file_size; +} + +// Maximum bytes of overlaps in grandparent (i.e., level+2) before we +// stop building a single file in a level->level+1 compaction. +static int64_t MaxGrandParentOverlapBytes(const Options* options) { + return 10 * TargetFileSize(options); +} + +// Maximum number of bytes in all compacted files. We avoid expanding +// the lower level file set of a compaction if it would make the +// total compaction cover more than this many bytes. +static int64_t ExpandedCompactionByteSizeLimit(const Options* options) { + return 25 * TargetFileSize(options); +} + +static double MaxBytesForLevel(const Options* options, int level) { + // Note: the result for level zero is not really used since we set + // the level-0 compaction threshold based on number of files. + + // Result for both level-0 and level-1 + double result = 10. * 1048576.0; + while (level > 1) { + result *= 10; + level--; + } + return result; +} + +static uint64_t MaxFileSizeForLevel(const Options* options, int level) { + // We could vary per level to reduce number of files? + return TargetFileSize(options); +} + +static int64_t TotalFileSize(const std::vector& files) { + int64_t sum = 0; + for (size_t i = 0; i < files.size(); i++) { + sum += files[i]->file_size; + } + return sum; +} + +Version::~Version() { + assert(refs_ == 0); + + // Remove from linked list + prev_->next_ = next_; + next_->prev_ = prev_; + + // Drop references to files + for (int level = 0; level < config::kNumLevels; level++) { + for (size_t i = 0; i < files_[level].size(); i++) { + FileMetaData* f = files_[level][i]; + assert(f->refs > 0); + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } +} + +int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key) { + uint32_t left = 0; + uint32_t right = files.size(); + while (left < right) { + uint32_t mid = (left + right) / 2; + const FileMetaData* f = files[mid]; + if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) { + // Key at "mid.largest" is < "target". Therefore all + // files at or before "mid" are uninteresting. + left = mid + 1; + } else { + // Key at "mid.largest" is >= "target". Therefore all files + // after "mid" are uninteresting. + right = mid; + } + } + return right; +} + +static bool AfterFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs before all keys and is therefore never after *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->largest.user_key()) > 0); +} + +static bool BeforeFile(const Comparator* ucmp, + const Slice* user_key, const FileMetaData* f) { + // NULL user_key occurs after all keys and is therefore never before *f + return (user_key != NULL && + ucmp->Compare(*user_key, f->smallest.user_key()) < 0); +} + +bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + const Comparator* ucmp = icmp.user_comparator(); + if (!disjoint_sorted_files) { + // Need to check against all files + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + if (AfterFile(ucmp, smallest_user_key, f) || + BeforeFile(ucmp, largest_user_key, f)) { + // No overlap + } else { + return true; // Overlap + } + } + return false; + } + + // Binary search over file list + uint32_t index = 0; + if (smallest_user_key != NULL) { + // Find the earliest possible internal key for smallest_user_key + InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); + index = FindFile(icmp, files, small.Encode()); + } + + if (index >= files.size()) { + // beginning of range is after all files, so no overlap. + return false; + } + + return !BeforeFile(ucmp, largest_user_key, files[index]); +} + +// An internal iterator. For a given version/level pair, yields +// information about the files in the level. For a given entry, key() +// is the largest key that occurs in the file, and value() is an +// 16-byte value containing the file number and file size, both +// encoded using EncodeFixed64. +class Version::LevelFileNumIterator : public Iterator { + public: + LevelFileNumIterator(const InternalKeyComparator& icmp, + const std::vector* flist) + : icmp_(icmp), + flist_(flist), + index_(flist->size()) { // Marks as invalid + } + virtual bool Valid() const { + return index_ < flist_->size(); + } + virtual void Seek(const Slice& target) { + index_ = FindFile(icmp_, *flist_, target); + } + virtual void SeekToFirst() { index_ = 0; } + virtual void SeekToLast() { + index_ = flist_->empty() ? 0 : flist_->size() - 1; + } + virtual void Next() { + assert(Valid()); + index_++; + } + virtual void Prev() { + assert(Valid()); + if (index_ == 0) { + index_ = flist_->size(); // Marks as invalid + } else { + index_--; + } + } + Slice key() const { + assert(Valid()); + return (*flist_)[index_]->largest.Encode(); + } + Slice value() const { + assert(Valid()); + EncodeFixed64(value_buf_, (*flist_)[index_]->number); + EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size); + return Slice(value_buf_, sizeof(value_buf_)); + } + virtual Status status() const { return Status::OK(); } + private: + const InternalKeyComparator icmp_; + const std::vector* const flist_; + uint32_t index_; + + // Backing store for value(). Holds the file number and size. + mutable char value_buf_[16]; +}; + +static Iterator* GetFileIterator(void* arg, + const ReadOptions& options, + const Slice& file_value) { + TableCache* cache = reinterpret_cast(arg); + if (file_value.size() != 16) { + return NewErrorIterator( + Status::Corruption("FileReader invoked with unexpected value")); + } else { + return cache->NewIterator(options, + DecodeFixed64(file_value.data()), + DecodeFixed64(file_value.data() + 8)); + } +} + +Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, + int level) const { + return NewTwoLevelIterator( + new LevelFileNumIterator(vset_->icmp_, &files_[level]), + &GetFileIterator, vset_->table_cache_, options); +} + +void Version::AddIterators(const ReadOptions& options, + std::vector* iters) { + // Merge all level zero files together since they may overlap + for (size_t i = 0; i < files_[0].size(); i++) { + iters->push_back( + vset_->table_cache_->NewIterator( + options, files_[0][i]->number, files_[0][i]->file_size)); + } + + // For levels > 0, we can use a concatenating iterator that sequentially + // walks through the non-overlapping files in the level, opening them + // lazily. + for (int level = 1; level < config::kNumLevels; level++) { + if (!files_[level].empty()) { + iters->push_back(NewConcatenatingIterator(options, level)); + } + } +} + +// Callback from TableCache::Get() +namespace { +enum SaverState { + kNotFound, + kFound, + kDeleted, + kCorrupt, +}; +struct Saver { + SaverState state; + const Comparator* ucmp; + Slice user_key; + std::string* value; +}; +} +static void SaveValue(void* arg, const Slice& ikey, const Slice& v) { + Saver* s = reinterpret_cast(arg); + ParsedInternalKey parsed_key; + if (!ParseInternalKey(ikey, &parsed_key)) { + s->state = kCorrupt; + } else { + if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) { + s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted; + if (s->state == kFound) { + s->value->assign(v.data(), v.size()); + } + } + } +} + +static bool NewestFirst(FileMetaData* a, FileMetaData* b) { + return a->number > b->number; +} + +void Version::ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)) { + // TODO(sanjay): Change Version::Get() to use this function. + const Comparator* ucmp = vset_->icmp_.user_comparator(); + + // Search level-0 in order from newest to oldest. + std::vector tmp; + tmp.reserve(files_[0].size()); + for (uint32_t i = 0; i < files_[0].size(); i++) { + FileMetaData* f = files_[0][i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (!tmp.empty()) { + std::sort(tmp.begin(), tmp.end(), NewestFirst); + for (uint32_t i = 0; i < tmp.size(); i++) { + if (!(*func)(arg, 0, tmp[i])) { + return; + } + } + } + + // Search other levels. + for (int level = 1; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Binary search to find earliest index whose largest key >= internal_key. + uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key); + if (index < num_files) { + FileMetaData* f = files_[level][index]; + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) { + // All of "f" is past any data for user_key + } else { + if (!(*func)(arg, level, f)) { + return; + } + } + } + } +} + +Status Version::Get(const ReadOptions& options, + const LookupKey& k, + std::string* value, + GetStats* stats) { + Slice ikey = k.internal_key(); + Slice user_key = k.user_key(); + const Comparator* ucmp = vset_->icmp_.user_comparator(); + Status s; + + stats->seek_file = NULL; + stats->seek_file_level = -1; + FileMetaData* last_file_read = NULL; + int last_file_read_level = -1; + + // We can search level-by-level since entries never hop across + // levels. Therefore we are guaranteed that if we find data + // in an smaller level, later levels are irrelevant. + std::vector tmp; + FileMetaData* tmp2; + for (int level = 0; level < config::kNumLevels; level++) { + size_t num_files = files_[level].size(); + if (num_files == 0) continue; + + // Get the list of files to search in this level + FileMetaData* const* files = &files_[level][0]; + if (level == 0) { + // Level-0 files may overlap each other. Find all files that + // overlap user_key and process them in order from newest to oldest. + tmp.reserve(num_files); + for (uint32_t i = 0; i < num_files; i++) { + FileMetaData* f = files[i]; + if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && + ucmp->Compare(user_key, f->largest.user_key()) <= 0) { + tmp.push_back(f); + } + } + if (tmp.empty()) continue; + + std::sort(tmp.begin(), tmp.end(), NewestFirst); + files = &tmp[0]; + num_files = tmp.size(); + } else { + // Binary search to find earliest index whose largest key >= ikey. + uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); + if (index >= num_files) { + files = NULL; + num_files = 0; + } else { + tmp2 = files[index]; + if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { + // All of "tmp2" is past any data for user_key + files = NULL; + num_files = 0; + } else { + files = &tmp2; + num_files = 1; + } + } + } + + for (uint32_t i = 0; i < num_files; ++i) { + if (last_file_read != NULL && stats->seek_file == NULL) { + // We have had more than one seek for this read. Charge the 1st file. + stats->seek_file = last_file_read; + stats->seek_file_level = last_file_read_level; + } + + FileMetaData* f = files[i]; + last_file_read = f; + last_file_read_level = level; + + Saver saver; + saver.state = kNotFound; + saver.ucmp = ucmp; + saver.user_key = user_key; + saver.value = value; + s = vset_->table_cache_->Get(options, f->number, f->file_size, + ikey, &saver, SaveValue); + if (!s.ok()) { + return s; + } + switch (saver.state) { + case kNotFound: + break; // Keep searching in other files + case kFound: + return s; + case kDeleted: + s = Status::NotFound(Slice()); // Use empty error message for speed + return s; + case kCorrupt: + s = Status::Corruption("corrupted key for ", user_key); + return s; + } + } + } + + return Status::NotFound(Slice()); // Use an empty error message for speed +} + +bool Version::UpdateStats(const GetStats& stats) { + FileMetaData* f = stats.seek_file; + if (f != NULL) { + f->allowed_seeks--; + if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) { + file_to_compact_ = f; + file_to_compact_level_ = stats.seek_file_level; + return true; + } + } + return false; +} + +bool Version::RecordReadSample(Slice internal_key) { + ParsedInternalKey ikey; + if (!ParseInternalKey(internal_key, &ikey)) { + return false; + } + + struct State { + GetStats stats; // Holds first matching file + int matches; + + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); + state->matches++; + if (state->matches == 1) { + // Remember first match. + state->stats.seek_file = f; + state->stats.seek_file_level = level; + } + // We can stop iterating once we have a second match. + return state->matches < 2; + } + }; + + State state; + state.matches = 0; + ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match); + + // Must have at least two matches since we want to merge across + // files. But what if we have a single file that contains many + // overwrites and deletions? Should we have another mechanism for + // finding such files? + if (state.matches >= 2) { + // 1MB cost is about 1 seek (see comment in Builder::Apply). + return UpdateStats(state.stats); + } + return false; +} + +void Version::Ref() { + ++refs_; +} + +void Version::Unref() { + assert(this != &vset_->dummy_versions_); + assert(refs_ >= 1); + --refs_; + if (refs_ == 0) { + delete this; + } +} + +bool Version::OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key) { + return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level], + smallest_user_key, largest_user_key); +} + +int Version::PickLevelForMemTableOutput( + const Slice& smallest_user_key, + const Slice& largest_user_key) { + int level = 0; + if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) { + // Push to next level if there is no overlap in next level, + // and the #bytes overlapping in the level after that are limited. + InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); + InternalKey limit(largest_user_key, 0, static_cast(0)); + std::vector overlaps; + while (level < config::kMaxMemCompactLevel) { + if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) { + break; + } + if (level + 2 < config::kNumLevels) { + // Check that file does not overlap too many grandparent bytes. + GetOverlappingInputs(level + 2, &start, &limit, &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > MaxGrandParentOverlapBytes(vset_->options_)) { + break; + } + } + level++; + } + } + return level; +} + +// Store in "*inputs" all files in "level" that overlap [begin,end] +void Version::GetOverlappingInputs( + int level, + const InternalKey* begin, + const InternalKey* end, + std::vector* inputs) { + assert(level >= 0); + assert(level < config::kNumLevels); + inputs->clear(); + Slice user_begin, user_end; + if (begin != NULL) { + user_begin = begin->user_key(); + } + if (end != NULL) { + user_end = end->user_key(); + } + const Comparator* user_cmp = vset_->icmp_.user_comparator(); + for (size_t i = 0; i < files_[level].size(); ) { + FileMetaData* f = files_[level][i++]; + const Slice file_start = f->smallest.user_key(); + const Slice file_limit = f->largest.user_key(); + if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) { + // "f" is completely before specified range; skip it + } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) { + // "f" is completely after specified range; skip it + } else { + inputs->push_back(f); + if (level == 0) { + // Level-0 files may overlap each other. So check if the newly + // added file has expanded the range. If so, restart search. + if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) { + user_begin = file_start; + inputs->clear(); + i = 0; + } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) { + user_end = file_limit; + inputs->clear(); + i = 0; + } + } + } + } +} + +std::string Version::DebugString() const { + std::string r; + for (int level = 0; level < config::kNumLevels; level++) { + // E.g., + // --- level 1 --- + // 17:123['a' .. 'd'] + // 20:43['e' .. 'g'] + r.append("--- level "); + AppendNumberTo(&r, level); + r.append(" ---\n"); + const std::vector& files = files_[level]; + for (size_t i = 0; i < files.size(); i++) { + r.push_back(' '); + AppendNumberTo(&r, files[i]->number); + r.push_back(':'); + AppendNumberTo(&r, files[i]->file_size); + r.append("["); + r.append(files[i]->smallest.DebugString()); + r.append(" .. "); + r.append(files[i]->largest.DebugString()); + r.append("]\n"); + } + } + return r; +} + +// A helper class so we can efficiently apply a whole sequence +// of edits to a particular state without creating intermediate +// Versions that contain full copies of the intermediate state. +class VersionSet::Builder { + private: + // Helper to sort by v->files_[file_number].smallest + struct BySmallestKey { + const InternalKeyComparator* internal_comparator; + + bool operator()(FileMetaData* f1, FileMetaData* f2) const { + int r = internal_comparator->Compare(f1->smallest, f2->smallest); + if (r != 0) { + return (r < 0); + } else { + // Break ties by file number + return (f1->number < f2->number); + } + } + }; + + typedef std::set FileSet; + struct LevelState { + std::set deleted_files; + FileSet* added_files; + }; + + VersionSet* vset_; + Version* base_; + LevelState levels_[config::kNumLevels]; + + public: + // Initialize a builder with the files from *base and other info from *vset + Builder(VersionSet* vset, Version* base) + : vset_(vset), + base_(base) { + base_->Ref(); + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + levels_[level].added_files = new FileSet(cmp); + } + } + + ~Builder() { + for (int level = 0; level < config::kNumLevels; level++) { + const FileSet* added = levels_[level].added_files; + std::vector to_unref; + to_unref.reserve(added->size()); + for (FileSet::const_iterator it = added->begin(); + it != added->end(); ++it) { + to_unref.push_back(*it); + } + delete added; + for (uint32_t i = 0; i < to_unref.size(); i++) { + FileMetaData* f = to_unref[i]; + f->refs--; + if (f->refs <= 0) { + delete f; + } + } + } + base_->Unref(); + } + + // Apply all of the edits in *edit to the current state. + void Apply(VersionEdit* edit) { + // Update compaction pointers + for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { + const int level = edit->compact_pointers_[i].first; + vset_->compact_pointer_[level] = + edit->compact_pointers_[i].second.Encode().ToString(); + } + + // Delete files + const VersionEdit::DeletedFileSet& del = edit->deleted_files_; + for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin(); + iter != del.end(); + ++iter) { + const int level = iter->first; + const uint64_t number = iter->second; + levels_[level].deleted_files.insert(number); + } + + // Add new files + for (size_t i = 0; i < edit->new_files_.size(); i++) { + const int level = edit->new_files_[i].first; + FileMetaData* f = new FileMetaData(edit->new_files_[i].second); + f->refs = 1; + + // We arrange to automatically compact this file after + // a certain number of seeks. Let's assume: + // (1) One seek costs 10ms + // (2) Writing or reading 1MB costs 10ms (100MB/s) + // (3) A compaction of 1MB does 25MB of IO: + // 1MB read from this level + // 10-12MB read from next level (boundaries may be misaligned) + // 10-12MB written to next level + // This implies that 25 seeks cost the same as the compaction + // of 1MB of data. I.e., one seek costs approximately the + // same as the compaction of 40KB of data. We are a little + // conservative and allow approximately one seek for every 16KB + // of data before triggering a compaction. + f->allowed_seeks = (f->file_size / 16384); + if (f->allowed_seeks < 100) f->allowed_seeks = 100; + + levels_[level].deleted_files.erase(f->number); + levels_[level].added_files->insert(f); + } + } + + // Save the current state in *v. + void SaveTo(Version* v) { + BySmallestKey cmp; + cmp.internal_comparator = &vset_->icmp_; + for (int level = 0; level < config::kNumLevels; level++) { + // Merge the set of added files with the set of pre-existing files. + // Drop any deleted files. Store the result in *v. + const std::vector& base_files = base_->files_[level]; + std::vector::const_iterator base_iter = base_files.begin(); + std::vector::const_iterator base_end = base_files.end(); + const FileSet* added = levels_[level].added_files; + v->files_[level].reserve(base_files.size() + added->size()); + for (FileSet::const_iterator added_iter = added->begin(); + added_iter != added->end(); + ++added_iter) { + // Add all smaller files listed in base_ + for (std::vector::const_iterator bpos + = std::upper_bound(base_iter, base_end, *added_iter, cmp); + base_iter != bpos; + ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + + MaybeAddFile(v, level, *added_iter); + } + + // Add remaining base files + for (; base_iter != base_end; ++base_iter) { + MaybeAddFile(v, level, *base_iter); + } + +#ifndef NDEBUG + // Make sure there is no overlap in levels > 0 + if (level > 0) { + for (uint32_t i = 1; i < v->files_[level].size(); i++) { + const InternalKey& prev_end = v->files_[level][i-1]->largest; + const InternalKey& this_begin = v->files_[level][i]->smallest; + if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) { + fprintf(stderr, "overlapping ranges in same level %s vs. %s\n", + prev_end.DebugString().c_str(), + this_begin.DebugString().c_str()); + abort(); + } + } + } +#endif + } + } + + void MaybeAddFile(Version* v, int level, FileMetaData* f) { + if (levels_[level].deleted_files.count(f->number) > 0) { + // File is deleted: do nothing + } else { + std::vector* files = &v->files_[level]; + if (level > 0 && !files->empty()) { + // Must not overlap + assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest, + f->smallest) < 0); + } + f->refs++; + files->push_back(f); + } + } +}; + +VersionSet::VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator* cmp) + : env_(options->env), + dbname_(dbname), + options_(options), + table_cache_(table_cache), + icmp_(*cmp), + next_file_number_(2), + manifest_file_number_(0), // Filled by Recover() + last_sequence_(0), + log_number_(0), + prev_log_number_(0), + descriptor_file_(NULL), + descriptor_log_(NULL), + dummy_versions_(this), + current_(NULL) { + AppendVersion(new Version(this)); +} + +VersionSet::~VersionSet() { + current_->Unref(); + assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty + delete descriptor_log_; + delete descriptor_file_; +} + +void VersionSet::AppendVersion(Version* v) { + // Make "v" current + assert(v->refs_ == 0); + assert(v != current_); + if (current_ != NULL) { + current_->Unref(); + } + current_ = v; + v->Ref(); + + // Append to linked list + v->prev_ = dummy_versions_.prev_; + v->next_ = &dummy_versions_; + v->prev_->next_ = v; + v->next_->prev_ = v; +} + +Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) { + if (edit->has_log_number_) { + assert(edit->log_number_ >= log_number_); + assert(edit->log_number_ < next_file_number_); + } else { + edit->SetLogNumber(log_number_); + } + + if (!edit->has_prev_log_number_) { + edit->SetPrevLogNumber(prev_log_number_); + } + + edit->SetNextFile(next_file_number_); + edit->SetLastSequence(last_sequence_); + + Version* v = new Version(this); + { + Builder builder(this, current_); + builder.Apply(edit); + builder.SaveTo(v); + } + Finalize(v); + + // Initialize new descriptor log file if necessary by creating + // a temporary file that contains a snapshot of the current version. + std::string new_manifest_file; + Status s; + if (descriptor_log_ == NULL) { + // No reason to unlock *mu here since we only hit this path in the + // first call to LogAndApply (when opening the database). + assert(descriptor_file_ == NULL); + new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_); + edit->SetNextFile(next_file_number_); + s = env_->NewWritableFile(new_manifest_file, &descriptor_file_); + if (s.ok()) { + descriptor_log_ = new log::Writer(descriptor_file_); + s = WriteSnapshot(descriptor_log_); + } + } + + // Unlock during expensive MANIFEST log write + { + mu->Unlock(); + + // Write new record to MANIFEST log + if (s.ok()) { + std::string record; + edit->EncodeTo(&record); + s = descriptor_log_->AddRecord(record); + if (s.ok()) { + s = descriptor_file_->Sync(); + } + if (!s.ok()) { + Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str()); + } + } + + // If we just created a new descriptor file, install it by writing a + // new CURRENT file that points to it. + if (s.ok() && !new_manifest_file.empty()) { + s = SetCurrentFile(env_, dbname_, manifest_file_number_); + } + + mu->Lock(); + } + + // Install the new version + if (s.ok()) { + AppendVersion(v); + log_number_ = edit->log_number_; + prev_log_number_ = edit->prev_log_number_; + } else { + delete v; + if (!new_manifest_file.empty()) { + delete descriptor_log_; + delete descriptor_file_; + descriptor_log_ = NULL; + descriptor_file_ = NULL; + env_->DeleteFile(new_manifest_file); + } + } + + return s; +} + +Status VersionSet::Recover(bool *save_manifest) { + struct LogReporter : public log::Reader::Reporter { + Status* status; + virtual void Corruption(size_t bytes, const Status& s) { + if (this->status->ok()) *this->status = s; + } + }; + + // Read "CURRENT" file, which contains a pointer to the current manifest file + std::string current; + Status s = ReadFileToString(env_, CurrentFileName(dbname_), ¤t); + if (!s.ok()) { + return s; + } + if (current.empty() || current[current.size()-1] != '\n') { + return Status::Corruption("CURRENT file does not end with newline"); + } + current.resize(current.size() - 1); + + std::string dscname = dbname_ + "/" + current; + SequentialFile* file; + s = env_->NewSequentialFile(dscname, &file); + if (!s.ok()) { + return s; + } + + bool have_log_number = false; + bool have_prev_log_number = false; + bool have_next_file = false; + bool have_last_sequence = false; + uint64_t next_file = 0; + uint64_t last_sequence = 0; + uint64_t log_number = 0; + uint64_t prev_log_number = 0; + Builder builder(this, current_); + + { + LogReporter reporter; + reporter.status = &s; + log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/); + Slice record; + std::string scratch; + while (reader.ReadRecord(&record, &scratch) && s.ok()) { + VersionEdit edit; + s = edit.DecodeFrom(record); + if (s.ok()) { + if (edit.has_comparator_ && + edit.comparator_ != icmp_.user_comparator()->Name()) { + s = Status::InvalidArgument( + edit.comparator_ + " does not match existing comparator ", + icmp_.user_comparator()->Name()); + } + } + + if (s.ok()) { + builder.Apply(&edit); + } + + if (edit.has_log_number_) { + log_number = edit.log_number_; + have_log_number = true; + } + + if (edit.has_prev_log_number_) { + prev_log_number = edit.prev_log_number_; + have_prev_log_number = true; + } + + if (edit.has_next_file_number_) { + next_file = edit.next_file_number_; + have_next_file = true; + } + + if (edit.has_last_sequence_) { + last_sequence = edit.last_sequence_; + have_last_sequence = true; + } + } + } + delete file; + file = NULL; + + if (s.ok()) { + if (!have_next_file) { + s = Status::Corruption("no meta-nextfile entry in descriptor"); + } else if (!have_log_number) { + s = Status::Corruption("no meta-lognumber entry in descriptor"); + } else if (!have_last_sequence) { + s = Status::Corruption("no last-sequence-number entry in descriptor"); + } + + if (!have_prev_log_number) { + prev_log_number = 0; + } + + MarkFileNumberUsed(prev_log_number); + MarkFileNumberUsed(log_number); + } + + if (s.ok()) { + Version* v = new Version(this); + builder.SaveTo(v); + // Install recovered version + Finalize(v); + AppendVersion(v); + manifest_file_number_ = next_file; + next_file_number_ = next_file + 1; + last_sequence_ = last_sequence; + log_number_ = log_number; + prev_log_number_ = prev_log_number; + + // See if we can reuse the existing MANIFEST file. + if (ReuseManifest(dscname, current)) { + // No need to save new manifest + } else { + *save_manifest = true; + } + } + + return s; +} + +bool VersionSet::ReuseManifest(const std::string& dscname, + const std::string& dscbase) { + if (!options_->reuse_logs) { + return false; + } + FileType manifest_type; + uint64_t manifest_number; + uint64_t manifest_size; + if (!ParseFileName(dscbase, &manifest_number, &manifest_type) || + manifest_type != kDescriptorFile || + !env_->GetFileSize(dscname, &manifest_size).ok() || + // Make new compacted MANIFEST if old one is too big + manifest_size >= TargetFileSize(options_)) { + return false; + } + + assert(descriptor_file_ == NULL); + assert(descriptor_log_ == NULL); + Status r = env_->NewAppendableFile(dscname, &descriptor_file_); + if (!r.ok()) { + Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str()); + assert(descriptor_file_ == NULL); + return false; + } + + Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str()); + descriptor_log_ = new log::Writer(descriptor_file_, manifest_size); + manifest_file_number_ = manifest_number; + return true; +} + +void VersionSet::MarkFileNumberUsed(uint64_t number) { + if (next_file_number_ <= number) { + next_file_number_ = number + 1; + } +} + +void VersionSet::Finalize(Version* v) { + // Precomputed best level for next compaction + int best_level = -1; + double best_score = -1; + + for (int level = 0; level < config::kNumLevels-1; level++) { + double score; + if (level == 0) { + // We treat level-0 specially by bounding the number of files + // instead of number of bytes for two reasons: + // + // (1) With larger write-buffer sizes, it is nice not to do too + // many level-0 compactions. + // + // (2) The files in level-0 are merged on every read and + // therefore we wish to avoid too many files when the individual + // file size is small (perhaps because of a small write-buffer + // setting, or very high compression ratios, or lots of + // overwrites/deletions). + score = v->files_[level].size() / + static_cast(config::kL0_CompactionTrigger); + } else { + // Compute the ratio of current size to size limit. + const uint64_t level_bytes = TotalFileSize(v->files_[level]); + score = + static_cast(level_bytes) / MaxBytesForLevel(options_, level); + } + + if (score > best_score) { + best_level = level; + best_score = score; + } + } + + v->compaction_level_ = best_level; + v->compaction_score_ = best_score; +} + +Status VersionSet::WriteSnapshot(log::Writer* log) { + // TODO: Break up into multiple records to reduce memory usage on recovery? + + // Save metadata + VersionEdit edit; + edit.SetComparatorName(icmp_.user_comparator()->Name()); + + // Save compaction pointers + for (int level = 0; level < config::kNumLevels; level++) { + if (!compact_pointer_[level].empty()) { + InternalKey key; + key.DecodeFrom(compact_pointer_[level]); + edit.SetCompactPointer(level, key); + } + } + + // Save files + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = current_->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + const FileMetaData* f = files[i]; + edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); + } + } + + std::string record; + edit.EncodeTo(&record); + return log->AddRecord(record); +} + +int VersionSet::NumLevelFiles(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return current_->files_[level].size(); +} + +const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const { + // Update code if kNumLevels changes + assert(config::kNumLevels == 7); + snprintf(scratch->buffer, sizeof(scratch->buffer), + "files[ %d %d %d %d %d %d %d ]", + int(current_->files_[0].size()), + int(current_->files_[1].size()), + int(current_->files_[2].size()), + int(current_->files_[3].size()), + int(current_->files_[4].size()), + int(current_->files_[5].size()), + int(current_->files_[6].size())); + return scratch->buffer; +} + +uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { + uint64_t result = 0; + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + if (icmp_.Compare(files[i]->largest, ikey) <= 0) { + // Entire file is before "ikey", so just add the file size + result += files[i]->file_size; + } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) { + // Entire file is after "ikey", so ignore + if (level > 0) { + // Files other than level 0 are sorted by meta->smallest, so + // no further files in this level will contain data for + // "ikey". + break; + } + } else { + // "ikey" falls in the range for this table. Add the + // approximate offset of "ikey" within the table. + Table* tableptr; + Iterator* iter = table_cache_->NewIterator( + ReadOptions(), files[i]->number, files[i]->file_size, &tableptr); + if (tableptr != NULL) { + result += tableptr->ApproximateOffsetOf(ikey.Encode()); + } + delete iter; + } + } + } + return result; +} + +void VersionSet::AddLiveFiles(std::set* live) { + for (Version* v = dummy_versions_.next_; + v != &dummy_versions_; + v = v->next_) { + for (int level = 0; level < config::kNumLevels; level++) { + const std::vector& files = v->files_[level]; + for (size_t i = 0; i < files.size(); i++) { + live->insert(files[i]->number); + } + } + } +} + +int64_t VersionSet::NumLevelBytes(int level) const { + assert(level >= 0); + assert(level < config::kNumLevels); + return TotalFileSize(current_->files_[level]); +} + +int64_t VersionSet::MaxNextLevelOverlappingBytes() { + int64_t result = 0; + std::vector overlaps; + for (int level = 1; level < config::kNumLevels - 1; level++) { + for (size_t i = 0; i < current_->files_[level].size(); i++) { + const FileMetaData* f = current_->files_[level][i]; + current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest, + &overlaps); + const int64_t sum = TotalFileSize(overlaps); + if (sum > result) { + result = sum; + } + } + } + return result; +} + +// Stores the minimal range that covers all entries in inputs in +// *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest) { + assert(!inputs.empty()); + smallest->Clear(); + largest->Clear(); + for (size_t i = 0; i < inputs.size(); i++) { + FileMetaData* f = inputs[i]; + if (i == 0) { + *smallest = f->smallest; + *largest = f->largest; + } else { + if (icmp_.Compare(f->smallest, *smallest) < 0) { + *smallest = f->smallest; + } + if (icmp_.Compare(f->largest, *largest) > 0) { + *largest = f->largest; + } + } + } +} + +// Stores the minimal range that covers all entries in inputs1 and inputs2 +// in *smallest, *largest. +// REQUIRES: inputs is not empty +void VersionSet::GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest) { + std::vector all = inputs1; + all.insert(all.end(), inputs2.begin(), inputs2.end()); + GetRange(all, smallest, largest); +} + +Iterator* VersionSet::MakeInputIterator(Compaction* c) { + ReadOptions options; + options.verify_checksums = options_->paranoid_checks; + options.fill_cache = false; + + // Level-0 files have to be merged together. For other levels, + // we will make a concatenating iterator per level. + // TODO(opt): use concatenating iterator for level-0 if there is no overlap + const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2); + Iterator** list = new Iterator*[space]; + int num = 0; + for (int which = 0; which < 2; which++) { + if (!c->inputs_[which].empty()) { + if (c->level() + which == 0) { + const std::vector& files = c->inputs_[which]; + for (size_t i = 0; i < files.size(); i++) { + list[num++] = table_cache_->NewIterator( + options, files[i]->number, files[i]->file_size); + } + } else { + // Create concatenating iterator for the files from this level + list[num++] = NewTwoLevelIterator( + new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]), + &GetFileIterator, table_cache_, options); + } + } + } + assert(num <= space); + Iterator* result = NewMergingIterator(&icmp_, list, num); + delete[] list; + return result; +} + +Compaction* VersionSet::PickCompaction() { + Compaction* c; + int level; + + // We prefer compactions triggered by too much data in a level over + // the compactions triggered by seeks. + const bool size_compaction = (current_->compaction_score_ >= 1); + const bool seek_compaction = (current_->file_to_compact_ != NULL); + if (size_compaction) { + level = current_->compaction_level_; + assert(level >= 0); + assert(level+1 < config::kNumLevels); + c = new Compaction(options_, level); + + // Pick the first file that comes after compact_pointer_[level] + for (size_t i = 0; i < current_->files_[level].size(); i++) { + FileMetaData* f = current_->files_[level][i]; + if (compact_pointer_[level].empty() || + icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { + c->inputs_[0].push_back(f); + break; + } + } + if (c->inputs_[0].empty()) { + // Wrap-around to the beginning of the key space + c->inputs_[0].push_back(current_->files_[level][0]); + } + } else if (seek_compaction) { + level = current_->file_to_compact_level_; + c = new Compaction(options_, level); + c->inputs_[0].push_back(current_->file_to_compact_); + } else { + return NULL; + } + + c->input_version_ = current_; + c->input_version_->Ref(); + + // Files in level 0 may overlap each other, so pick up all overlapping ones + if (level == 0) { + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + // Note that the next call will discard the file we placed in + // c->inputs_[0] earlier and replace it with an overlapping set + // which will include the picked file. + current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); + assert(!c->inputs_[0].empty()); + } + + SetupOtherInputs(c); + + return c; +} + +void VersionSet::SetupOtherInputs(Compaction* c) { + const int level = c->level(); + InternalKey smallest, largest; + GetRange(c->inputs_[0], &smallest, &largest); + + current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]); + + // Get entire range covered by compaction + InternalKey all_start, all_limit; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + + // See if we can grow the number of inputs in "level" without + // changing the number of "level+1" files we pick up. + if (!c->inputs_[1].empty()) { + std::vector expanded0; + current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0); + const int64_t inputs0_size = TotalFileSize(c->inputs_[0]); + const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); + const int64_t expanded0_size = TotalFileSize(expanded0); + if (expanded0.size() > c->inputs_[0].size() && + inputs1_size + expanded0_size < + ExpandedCompactionByteSizeLimit(options_)) { + InternalKey new_start, new_limit; + GetRange(expanded0, &new_start, &new_limit); + std::vector expanded1; + current_->GetOverlappingInputs(level+1, &new_start, &new_limit, + &expanded1); + if (expanded1.size() == c->inputs_[1].size()) { + Log(options_->info_log, + "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n", + level, + int(c->inputs_[0].size()), + int(c->inputs_[1].size()), + long(inputs0_size), long(inputs1_size), + int(expanded0.size()), + int(expanded1.size()), + long(expanded0_size), long(inputs1_size)); + smallest = new_start; + largest = new_limit; + c->inputs_[0] = expanded0; + c->inputs_[1] = expanded1; + GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit); + } + } + } + + // Compute the set of grandparent files that overlap this compaction + // (parent == level+1; grandparent == level+2) + if (level + 2 < config::kNumLevels) { + current_->GetOverlappingInputs(level + 2, &all_start, &all_limit, + &c->grandparents_); + } + + if (false) { + Log(options_->info_log, "Compacting %d '%s' .. '%s'", + level, + smallest.DebugString().c_str(), + largest.DebugString().c_str()); + } + + // Update the place where we will do the next compaction for this level. + // We update this immediately instead of waiting for the VersionEdit + // to be applied so that if the compaction fails, we will try a different + // key range next time. + compact_pointer_[level] = largest.Encode().ToString(); + c->edit_.SetCompactPointer(level, largest); +} + +Compaction* VersionSet::CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end) { + std::vector inputs; + current_->GetOverlappingInputs(level, begin, end, &inputs); + if (inputs.empty()) { + return NULL; + } + + // Avoid compacting too much in one shot in case the range is large. + // But we cannot do this for level-0 since level-0 files can overlap + // and we must not pick one file and drop another older file if the + // two files overlap. + if (level > 0) { + const uint64_t limit = MaxFileSizeForLevel(options_, level); + uint64_t total = 0; + for (size_t i = 0; i < inputs.size(); i++) { + uint64_t s = inputs[i]->file_size; + total += s; + if (total >= limit) { + inputs.resize(i + 1); + break; + } + } + } + + Compaction* c = new Compaction(options_, level); + c->input_version_ = current_; + c->input_version_->Ref(); + c->inputs_[0] = inputs; + SetupOtherInputs(c); + return c; +} + +Compaction::Compaction(const Options* options, int level) + : level_(level), + max_output_file_size_(MaxFileSizeForLevel(options, level)), + input_version_(NULL), + grandparent_index_(0), + seen_key_(false), + overlapped_bytes_(0) { + for (int i = 0; i < config::kNumLevels; i++) { + level_ptrs_[i] = 0; + } +} + +Compaction::~Compaction() { + if (input_version_ != NULL) { + input_version_->Unref(); + } +} + +bool Compaction::IsTrivialMove() const { + const VersionSet* vset = input_version_->vset_; + // Avoid a move if there is lots of overlapping grandparent data. + // Otherwise, the move could create a parent file that will require + // a very expensive merge later on. + return (num_input_files(0) == 1 && num_input_files(1) == 0 && + TotalFileSize(grandparents_) <= + MaxGrandParentOverlapBytes(vset->options_)); +} + +void Compaction::AddInputDeletions(VersionEdit* edit) { + for (int which = 0; which < 2; which++) { + for (size_t i = 0; i < inputs_[which].size(); i++) { + edit->DeleteFile(level_ + which, inputs_[which][i]->number); + } + } +} + +bool Compaction::IsBaseLevelForKey(const Slice& user_key) { + // Maybe use binary search to find right entry instead of linear search? + const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator(); + for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) { + const std::vector& files = input_version_->files_[lvl]; + for (; level_ptrs_[lvl] < files.size(); ) { + FileMetaData* f = files[level_ptrs_[lvl]]; + if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) { + // We've advanced far enough + if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) { + // Key falls in this file's range, so definitely not base level + return false; + } + break; + } + level_ptrs_[lvl]++; + } + } + return true; +} + +bool Compaction::ShouldStopBefore(const Slice& internal_key) { + const VersionSet* vset = input_version_->vset_; + // Scan to find earliest grandparent file that contains key. + const InternalKeyComparator* icmp = &vset->icmp_; + while (grandparent_index_ < grandparents_.size() && + icmp->Compare(internal_key, + grandparents_[grandparent_index_]->largest.Encode()) > 0) { + if (seen_key_) { + overlapped_bytes_ += grandparents_[grandparent_index_]->file_size; + } + grandparent_index_++; + } + seen_key_ = true; + + if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) { + // Too much overlap for current output; start new output + overlapped_bytes_ = 0; + return true; + } else { + return false; + } +} + +void Compaction::ReleaseInputs() { + if (input_version_ != NULL) { + input_version_->Unref(); + input_version_ = NULL; + } +} + +} // namespace leveldb diff --git a/db/version_set.h b/db/version_set.h new file mode 100644 index 0000000000..7935a965a7 --- /dev/null +++ b/db/version_set.h @@ -0,0 +1,398 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// The representation of a DBImpl consists of a set of Versions. The +// newest version is called "current". Older versions may be kept +// around to provide a consistent view to live iterators. +// +// Each Version keeps track of a set of Table files per level. The +// entire set of versions is maintained in a VersionSet. +// +// Version,VersionSet are thread-compatible, but require external +// synchronization on all accesses. + +#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_ +#define STORAGE_LEVELDB_DB_VERSION_SET_H_ + +#include +#include +#include +#include "db/dbformat.h" +#include "db/version_edit.h" +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +namespace log { class Writer; } + +class Compaction; +class Iterator; +class MemTable; +class TableBuilder; +class TableCache; +class Version; +class VersionSet; +class WritableFile; + +// Return the smallest index i such that files[i]->largest >= key. +// Return files.size() if there is no such file. +// REQUIRES: "files" contains a sorted list of non-overlapping files. +extern int FindFile(const InternalKeyComparator& icmp, + const std::vector& files, + const Slice& key); + +// Returns true iff some file in "files" overlaps the user key range +// [*smallest,*largest]. +// smallest==NULL represents a key smaller than all keys in the DB. +// largest==NULL represents a key largest than all keys in the DB. +// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges +// in sorted order. +extern bool SomeFileOverlapsRange( + const InternalKeyComparator& icmp, + bool disjoint_sorted_files, + const std::vector& files, + const Slice* smallest_user_key, + const Slice* largest_user_key); + +class Version { + public: + // Append to *iters a sequence of iterators that will + // yield the contents of this Version when merged together. + // REQUIRES: This version has been saved (see VersionSet::SaveTo) + void AddIterators(const ReadOptions&, std::vector* iters); + + // Lookup the value for key. If found, store it in *val and + // return OK. Else return a non-OK status. Fills *stats. + // REQUIRES: lock is not held + struct GetStats { + FileMetaData* seek_file; + int seek_file_level; + }; + Status Get(const ReadOptions&, const LookupKey& key, std::string* val, + GetStats* stats); + + // Adds "stats" into the current state. Returns true if a new + // compaction may need to be triggered, false otherwise. + // REQUIRES: lock is held + bool UpdateStats(const GetStats& stats); + + // Record a sample of bytes read at the specified internal key. + // Samples are taken approximately once every config::kReadBytesPeriod + // bytes. Returns true if a new compaction may need to be triggered. + // REQUIRES: lock is held + bool RecordReadSample(Slice key); + + // Reference count management (so Versions do not disappear out from + // under live iterators) + void Ref(); + void Unref(); + + void GetOverlappingInputs( + int level, + const InternalKey* begin, // NULL means before all keys + const InternalKey* end, // NULL means after all keys + std::vector* inputs); + + // Returns true iff some file in the specified level overlaps + // some part of [*smallest_user_key,*largest_user_key]. + // smallest_user_key==NULL represents a key smaller than all keys in the DB. + // largest_user_key==NULL represents a key largest than all keys in the DB. + bool OverlapInLevel(int level, + const Slice* smallest_user_key, + const Slice* largest_user_key); + + // Return the level at which we should place a new memtable compaction + // result that covers the range [smallest_user_key,largest_user_key]. + int PickLevelForMemTableOutput(const Slice& smallest_user_key, + const Slice& largest_user_key); + + int NumFiles(int level) const { return files_[level].size(); } + + // Return a human readable string that describes this version's contents. + std::string DebugString() const; + + private: + friend class Compaction; + friend class VersionSet; + + class LevelFileNumIterator; + Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const; + + // Call func(arg, level, f) for every file that overlaps user_key in + // order from newest to oldest. If an invocation of func returns + // false, makes no more calls. + // + // REQUIRES: user portion of internal_key == user_key. + void ForEachOverlapping(Slice user_key, Slice internal_key, + void* arg, + bool (*func)(void*, int, FileMetaData*)); + + VersionSet* vset_; // VersionSet to which this Version belongs + Version* next_; // Next version in linked list + Version* prev_; // Previous version in linked list + int refs_; // Number of live refs to this version + + // List of files per level + std::vector files_[config::kNumLevels]; + + // Next file to compact based on seek stats. + FileMetaData* file_to_compact_; + int file_to_compact_level_; + + // Level that should be compacted next and its compaction score. + // Score < 1 means compaction is not strictly needed. These fields + // are initialized by Finalize(). + double compaction_score_; + int compaction_level_; + + explicit Version(VersionSet* vset) + : vset_(vset), next_(this), prev_(this), refs_(0), + file_to_compact_(NULL), + file_to_compact_level_(-1), + compaction_score_(-1), + compaction_level_(-1) { + } + + ~Version(); + + // No copying allowed + Version(const Version&); + void operator=(const Version&); +}; + +class VersionSet { + public: + VersionSet(const std::string& dbname, + const Options* options, + TableCache* table_cache, + const InternalKeyComparator*); + ~VersionSet(); + + // Apply *edit to the current version to form a new descriptor that + // is both saved to persistent state and installed as the new + // current version. Will release *mu while actually writing to the file. + // REQUIRES: *mu is held on entry. + // REQUIRES: no other thread concurrently calls LogAndApply() + Status LogAndApply(VersionEdit* edit, port::Mutex* mu) + EXCLUSIVE_LOCKS_REQUIRED(mu); + + // Recover the last saved descriptor from persistent storage. + Status Recover(bool *save_manifest); + + // Return the current version. + Version* current() const { return current_; } + + // Return the current manifest file number + uint64_t ManifestFileNumber() const { return manifest_file_number_; } + + // Allocate and return a new file number + uint64_t NewFileNumber() { return next_file_number_++; } + + // Arrange to reuse "file_number" unless a newer file number has + // already been allocated. + // REQUIRES: "file_number" was returned by a call to NewFileNumber(). + void ReuseFileNumber(uint64_t file_number) { + if (next_file_number_ == file_number + 1) { + next_file_number_ = file_number; + } + } + + // Return the number of Table files at the specified level. + int NumLevelFiles(int level) const; + + // Return the combined file size of all files at the specified level. + int64_t NumLevelBytes(int level) const; + + // Return the last sequence number. + uint64_t LastSequence() const { return last_sequence_; } + + // Set the last sequence number to s. + void SetLastSequence(uint64_t s) { + assert(s >= last_sequence_); + last_sequence_ = s; + } + + // Mark the specified file number as used. + void MarkFileNumberUsed(uint64_t number); + + // Return the current log file number. + uint64_t LogNumber() const { return log_number_; } + + // Return the log file number for the log file that is currently + // being compacted, or zero if there is no such log file. + uint64_t PrevLogNumber() const { return prev_log_number_; } + + // Pick level and inputs for a new compaction. + // Returns NULL if there is no compaction to be done. + // Otherwise returns a pointer to a heap-allocated object that + // describes the compaction. Caller should delete the result. + Compaction* PickCompaction(); + + // Return a compaction object for compacting the range [begin,end] in + // the specified level. Returns NULL if there is nothing in that + // level that overlaps the specified range. Caller should delete + // the result. + Compaction* CompactRange( + int level, + const InternalKey* begin, + const InternalKey* end); + + // Return the maximum overlapping data (in bytes) at next level for any + // file at a level >= 1. + int64_t MaxNextLevelOverlappingBytes(); + + // Create an iterator that reads over the compaction inputs for "*c". + // The caller should delete the iterator when no longer needed. + Iterator* MakeInputIterator(Compaction* c); + + // Returns true iff some level needs a compaction. + bool NeedsCompaction() const { + Version* v = current_; + return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL); + } + + // Add all files listed in any live version to *live. + // May also mutate some internal state. + void AddLiveFiles(std::set* live); + + // Return the approximate offset in the database of the data for + // "key" as of version "v". + uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key); + + // Return a human-readable short (single-line) summary of the number + // of files per level. Uses *scratch as backing store. + struct LevelSummaryStorage { + char buffer[100]; + }; + const char* LevelSummary(LevelSummaryStorage* scratch) const; + + private: + class Builder; + + friend class Compaction; + friend class Version; + + bool ReuseManifest(const std::string& dscname, const std::string& dscbase); + + void Finalize(Version* v); + + void GetRange(const std::vector& inputs, + InternalKey* smallest, + InternalKey* largest); + + void GetRange2(const std::vector& inputs1, + const std::vector& inputs2, + InternalKey* smallest, + InternalKey* largest); + + void SetupOtherInputs(Compaction* c); + + // Save current contents to *log + Status WriteSnapshot(log::Writer* log); + + void AppendVersion(Version* v); + + Env* const env_; + const std::string dbname_; + const Options* const options_; + TableCache* const table_cache_; + const InternalKeyComparator icmp_; + uint64_t next_file_number_; + uint64_t manifest_file_number_; + uint64_t last_sequence_; + uint64_t log_number_; + uint64_t prev_log_number_; // 0 or backing store for memtable being compacted + + // Opened lazily + WritableFile* descriptor_file_; + log::Writer* descriptor_log_; + Version dummy_versions_; // Head of circular doubly-linked list of versions. + Version* current_; // == dummy_versions_.prev_ + + // Per-level key at which the next compaction at that level should start. + // Either an empty string, or a valid InternalKey. + std::string compact_pointer_[config::kNumLevels]; + + // No copying allowed + VersionSet(const VersionSet&); + void operator=(const VersionSet&); +}; + +// A Compaction encapsulates information about a compaction. +class Compaction { + public: + ~Compaction(); + + // Return the level that is being compacted. Inputs from "level" + // and "level+1" will be merged to produce a set of "level+1" files. + int level() const { return level_; } + + // Return the object that holds the edits to the descriptor done + // by this compaction. + VersionEdit* edit() { return &edit_; } + + // "which" must be either 0 or 1 + int num_input_files(int which) const { return inputs_[which].size(); } + + // Return the ith input file at "level()+which" ("which" must be 0 or 1). + FileMetaData* input(int which, int i) const { return inputs_[which][i]; } + + // Maximum size of files to build during this compaction. + uint64_t MaxOutputFileSize() const { return max_output_file_size_; } + + // Is this a trivial compaction that can be implemented by just + // moving a single input file to the next level (no merging or splitting) + bool IsTrivialMove() const; + + // Add all inputs to this compaction as delete operations to *edit. + void AddInputDeletions(VersionEdit* edit); + + // Returns true if the information we have available guarantees that + // the compaction is producing data in "level+1" for which no data exists + // in levels greater than "level+1". + bool IsBaseLevelForKey(const Slice& user_key); + + // Returns true iff we should stop building the current output + // before processing "internal_key". + bool ShouldStopBefore(const Slice& internal_key); + + // Release the input version for the compaction, once the compaction + // is successful. + void ReleaseInputs(); + + private: + friend class Version; + friend class VersionSet; + + Compaction(const Options* options, int level); + + int level_; + uint64_t max_output_file_size_; + Version* input_version_; + VersionEdit edit_; + + // Each compaction reads inputs from "level_" and "level_+1" + std::vector inputs_[2]; // The two sets of inputs + + // State used to check for number of overlapping grandparent files + // (parent == level_ + 1, grandparent == level_ + 2) + std::vector grandparents_; + size_t grandparent_index_; // Index in grandparent_starts_ + bool seen_key_; // Some output key has been seen + int64_t overlapped_bytes_; // Bytes of overlap between current output + // and grandparent files + + // State for implementing IsBaseLevelForKey + + // level_ptrs_ holds indices into input_version_->levels_: our state + // is that we are positioned at one of the file ranges for each + // higher level than the ones involved in this compaction (i.e. for + // all L >= level_ + 2). + size_t level_ptrs_[config::kNumLevels]; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_ diff --git a/db/version_set_test.cc b/db/version_set_test.cc new file mode 100644 index 0000000000..501e34d133 --- /dev/null +++ b/db/version_set_test.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/version_set.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +class FindFileTest { + public: + std::vector files_; + bool disjoint_sorted_files_; + + FindFileTest() : disjoint_sorted_files_(true) { } + + ~FindFileTest() { + for (int i = 0; i < files_.size(); i++) { + delete files_[i]; + } + } + + void Add(const char* smallest, const char* largest, + SequenceNumber smallest_seq = 100, + SequenceNumber largest_seq = 100) { + FileMetaData* f = new FileMetaData; + f->number = files_.size() + 1; + f->smallest = InternalKey(smallest, smallest_seq, kTypeValue); + f->largest = InternalKey(largest, largest_seq, kTypeValue); + files_.push_back(f); + } + + int Find(const char* key) { + InternalKey target(key, 100, kTypeValue); + InternalKeyComparator cmp(BytewiseComparator()); + return FindFile(cmp, files_, target.Encode()); + } + + bool Overlaps(const char* smallest, const char* largest) { + InternalKeyComparator cmp(BytewiseComparator()); + Slice s(smallest != NULL ? smallest : ""); + Slice l(largest != NULL ? largest : ""); + return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_, + (smallest != NULL ? &s : NULL), + (largest != NULL ? &l : NULL)); + } +}; + +TEST(FindFileTest, Empty) { + ASSERT_EQ(0, Find("foo")); + ASSERT_TRUE(! Overlaps("a", "z")); + ASSERT_TRUE(! Overlaps(NULL, "z")); + ASSERT_TRUE(! Overlaps("a", NULL)); + ASSERT_TRUE(! Overlaps(NULL, NULL)); +} + +TEST(FindFileTest, Single) { + Add("p", "q"); + ASSERT_EQ(0, Find("a")); + ASSERT_EQ(0, Find("p")); + ASSERT_EQ(0, Find("p1")); + ASSERT_EQ(0, Find("q")); + ASSERT_EQ(1, Find("q1")); + ASSERT_EQ(1, Find("z")); + + ASSERT_TRUE(! Overlaps("a", "b")); + ASSERT_TRUE(! Overlaps("z1", "z2")); + ASSERT_TRUE(Overlaps("a", "p")); + ASSERT_TRUE(Overlaps("a", "q")); + ASSERT_TRUE(Overlaps("a", "z")); + ASSERT_TRUE(Overlaps("p", "p1")); + ASSERT_TRUE(Overlaps("p", "q")); + ASSERT_TRUE(Overlaps("p", "z")); + ASSERT_TRUE(Overlaps("p1", "p2")); + ASSERT_TRUE(Overlaps("p1", "z")); + ASSERT_TRUE(Overlaps("q", "q")); + ASSERT_TRUE(Overlaps("q", "q1")); + + ASSERT_TRUE(! Overlaps(NULL, "j")); + ASSERT_TRUE(! Overlaps("r", NULL)); + ASSERT_TRUE(Overlaps(NULL, "p")); + ASSERT_TRUE(Overlaps(NULL, "p1")); + ASSERT_TRUE(Overlaps("q", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); +} + + +TEST(FindFileTest, Multiple) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_EQ(0, Find("100")); + ASSERT_EQ(0, Find("150")); + ASSERT_EQ(0, Find("151")); + ASSERT_EQ(0, Find("199")); + ASSERT_EQ(0, Find("200")); + ASSERT_EQ(1, Find("201")); + ASSERT_EQ(1, Find("249")); + ASSERT_EQ(1, Find("250")); + ASSERT_EQ(2, Find("251")); + ASSERT_EQ(2, Find("299")); + ASSERT_EQ(2, Find("300")); + ASSERT_EQ(2, Find("349")); + ASSERT_EQ(2, Find("350")); + ASSERT_EQ(3, Find("351")); + ASSERT_EQ(3, Find("400")); + ASSERT_EQ(3, Find("450")); + ASSERT_EQ(4, Find("451")); + + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("251", "299")); + ASSERT_TRUE(! Overlaps("451", "500")); + ASSERT_TRUE(! Overlaps("351", "399")); + + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); +} + +TEST(FindFileTest, MultipleNullBoundaries) { + Add("150", "200"); + Add("200", "250"); + Add("300", "350"); + Add("400", "450"); + ASSERT_TRUE(! Overlaps(NULL, "149")); + ASSERT_TRUE(! Overlaps("451", NULL)); + ASSERT_TRUE(Overlaps(NULL, NULL)); + ASSERT_TRUE(Overlaps(NULL, "150")); + ASSERT_TRUE(Overlaps(NULL, "199")); + ASSERT_TRUE(Overlaps(NULL, "200")); + ASSERT_TRUE(Overlaps(NULL, "201")); + ASSERT_TRUE(Overlaps(NULL, "400")); + ASSERT_TRUE(Overlaps(NULL, "800")); + ASSERT_TRUE(Overlaps("100", NULL)); + ASSERT_TRUE(Overlaps("200", NULL)); + ASSERT_TRUE(Overlaps("449", NULL)); + ASSERT_TRUE(Overlaps("450", NULL)); +} + +TEST(FindFileTest, OverlapSequenceChecks) { + Add("200", "200", 5000, 3000); + ASSERT_TRUE(! Overlaps("199", "199")); + ASSERT_TRUE(! Overlaps("201", "300")); + ASSERT_TRUE(Overlaps("200", "200")); + ASSERT_TRUE(Overlaps("190", "200")); + ASSERT_TRUE(Overlaps("200", "210")); +} + +TEST(FindFileTest, OverlappingFiles) { + Add("150", "600"); + Add("400", "500"); + disjoint_sorted_files_ = false; + ASSERT_TRUE(! Overlaps("100", "149")); + ASSERT_TRUE(! Overlaps("601", "700")); + ASSERT_TRUE(Overlaps("100", "150")); + ASSERT_TRUE(Overlaps("100", "200")); + ASSERT_TRUE(Overlaps("100", "300")); + ASSERT_TRUE(Overlaps("100", "400")); + ASSERT_TRUE(Overlaps("100", "500")); + ASSERT_TRUE(Overlaps("375", "400")); + ASSERT_TRUE(Overlaps("450", "450")); + ASSERT_TRUE(Overlaps("450", "500")); + ASSERT_TRUE(Overlaps("450", "700")); + ASSERT_TRUE(Overlaps("600", "700")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/db/write_batch.cc b/db/write_batch.cc new file mode 100644 index 0000000000..33f4a4257e --- /dev/null +++ b/db/write_batch.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch::rep_ := +// sequence: fixed64 +// count: fixed32 +// data: record[count] +// record := +// kTypeValue varstring varstring | +// kTypeDeletion varstring +// varstring := +// len: varint32 +// data: uint8[len] + +#include "leveldb/write_batch.h" + +#include "leveldb/db.h" +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "util/coding.h" + +namespace leveldb { + +// WriteBatch header has an 8-byte sequence number followed by a 4-byte count. +static const size_t kHeader = 12; + +WriteBatch::WriteBatch() { + Clear(); +} + +WriteBatch::~WriteBatch() { } + +WriteBatch::Handler::~Handler() { } + +void WriteBatch::Clear() { + rep_.clear(); + rep_.resize(kHeader); +} + +Status WriteBatch::Iterate(Handler* handler) const { + Slice input(rep_); + if (input.size() < kHeader) { + return Status::Corruption("malformed WriteBatch (too small)"); + } + + input.remove_prefix(kHeader); + Slice key, value; + int found = 0; + while (!input.empty()) { + found++; + char tag = input[0]; + input.remove_prefix(1); + switch (tag) { + case kTypeValue: + if (GetLengthPrefixedSlice(&input, &key) && + GetLengthPrefixedSlice(&input, &value)) { + handler->Put(key, value); + } else { + return Status::Corruption("bad WriteBatch Put"); + } + break; + case kTypeDeletion: + if (GetLengthPrefixedSlice(&input, &key)) { + handler->Delete(key); + } else { + return Status::Corruption("bad WriteBatch Delete"); + } + break; + default: + return Status::Corruption("unknown WriteBatch tag"); + } + } + if (found != WriteBatchInternal::Count(this)) { + return Status::Corruption("WriteBatch has wrong count"); + } else { + return Status::OK(); + } +} + +int WriteBatchInternal::Count(const WriteBatch* b) { + return DecodeFixed32(b->rep_.data() + 8); +} + +void WriteBatchInternal::SetCount(WriteBatch* b, int n) { + EncodeFixed32(&b->rep_[8], n); +} + +SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) { + return SequenceNumber(DecodeFixed64(b->rep_.data())); +} + +void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) { + EncodeFixed64(&b->rep_[0], seq); +} + +void WriteBatch::Put(const Slice& key, const Slice& value) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeValue)); + PutLengthPrefixedSlice(&rep_, key); + PutLengthPrefixedSlice(&rep_, value); +} + +void WriteBatch::Delete(const Slice& key) { + WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1); + rep_.push_back(static_cast(kTypeDeletion)); + PutLengthPrefixedSlice(&rep_, key); +} + +namespace { +class MemTableInserter : public WriteBatch::Handler { + public: + SequenceNumber sequence_; + MemTable* mem_; + + virtual void Put(const Slice& key, const Slice& value) { + mem_->Add(sequence_, kTypeValue, key, value); + sequence_++; + } + virtual void Delete(const Slice& key) { + mem_->Add(sequence_, kTypeDeletion, key, Slice()); + sequence_++; + } +}; +} // namespace + +Status WriteBatchInternal::InsertInto(const WriteBatch* b, + MemTable* memtable) { + MemTableInserter inserter; + inserter.sequence_ = WriteBatchInternal::Sequence(b); + inserter.mem_ = memtable; + return b->Iterate(&inserter); +} + +void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) { + assert(contents.size() >= kHeader); + b->rep_.assign(contents.data(), contents.size()); +} + +void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) { + SetCount(dst, Count(dst) + Count(src)); + assert(src->rep_.size() >= kHeader); + dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader); +} + +} // namespace leveldb diff --git a/db/write_batch_internal.h b/db/write_batch_internal.h new file mode 100644 index 0000000000..9448ef7b21 --- /dev/null +++ b/db/write_batch_internal.h @@ -0,0 +1,50 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ +#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ + +#include "db/dbformat.h" +#include "leveldb/write_batch.h" + +namespace leveldb { + +class MemTable; + +// WriteBatchInternal provides static methods for manipulating a +// WriteBatch that we don't want in the public WriteBatch interface. +class WriteBatchInternal { + public: + // Return the number of entries in the batch. + static int Count(const WriteBatch* batch); + + // Set the count for the number of entries in the batch. + static void SetCount(WriteBatch* batch, int n); + + // Return the sequence number for the start of this batch. + static SequenceNumber Sequence(const WriteBatch* batch); + + // Store the specified number as the sequence number for the start of + // this batch. + static void SetSequence(WriteBatch* batch, SequenceNumber seq); + + static Slice Contents(const WriteBatch* batch) { + return Slice(batch->rep_); + } + + static size_t ByteSize(const WriteBatch* batch) { + return batch->rep_.size(); + } + + static void SetContents(WriteBatch* batch, const Slice& contents); + + static Status InsertInto(const WriteBatch* batch, MemTable* memtable); + + static void Append(WriteBatch* dst, const WriteBatch* src); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_ diff --git a/db/write_batch_test.cc b/db/write_batch_test.cc new file mode 100644 index 0000000000..9064e3d85e --- /dev/null +++ b/db/write_batch_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/db.h" + +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/env.h" +#include "util/logging.h" +#include "util/testharness.h" + +namespace leveldb { + +static std::string PrintContents(WriteBatch* b) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* mem = new MemTable(cmp); + mem->Ref(); + std::string state; + Status s = WriteBatchInternal::InsertInto(b, mem); + int count = 0; + Iterator* iter = mem->NewIterator(); + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + ParsedInternalKey ikey; + ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey)); + switch (ikey.type) { + case kTypeValue: + state.append("Put("); + state.append(ikey.user_key.ToString()); + state.append(", "); + state.append(iter->value().ToString()); + state.append(")"); + count++; + break; + case kTypeDeletion: + state.append("Delete("); + state.append(ikey.user_key.ToString()); + state.append(")"); + count++; + break; + } + state.append("@"); + state.append(NumberToString(ikey.sequence)); + } + delete iter; + if (!s.ok()) { + state.append("ParseError()"); + } else if (count != WriteBatchInternal::Count(b)) { + state.append("CountMismatch()"); + } + mem->Unref(); + return state; +} + +class WriteBatchTest { }; + +TEST(WriteBatchTest, Empty) { + WriteBatch batch; + ASSERT_EQ("", PrintContents(&batch)); + ASSERT_EQ(0, WriteBatchInternal::Count(&batch)); +} + +TEST(WriteBatchTest, Multiple) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + batch.Put(Slice("baz"), Slice("boo")); + WriteBatchInternal::SetSequence(&batch, 100); + ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch)); + ASSERT_EQ(3, WriteBatchInternal::Count(&batch)); + ASSERT_EQ("Put(baz, boo)@102" + "Delete(box)@101" + "Put(foo, bar)@100", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Corruption) { + WriteBatch batch; + batch.Put(Slice("foo"), Slice("bar")); + batch.Delete(Slice("box")); + WriteBatchInternal::SetSequence(&batch, 200); + Slice contents = WriteBatchInternal::Contents(&batch); + WriteBatchInternal::SetContents(&batch, + Slice(contents.data(),contents.size()-1)); + ASSERT_EQ("Put(foo, bar)@200" + "ParseError()", + PrintContents(&batch)); +} + +TEST(WriteBatchTest, Append) { + WriteBatch b1, b2; + WriteBatchInternal::SetSequence(&b1, 200); + WriteBatchInternal::SetSequence(&b2, 300); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("", + PrintContents(&b1)); + b2.Put("a", "va"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200", + PrintContents(&b1)); + b2.Clear(); + b2.Put("b", "vb"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@201", + PrintContents(&b1)); + b2.Delete("foo"); + WriteBatchInternal::Append(&b1, &b2); + ASSERT_EQ("Put(a, va)@200" + "Put(b, vb)@202" + "Put(b, vb)@201" + "Delete(foo)@203", + PrintContents(&b1)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/doc/bench/db_bench_sqlite3.cc b/doc/bench/db_bench_sqlite3.cc new file mode 100644 index 0000000000..e63aaa8dcc --- /dev/null +++ b/doc/bench/db_bench_sqlite3.cc @@ -0,0 +1,718 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillseqbatch -- batch write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrandbatch -- batch write N values in sequential key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in sequential order in async mode +// readseq -- read N times sequentially +// readrandom -- read N times in random order +// readrand100K -- read N/1000 100K values in sequential order in async mode +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillseqbatch," + "fillrandom," + "fillrandsync," + "fillrandbatch," + "overwrite," + "overwritebatch," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Page size. Default 1 KB. +static int FLAGS_page_size = 1024; + +// Number of pages. +// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB. +static int FLAGS_num_pages = 4096; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// If true, we allow batch writes to occur +static bool FLAGS_transaction = true; + +// If true, we enable Write-Ahead Logging +static bool FLAGS_WAL_enabled = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void ExecErrorCheck(int status, char *err_msg) { + if (status != SQLITE_OK) { + fprintf(stderr, "SQL error: %s\n", err_msg); + sqlite3_free(err_msg); + exit(1); + } +} + +inline +static void StepErrorCheck(int status) { + if (status != SQLITE_DONE) { + fprintf(stderr, "SQL step error: status = %d\n", status); + exit(1); + } +} + +inline +static void ErrorCheck(int status) { + if (status != SQLITE_OK) { + fprintf(stderr, "sqlite3 error: status = %d\n", status); + exit(1); + } +} + +inline +static void WalCheckpoint(sqlite3* db_) { + // Flush all writes to disk + if (FLAGS_WAL_enabled) { + sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + sqlite3* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + db_num_(0), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir, &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_sqlite3")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + int status = sqlite3_close(db_); + ErrorCheck(status); + } + + void Run() { + PrintHeader(); + Open(); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + bytes_ = 0; + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqbatch")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrandbatch")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("overwritebatch")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000); + WalCheckpoint(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + WalCheckpoint(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + Read(RANDOM, 1); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + Read(RANDOM, 1); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + void Open() { + assert(db_ == NULL); + + int status; + char file_name[100]; + char* err_msg = NULL; + db_num_++; + + // Open database + std::string tmp_dir; + Env::Default()->GetTestDirectory(&tmp_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_sqlite3-%d.db", + tmp_dir.c_str(), + db_num_); + status = sqlite3_open(file_name, &db_); + if (status) { + fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_)); + exit(1); + } + + // Change SQLite cache size + char cache_size[100]; + snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d", + FLAGS_num_pages); + status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // FLAGS_page_size is defaulted to 1024 + if (FLAGS_page_size != 1024) { + char page_size[100]; + snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d", + FLAGS_page_size); + status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change journal mode to WAL if WAL enabled flag is on + if (FLAGS_WAL_enabled) { + std::string WAL_stmt = "PRAGMA journal_mode = WAL"; + + // LevelDB's default cache size is a combined 4 MB + std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096"; + status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + status = sqlite3_exec(db_, WAL_checkpoint.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + + // Change locking mode to exclusive and create tables/index for database + std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE"; + std::string create_stmt = + "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))"; + std::string stmt_array[] = { locking_stmt, create_stmt }; + int stmt_array_length = sizeof(stmt_array) / sizeof(std::string); + for (int i = 0; i < stmt_array_length; i++) { + status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + } + } + + void Write(bool write_sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + sqlite3_close(db_); + db_ = NULL; + Open(); + Start(); + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + char* err_msg = NULL; + int status; + + sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt; + std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Check for synchronous flag in options + std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" : + "PRAGMA synchronous = OFF"; + status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg); + ExecErrorCheck(status, err_msg); + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, + &replace_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < num_entries; i += entries_per_batch) { + // Begin write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + const char* value = gen_.Generate(value_size).data(); + + // Create values for key-value pair + const int k = (order == SEQUENTIAL) ? i + j : + (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + + // Bind KV values into replace_stmt + status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + status = sqlite3_bind_blob(replace_stmt, 2, value, + value_size, SQLITE_STATIC); + ErrorCheck(status); + + // Execute replace_stmt + bytes_ += value_size + strlen(key); + status = sqlite3_step(replace_stmt); + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(replace_stmt); + ErrorCheck(status); + status = sqlite3_reset(replace_stmt); + ErrorCheck(status); + + FinishedSingleOp(); + } + + // End write transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(replace_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void Read(Order order, int entries_per_batch) { + int status; + sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt; + + std::string read_str = "SELECT * FROM test WHERE key = ?"; + std::string begin_trans_str = "BEGIN TRANSACTION;"; + std::string end_trans_str = "END TRANSACTION;"; + + // Preparing sqlite3 statements + status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1, + &begin_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, + &end_trans_stmt, NULL); + ErrorCheck(status); + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL); + ErrorCheck(status); + + bool transaction = (entries_per_batch > 1); + for (int i = 0; i < reads_; i += entries_per_batch) { + // Begin read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(begin_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(begin_trans_stmt); + ErrorCheck(status); + } + + // Create and execute SQL statements + for (int j = 0; j < entries_per_batch; j++) { + // Create key value + char key[100]; + int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_); + snprintf(key, sizeof(key), "%016d", k); + + // Bind key value into read_stmt + status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC); + ErrorCheck(status); + + // Execute read statement + while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {} + StepErrorCheck(status); + + // Reset SQLite statement for another use + status = sqlite3_clear_bindings(read_stmt); + ErrorCheck(status); + status = sqlite3_reset(read_stmt); + ErrorCheck(status); + FinishedSingleOp(); + } + + // End read transaction + if (FLAGS_transaction && transaction) { + status = sqlite3_step(end_trans_stmt); + StepErrorCheck(status); + status = sqlite3_reset(end_trans_stmt); + ErrorCheck(status); + } + } + + status = sqlite3_finalize(read_stmt); + ErrorCheck(status); + status = sqlite3_finalize(begin_trans_stmt); + ErrorCheck(status); + status = sqlite3_finalize(end_trans_stmt); + ErrorCheck(status); + } + + void ReadSequential() { + int status; + sqlite3_stmt *pStmt; + std::string read_str = "SELECT * FROM test ORDER BY key"; + + status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, NULL); + ErrorCheck(status); + for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) { + bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2); + FinishedSingleOp(); + } + + status = sqlite3_finalize(pStmt); + ErrorCheck(status); + } + +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_use_existing_db = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) { + FLAGS_transaction = false; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) { + FLAGS_num_pages = n; + } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_WAL_enabled = n; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/doc/bench/db_bench_tree_db.cc b/doc/bench/db_bench_tree_db.cc new file mode 100644 index 0000000000..4ca381f11f --- /dev/null +++ b/doc/bench/db_bench_tree_db.cc @@ -0,0 +1,528 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include +#include "util/histogram.h" +#include "util/random.h" +#include "util/testutil.h" + +// Comma-separated list of operations to run in the specified order +// Actual benchmarks: +// +// fillseq -- write N values in sequential key order in async mode +// fillrandom -- write N values in random key order in async mode +// overwrite -- overwrite N values in random key order in async mode +// fillseqsync -- write N/100 values in sequential key order in sync mode +// fillrandsync -- write N/100 values in random key order in sync mode +// fillrand100K -- write N/1000 100K values in random order in async mode +// fillseq100K -- write N/1000 100K values in seq order in async mode +// readseq -- read N times sequentially +// readseq100K -- read N/1000 100K values in sequential order in async mode +// readrand100K -- read N/1000 100K values in sequential order in async mode +// readrandom -- read N times in random order +static const char* FLAGS_benchmarks = + "fillseq," + "fillseqsync," + "fillrandsync," + "fillrandom," + "overwrite," + "readrandom," + "readseq," + "fillrand100K," + "fillseq100K," + "readseq100K," + "readrand100K," + ; + +// Number of key/values to place in database +static int FLAGS_num = 1000000; + +// Number of read operations to do. If negative, do FLAGS_num reads. +static int FLAGS_reads = -1; + +// Size of each value +static int FLAGS_value_size = 100; + +// Arrange to generate values that shrink to this fraction of +// their original size after compression +static double FLAGS_compression_ratio = 0.5; + +// Print histogram of operation timings +static bool FLAGS_histogram = false; + +// Cache size. Default 4 MB +static int FLAGS_cache_size = 4194304; + +// Page size. Default 1 KB +static int FLAGS_page_size = 1024; + +// If true, do not destroy the existing database. If you set this +// flag and also specify a benchmark that wants a fresh database, that +// benchmark will fail. +static bool FLAGS_use_existing_db = false; + +// Compression flag. If true, compression is on. If false, compression +// is off. +static bool FLAGS_compression = true; + +// Use the db with the following name. +static const char* FLAGS_db = NULL; + +inline +static void DBSynchronize(kyotocabinet::TreeDB* db_) +{ + // Synchronize will flush writes to disk + if (!db_->synchronize()) { + fprintf(stderr, "synchronize error: %s\n", db_->error().name()); + } +} + +namespace leveldb { + +// Helper for quickly generating random data. +namespace { +class RandomGenerator { + private: + std::string data_; + int pos_; + + public: + RandomGenerator() { + // We use a limited amount of data over and over again and ensure + // that it is larger than the compression window (32KB), and also + // large enough to serve all typical value sizes we want to write. + Random rnd(301); + std::string piece; + while (data_.size() < 1048576) { + // Add a short fragment that is as compressible as specified + // by FLAGS_compression_ratio. + test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece); + data_.append(piece); + } + pos_ = 0; + } + + Slice Generate(int len) { + if (pos_ + len > data_.size()) { + pos_ = 0; + assert(len < data_.size()); + } + pos_ += len; + return Slice(data_.data() + pos_ - len, len); + } +}; + +static Slice TrimSpace(Slice s) { + int start = 0; + while (start < s.size() && isspace(s[start])) { + start++; + } + int limit = s.size(); + while (limit > start && isspace(s[limit-1])) { + limit--; + } + return Slice(s.data() + start, limit - start); +} + +} // namespace + +class Benchmark { + private: + kyotocabinet::TreeDB* db_; + int db_num_; + int num_; + int reads_; + double start_; + double last_op_finish_; + int64_t bytes_; + std::string message_; + Histogram hist_; + RandomGenerator gen_; + Random rand_; + kyotocabinet::LZOCompressor comp_; + + // State kept for progress messages + int done_; + int next_report_; // When to report next + + void PrintHeader() { + const int kKeySize = 16; + PrintEnvironment(); + fprintf(stdout, "Keys: %d bytes each\n", kKeySize); + fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n", + FLAGS_value_size, + static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5)); + fprintf(stdout, "Entries: %d\n", num_); + fprintf(stdout, "RawSize: %.1f MB (estimated)\n", + ((static_cast(kKeySize + FLAGS_value_size) * num_) + / 1048576.0)); + fprintf(stdout, "FileSize: %.1f MB (estimated)\n", + (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) + / 1048576.0)); + PrintWarnings(); + fprintf(stdout, "------------------------------------------------\n"); + } + + void PrintWarnings() { +#if defined(__GNUC__) && !defined(__OPTIMIZE__) + fprintf(stdout, + "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n" + ); +#endif +#ifndef NDEBUG + fprintf(stdout, + "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n"); +#endif + } + + void PrintEnvironment() { + fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n", + kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV); + +#if defined(__linux) + time_t now = time(NULL); + fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline + + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if (cpuinfo != NULL) { + char line[1000]; + int num_cpus = 0; + std::string cpu_type; + std::string cache_size; + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + const char* sep = strchr(line, ':'); + if (sep == NULL) { + continue; + } + Slice key = TrimSpace(Slice(line, sep - 1 - line)); + Slice val = TrimSpace(Slice(sep + 1)); + if (key == "model name") { + ++num_cpus; + cpu_type = val.ToString(); + } else if (key == "cache size") { + cache_size = val.ToString(); + } + } + fclose(cpuinfo); + fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str()); + fprintf(stderr, "CPUCache: %s\n", cache_size.c_str()); + } +#endif + } + + void Start() { + start_ = Env::Default()->NowMicros() * 1e-6; + bytes_ = 0; + message_.clear(); + last_op_finish_ = start_; + hist_.Clear(); + done_ = 0; + next_report_ = 100; + } + + void FinishedSingleOp() { + if (FLAGS_histogram) { + double now = Env::Default()->NowMicros() * 1e-6; + double micros = (now - last_op_finish_) * 1e6; + hist_.Add(micros); + if (micros > 20000) { + fprintf(stderr, "long op: %.1f micros%30s\r", micros, ""); + fflush(stderr); + } + last_op_finish_ = now; + } + + done_++; + if (done_ >= next_report_) { + if (next_report_ < 1000) next_report_ += 100; + else if (next_report_ < 5000) next_report_ += 500; + else if (next_report_ < 10000) next_report_ += 1000; + else if (next_report_ < 50000) next_report_ += 5000; + else if (next_report_ < 100000) next_report_ += 10000; + else if (next_report_ < 500000) next_report_ += 50000; + else next_report_ += 100000; + fprintf(stderr, "... finished %d ops%30s\r", done_, ""); + fflush(stderr); + } + } + + void Stop(const Slice& name) { + double finish = Env::Default()->NowMicros() * 1e-6; + + // Pretend at least one op was done in case we are running a benchmark + // that does not call FinishedSingleOp(). + if (done_ < 1) done_ = 1; + + if (bytes_ > 0) { + char rate[100]; + snprintf(rate, sizeof(rate), "%6.1f MB/s", + (bytes_ / 1048576.0) / (finish - start_)); + if (!message_.empty()) { + message_ = std::string(rate) + " " + message_; + } else { + message_ = rate; + } + } + + fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", + name.ToString().c_str(), + (finish - start_) * 1e6 / done_, + (message_.empty() ? "" : " "), + message_.c_str()); + if (FLAGS_histogram) { + fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str()); + } + fflush(stdout); + } + + public: + enum Order { + SEQUENTIAL, + RANDOM + }; + enum DBState { + FRESH, + EXISTING + }; + + Benchmark() + : db_(NULL), + num_(FLAGS_num), + reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads), + bytes_(0), + rand_(301) { + std::vector files; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + Env::Default()->GetChildren(test_dir.c_str(), &files); + if (!FLAGS_use_existing_db) { + for (int i = 0; i < files.size(); i++) { + if (Slice(files[i]).starts_with("dbbench_polyDB")) { + std::string file_name(test_dir); + file_name += "/"; + file_name += files[i]; + Env::Default()->DeleteFile(file_name.c_str()); + } + } + } + } + + ~Benchmark() { + if (!db_->close()) { + fprintf(stderr, "close error: %s\n", db_->error().name()); + } + } + + void Run() { + PrintHeader(); + Open(false); + + const char* benchmarks = FLAGS_benchmarks; + while (benchmarks != NULL) { + const char* sep = strchr(benchmarks, ','); + Slice name; + if (sep == NULL) { + name = benchmarks; + benchmarks = NULL; + } else { + name = Slice(benchmarks, sep - benchmarks); + benchmarks = sep + 1; + } + + Start(); + + bool known = true; + bool write_sync = false; + if (name == Slice("fillseq")) { + Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrandom")) { + Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("overwrite")) { + Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrandsync")) { + write_sync = true; + Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseqsync")) { + write_sync = true; + Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1); + DBSynchronize(db_); + } else if (name == Slice("fillrand100K")) { + Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("fillseq100K")) { + Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1); + DBSynchronize(db_); + } else if (name == Slice("readseq")) { + ReadSequential(); + } else if (name == Slice("readrandom")) { + ReadRandom(); + } else if (name == Slice("readrand100K")) { + int n = reads_; + reads_ /= 1000; + ReadRandom(); + reads_ = n; + } else if (name == Slice("readseq100K")) { + int n = reads_; + reads_ /= 1000; + ReadSequential(); + reads_ = n; + } else { + known = false; + if (name != Slice()) { // No error message for empty name + fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str()); + } + } + if (known) { + Stop(name); + } + } + } + + private: + void Open(bool sync) { + assert(db_ == NULL); + + // Initialize db_ + db_ = new kyotocabinet::TreeDB(); + char file_name[100]; + db_num_++; + std::string test_dir; + Env::Default()->GetTestDirectory(&test_dir); + snprintf(file_name, sizeof(file_name), + "%s/dbbench_polyDB-%d.kct", + test_dir.c_str(), + db_num_); + + // Create tuning options and open the database + int open_options = kyotocabinet::PolyDB::OWRITER | + kyotocabinet::PolyDB::OCREATE; + int tune_options = kyotocabinet::TreeDB::TSMALL | + kyotocabinet::TreeDB::TLINEAR; + if (FLAGS_compression) { + tune_options |= kyotocabinet::TreeDB::TCOMPRESS; + db_->tune_compressor(&comp_); + } + db_->tune_options(tune_options); + db_->tune_page_cache(FLAGS_cache_size); + db_->tune_page(FLAGS_page_size); + db_->tune_map(256LL<<20); + if (sync) { + open_options |= kyotocabinet::PolyDB::OAUTOSYNC; + } + if (!db_->open(file_name, open_options)) { + fprintf(stderr, "open error: %s\n", db_->error().name()); + } + } + + void Write(bool sync, Order order, DBState state, + int num_entries, int value_size, int entries_per_batch) { + // Create new database if state == FRESH + if (state == FRESH) { + if (FLAGS_use_existing_db) { + message_ = "skipping (--use_existing_db is true)"; + return; + } + delete db_; + db_ = NULL; + Open(sync); + Start(); // Do not count time taken to destroy/open + } + + if (num_entries != num_) { + char msg[100]; + snprintf(msg, sizeof(msg), "(%d ops)", num_entries); + message_ = msg; + } + + // Write to database + for (int i = 0; i < num_entries; i++) + { + const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries); + char key[100]; + snprintf(key, sizeof(key), "%016d", k); + bytes_ += value_size + strlen(key); + std::string cpp_key = key; + if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) { + fprintf(stderr, "set error: %s\n", db_->error().name()); + } + FinishedSingleOp(); + } + } + + void ReadSequential() { + kyotocabinet::DB::Cursor* cur = db_->cursor(); + cur->jump(); + std::string ckey, cvalue; + while (cur->get(&ckey, &cvalue, true)) { + bytes_ += ckey.size() + cvalue.size(); + FinishedSingleOp(); + } + delete cur; + } + + void ReadRandom() { + std::string value; + for (int i = 0; i < reads_; i++) { + char key[100]; + const int k = rand_.Next() % reads_; + snprintf(key, sizeof(key), "%016d", k); + db_->get(key, &value); + FinishedSingleOp(); + } + } +}; + +} // namespace leveldb + +int main(int argc, char** argv) { + std::string default_db_path; + for (int i = 1; i < argc; i++) { + double d; + int n; + char junk; + if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) { + FLAGS_benchmarks = argv[i] + strlen("--benchmarks="); + } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) { + FLAGS_compression_ratio = d; + } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_histogram = n; + } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) { + FLAGS_num = n; + } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) { + FLAGS_reads = n; + } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) { + FLAGS_value_size = n; + } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) { + FLAGS_cache_size = n; + } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) { + FLAGS_page_size = n; + } else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + FLAGS_compression = (n == 1) ? true : false; + } else if (strncmp(argv[i], "--db=", 5) == 0) { + FLAGS_db = argv[i] + 5; + } else { + fprintf(stderr, "Invalid flag '%s'\n", argv[i]); + exit(1); + } + } + + // Choose a location for the test database if none given with --db= + if (FLAGS_db == NULL) { + leveldb::Env::Default()->GetTestDirectory(&default_db_path); + default_db_path += "/dbbench"; + FLAGS_db = default_db_path.c_str(); + } + + leveldb::Benchmark benchmark; + benchmark.Run(); + return 0; +} diff --git a/doc/benchmark.html b/doc/benchmark.html new file mode 100644 index 0000000000..c4639772c1 --- /dev/null +++ b/doc/benchmark.html @@ -0,0 +1,459 @@ + + + +LevelDB Benchmarks + + + + +

      LevelDB Benchmarks

      +

      Google, July 2011

      +
      + +

      In order to test LevelDB's performance, we benchmark it against other well-established database implementations. We compare LevelDB (revision 39) against SQLite3 (version 3.7.6.3) and Kyoto Cabinet's (version 1.2.67) TreeDB (a B+Tree based key-value store). We would like to acknowledge Scott Hess and Mikio Hirabayashi for their suggestions and contributions to the SQLite3 and Kyoto Cabinet benchmarks, respectively.

      + +

      Benchmarks were all performed on a six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz. (Note that LevelDB uses at most two CPUs since the benchmarks are single threaded: one to run the benchmark, and one for background compactions.) We ran the benchmarks on two machines (with identical processors), one with an Ext3 file system and one with an Ext4 file system. The machine with the Ext3 file system has a SATA Hitachi HDS721050CLA362 hard drive. The machine with the Ext4 file system has a SATA Samsung HD502HJ hard drive. Both hard drives spin at 7200 RPM and have hard drive write-caching enabled (using `hdparm -W 1 [device]`). The numbers reported below are the median of three measurements.

      + +

      Benchmark Source Code

      +

      We wrote benchmark tools for SQLite and Kyoto TreeDB based on LevelDB's db_bench. The code for each of the benchmarks resides here:

      + + +

      Custom Build Specifications

      +
        +
      • LevelDB: LevelDB was compiled with the tcmalloc library and the Snappy compression library (revision 33). Assertions were disabled.
      • +
      • TreeDB: TreeDB was compiled using the LZO compression library (version 2.03). Furthermore, we enabled the TSMALL and TLINEAR options when opening the database in order to reduce the footprint of each record.
      • +
      • SQLite: We tuned SQLite's performance, by setting its locking mode to exclusive. We also enabled SQLite's write-ahead logging.
      • +
      + +

      1. Baseline Performance

      +

      This section gives the baseline performance of all the +databases. Following sections show how performance changes as various +parameters are varied. For the baseline:

      +
        +
      • Each database is allowed 4 MB of cache memory.
      • +
      • Databases are opened in asynchronous write mode. + (LevelDB's sync option, TreeDB's OAUTOSYNC option, and + SQLite3's synchronous options are all turned off). I.e., + every write is pushed to the operating system, but the + benchmark does not wait for the write to reach the disk.
      • +
      • Keys are 16 bytes each.
      • +
      • Value are 100 bytes each (with enough redundancy so that + a simple compressor shrinks them to 50% of their original + size).
      • +
      • Sequential reads/writes traverse the key space in increasing order.
      • +
      • Random reads/writes traverse the key space in random order.
      • +
      + +

      A. Sequential Reads

      + + + + + + + + + + +
      LevelDB4,030,000 ops/sec
       
      Kyoto TreeDB1,010,000 ops/sec
       
      SQLite3383,000 ops/sec
       
      +

      B. Random Reads

      + + + + + + + + + + +
      LevelDB129,000 ops/sec
       
      Kyoto TreeDB151,000 ops/sec
       
      SQLite3134,000 ops/sec
       
      +

      C. Sequential Writes

      + + + + + + + + + + +
      LevelDB779,000 ops/sec
       
      Kyoto TreeDB342,000 ops/sec
       
      SQLite348,600 ops/sec
       
      +

      D. Random Writes

      + + + + + + + + + + +
      LevelDB164,000 ops/sec
       
      Kyoto TreeDB88,500 ops/sec
       
      SQLite39,860 ops/sec
       
      + +

      LevelDB outperforms both SQLite3 and TreeDB in sequential and random write operations and sequential read operations. Kyoto Cabinet has the fastest random read operations.

      + +

      2. Write Performance under Different Configurations

      +

      A. Large Values

      +

      For this benchmark, we start with an empty database, and write 100,000 byte values (~50% compressible). To keep the benchmark running time reasonable, we stop after writing 1000 values.

      +

      Sequential Writes

      + + + + + + + + + + +
      LevelDB1,100 ops/sec
       
      Kyoto TreeDB1,000 ops/sec
       
      SQLite31,600 ops/sec
       
      +

      Random Writes

      + + + + + + + + + + +
      LevelDB480 ops/sec
       
      Kyoto TreeDB1,100 ops/sec
       
      SQLite31,600 ops/sec
       
      +

      LevelDB doesn't perform as well with large values of 100,000 bytes each. This is because LevelDB writes keys and values at least twice: first time to the transaction log, and second time (during a compaction) to a sorted file. +With larger values, LevelDB's per-operation efficiency is swamped by the +cost of extra copies of large values.

      +

      B. Batch Writes

      +

      A batch write is a set of writes that are applied atomically to the underlying database. A single batch of N writes may be significantly faster than N individual writes. The following benchmark writes one thousand batches where each batch contains one thousand 100-byte values. TreeDB does not support batch writes and is omitted from this benchmark.

      +

      Sequential Writes

      + + + + + + + + + +
      LevelDB840,000 entries/sec
       
      (1.08x baseline)
      SQLite3124,000 entries/sec
       
      (2.55x baseline)
      +

      Random Writes

      + + + + + + + + + +
      LevelDB221,000 entries/sec
       
      (1.35x baseline)
      SQLite322,000 entries/sec
       
      (2.23x baseline)
      + +

      Because of the way LevelDB persistent storage is organized, batches of +random writes are not much slower (only a factor of 4x) than batches +of sequential writes.

      + +

      C. Synchronous Writes

      +

      In the following benchmark, we enable the synchronous writing modes +of all of the databases. Since this change significantly slows down the +benchmark, we stop after 10,000 writes. For synchronous write tests, we've +disabled hard drive write-caching (using `hdparm -W 0 [device]`).

      +
        +
      • For LevelDB, we set WriteOptions.sync = true.
      • +
      • In TreeDB, we enabled TreeDB's OAUTOSYNC option.
      • +
      • For SQLite3, we set "PRAGMA synchronous = FULL".
      • +
      +

      Sequential Writes

      + + + + + + + + + + + + + +
      LevelDB100 ops/sec
       
      (0.003x baseline)
      Kyoto TreeDB7 ops/sec
       
      (0.0004x baseline)
      SQLite388 ops/sec
       
      (0.002x baseline)
      +

      Random Writes

      + + + + + + + + + + + + + +
      LevelDB100 ops/sec
       
      (0.015x baseline)
      Kyoto TreeDB8 ops/sec
       
      (0.001x baseline)
      SQLite388 ops/sec
       
      (0.009x baseline)
      + +

      Also see the ext4 performance numbers below +since synchronous writes behave significantly differently +on ext3 and ext4.

      + +

      D. Turning Compression Off

      + +

      In the baseline measurements, LevelDB and TreeDB were using +light-weight compression +(Snappy for LevelDB, +and LZO for +TreeDB). SQLite3, by default does not use compression. The +experiments below show what happens when compression is disabled in +all of the databases (the SQLite3 numbers are just a copy of +its baseline measurements):

      + +

      Sequential Writes

      + + + + + + + + + + + + + +
      LevelDB594,000 ops/sec
       
      (0.76x baseline)
      Kyoto TreeDB485,000 ops/sec
       
      (1.42x baseline)
      SQLite348,600 ops/sec
       
      (1.00x baseline)
      +

      Random Writes

      + + + + + + + + + + + + + +
      LevelDB135,000 ops/sec
       
      (0.82x baseline)
      Kyoto TreeDB159,000 ops/sec
       
      (1.80x baseline)
      SQLite39,860 ops/sec
       
      (1.00x baseline)
      + +

      LevelDB's write performance is better with compression than without +since compression decreases the amount of data that has to be written +to disk. Therefore LevelDB users can leave compression enabled in +most scenarios without having worry about a tradeoff between space +usage and performance. TreeDB's performance on the other hand is +better without compression than with compression. Presumably this is +because TreeDB's compression library (LZO) is more expensive than +LevelDB's compression library (Snappy).

      + +

      E. Using More Memory

      +

      We increased the overall cache size for each database to 128 MB. For LevelDB, we partitioned 128 MB into a 120 MB write buffer and 8 MB of cache (up from 2 MB of write buffer and 2 MB of cache). For SQLite3, we kept the page size at 1024 bytes, but increased the number of pages to 131,072 (up from 4096). For TreeDB, we also kept the page size at 1024 bytes, but increased the cache size to 128 MB (up from 4 MB).

      +

      Sequential Writes

      + + + + + + + + + + + + + +
      LevelDB812,000 ops/sec
       
      (1.04x baseline)
      Kyoto TreeDB321,000 ops/sec
       
      (0.94x baseline)
      SQLite348,500 ops/sec
       
      (1.00x baseline)
      +

      Random Writes

      + + + + + + + + + + + + + +
      LevelDB355,000 ops/sec
       
      (2.16x baseline)
      Kyoto TreeDB284,000 ops/sec
       
      (3.21x baseline)
      SQLite39,670 ops/sec
       
      (0.98x baseline)
      + +

      SQLite's performance does not change substantially when compared to +the baseline, but the random write performance for both LevelDB and +TreeDB increases significantly. LevelDB's performance improves +because a larger write buffer reduces the need to merge sorted files +(since it creates a smaller number of larger sorted files). TreeDB's +performance goes up because the entire database is available in memory +for fast in-place updates.

      + +

      3. Read Performance under Different Configurations

      +

      A. Larger Caches

      +

      We increased the overall memory usage to 128 MB for each database. +For LevelDB, we allocated 8 MB to LevelDB's write buffer and 120 MB +to LevelDB's cache. The other databases don't differentiate between a +write buffer and a cache, so we simply set their cache size to 128 +MB.

      +

      Sequential Reads

      + + + + + + + + + + + + + +
      LevelDB5,210,000 ops/sec
       
      (1.29x baseline)
      Kyoto TreeDB1,070,000 ops/sec
       
      (1.06x baseline)
      SQLite3609,000 ops/sec
       
      (1.59x baseline)
      + +

      Random Reads

      + + + + + + + + + + + + + +
      LevelDB190,000 ops/sec
       
      (1.47x baseline)
      Kyoto TreeDB463,000 ops/sec
       
      (3.07x baseline)
      SQLite3186,000 ops/sec
       
      (1.39x baseline)
      + +

      As expected, the read performance of all of the databases increases +when the caches are enlarged. In particular, TreeDB seems to make +very effective use of a cache that is large enough to hold the entire +database.

      + +

      B. No Compression Reads

      +

      For this benchmark, we populated a database with 1 million entries consisting of 16 byte keys and 100 byte values. We compiled LevelDB and Kyoto Cabinet without compression support, so results that are read out from the database are already uncompressed. We've listed the SQLite3 baseline read performance as a point of comparison.

      +

      Sequential Reads

      + + + + + + + + + + + + + +
      LevelDB4,880,000 ops/sec
       
      (1.21x baseline)
      Kyoto TreeDB1,230,000 ops/sec
       
      (3.60x baseline)
      SQLite3383,000 ops/sec
       
      (1.00x baseline)
      +

      Random Reads

      + + + + + + + + + + + + + +
      LevelDB149,000 ops/sec
       
      (1.16x baseline)
      Kyoto TreeDB175,000 ops/sec
       
      (1.16x baseline)
      SQLite3134,000 ops/sec
       
      (1.00x baseline)
      + +

      Performance of both LevelDB and TreeDB improves a small amount when +compression is disabled. Note however that under different workloads, +performance may very well be better with compression if it allows more +of the working set to fit in memory.

      + +

      Note about Ext4 Filesystems

      +

      The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.

      + +

      Acknowledgements

      +

      Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.

      + + diff --git a/doc/impl.md b/doc/impl.md new file mode 100644 index 0000000000..4b13f2a6ba --- /dev/null +++ b/doc/impl.md @@ -0,0 +1,170 @@ +## Files + +The implementation of leveldb is similar in spirit to the representation of a +single [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html). +However the organization of the files that make up the representation is +somewhat different and is explained below. + +Each database is represented by a set of files stored in a directory. There are +several different types of files as documented below: + +### Log files + +A log file (*.log) stores a sequence of recent updates. Each update is appended +to the current log file. When the log file reaches a pre-determined size +(approximately 4MB by default), it is converted to a sorted table (see below) +and a new log file is created for future updates. + +A copy of the current log file is kept in an in-memory structure (the +`memtable`). This copy is consulted on every read so that read operations +reflect all logged updates. + +## Sorted tables + +A sorted table (*.ldb) stores a sequence of entries sorted by key. Each entry is +either a value for the key, or a deletion marker for the key. (Deletion markers +are kept around to hide obsolete values present in older sorted tables). + +The set of sorted tables are organized into a sequence of levels. The sorted +table generated from a log file is placed in a special **young** level (also +called level-0). When the number of young files exceeds a certain threshold +(currently four), all of the young files are merged together with all of the +overlapping level-1 files to produce a sequence of new level-1 files (we create +a new level-1 file for every 2MB of data.) + +Files in the young level may contain overlapping keys. However files in other +levels have distinct non-overlapping key ranges. Consider level number L where +L >= 1. When the combined size of files in level-L exceeds (10^L) MB (i.e., 10MB +for level-1, 100MB for level-2, ...), one file in level-L, and all of the +overlapping files in level-(L+1) are merged to form a set of new files for +level-(L+1). These merges have the effect of gradually migrating new updates +from the young level to the largest level using only bulk reads and writes +(i.e., minimizing expensive seeks). + +### Manifest + +A MANIFEST file lists the set of sorted tables that make up each level, the +corresponding key ranges, and other important metadata. A new MANIFEST file +(with a new number embedded in the file name) is created whenever the database +is reopened. The MANIFEST file is formatted as a log, and changes made to the +serving state (as files are added or removed) are appended to this log. + +### Current + +CURRENT is a simple text file that contains the name of the latest MANIFEST +file. + +### Info logs + +Informational messages are printed to files named LOG and LOG.old. + +### Others + +Other files used for miscellaneous purposes may also be present (LOCK, *.dbtmp). + +## Level 0 + +When the log file grows above a certain size (1MB by default): +Create a brand new memtable and log file and direct future updates here +In the background: +Write the contents of the previous memtable to an sstable +Discard the memtable +Delete the old log file and the old memtable +Add the new sstable to the young (level-0) level. + +## Compactions + +When the size of level L exceeds its limit, we compact it in a background +thread. The compaction picks a file from level L and all overlapping files from +the next level L+1. Note that if a level-L file overlaps only part of a +level-(L+1) file, the entire file at level-(L+1) is used as an input to the +compaction and will be discarded after the compaction. Aside: because level-0 +is special (files in it may overlap each other), we treat compactions from +level-0 to level-1 specially: a level-0 compaction may pick more than one +level-0 file in case some of these files overlap each other. + +A compaction merges the contents of the picked files to produce a sequence of +level-(L+1) files. We switch to producing a new level-(L+1) file after the +current output file has reached the target file size (2MB). We also switch to a +new output file when the key range of the current output file has grown enough +to overlap more than ten level-(L+2) files. This last rule ensures that a later +compaction of a level-(L+1) file will not pick up too much data from +level-(L+2). + +The old files are discarded and the new files are added to the serving state. + +Compactions for a particular level rotate through the key space. In more detail, +for each level L, we remember the ending key of the last compaction at level L. +The next compaction for level L will pick the first file that starts after this +key (wrapping around to the beginning of the key space if there is no such +file). + +Compactions drop overwritten values. They also drop deletion markers if there +are no higher numbered levels that contain a file whose range overlaps the +current key. + +### Timing + +Level-0 compactions will read up to four 1MB files from level-0, and at worst +all the level-1 files (10MB). I.e., we will read 14MB and write 14MB. + +Other than the special level-0 compactions, we will pick one 2MB file from level +L. In the worst case, this will overlap ~ 12 files from level L+1 (10 because +level-(L+1) is ten times the size of level-L, and another two at the boundaries +since the file ranges at level-L will usually not be aligned with the file +ranges at level-L+1). The compaction will therefore read 26MB and write 26MB. +Assuming a disk IO rate of 100MB/s (ballpark range for modern drives), the worst +compaction cost will be approximately 0.5 second. + +If we throttle the background writing to something small, say 10% of the full +100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at +10MB/s, we might build up lots of level-0 files (~50 to hold the 5*10MB). This +may significantly increase the cost of reads due to the overhead of merging more +files together on every read. + +Solution 1: To reduce this problem, we might want to increase the log switching +threshold when the number of level-0 files is large. Though the downside is that +the larger this threshold, the more memory we will need to hold the +corresponding memtable. + +Solution 2: We might want to decrease write rate artificially when the number of +level-0 files goes up. + +Solution 3: We work on reducing the cost of very wide merges. Perhaps most of +the level-0 files will have their blocks sitting uncompressed in the cache and +we will only need to worry about the O(N) complexity in the merging iterator. + +### Number of files + +Instead of always making 2MB files, we could make larger files for larger levels +to reduce the total file count, though at the expense of more bursty +compactions. Alternatively, we could shard the set of files into multiple +directories. + +An experiment on an ext3 filesystem on Feb 04, 2011 shows the following timings +to do 100K file opens in directories with varying number of files: + + +| Files in directory | Microseconds to open a file | +|-------------------:|----------------------------:| +| 1000 | 9 | +| 10000 | 10 | +| 100000 | 16 | + +So maybe even the sharding is not necessary on modern filesystems? + +## Recovery + +* Read CURRENT to find name of the latest committed MANIFEST +* Read the named MANIFEST file +* Clean up stale files +* We could open all sstables here, but it is probably better to be lazy... +* Convert log chunk to a new level-0 sstable +* Start directing new writes to a new log file with recovered sequence# + +## Garbage collection of files + +`DeleteObsoleteFiles()` is called at the end of every compaction and at the end +of recovery. It finds the names of all files in the database. It deletes all log +files that are not the current log file. It deletes all table files that are not +referenced from some level and are not the output of an active compaction. diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 0000000000..be8569692b --- /dev/null +++ b/doc/index.md @@ -0,0 +1,523 @@ +leveldb +======= + +_Jeff Dean, Sanjay Ghemawat_ + +The leveldb library provides a persistent key value store. Keys and values are +arbitrary byte arrays. The keys are ordered within the key value store +according to a user-specified comparator function. + +## Opening A Database + +A leveldb database has a name which corresponds to a file system directory. All +of the contents of database are stored in this directory. The following example +shows how to open a database, creating it if necessary: + +```c++ +#include +#include "leveldb/db.h" + +leveldb::DB* db; +leveldb::Options options; +options.create_if_missing = true; +leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); +assert(status.ok()); +... +``` + +If you want to raise an error if the database already exists, add the following +line before the `leveldb::DB::Open` call: + +```c++ +options.error_if_exists = true; +``` + +## Status + +You may have noticed the `leveldb::Status` type above. Values of this type are +returned by most functions in leveldb that may encounter an error. You can check +if such a result is ok, and also print an associated error message: + +```c++ +leveldb::Status s = ...; +if (!s.ok()) cerr << s.ToString() << endl; +``` + +## Closing A Database + +When you are done with a database, just delete the database object. Example: + +```c++ +... open the db as described above ... +... do something with db ... +delete db; +``` + +## Reads And Writes + +The database provides Put, Delete, and Get methods to modify/query the database. +For example, the following code moves the value stored under key1 to key2. + +```c++ +std::string value; +leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); +if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value); +if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1); +``` + +## Atomic Updates + +Note that if the process dies after the Put of key2 but before the delete of +key1, the same value may be left stored under multiple keys. Such problems can +be avoided by using the `WriteBatch` class to atomically apply a set of updates: + +```c++ +#include "leveldb/write_batch.h" +... +std::string value; +leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value); +if (s.ok()) { + leveldb::WriteBatch batch; + batch.Delete(key1); + batch.Put(key2, value); + s = db->Write(leveldb::WriteOptions(), &batch); +} +``` + +The `WriteBatch` holds a sequence of edits to be made to the database, and these +edits within the batch are applied in order. Note that we called Delete before +Put so that if key1 is identical to key2, we do not end up erroneously dropping +the value entirely. + +Apart from its atomicity benefits, `WriteBatch` may also be used to speed up +bulk updates by placing lots of individual mutations into the same batch. + +## Synchronous Writes + +By default, each write to leveldb is asynchronous: it returns after pushing the +write from the process into the operating system. The transfer from operating +system memory to the underlying persistent storage happens asynchronously. The +sync flag can be turned on for a particular write to make the write operation +not return until the data being written has been pushed all the way to +persistent storage. (On Posix systems, this is implemented by calling either +`fsync(...)` or `fdatasync(...)` or `msync(..., MS_SYNC)` before the write +operation returns.) + +```c++ +leveldb::WriteOptions write_options; +write_options.sync = true; +db->Put(write_options, ...); +``` + +Asynchronous writes are often more than a thousand times as fast as synchronous +writes. The downside of asynchronous writes is that a crash of the machine may +cause the last few updates to be lost. Note that a crash of just the writing +process (i.e., not a reboot) will not cause any loss since even when sync is +false, an update is pushed from the process memory into the operating system +before it is considered done. + +Asynchronous writes can often be used safely. For example, when loading a large +amount of data into the database you can handle lost updates by restarting the +bulk load after a crash. A hybrid scheme is also possible where every Nth write +is synchronous, and in the event of a crash, the bulk load is restarted just +after the last synchronous write finished by the previous run. (The synchronous +write can update a marker that describes where to restart on a crash.) + +`WriteBatch` provides an alternative to asynchronous writes. Multiple updates +may be placed in the same WriteBatch and applied together using a synchronous +write (i.e., `write_options.sync` is set to true). The extra cost of the +synchronous write will be amortized across all of the writes in the batch. + +## Concurrency + +A database may only be opened by one process at a time. The leveldb +implementation acquires a lock from the operating system to prevent misuse. +Within a single process, the same `leveldb::DB` object may be safely shared by +multiple concurrent threads. I.e., different threads may write into or fetch +iterators or call Get on the same database without any external synchronization +(the leveldb implementation will automatically do the required synchronization). +However other objects (like Iterator and `WriteBatch`) may require external +synchronization. If two threads share such an object, they must protect access +to it using their own locking protocol. More details are available in the public +header files. + +## Iteration + +The following example demonstrates how to print all key,value pairs in a +database. + +```c++ +leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); +for (it->SeekToFirst(); it->Valid(); it->Next()) { + cout << it->key().ToString() << ": " << it->value().ToString() << endl; +} +assert(it->status().ok()); // Check for any errors found during the scan +delete it; +``` + +The following variation shows how to process just the keys in the range +[start,limit): + +```c++ +for (it->Seek(start); + it->Valid() && it->key().ToString() < limit; + it->Next()) { + ... +} +``` + +You can also process entries in reverse order. (Caveat: reverse iteration may be +somewhat slower than forward iteration.) + +```c++ +for (it->SeekToLast(); it->Valid(); it->Prev()) { + ... +} +``` + +## Snapshots + +Snapshots provide consistent read-only views over the entire state of the +key-value store. `ReadOptions::snapshot` may be non-NULL to indicate that a +read should operate on a particular version of the DB state. If +`ReadOptions::snapshot` is NULL, the read will operate on an implicit snapshot +of the current state. + +Snapshots are created by the `DB::GetSnapshot()` method: + +```c++ +leveldb::ReadOptions options; +options.snapshot = db->GetSnapshot(); +... apply some updates to db ... +leveldb::Iterator* iter = db->NewIterator(options); +... read using iter to view the state when the snapshot was created ... +delete iter; +db->ReleaseSnapshot(options.snapshot); +``` + +Note that when a snapshot is no longer needed, it should be released using the +`DB::ReleaseSnapshot` interface. This allows the implementation to get rid of +state that was being maintained just to support reading as of that snapshot. + +## Slice + +The return value of the `it->key()` and `it->value()` calls above are instances +of the `leveldb::Slice` type. Slice is a simple structure that contains a length +and a pointer to an external byte array. Returning a Slice is a cheaper +alternative to returning a `std::string` since we do not need to copy +potentially large keys and values. In addition, leveldb methods do not return +null-terminated C-style strings since leveldb keys and values are allowed to +contain `'\0'` bytes. + +C++ strings and null-terminated C-style strings can be easily converted to a +Slice: + +```c++ +leveldb::Slice s1 = "hello"; + +std::string str("world"); +leveldb::Slice s2 = str; +``` + +A Slice can be easily converted back to a C++ string: + +```c++ +std::string str = s1.ToString(); +assert(str == std::string("hello")); +``` + +Be careful when using Slices since it is up to the caller to ensure that the +external byte array into which the Slice points remains live while the Slice is +in use. For example, the following is buggy: + +```c++ +leveldb::Slice slice; +if (...) { + std::string str = ...; + slice = str; +} +Use(slice); +``` + +When the if statement goes out of scope, str will be destroyed and the backing +storage for slice will disappear. + +## Comparators + +The preceding examples used the default ordering function for key, which orders +bytes lexicographically. You can however supply a custom comparator when opening +a database. For example, suppose each database key consists of two numbers and +we should sort by the first number, breaking ties by the second number. First, +define a proper subclass of `leveldb::Comparator` that expresses these rules: + +```c++ +class TwoPartComparator : public leveldb::Comparator { + public: + // Three-way comparison function: + // if a < b: negative result + // if a > b: positive result + // else: zero result + int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const { + int a1, a2, b1, b2; + ParseKey(a, &a1, &a2); + ParseKey(b, &b1, &b2); + if (a1 < b1) return -1; + if (a1 > b1) return +1; + if (a2 < b2) return -1; + if (a2 > b2) return +1; + return 0; + } + + // Ignore the following methods for now: + const char* Name() const { return "TwoPartComparator"; } + void FindShortestSeparator(std::string*, const leveldb::Slice&) const {} + void FindShortSuccessor(std::string*) const {} +}; +``` + +Now create a database using this custom comparator: + +```c++ +TwoPartComparator cmp; +leveldb::DB* db; +leveldb::Options options; +options.create_if_missing = true; +options.comparator = &cmp; +leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); +... +``` + +### Backwards compatibility + +The result of the comparator's Name method is attached to the database when it +is created, and is checked on every subsequent database open. If the name +changes, the `leveldb::DB::Open` call will fail. Therefore, change the name if +and only if the new key format and comparison function are incompatible with +existing databases, and it is ok to discard the contents of all existing +databases. + +You can however still gradually evolve your key format over time with a little +bit of pre-planning. For example, you could store a version number at the end of +each key (one byte should suffice for most uses). When you wish to switch to a +new key format (e.g., adding an optional third part to the keys processed by +`TwoPartComparator`), (a) keep the same comparator name (b) increment the +version number for new keys (c) change the comparator function so it uses the +version numbers found in the keys to decide how to interpret them. + +## Performance + +Performance can be tuned by changing the default values of the types defined in +`include/leveldb/options.h`. + +### Block size + +leveldb groups adjacent keys together into the same block and such a block is +the unit of transfer to and from persistent storage. The default block size is +approximately 4096 uncompressed bytes. Applications that mostly do bulk scans +over the contents of the database may wish to increase this size. Applications +that do a lot of point reads of small values may wish to switch to a smaller +block size if performance measurements indicate an improvement. There isn't much +benefit in using blocks smaller than one kilobyte, or larger than a few +megabytes. Also note that compression will be more effective with larger block +sizes. + +### Compression + +Each block is individually compressed before being written to persistent +storage. Compression is on by default since the default compression method is +very fast, and is automatically disabled for uncompressible data. In rare cases, +applications may want to disable compression entirely, but should only do so if +benchmarks show a performance improvement: + +```c++ +leveldb::Options options; +options.compression = leveldb::kNoCompression; +... leveldb::DB::Open(options, name, ...) .... +``` + +### Cache + +The contents of the database are stored in a set of files in the filesystem and +each file stores a sequence of compressed blocks. If options.cache is non-NULL, +it is used to cache frequently used uncompressed block contents. + +```c++ +#include "leveldb/cache.h" + +leveldb::Options options; +options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache +leveldb::DB* db; +leveldb::DB::Open(options, name, &db); +... use the db ... +delete db +delete options.cache; +``` + +Note that the cache holds uncompressed data, and therefore it should be sized +according to application level data sizes, without any reduction from +compression. (Caching of compressed blocks is left to the operating system +buffer cache, or any custom Env implementation provided by the client.) + +When performing a bulk read, the application may wish to disable caching so that +the data processed by the bulk read does not end up displacing most of the +cached contents. A per-iterator option can be used to achieve this: + +```c++ +leveldb::ReadOptions options; +options.fill_cache = false; +leveldb::Iterator* it = db->NewIterator(options); +for (it->SeekToFirst(); it->Valid(); it->Next()) { + ... +} +``` + +### Key Layout + +Note that the unit of disk transfer and caching is a block. Adjacent keys +(according to the database sort order) will usually be placed in the same block. +Therefore the application can improve its performance by placing keys that are +accessed together near each other and placing infrequently used keys in a +separate region of the key space. + +For example, suppose we are implementing a simple file system on top of leveldb. +The types of entries we might wish to store are: + + filename -> permission-bits, length, list of file_block_ids + file_block_id -> data + +We might want to prefix filename keys with one letter (say '/') and the +`file_block_id` keys with a different letter (say '0') so that scans over just +the metadata do not force us to fetch and cache bulky file contents. + +### Filters + +Because of the way leveldb data is organized on disk, a single `Get()` call may +involve multiple reads from disk. The optional FilterPolicy mechanism can be +used to reduce the number of disk reads substantially. + +```c++ +leveldb::Options options; +options.filter_policy = NewBloomFilterPolicy(10); +leveldb::DB* db; +leveldb::DB::Open(options, "/tmp/testdb", &db); +... use the database ... +delete db; +delete options.filter_policy; +``` + +The preceding code associates a Bloom filter based filtering policy with the +database. Bloom filter based filtering relies on keeping some number of bits of +data in memory per key (in this case 10 bits per key since that is the argument +we passed to `NewBloomFilterPolicy`). This filter will reduce the number of +unnecessary disk reads needed for Get() calls by a factor of approximately +a 100. Increasing the bits per key will lead to a larger reduction at the cost +of more memory usage. We recommend that applications whose working set does not +fit in memory and that do a lot of random reads set a filter policy. + +If you are using a custom comparator, you should ensure that the filter policy +you are using is compatible with your comparator. For example, consider a +comparator that ignores trailing spaces when comparing keys. +`NewBloomFilterPolicy` must not be used with such a comparator. Instead, the +application should provide a custom filter policy that also ignores trailing +spaces. For example: + +```c++ +class CustomFilterPolicy : public leveldb::FilterPolicy { + private: + FilterPolicy* builtin_policy_; + + public: + CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {} + ~CustomFilterPolicy() { delete builtin_policy_; } + + const char* Name() const { return "IgnoreTrailingSpacesFilter"; } + + void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Use builtin bloom filter code after removing trailing spaces + std::vector trimmed(n); + for (int i = 0; i < n; i++) { + trimmed[i] = RemoveTrailingSpaces(keys[i]); + } + return builtin_policy_->CreateFilter(&trimmed[i], n, dst); + } +}; +``` + +Advanced applications may provide a filter policy that does not use a bloom +filter but uses some other mechanism for summarizing a set of keys. See +`leveldb/filter_policy.h` for detail. + +## Checksums + +leveldb associates checksums with all data it stores in the file system. There +are two separate controls provided over how aggressively these checksums are +verified: + +`ReadOptions::verify_checksums` may be set to true to force checksum +verification of all data that is read from the file system on behalf of a +particular read. By default, no such verification is done. + +`Options::paranoid_checks` may be set to true before opening a database to make +the database implementation raise an error as soon as it detects an internal +corruption. Depending on which portion of the database has been corrupted, the +error may be raised when the database is opened, or later by another database +operation. By default, paranoid checking is off so that the database can be used +even if parts of its persistent storage have been corrupted. + +If a database is corrupted (perhaps it cannot be opened when paranoid checking +is turned on), the `leveldb::RepairDB` function may be used to recover as much +of the data as possible + +## Approximate Sizes + +The `GetApproximateSizes` method can used to get the approximate number of bytes +of file system space used by one or more key ranges. + +```c++ +leveldb::Range ranges[2]; +ranges[0] = leveldb::Range("a", "c"); +ranges[1] = leveldb::Range("x", "z"); +uint64_t sizes[2]; +leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes); +``` + +The preceding call will set `sizes[0]` to the approximate number of bytes of +file system space used by the key range `[a..c)` and `sizes[1]` to the +approximate number of bytes used by the key range `[x..z)`. + +## Environment + +All file operations (and other operating system calls) issued by the leveldb +implementation are routed through a `leveldb::Env` object. Sophisticated clients +may wish to provide their own Env implementation to get better control. +For example, an application may introduce artificial delays in the file IO +paths to limit the impact of leveldb on other activities in the system. + +```c++ +class SlowEnv : public leveldb::Env { + ... implementation of the Env interface ... +}; + +SlowEnv env; +leveldb::Options options; +options.env = &env; +Status s = leveldb::DB::Open(options, ...); +``` + +## Porting + +leveldb may be ported to a new platform by providing platform specific +implementations of the types/methods/functions exported by +`leveldb/port/port.h`. See `leveldb/port/port_example.h` for more details. + +In addition, the new platform may need a new default `leveldb::Env` +implementation. See `leveldb/util/env_posix.h` for an example. + +## Other Information + +Details about the leveldb implementation may be found in the following +documents: + +1. [Implementation notes](impl.md) +2. [Format of an immutable Table file](table_format.md) +3. [Format of a log file](log_format.md) diff --git a/doc/log_format.md b/doc/log_format.md new file mode 100644 index 0000000000..f32cb5d7da --- /dev/null +++ b/doc/log_format.md @@ -0,0 +1,75 @@ +leveldb Log format +================== +The log file contents are a sequence of 32KB blocks. The only exception is that +the tail of the file may contain a partial block. + +Each block consists of a sequence of records: + + block := record* trailer? + record := + checksum: uint32 // crc32c of type and data[] ; little-endian + length: uint16 // little-endian + type: uint8 // One of FULL, FIRST, MIDDLE, LAST + data: uint8[length] + +A record never starts within the last six bytes of a block (since it won't fit). +Any leftover bytes here form the trailer, which must consist entirely of zero +bytes and must be skipped by readers. + +Aside: if exactly seven bytes are left in the current block, and a new non-zero +length record is added, the writer must emit a FIRST record (which contains zero +bytes of user data) to fill up the trailing seven bytes of the block and then +emit all of the user data in subsequent blocks. + +More types may be added in the future. Some Readers may skip record types they +do not understand, others may report that some data was skipped. + + FULL == 1 + FIRST == 2 + MIDDLE == 3 + LAST == 4 + +The FULL record contains the contents of an entire user record. + +FIRST, MIDDLE, LAST are types used for user records that have been split into +multiple fragments (typically because of block boundaries). FIRST is the type +of the first fragment of a user record, LAST is the type of the last fragment of +a user record, and MIDDLE is the type of all interior fragments of a user +record. + +Example: consider a sequence of user records: + + A: length 1000 + B: length 97270 + C: length 8000 + +**A** will be stored as a FULL record in the first block. + +**B** will be split into three fragments: first fragment occupies the rest of +the first block, second fragment occupies the entirety of the second block, and +the third fragment occupies a prefix of the third block. This will leave six +bytes free in the third block, which will be left empty as the trailer. + +**C** will be stored as a FULL record in the fourth block. + +---- + +## Some benefits over the recordio format: + +1. We do not need any heuristics for resyncing - just go to next block boundary + and scan. If there is a corruption, skip to the next block. As a + side-benefit, we do not get confused when part of the contents of one log + file are embedded as a record inside another log file. + +2. Splitting at approximate boundaries (e.g., for mapreduce) is simple: find the + next block boundary and skip records until we hit a FULL or FIRST record. + +3. We do not need extra buffering for large records. + +## Some downsides compared to recordio format: + +1. No packing of tiny records. This could be fixed by adding a new record type, + so it is a shortcoming of the current implementation, not necessarily the + format. + +2. No compression. Again, this could be fixed by adding new record types. diff --git a/doc/table_format.md b/doc/table_format.md new file mode 100644 index 0000000000..5fe7e72411 --- /dev/null +++ b/doc/table_format.md @@ -0,0 +1,107 @@ +leveldb File format +=================== + + + [data block 1] + [data block 2] + ... + [data block N] + [meta block 1] + ... + [meta block K] + [metaindex block] + [index block] + [Footer] (fixed size; starts at file_size - sizeof(Footer)) + + +The file contains internal pointers. Each such pointer is called +a BlockHandle and contains the following information: + + offset: varint64 + size: varint64 + +See [varints](https://developers.google.com/protocol-buffers/docs/encoding#varints) +for an explanation of varint64 format. + +1. The sequence of key/value pairs in the file are stored in sorted +order and partitioned into a sequence of data blocks. These blocks +come one after another at the beginning of the file. Each data block +is formatted according to the code in `block_builder.cc`, and then +optionally compressed. + +2. After the data blocks we store a bunch of meta blocks. The +supported meta block types are described below. More meta block types +may be added in the future. Each meta block is again formatted using +`block_builder.cc` and then optionally compressed. + +3. A "metaindex" block. It contains one entry for every other meta +block where the key is the name of the meta block and the value is a +BlockHandle pointing to that meta block. + +4. An "index" block. This block contains one entry per data block, +where the key is a string >= last key in that data block and before +the first key in the successive data block. The value is the +BlockHandle for the data block. + +5. At the very end of the file is a fixed length footer that contains +the BlockHandle of the metaindex and index blocks as well as a magic number. + + metaindex_handle: char[p]; // Block handle for metaindex + index_handle: char[q]; // Block handle for index + padding: char[40-p-q];// zeroed bytes to make fixed length + // (40==2*BlockHandle::kMaxEncodedLength) + magic: fixed64; // == 0xdb4775248b80fb57 (little-endian) + +## "filter" Meta Block + +If a `FilterPolicy` was specified when the database was opened, a +filter block is stored in each table. The "metaindex" block contains +an entry that maps from `filter.` to the BlockHandle for the filter +block where `` is the string returned by the filter policy's +`Name()` method. + +The filter block stores a sequence of filters, where filter i contains +the output of `FilterPolicy::CreateFilter()` on all keys that are stored +in a block whose file offset falls within the range + + [ i*base ... (i+1)*base-1 ] + +Currently, "base" is 2KB. So for example, if blocks X and Y start in +the range `[ 0KB .. 2KB-1 ]`, all of the keys in X and Y will be +converted to a filter by calling `FilterPolicy::CreateFilter()`, and the +resulting filter will be stored as the first filter in the filter +block. + +The filter block is formatted as follows: + + [filter 0] + [filter 1] + [filter 2] + ... + [filter N-1] + + [offset of filter 0] : 4 bytes + [offset of filter 1] : 4 bytes + [offset of filter 2] : 4 bytes + ... + [offset of filter N-1] : 4 bytes + + [offset of beginning of offset array] : 4 bytes + lg(base) : 1 byte + +The offset array at the end of the filter block allows efficient +mapping from a data block offset to the corresponding filter. + +## "stats" Meta Block + +This meta block contains a bunch of stats. The key is the name +of the statistic. The value contains the statistic. + +TODO(postrelease): record following stats. + + data size + index size + key size (uncompressed) + value size (uncompressed) + number of entries + number of data blocks diff --git a/helpers/memenv/memenv.cc b/helpers/memenv/memenv.cc new file mode 100644 index 0000000000..68c0614a59 --- /dev/null +++ b/helpers/memenv/memenv.cc @@ -0,0 +1,401 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "leveldb/env.h" +#include "leveldb/status.h" +#include "port/port.h" +#include "util/mutexlock.h" +#include +#include +#include +#include + +namespace leveldb { + +namespace { + +class FileState { + public: + // FileStates are reference counted. The initial reference count is zero + // and the caller must call Ref() at least once. + FileState() : refs_(0), size_(0) {} + + // Increase the reference count. + void Ref() { + MutexLock lock(&refs_mutex_); + ++refs_; + } + + // Decrease the reference count. Delete if this is the last reference. + void Unref() { + bool do_delete = false; + + { + MutexLock lock(&refs_mutex_); + --refs_; + assert(refs_ >= 0); + if (refs_ <= 0) { + do_delete = true; + } + } + + if (do_delete) { + delete this; + } + } + + uint64_t Size() const { return size_; } + + Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { + if (offset > size_) { + return Status::IOError("Offset greater than file size."); + } + const uint64_t available = size_ - offset; + if (n > available) { + n = static_cast(available); + } + if (n == 0) { + *result = Slice(); + return Status::OK(); + } + + assert(offset / kBlockSize <= SIZE_MAX); + size_t block = static_cast(offset / kBlockSize); + size_t block_offset = offset % kBlockSize; + + if (n <= kBlockSize - block_offset) { + // The requested bytes are all in the first block. + *result = Slice(blocks_[block] + block_offset, n); + return Status::OK(); + } + + size_t bytes_to_copy = n; + char* dst = scratch; + + while (bytes_to_copy > 0) { + size_t avail = kBlockSize - block_offset; + if (avail > bytes_to_copy) { + avail = bytes_to_copy; + } + memcpy(dst, blocks_[block] + block_offset, avail); + + bytes_to_copy -= avail; + dst += avail; + block++; + block_offset = 0; + } + + *result = Slice(scratch, n); + return Status::OK(); + } + + Status Append(const Slice& data) { + const char* src = data.data(); + size_t src_len = data.size(); + + while (src_len > 0) { + size_t avail; + size_t offset = size_ % kBlockSize; + + if (offset != 0) { + // There is some room in the last block. + avail = kBlockSize - offset; + } else { + // No room in the last block; push new one. + blocks_.push_back(new char[kBlockSize]); + avail = kBlockSize; + } + + if (avail > src_len) { + avail = src_len; + } + memcpy(blocks_.back() + offset, src, avail); + src_len -= avail; + src += avail; + size_ += avail; + } + + return Status::OK(); + } + + private: + // Private since only Unref() should be used to delete it. + ~FileState() { + for (std::vector::iterator i = blocks_.begin(); i != blocks_.end(); + ++i) { + delete [] *i; + } + } + + // No copying allowed. + FileState(const FileState&); + void operator=(const FileState&); + + port::Mutex refs_mutex_; + int refs_; // Protected by refs_mutex_; + + // The following fields are not protected by any mutex. They are only mutable + // while the file is being written, and concurrent access is not allowed + // to writable files. + std::vector blocks_; + uint64_t size_; + + enum { kBlockSize = 8 * 1024 }; +}; + +class SequentialFileImpl : public SequentialFile { + public: + explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) { + file_->Ref(); + } + + ~SequentialFileImpl() { + file_->Unref(); + } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s = file_->Read(pos_, n, result, scratch); + if (s.ok()) { + pos_ += result->size(); + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (pos_ > file_->Size()) { + return Status::IOError("pos_ > file_->Size()"); + } + const uint64_t available = file_->Size() - pos_; + if (n > available) { + n = available; + } + pos_ += n; + return Status::OK(); + } + + virtual std::string GetName() const { return "[memenv]"; } + private: + FileState* file_; + uint64_t pos_; +}; + +class RandomAccessFileImpl : public RandomAccessFile { + public: + explicit RandomAccessFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~RandomAccessFileImpl() { + file_->Unref(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + return file_->Read(offset, n, result, scratch); + } + + virtual std::string GetName() const { return "[memenv]"; } + private: + FileState* file_; +}; + +class WritableFileImpl : public WritableFile { + public: + WritableFileImpl(FileState* file) : file_(file) { + file_->Ref(); + } + + ~WritableFileImpl() { + file_->Unref(); + } + + virtual Status Append(const Slice& data) { + return file_->Append(data); + } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + virtual std::string GetName() const { return "[memenv]"; } + private: + FileState* file_; +}; + +class NoOpLogger : public Logger { + public: + virtual void Logv(const char* format, va_list ap) { } +}; + +class InMemoryEnv : public EnvWrapper { + public: + explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { } + + virtual ~InMemoryEnv() { + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + i->second->Unref(); + } + } + + // Partial implementation of the Env interface. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new SequentialFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + *result = NULL; + return Status::IOError(fname, "File not found"); + } + + *result = new RandomAccessFileImpl(file_map_[fname]); + return Status::OK(); + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) != file_map_.end()) { + DeleteFileInternal(fname); + } + + FileState* file = new FileState(); + file->Ref(); + file_map_[fname] = file; + + *result = new WritableFileImpl(file); + return Status::OK(); + } + + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + MutexLock lock(&mutex_); + FileState** sptr = &file_map_[fname]; + FileState* file = *sptr; + if (file == NULL) { + file = new FileState(); + file->Ref(); + } + *result = new WritableFileImpl(file); + return Status::OK(); + } + + virtual bool FileExists(const std::string& fname) { + MutexLock lock(&mutex_); + return file_map_.find(fname) != file_map_.end(); + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + MutexLock lock(&mutex_); + result->clear(); + + for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){ + const std::string& filename = i->first; + + if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' && + Slice(filename).starts_with(Slice(dir))) { + result->push_back(filename.substr(dir.size() + 1)); + } + } + + return Status::OK(); + } + + void DeleteFileInternal(const std::string& fname) { + if (file_map_.find(fname) == file_map_.end()) { + return; + } + + file_map_[fname]->Unref(); + file_map_.erase(fname); + } + + virtual Status DeleteFile(const std::string& fname) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + DeleteFileInternal(fname); + return Status::OK(); + } + + virtual Status CreateDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status DeleteDir(const std::string& dirname) { + return Status::OK(); + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) { + MutexLock lock(&mutex_); + if (file_map_.find(fname) == file_map_.end()) { + return Status::IOError(fname, "File not found"); + } + + *file_size = file_map_[fname]->Size(); + return Status::OK(); + } + + virtual Status RenameFile(const std::string& src, + const std::string& target) { + MutexLock lock(&mutex_); + if (file_map_.find(src) == file_map_.end()) { + return Status::IOError(src, "File not found"); + } + + DeleteFileInternal(target); + file_map_[target] = file_map_[src]; + file_map_.erase(src); + return Status::OK(); + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = new FileLock; + return Status::OK(); + } + + virtual Status UnlockFile(FileLock* lock) { + delete lock; + return Status::OK(); + } + + virtual Status GetTestDirectory(std::string* path) { + *path = "/test"; + return Status::OK(); + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + *result = new NoOpLogger; + return Status::OK(); + } + + private: + // Map from filenames to FileState objects, representing a simple file system. + typedef std::map FileSystem; + port::Mutex mutex_; + FileSystem file_map_; // Protected by mutex_. +}; + +} // namespace + +Env* NewMemEnv(Env* base_env) { + return new InMemoryEnv(base_env); +} + +} // namespace leveldb diff --git a/helpers/memenv/memenv.h b/helpers/memenv/memenv.h new file mode 100644 index 0000000000..03b88de761 --- /dev/null +++ b/helpers/memenv/memenv.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ +#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ + +namespace leveldb { + +class Env; + +// Returns a new environment that stores its data in memory and delegates +// all non-file-storage tasks to base_env. The caller must delete the result +// when it is no longer needed. +// *base_env must remain live while the result is in use. +Env* NewMemEnv(Env* base_env); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_ diff --git a/helpers/memenv/memenv_test.cc b/helpers/memenv/memenv_test.cc new file mode 100644 index 0000000000..5cff77613f --- /dev/null +++ b/helpers/memenv/memenv_test.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "helpers/memenv/memenv.h" + +#include "db/db_impl.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "util/testharness.h" +#include +#include + +namespace leveldb { + +class MemEnvTest { + public: + Env* env_; + + MemEnvTest() + : env_(NewMemEnv(Env::Default())) { + } + ~MemEnvTest() { + delete env_; + } +}; + +TEST(MemEnvTest, Basics) { + uint64_t file_size; + WritableFile* writable_file; + std::vector children; + + ASSERT_OK(env_->CreateDir("/dir")); + + // Check that the directory is empty. + ASSERT_TRUE(!env_->FileExists("/dir/non_existent")); + ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok()); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + + // Create a file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(0, file_size); + delete writable_file; + + // Check that the file exists. + ASSERT_TRUE(env_->FileExists("/dir/f")); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(0, file_size); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(1, children.size()); + ASSERT_EQ("f", children[0]); + + // Write to the file. + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("abc")); + delete writable_file; + + // Check that append works. + ASSERT_OK(env_->NewAppendableFile("/dir/f", &writable_file)); + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(3, file_size); + ASSERT_OK(writable_file->Append("hello")); + delete writable_file; + + // Check for expected size. + ASSERT_OK(env_->GetFileSize("/dir/f", &file_size)); + ASSERT_EQ(8, file_size); + + // Check that renaming works. + ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok()); + ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g")); + ASSERT_TRUE(!env_->FileExists("/dir/f")); + ASSERT_TRUE(env_->FileExists("/dir/g")); + ASSERT_OK(env_->GetFileSize("/dir/g", &file_size)); + ASSERT_EQ(8, file_size); + + // Check that opening non-existent file fails. + SequentialFile* seq_file; + RandomAccessFile* rand_file; + ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok()); + ASSERT_TRUE(!seq_file); + ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok()); + ASSERT_TRUE(!rand_file); + + // Check that deleting works. + ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok()); + ASSERT_OK(env_->DeleteFile("/dir/g")); + ASSERT_TRUE(!env_->FileExists("/dir/g")); + ASSERT_OK(env_->GetChildren("/dir", &children)); + ASSERT_EQ(0, children.size()); + ASSERT_OK(env_->DeleteDir("/dir")); +} + +TEST(MemEnvTest, ReadWrite) { + WritableFile* writable_file; + SequentialFile* seq_file; + RandomAccessFile* rand_file; + Slice result; + char scratch[100]; + + ASSERT_OK(env_->CreateDir("/dir")); + + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("hello ")); + ASSERT_OK(writable_file->Append("world")); + delete writable_file; + + // Read sequentially. + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(seq_file->Skip(1)); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF. + ASSERT_EQ(0, result.size()); + ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file. + ASSERT_OK(seq_file->Read(1000, &result, scratch)); + ASSERT_EQ(0, result.size()); + delete seq_file; + + // Random reads. + ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file)); + ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world". + ASSERT_EQ(0, result.compare("world")); + ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello". + ASSERT_EQ(0, result.compare("hello")); + ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d". + ASSERT_EQ(0, result.compare("d")); + + // Too high offset. + ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok()); + delete rand_file; +} + +TEST(MemEnvTest, Locks) { + FileLock* lock; + + // These are no-ops, but we test they return success. + ASSERT_OK(env_->LockFile("some file", &lock)); + ASSERT_OK(env_->UnlockFile(lock)); +} + +TEST(MemEnvTest, Misc) { + std::string test_dir; + ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_TRUE(!test_dir.empty()); + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file)); + + // These are no-ops, but we test they return success. + ASSERT_OK(writable_file->Sync()); + ASSERT_OK(writable_file->Flush()); + ASSERT_OK(writable_file->Close()); + delete writable_file; +} + +TEST(MemEnvTest, LargeWrite) { + const size_t kWriteSize = 300 * 1024; + char* scratch = new char[kWriteSize * 2]; + + std::string write_data; + for (size_t i = 0; i < kWriteSize; ++i) { + write_data.append(1, static_cast(i)); + } + + WritableFile* writable_file; + ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file)); + ASSERT_OK(writable_file->Append("foo")); + ASSERT_OK(writable_file->Append(write_data)); + delete writable_file; + + SequentialFile* seq_file; + Slice result; + ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file)); + ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo". + ASSERT_EQ(0, result.compare("foo")); + + size_t read = 0; + std::string read_data; + while (read < kWriteSize) { + ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch)); + read_data.append(result.data(), result.size()); + read += result.size(); + } + ASSERT_TRUE(write_data == read_data); + delete seq_file; + delete [] scratch; +} + +TEST(MemEnvTest, DBTest) { + Options options; + options.create_if_missing = true; + options.env = env_; + DB* db; + + const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")}; + const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")}; + + ASSERT_OK(DB::Open(options, "/dir/db", &db)); + for (size_t i = 0; i < 3; ++i) { + ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i])); + } + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + Iterator* iterator = db->NewIterator(ReadOptions()); + iterator->SeekToFirst(); + for (size_t i = 0; i < 3; ++i) { + ASSERT_TRUE(iterator->Valid()); + ASSERT_TRUE(keys[i] == iterator->key()); + ASSERT_TRUE(vals[i] == iterator->value()); + iterator->Next(); + } + ASSERT_TRUE(!iterator->Valid()); + delete iterator; + + DBImpl* dbi = reinterpret_cast(db); + ASSERT_OK(dbi->TEST_CompactMemTable()); + + for (size_t i = 0; i < 3; ++i) { + std::string res; + ASSERT_OK(db->Get(ReadOptions(), keys[i], &res)); + ASSERT_TRUE(res == vals[i]); + } + + delete db; +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/include/leveldb/c.h b/include/leveldb/c.h new file mode 100644 index 0000000000..1048fe3b86 --- /dev/null +++ b/include/leveldb/c.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2011 The LevelDB Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. See the AUTHORS file for names of contributors. + + C bindings for leveldb. May be useful as a stable ABI that can be + used by programs that keep leveldb in a shared library, or for + a JNI api. + + Does not support: + . getters for the option types + . custom comparators that implement key shortening + . custom iter, db, env, cache implementations using just the C bindings + + Some conventions: + + (1) We expose just opaque struct pointers and functions to clients. + This allows us to change internal representations without having to + recompile clients. + + (2) For simplicity, there is no equivalent to the Slice type. Instead, + the caller has to pass the pointer and length as separate + arguments. + + (3) Errors are represented by a null-terminated c string. NULL + means no error. All operations that can raise an error are passed + a "char** errptr" as the last argument. One of the following must + be true on entry: + *errptr == NULL + *errptr points to a malloc()ed null-terminated error message + (On Windows, *errptr must have been malloc()-ed by this library.) + On success, a leveldb routine leaves *errptr unchanged. + On failure, leveldb frees the old value of *errptr and + set *errptr to a malloc()ed error message. + + (4) Bools have the type unsigned char (0 == false; rest == true) + + (5) All of the pointer arguments must be non-NULL. +*/ + +#ifndef STORAGE_LEVELDB_INCLUDE_C_H_ +#define STORAGE_LEVELDB_INCLUDE_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Exported types */ + +typedef struct leveldb_t leveldb_t; +typedef struct leveldb_cache_t leveldb_cache_t; +typedef struct leveldb_comparator_t leveldb_comparator_t; +typedef struct leveldb_env_t leveldb_env_t; +typedef struct leveldb_filelock_t leveldb_filelock_t; +typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t; +typedef struct leveldb_iterator_t leveldb_iterator_t; +typedef struct leveldb_logger_t leveldb_logger_t; +typedef struct leveldb_options_t leveldb_options_t; +typedef struct leveldb_randomfile_t leveldb_randomfile_t; +typedef struct leveldb_readoptions_t leveldb_readoptions_t; +typedef struct leveldb_seqfile_t leveldb_seqfile_t; +typedef struct leveldb_snapshot_t leveldb_snapshot_t; +typedef struct leveldb_writablefile_t leveldb_writablefile_t; +typedef struct leveldb_writebatch_t leveldb_writebatch_t; +typedef struct leveldb_writeoptions_t leveldb_writeoptions_t; + +/* DB operations */ + +extern leveldb_t* leveldb_open( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_close(leveldb_t* db); + +extern void leveldb_put( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + const char* val, size_t vallen, + char** errptr); + +extern void leveldb_delete( + leveldb_t* db, + const leveldb_writeoptions_t* options, + const char* key, size_t keylen, + char** errptr); + +extern void leveldb_write( + leveldb_t* db, + const leveldb_writeoptions_t* options, + leveldb_writebatch_t* batch, + char** errptr); + +/* Returns NULL if not found. A malloc()ed array otherwise. + Stores the length of the array in *vallen. */ +extern char* leveldb_get( + leveldb_t* db, + const leveldb_readoptions_t* options, + const char* key, size_t keylen, + size_t* vallen, + char** errptr); + +extern leveldb_iterator_t* leveldb_create_iterator( + leveldb_t* db, + const leveldb_readoptions_t* options); + +extern const leveldb_snapshot_t* leveldb_create_snapshot( + leveldb_t* db); + +extern void leveldb_release_snapshot( + leveldb_t* db, + const leveldb_snapshot_t* snapshot); + +/* Returns NULL if property name is unknown. + Else returns a pointer to a malloc()-ed null-terminated value. */ +extern char* leveldb_property_value( + leveldb_t* db, + const char* propname); + +extern void leveldb_approximate_sizes( + leveldb_t* db, + int num_ranges, + const char* const* range_start_key, const size_t* range_start_key_len, + const char* const* range_limit_key, const size_t* range_limit_key_len, + uint64_t* sizes); + +extern void leveldb_compact_range( + leveldb_t* db, + const char* start_key, size_t start_key_len, + const char* limit_key, size_t limit_key_len); + +/* Management operations */ + +extern void leveldb_destroy_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +extern void leveldb_repair_db( + const leveldb_options_t* options, + const char* name, + char** errptr); + +/* Iterator */ + +extern void leveldb_iter_destroy(leveldb_iterator_t*); +extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*); +extern void leveldb_iter_seek_to_first(leveldb_iterator_t*); +extern void leveldb_iter_seek_to_last(leveldb_iterator_t*); +extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen); +extern void leveldb_iter_next(leveldb_iterator_t*); +extern void leveldb_iter_prev(leveldb_iterator_t*); +extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen); +extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen); +extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr); + +/* Write batch */ + +extern leveldb_writebatch_t* leveldb_writebatch_create(); +extern void leveldb_writebatch_destroy(leveldb_writebatch_t*); +extern void leveldb_writebatch_clear(leveldb_writebatch_t*); +extern void leveldb_writebatch_put( + leveldb_writebatch_t*, + const char* key, size_t klen, + const char* val, size_t vlen); +extern void leveldb_writebatch_delete( + leveldb_writebatch_t*, + const char* key, size_t klen); +extern void leveldb_writebatch_iterate( + leveldb_writebatch_t*, + void* state, + void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), + void (*deleted)(void*, const char* k, size_t klen)); + +/* Options */ + +extern leveldb_options_t* leveldb_options_create(); +extern void leveldb_options_destroy(leveldb_options_t*); +extern void leveldb_options_set_comparator( + leveldb_options_t*, + leveldb_comparator_t*); +extern void leveldb_options_set_filter_policy( + leveldb_options_t*, + leveldb_filterpolicy_t*); +extern void leveldb_options_set_create_if_missing( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_error_if_exists( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_paranoid_checks( + leveldb_options_t*, unsigned char); +extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*); +extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*); +extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_max_open_files(leveldb_options_t*, int); +extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*); +extern void leveldb_options_set_block_size(leveldb_options_t*, size_t); +extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int); + +enum { + leveldb_no_compression = 0, + leveldb_snappy_compression = 1 +}; +extern void leveldb_options_set_compression(leveldb_options_t*, int); + +/* Comparator */ + +extern leveldb_comparator_t* leveldb_comparator_create( + void* state, + void (*destructor)(void*), + int (*compare)( + void*, + const char* a, size_t alen, + const char* b, size_t blen), + const char* (*name)(void*)); +extern void leveldb_comparator_destroy(leveldb_comparator_t*); + +/* Filter policy */ + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create( + void* state, + void (*destructor)(void*), + char* (*create_filter)( + void*, + const char* const* key_array, const size_t* key_length_array, + int num_keys, + size_t* filter_length), + unsigned char (*key_may_match)( + void*, + const char* key, size_t length, + const char* filter, size_t filter_length), + const char* (*name)(void*)); +extern void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t*); + +extern leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom( + int bits_per_key); + +/* Read options */ + +extern leveldb_readoptions_t* leveldb_readoptions_create(); +extern void leveldb_readoptions_destroy(leveldb_readoptions_t*); +extern void leveldb_readoptions_set_verify_checksums( + leveldb_readoptions_t*, + unsigned char); +extern void leveldb_readoptions_set_fill_cache( + leveldb_readoptions_t*, unsigned char); +extern void leveldb_readoptions_set_snapshot( + leveldb_readoptions_t*, + const leveldb_snapshot_t*); + +/* Write options */ + +extern leveldb_writeoptions_t* leveldb_writeoptions_create(); +extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*); +extern void leveldb_writeoptions_set_sync( + leveldb_writeoptions_t*, unsigned char); + +/* Cache */ + +extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity); +extern void leveldb_cache_destroy(leveldb_cache_t* cache); + +/* Env */ + +extern leveldb_env_t* leveldb_create_default_env(); +extern void leveldb_env_destroy(leveldb_env_t*); + +/* Utility */ + +/* Calls free(ptr). + REQUIRES: ptr was malloc()-ed and returned by one of the routines + in this file. Note that in certain cases (typically on Windows), you + may need to call this routine instead of free(ptr) to dispose of + malloc()-ed memory returned by this library. */ +extern void leveldb_free(void* ptr); + +/* Return the major version number for this release. */ +extern int leveldb_major_version(); + +/* Return the minor version number for this release. */ +extern int leveldb_minor_version(); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */ diff --git a/include/leveldb/cache.h b/include/leveldb/cache.h new file mode 100644 index 0000000000..6819d5bc49 --- /dev/null +++ b/include/leveldb/cache.h @@ -0,0 +1,110 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Cache is an interface that maps keys to values. It has internal +// synchronization and may be safely accessed concurrently from +// multiple threads. It may automatically evict entries to make room +// for new entries. Values have a specified charge against the cache +// capacity. For example, a cache where the values are variable +// length strings, may use the length of the string as the charge for +// the string. +// +// A builtin cache implementation with a least-recently-used eviction +// policy is provided. Clients may use their own implementations if +// they want something more sophisticated (like scan-resistance, a +// custom eviction policy, variable cache sizing, etc.) + +#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_ +#define STORAGE_LEVELDB_INCLUDE_CACHE_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Cache; + +// Create a new cache with a fixed size capacity. This implementation +// of Cache uses a least-recently-used eviction policy. +extern Cache* NewLRUCache(size_t capacity); + +class Cache { + public: + Cache() { } + + // Destroys all existing entries by calling the "deleter" + // function that was passed to the constructor. + virtual ~Cache(); + + // Opaque handle to an entry stored in the cache. + struct Handle { }; + + // Insert a mapping from key->value into the cache and assign it + // the specified charge against the total cache capacity. + // + // Returns a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + // + // When the inserted entry is no longer needed, the key and + // value will be passed to "deleter". + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) = 0; + + // If the cache has no mapping for "key", returns NULL. + // + // Else return a handle that corresponds to the mapping. The caller + // must call this->Release(handle) when the returned mapping is no + // longer needed. + virtual Handle* Lookup(const Slice& key) = 0; + + // Release a mapping returned by a previous Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void Release(Handle* handle) = 0; + + // Return the value encapsulated in a handle returned by a + // successful Lookup(). + // REQUIRES: handle must not have been released yet. + // REQUIRES: handle must have been returned by a method on *this. + virtual void* Value(Handle* handle) = 0; + + // If the cache contains entry for key, erase it. Note that the + // underlying entry will be kept around until all existing handles + // to it have been released. + virtual void Erase(const Slice& key) = 0; + + // Return a new numeric id. May be used by multiple clients who are + // sharing the same cache to partition the key space. Typically the + // client will allocate a new id at startup and prepend the id to + // its cache keys. + virtual uint64_t NewId() = 0; + + // Remove all cache entries that are not actively in use. Memory-constrained + // applications may wish to call this method to reduce memory usage. + // Default implementation of Prune() does nothing. Subclasses are strongly + // encouraged to override the default implementation. A future release of + // leveldb may change Prune() to a pure abstract method. + virtual void Prune() {} + + // Return an estimate of the combined charges of all elements stored in the + // cache. + virtual size_t TotalCharge() const = 0; + + private: + void LRU_Remove(Handle* e); + void LRU_Append(Handle* e); + void Unref(Handle* e); + + struct Rep; + Rep* rep_; + + // No copying allowed + Cache(const Cache&); + void operator=(const Cache&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_CACHE_H_ diff --git a/include/leveldb/comparator.h b/include/leveldb/comparator.h new file mode 100644 index 0000000000..556b984c76 --- /dev/null +++ b/include/leveldb/comparator.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ + +#include + +namespace leveldb { + +class Slice; + +// A Comparator object provides a total order across slices that are +// used as keys in an sstable or a database. A Comparator implementation +// must be thread-safe since leveldb may invoke its methods concurrently +// from multiple threads. +class Comparator { + public: + virtual ~Comparator(); + + // Three-way comparison. Returns value: + // < 0 iff "a" < "b", + // == 0 iff "a" == "b", + // > 0 iff "a" > "b" + virtual int Compare(const Slice& a, const Slice& b) const = 0; + + // The name of the comparator. Used to check for comparator + // mismatches (i.e., a DB created with one comparator is + // accessed using a different comparator. + // + // The client of this package should switch to a new name whenever + // the comparator implementation changes in a way that will cause + // the relative ordering of any two keys to change. + // + // Names starting with "leveldb." are reserved and should not be used + // by any clients of this package. + virtual const char* Name() const = 0; + + // Advanced functions: these are used to reduce the space requirements + // for internal data structures like index blocks. + + // If *start < limit, changes *start to a short string in [start,limit). + // Simple comparator implementations may return with *start unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const = 0; + + // Changes *key to a short string >= *key. + // Simple comparator implementations may return with *key unchanged, + // i.e., an implementation of this method that does nothing is correct. + virtual void FindShortSuccessor(std::string* key) const = 0; +}; + +// Return a builtin comparator that uses lexicographic byte-wise +// ordering. The result remains the property of this module and +// must not be deleted. +extern const Comparator* BytewiseComparator(); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_ diff --git a/include/leveldb/db.h b/include/leveldb/db.h new file mode 100644 index 0000000000..bfab10a0b7 --- /dev/null +++ b/include/leveldb/db.h @@ -0,0 +1,163 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_ +#define STORAGE_LEVELDB_INCLUDE_DB_H_ + +#include +#include +#include "leveldb/iterator.h" +#include "leveldb/options.h" + +namespace leveldb { + +// Update Makefile if you change these +static const int kMajorVersion = 1; +static const int kMinorVersion = 20; + +struct Options; +struct ReadOptions; +struct WriteOptions; +class WriteBatch; + +// Abstract handle to particular state of a DB. +// A Snapshot is an immutable object and can therefore be safely +// accessed from multiple threads without any external synchronization. +class Snapshot { + protected: + virtual ~Snapshot(); +}; + +// A range of keys +struct Range { + Slice start; // Included in the range + Slice limit; // Not included in the range + + Range() { } + Range(const Slice& s, const Slice& l) : start(s), limit(l) { } +}; + +// A DB is a persistent ordered map from keys to values. +// A DB is safe for concurrent access from multiple threads without +// any external synchronization. +class DB { + public: + // Open the database with the specified "name". + // Stores a pointer to a heap-allocated database in *dbptr and returns + // OK on success. + // Stores NULL in *dbptr and returns a non-OK status on error. + // Caller should delete *dbptr when it is no longer needed. + static Status Open(const Options& options, + const std::string& name, + DB** dbptr); + + DB() { } + virtual ~DB(); + + // Set the database entry for "key" to "value". Returns OK on success, + // and a non-OK status on error. + // Note: consider setting options.sync = true. + virtual Status Put(const WriteOptions& options, + const Slice& key, + const Slice& value) = 0; + + // Remove the database entry (if any) for "key". Returns OK on + // success, and a non-OK status on error. It is not an error if "key" + // did not exist in the database. + // Note: consider setting options.sync = true. + virtual Status Delete(const WriteOptions& options, const Slice& key) = 0; + + // Apply the specified updates to the database. + // Returns OK on success, non-OK on failure. + // Note: consider setting options.sync = true. + virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0; + + // If the database contains an entry for "key" store the + // corresponding value in *value and return OK. + // + // If there is no entry for "key" leave *value unchanged and return + // a status for which Status::IsNotFound() returns true. + // + // May return some other Status on an error. + virtual Status Get(const ReadOptions& options, + const Slice& key, std::string* value) = 0; + + // Return a heap-allocated iterator over the contents of the database. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + // + // Caller should delete the iterator when it is no longer needed. + // The returned iterator should be deleted before this db is deleted. + virtual Iterator* NewIterator(const ReadOptions& options) = 0; + + // Return a handle to the current DB state. Iterators created with + // this handle will all observe a stable snapshot of the current DB + // state. The caller must call ReleaseSnapshot(result) when the + // snapshot is no longer needed. + virtual const Snapshot* GetSnapshot() = 0; + + // Release a previously acquired snapshot. The caller must not + // use "snapshot" after this call. + virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0; + + // DB implementations can export properties about their state + // via this method. If "property" is a valid property understood by this + // DB implementation, fills "*value" with its current value and returns + // true. Otherwise returns false. + // + // + // Valid property names include: + // + // "leveldb.num-files-at-level" - return the number of files at level , + // where is an ASCII representation of a level number (e.g. "0"). + // "leveldb.stats" - returns a multi-line string that describes statistics + // about the internal operation of the DB. + // "leveldb.sstables" - returns a multi-line string that describes all + // of the sstables that make up the db contents. + // "leveldb.approximate-memory-usage" - returns the approximate number of + // bytes of memory in use by the DB. + virtual bool GetProperty(const Slice& property, std::string* value) = 0; + + // For each i in [0,n-1], store in "sizes[i]", the approximate + // file system space used by keys in "[range[i].start .. range[i].limit)". + // + // Note that the returned sizes measure file system space usage, so + // if the user data compresses by a factor of ten, the returned + // sizes will be one-tenth the size of the corresponding user data size. + // + // The results may not include the sizes of recently written data. + virtual void GetApproximateSizes(const Range* range, int n, + uint64_t* sizes) = 0; + + // Compact the underlying storage for the key range [*begin,*end]. + // In particular, deleted and overwritten versions are discarded, + // and the data is rearranged to reduce the cost of operations + // needed to access the data. This operation should typically only + // be invoked by users who understand the underlying implementation. + // + // begin==NULL is treated as a key before all keys in the database. + // end==NULL is treated as a key after all keys in the database. + // Therefore the following call will compact the entire database: + // db->CompactRange(NULL, NULL); + virtual void CompactRange(const Slice* begin, const Slice* end) = 0; + + private: + // No copying allowed + DB(const DB&); + void operator=(const DB&); +}; + +// Destroy the contents of the specified database. +// Be very careful using this method. +Status DestroyDB(const std::string& name, const Options& options); + +// If a DB cannot be opened, you may attempt to call this method to +// resurrect as much of the contents of the database as possible. +// Some data may be lost, so be careful when calling this function +// on a database that contains important information. +Status RepairDB(const std::string& dbname, const Options& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DB_H_ diff --git a/include/leveldb/dumpfile.h b/include/leveldb/dumpfile.h new file mode 100644 index 0000000000..3f97fda16b --- /dev/null +++ b/include/leveldb/dumpfile.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ +#define STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ + +#include +#include "leveldb/env.h" +#include "leveldb/status.h" + +namespace leveldb { + +// Dump the contents of the file named by fname in text format to +// *dst. Makes a sequence of dst->Append() calls; each call is passed +// the newline-terminated text corresponding to a single item found +// in the file. +// +// Returns a non-OK result if fname does not name a leveldb storage +// file, or if the file cannot be read. +Status DumpFile(Env* env, const std::string& fname, WritableFile* dst); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_DUMPFILE_H_ diff --git a/include/leveldb/env.h b/include/leveldb/env.h new file mode 100644 index 0000000000..275d441eae --- /dev/null +++ b/include/leveldb/env.h @@ -0,0 +1,360 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An Env is an interface used by the leveldb implementation to access +// operating system functionality like the filesystem etc. Callers +// may wish to provide a custom Env object when opening a database to +// get fine gain control; e.g., to rate limit file system operations. +// +// All Env implementations are safe for concurrent access from +// multiple threads without any external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_ +#define STORAGE_LEVELDB_INCLUDE_ENV_H_ + +#include +#include +#include +#include +#include "leveldb/status.h" + +namespace leveldb { + +class FileLock; +class Logger; +class RandomAccessFile; +class SequentialFile; +class Slice; +class WritableFile; + +class Env { + public: + Env() { } + virtual ~Env(); + + // Return a default environment suitable for the current operating + // system. Sophisticated users may wish to provide their own Env + // implementation instead of relying on this default environment. + // + // The result of Default() belongs to leveldb and must never be deleted. + static Env* Default(); + + // Create a brand new sequentially-readable file with the specified name. + // On success, stores a pointer to the new file in *result and returns OK. + // On failure stores NULL in *result and returns non-OK. If the file does + // not exist, returns a non-OK status. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) = 0; + + // Create a brand new random access read-only file with the + // specified name. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. If the file does not exist, returns a non-OK + // status. + // + // The returned file may be concurrently accessed by multiple threads. + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) = 0; + + // Create an object that writes to a new file with the specified + // name. Deletes any existing file with the same name and creates a + // new file. On success, stores a pointer to the new file in + // *result and returns OK. On failure stores NULL in *result and + // returns non-OK. + // + // The returned file will only be accessed by one thread at a time. + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) = 0; + + // Create an object that either appends to an existing file, or + // writes to a new file (if the file does not exist to begin with). + // On success, stores a pointer to the new file in *result and + // returns OK. On failure stores NULL in *result and returns + // non-OK. + // + // The returned file will only be accessed by one thread at a time. + // + // May return an IsNotSupportedError error if this Env does + // not allow appending to an existing file. Users of Env (including + // the leveldb implementation) must be prepared to deal with + // an Env that does not support appending. + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + + // Returns true iff the named file exists. + virtual bool FileExists(const std::string& fname) = 0; + + // Store in *result the names of the children of the specified directory. + // The names are relative to "dir". + // Original contents of *results are dropped. + virtual Status GetChildren(const std::string& dir, + std::vector* result) = 0; + + // Delete the named file. + virtual Status DeleteFile(const std::string& fname) = 0; + + // Create the specified directory. + virtual Status CreateDir(const std::string& dirname) = 0; + + // Delete the specified directory. + virtual Status DeleteDir(const std::string& dirname) = 0; + + // Store the size of fname in *file_size. + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; + + // Rename file src to target. + virtual Status RenameFile(const std::string& src, + const std::string& target) = 0; + + // Lock the specified file. Used to prevent concurrent access to + // the same db by multiple processes. On failure, stores NULL in + // *lock and returns non-OK. + // + // On success, stores a pointer to the object that represents the + // acquired lock in *lock and returns OK. The caller should call + // UnlockFile(*lock) to release the lock. If the process exits, + // the lock will be automatically released. + // + // If somebody else already holds the lock, finishes immediately + // with a failure. I.e., this call does not wait for existing locks + // to go away. + // + // May create the named file if it does not already exist. + virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; + + // Release the lock acquired by a previous successful call to LockFile. + // REQUIRES: lock was returned by a successful LockFile() call + // REQUIRES: lock has not already been unlocked. + virtual Status UnlockFile(FileLock* lock) = 0; + + // Arrange to run "(*function)(arg)" once in a background thread. + // + // "function" may run in an unspecified thread. Multiple functions + // added to the same Env may run concurrently in different threads. + // I.e., the caller may not assume that background work items are + // serialized. + virtual void Schedule( + void (*function)(void* arg), + void* arg) = 0; + + // Start a new thread, invoking "function(arg)" within the new thread. + // When "function(arg)" returns, the thread will be destroyed. + virtual void StartThread(void (*function)(void* arg), void* arg) = 0; + + // *path is set to a temporary directory that can be used for testing. It may + // or many not have just been created. The directory may or may not differ + // between runs of the same process, but subsequent calls will return the + // same directory. + virtual Status GetTestDirectory(std::string* path) = 0; + + // Create and return a log file for storing informational messages. + virtual Status NewLogger(const std::string& fname, Logger** result) = 0; + + // Returns the number of micro-seconds since some fixed point in time. Only + // useful for computing deltas of time. + virtual uint64_t NowMicros() = 0; + + // Sleep/delay the thread for the prescribed number of micro-seconds. + virtual void SleepForMicroseconds(int micros) = 0; + + private: + // No copying allowed + Env(const Env&); + void operator=(const Env&); +}; + +// A file abstraction for reading sequentially through a file +class SequentialFile { + public: + SequentialFile() { } + virtual ~SequentialFile(); + + // Read up to "n" bytes from the file. "scratch[0..n-1]" may be + // written by this routine. Sets "*result" to the data that was + // read (including if fewer than "n" bytes were successfully read). + // May set "*result" to point at data in "scratch[0..n-1]", so + // "scratch[0..n-1]" must be live when "*result" is used. + // If an error was encountered, returns a non-OK status. + // + // REQUIRES: External synchronization + virtual Status Read(size_t n, Slice* result, char* scratch) = 0; + + // Skip "n" bytes from the file. This is guaranteed to be no + // slower that reading the same data, but may be faster. + // + // If end of file is reached, skipping will stop at the end of the + // file, and Skip will return OK. + // + // REQUIRES: External synchronization + virtual Status Skip(uint64_t n) = 0; + + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + + private: + // No copying allowed + SequentialFile(const SequentialFile&); + void operator=(const SequentialFile&); +}; + +// A file abstraction for randomly reading the contents of a file. +class RandomAccessFile { + public: + RandomAccessFile() { } + virtual ~RandomAccessFile(); + + // Read up to "n" bytes from the file starting at "offset". + // "scratch[0..n-1]" may be written by this routine. Sets "*result" + // to the data that was read (including if fewer than "n" bytes were + // successfully read). May set "*result" to point at data in + // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when + // "*result" is used. If an error was encountered, returns a non-OK + // status. + // + // Safe for concurrent use by multiple threads. + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const = 0; + + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + + private: + // No copying allowed + RandomAccessFile(const RandomAccessFile&); + void operator=(const RandomAccessFile&); +}; + +// A file abstraction for sequential writing. The implementation +// must provide buffering since callers may append small fragments +// at a time to the file. +class WritableFile { + public: + WritableFile() { } + virtual ~WritableFile(); + + virtual Status Append(const Slice& data) = 0; + virtual Status Close() = 0; + virtual Status Flush() = 0; + virtual Status Sync() = 0; + + // Get a name for the file, only for error reporting + virtual std::string GetName() const = 0; + + private: + // No copying allowed + WritableFile(const WritableFile&); + void operator=(const WritableFile&); +}; + +// An interface for writing log messages. +class Logger { + public: + Logger() { } + virtual ~Logger(); + + // Write an entry to the log file with the specified format. + virtual void Logv(const char* format, va_list ap) = 0; + + private: + // No copying allowed + Logger(const Logger&); + void operator=(const Logger&); +}; + + +// Identifies a locked file. +class FileLock { + public: + FileLock() { } + virtual ~FileLock(); + private: + // No copying allowed + FileLock(const FileLock&); + void operator=(const FileLock&); +}; + +// Log the specified data to *info_log if info_log is non-NULL. +extern void Log(Logger* info_log, const char* format, ...) +# if defined(__GNUC__) || defined(__clang__) + __attribute__((__format__ (__printf__, 2, 3))) +# endif + ; + +// A utility routine: write "data" to the named file. +extern Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname); + +// A utility routine: read contents of named file into *data +extern Status ReadFileToString(Env* env, const std::string& fname, + std::string* data); + +// An implementation of Env that forwards all calls to another Env. +// May be useful to clients who wish to override just part of the +// functionality of another Env. +class EnvWrapper : public Env { + public: + // Initialize an EnvWrapper that delegates all calls to *t + explicit EnvWrapper(Env* t) : target_(t) { } + virtual ~EnvWrapper(); + + // Return the target to which this Env forwards all calls + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target() + Status NewSequentialFile(const std::string& f, SequentialFile** r) { + return target_->NewSequentialFile(f, r); + } + Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) { + return target_->NewRandomAccessFile(f, r); + } + Status NewWritableFile(const std::string& f, WritableFile** r) { + return target_->NewWritableFile(f, r); + } + Status NewAppendableFile(const std::string& f, WritableFile** r) { + return target_->NewAppendableFile(f, r); + } + bool FileExists(const std::string& f) { return target_->FileExists(f); } + Status GetChildren(const std::string& dir, std::vector* r) { + return target_->GetChildren(dir, r); + } + Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); } + Status CreateDir(const std::string& d) { return target_->CreateDir(d); } + Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); } + Status GetFileSize(const std::string& f, uint64_t* s) { + return target_->GetFileSize(f, s); + } + Status RenameFile(const std::string& s, const std::string& t) { + return target_->RenameFile(s, t); + } + Status LockFile(const std::string& f, FileLock** l) { + return target_->LockFile(f, l); + } + Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); } + void Schedule(void (*f)(void*), void* a) { + return target_->Schedule(f, a); + } + void StartThread(void (*f)(void*), void* a) { + return target_->StartThread(f, a); + } + virtual Status GetTestDirectory(std::string* path) { + return target_->GetTestDirectory(path); + } + virtual Status NewLogger(const std::string& fname, Logger** result) { + return target_->NewLogger(fname, result); + } + uint64_t NowMicros() { + return target_->NowMicros(); + } + void SleepForMicroseconds(int micros) { + target_->SleepForMicroseconds(micros); + } + private: + Env* target_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_ diff --git a/include/leveldb/filter_policy.h b/include/leveldb/filter_policy.h new file mode 100644 index 0000000000..1fba08001f --- /dev/null +++ b/include/leveldb/filter_policy.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A database can be configured with a custom FilterPolicy object. +// This object is responsible for creating a small filter from a set +// of keys. These filters are stored in leveldb and are consulted +// automatically by leveldb to decide whether or not to read some +// information from disk. In many cases, a filter can cut down the +// number of disk seeks form a handful to a single disk seek per +// DB::Get() call. +// +// Most people will want to use the builtin bloom filter support (see +// NewBloomFilterPolicy() below). + +#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ +#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ + +#include + +namespace leveldb { + +class Slice; + +class FilterPolicy { + public: + virtual ~FilterPolicy(); + + // Return the name of this policy. Note that if the filter encoding + // changes in an incompatible way, the name returned by this method + // must be changed. Otherwise, old incompatible filters may be + // passed to methods of this type. + virtual const char* Name() const = 0; + + // keys[0,n-1] contains a list of keys (potentially with duplicates) + // that are ordered according to the user supplied comparator. + // Append a filter that summarizes keys[0,n-1] to *dst. + // + // Warning: do not change the initial contents of *dst. Instead, + // append the newly constructed filter to *dst. + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) + const = 0; + + // "filter" contains the data appended by a preceding call to + // CreateFilter() on this class. This method must return true if + // the key was in the list of keys passed to CreateFilter(). + // This method may return true or false if the key was not on the + // list, but it should aim to return false with a high probability. + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0; +}; + +// Return a new filter policy that uses a bloom filter with approximately +// the specified number of bits per key. A good value for bits_per_key +// is 10, which yields a filter with ~ 1% false positive rate. +// +// Callers must delete the result after any database that is using the +// result has been closed. +// +// Note: if you are using a custom comparator that ignores some parts +// of the keys being compared, you must not use NewBloomFilterPolicy() +// and must provide your own FilterPolicy that also ignores the +// corresponding parts of the keys. For example, if the comparator +// ignores trailing spaces, it would be incorrect to use a +// FilterPolicy (like NewBloomFilterPolicy) that does not ignore +// trailing spaces in keys. +extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key); + +} + +#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_ diff --git a/include/leveldb/iterator.h b/include/leveldb/iterator.h new file mode 100644 index 0000000000..da631ed9d8 --- /dev/null +++ b/include/leveldb/iterator.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// An iterator yields a sequence of key/value pairs from a source. +// The following class defines the interface. Multiple implementations +// are provided by this library. In particular, iterators are provided +// to access the contents of a Table or a DB. +// +// Multiple threads can invoke const methods on an Iterator without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Iterator must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ +#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ + +#include "leveldb/slice.h" +#include "leveldb/status.h" + +namespace leveldb { + +class Iterator { + public: + Iterator(); + virtual ~Iterator(); + + // An iterator is either positioned at a key/value pair, or + // not valid. This method returns true iff the iterator is valid. + virtual bool Valid() const = 0; + + // Position at the first key in the source. The iterator is Valid() + // after this call iff the source is not empty. + virtual void SeekToFirst() = 0; + + // Position at the last key in the source. The iterator is + // Valid() after this call iff the source is not empty. + virtual void SeekToLast() = 0; + + // Position at the first key in the source that is at or past target. + // The iterator is Valid() after this call iff the source contains + // an entry that comes at or past target. + virtual void Seek(const Slice& target) = 0; + + // Moves to the next entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the last entry in the source. + // REQUIRES: Valid() + virtual void Next() = 0; + + // Moves to the previous entry in the source. After this call, Valid() is + // true iff the iterator was not positioned at the first entry in source. + // REQUIRES: Valid() + virtual void Prev() = 0; + + // Return the key for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice key() const = 0; + + // Return the value for the current entry. The underlying storage for + // the returned slice is valid only until the next modification of + // the iterator. + // REQUIRES: Valid() + virtual Slice value() const = 0; + + // If an error has occurred, return it. Else return an ok status. + virtual Status status() const = 0; + + // Clients are allowed to register function/arg1/arg2 triples that + // will be invoked when this iterator is destroyed. + // + // Note that unlike all of the preceding methods, this method is + // not abstract and therefore clients should not override it. + typedef void (*CleanupFunction)(void* arg1, void* arg2); + void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2); + + private: + struct Cleanup { + CleanupFunction function; + void* arg1; + void* arg2; + Cleanup* next; + }; + Cleanup cleanup_; + + // No copying allowed + Iterator(const Iterator&); + void operator=(const Iterator&); +}; + +// Return an empty iterator (yields nothing). +extern Iterator* NewEmptyIterator(); + +// Return an empty iterator with the specified status. +extern Iterator* NewErrorIterator(const Status& status); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_ diff --git a/include/leveldb/options.h b/include/leveldb/options.h new file mode 100644 index 0000000000..976e38122a --- /dev/null +++ b/include/leveldb/options.h @@ -0,0 +1,213 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ +#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ + +#include + +namespace leveldb { + +class Cache; +class Comparator; +class Env; +class FilterPolicy; +class Logger; +class Snapshot; + +// DB contents are stored in a set of blocks, each of which holds a +// sequence of key,value pairs. Each block may be compressed before +// being stored in a file. The following enum describes which +// compression method (if any) is used to compress a block. +enum CompressionType { + // NOTE: do not change the values of existing entries, as these are + // part of the persistent format on disk. + kNoCompression = 0x0, + kSnappyCompression = 0x1 +}; + +// Options to control the behavior of a database (passed to DB::Open) +struct Options { + // ------------------- + // Parameters that affect behavior + + // Comparator used to define the order of keys in the table. + // Default: a comparator that uses lexicographic byte-wise ordering + // + // REQUIRES: The client must ensure that the comparator supplied + // here has the same name and orders keys *exactly* the same as the + // comparator provided to previous open calls on the same DB. + const Comparator* comparator; + + // If true, the database will be created if it is missing. + // Default: false + bool create_if_missing; + + // If true, an error is raised if the database already exists. + // Default: false + bool error_if_exists; + + // If true, the implementation will do aggressive checking of the + // data it is processing and will stop early if it detects any + // errors. This may have unforeseen ramifications: for example, a + // corruption of one DB entry may cause a large number of entries to + // become unreadable or for the entire DB to become unopenable. + // Default: false + bool paranoid_checks; + + // Use the specified object to interact with the environment, + // e.g. to read/write files, schedule background work, etc. + // Default: Env::Default() + Env* env; + + // Any internal progress/error information generated by the db will + // be written to info_log if it is non-NULL, or to a file stored + // in the same directory as the DB contents if info_log is NULL. + // Default: NULL + Logger* info_log; + + // ------------------- + // Parameters that affect performance + + // Amount of data to build up in memory (backed by an unsorted log + // on disk) before converting to a sorted on-disk file. + // + // Larger values increase performance, especially during bulk loads. + // Up to two write buffers may be held in memory at the same time, + // so you may wish to adjust this parameter to control memory usage. + // Also, a larger write buffer will result in a longer recovery time + // the next time the database is opened. + // + // Default: 4MB + size_t write_buffer_size; + + // Number of open files that can be used by the DB. You may need to + // increase this if your database has a large working set (budget + // one open file per 2MB of working set). + // + // Default: 1000 + int max_open_files; + + // Control over blocks (user data is stored in a set of blocks, and + // a block is the unit of reading from disk). + + // If non-NULL, use the specified cache for blocks. + // If NULL, leveldb will automatically create and use an 8MB internal cache. + // Default: NULL + Cache* block_cache; + + // Approximate size of user data packed per block. Note that the + // block size specified here corresponds to uncompressed data. The + // actual size of the unit read from disk may be smaller if + // compression is enabled. This parameter can be changed dynamically. + // + // Default: 4K + size_t block_size; + + // Number of keys between restart points for delta encoding of keys. + // This parameter can be changed dynamically. Most clients should + // leave this parameter alone. + // + // Default: 16 + int block_restart_interval; + + // Leveldb will write up to this amount of bytes to a file before + // switching to a new one. + // Most clients should leave this parameter alone. However if your + // filesystem is more efficient with larger files, you could + // consider increasing the value. The downside will be longer + // compactions and hence longer latency/performance hiccups. + // Another reason to increase this parameter might be when you are + // initially populating a large database. + // + // Default: 2MB + size_t max_file_size; + + // Compress blocks using the specified compression algorithm. This + // parameter can be changed dynamically. + // + // Default: kSnappyCompression, which gives lightweight but fast + // compression. + // + // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz: + // ~200-500MB/s compression + // ~400-800MB/s decompression + // Note that these speeds are significantly faster than most + // persistent storage speeds, and therefore it is typically never + // worth switching to kNoCompression. Even if the input data is + // incompressible, the kSnappyCompression implementation will + // efficiently detect that and will switch to uncompressed mode. + CompressionType compression; + + // EXPERIMENTAL: If true, append to existing MANIFEST and log files + // when a database is opened. This can significantly speed up open. + // + // Default: currently false, but may become true later. + bool reuse_logs; + + // If non-NULL, use the specified filter policy to reduce disk reads. + // Many applications will benefit from passing the result of + // NewBloomFilterPolicy() here. + // + // Default: NULL + const FilterPolicy* filter_policy; + + // Create an Options object with default values for all fields. + Options(); +}; + +// Options that control read operations +struct ReadOptions { + // If true, all data read from underlying storage will be + // verified against corresponding checksums. + // Default: false + bool verify_checksums; + + // Should the data read for this iteration be cached in memory? + // Callers may wish to set this field to false for bulk scans. + // Default: true + bool fill_cache; + + // If "snapshot" is non-NULL, read as of the supplied snapshot + // (which must belong to the DB that is being read and which must + // not have been released). If "snapshot" is NULL, use an implicit + // snapshot of the state at the beginning of this read operation. + // Default: NULL + const Snapshot* snapshot; + + ReadOptions() + : verify_checksums(false), + fill_cache(true), + snapshot(NULL) { + } +}; + +// Options that control write operations +struct WriteOptions { + // If true, the write will be flushed from the operating system + // buffer cache (by calling WritableFile::Sync()) before the write + // is considered complete. If this flag is true, writes will be + // slower. + // + // If this flag is false, and the machine crashes, some recent + // writes may be lost. Note that if it is just the process that + // crashes (i.e., the machine does not reboot), no writes will be + // lost even if sync==false. + // + // In other words, a DB write with sync==false has similar + // crash semantics as the "write()" system call. A DB write + // with sync==true has similar crash semantics to a "write()" + // system call followed by "fsync()". + // + // Default: false + bool sync; + + WriteOptions() + : sync(false) { + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_ diff --git a/include/leveldb/slice.h b/include/leveldb/slice.h new file mode 100644 index 0000000000..bc367986f7 --- /dev/null +++ b/include/leveldb/slice.h @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Slice is a simple structure containing a pointer into some external +// storage and a size. The user of a Slice must ensure that the slice +// is not used after the corresponding external storage has been +// deallocated. +// +// Multiple threads can invoke const methods on a Slice without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Slice must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_ +#define STORAGE_LEVELDB_INCLUDE_SLICE_H_ + +#include +#include +#include +#include + +namespace leveldb { + +class Slice { + public: + // Create an empty slice. + Slice() : data_(""), size_(0) { } + + // Create a slice that refers to d[0,n-1]. + Slice(const char* d, size_t n) : data_(d), size_(n) { } + + // Create a slice that refers to the contents of "s" + Slice(const std::string& s) : data_(s.data()), size_(s.size()) { } + + // Create a slice that refers to s[0,strlen(s)-1] + Slice(const char* s) : data_(s), size_(strlen(s)) { } + + // Return a pointer to the beginning of the referenced data + const char* data() const { return data_; } + + // Return the length (in bytes) of the referenced data + size_t size() const { return size_; } + + // Return true iff the length of the referenced data is zero + bool empty() const { return size_ == 0; } + + // Return the ith byte in the referenced data. + // REQUIRES: n < size() + char operator[](size_t n) const { + assert(n < size()); + return data_[n]; + } + + // Change this slice to refer to an empty array + void clear() { data_ = ""; size_ = 0; } + + // Drop the first "n" bytes from this slice. + void remove_prefix(size_t n) { + assert(n <= size()); + data_ += n; + size_ -= n; + } + + // Return a string that contains the copy of the referenced data. + std::string ToString() const { return std::string(data_, size_); } + + // Three-way comparison. Returns value: + // < 0 iff "*this" < "b", + // == 0 iff "*this" == "b", + // > 0 iff "*this" > "b" + int compare(const Slice& b) const; + + // Return true iff "x" is a prefix of "*this" + bool starts_with(const Slice& x) const { + return ((size_ >= x.size_) && + (memcmp(data_, x.data_, x.size_) == 0)); + } + + private: + const char* data_; + size_t size_; + + // Intentionally copyable +}; + +inline bool operator==(const Slice& x, const Slice& y) { + return ((x.size() == y.size()) && + (memcmp(x.data(), y.data(), x.size()) == 0)); +} + +inline bool operator!=(const Slice& x, const Slice& y) { + return !(x == y); +} + +inline int Slice::compare(const Slice& b) const { + const size_t min_len = (size_ < b.size_) ? size_ : b.size_; + int r = memcmp(data_, b.data_, min_len); + if (r == 0) { + if (size_ < b.size_) r = -1; + else if (size_ > b.size_) r = +1; + } + return r; +} + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_INCLUDE_SLICE_H_ diff --git a/include/leveldb/status.h b/include/leveldb/status.h new file mode 100644 index 0000000000..d9575f9753 --- /dev/null +++ b/include/leveldb/status.h @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A Status encapsulates the result of an operation. It may indicate success, +// or it may indicate an error with an associated error message. +// +// Multiple threads can invoke const methods on a Status without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same Status must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATUS_H_ + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +class Status { + public: + // Create a success status. + Status() : state_(NULL) { } + ~Status() { delete[] state_; } + + // Copy the specified status. + Status(const Status& s); + void operator=(const Status& s); + + // Return a success status. + static Status OK() { return Status(); } + + // Return error status of an appropriate type. + static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotFound, msg, msg2); + } + static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kCorruption, msg, msg2); + } + static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kNotSupported, msg, msg2); + } + static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kInvalidArgument, msg, msg2); + } + static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { + return Status(kIOError, msg, msg2); + } + + // Returns true iff the status indicates success. + bool ok() const { return (state_ == NULL); } + + // Returns true iff the status indicates a NotFound error. + bool IsNotFound() const { return code() == kNotFound; } + + // Returns true iff the status indicates a Corruption error. + bool IsCorruption() const { return code() == kCorruption; } + + // Returns true iff the status indicates an IOError. + bool IsIOError() const { return code() == kIOError; } + + // Returns true iff the status indicates a NotSupportedError. + bool IsNotSupportedError() const { return code() == kNotSupported; } + + // Returns true iff the status indicates an InvalidArgument. + bool IsInvalidArgument() const { return code() == kInvalidArgument; } + + // Return a string representation of this status suitable for printing. + // Returns the string "OK" for success. + std::string ToString() const; + + private: + // OK status has a NULL state_. Otherwise, state_ is a new[] array + // of the following form: + // state_[0..3] == length of message + // state_[4] == code + // state_[5..] == message + const char* state_; + + enum Code { + kOk = 0, + kNotFound = 1, + kCorruption = 2, + kNotSupported = 3, + kInvalidArgument = 4, + kIOError = 5 + }; + + Code code() const { + return (state_ == NULL) ? kOk : static_cast(state_[4]); + } + + Status(Code code, const Slice& msg, const Slice& msg2); + static const char* CopyState(const char* s); +}; + +inline Status::Status(const Status& s) { + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); +} +inline void Status::operator=(const Status& s) { + // The following condition catches both aliasing (when this == &s), + // and the common case where both s and *this are ok. + if (state_ != s.state_) { + delete[] state_; + state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_); + } +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATUS_H_ diff --git a/include/leveldb/table.h b/include/leveldb/table.h new file mode 100644 index 0000000000..a9746c3f5e --- /dev/null +++ b/include/leveldb/table.h @@ -0,0 +1,85 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_H_ + +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +class Block; +class BlockHandle; +class Footer; +struct Options; +class RandomAccessFile; +struct ReadOptions; +class TableCache; + +// A Table is a sorted map from strings to strings. Tables are +// immutable and persistent. A Table may be safely accessed from +// multiple threads without external synchronization. +class Table { + public: + // Attempt to open the table that is stored in bytes [0..file_size) + // of "file", and read the metadata entries necessary to allow + // retrieving data from the table. + // + // If successful, returns ok and sets "*table" to the newly opened + // table. The client should delete "*table" when no longer needed. + // If there was an error while initializing the table, sets "*table" + // to NULL and returns a non-ok status. Does not take ownership of + // "*source", but the client must ensure that "source" remains live + // for the duration of the returned table's lifetime. + // + // *file must remain live while this Table is in use. + static Status Open(const Options& options, + RandomAccessFile* file, + uint64_t file_size, + Table** table); + + ~Table(); + + // Returns a new iterator over the table contents. + // The result of NewIterator() is initially invalid (caller must + // call one of the Seek methods on the iterator before using it). + Iterator* NewIterator(const ReadOptions&) const; + + // Given a key, return an approximate byte offset in the file where + // the data for that key begins (or would begin if the key were + // present in the file). The returned value is in terms of file + // bytes, and so includes effects like compression of the underlying data. + // E.g., the approximate offset of the last key in the table will + // be close to the file length. + uint64_t ApproximateOffsetOf(const Slice& key) const; + + private: + struct Rep; + Rep* rep_; + + explicit Table(Rep* rep) { rep_ = rep; } + static Iterator* BlockReader(void*, const ReadOptions&, const Slice&); + + // Calls (*handle_result)(arg, ...) with the entry found after a call + // to Seek(key). May not make such a call if filter policy says + // that key is not present. + friend class TableCache; + Status InternalGet( + const ReadOptions&, const Slice& key, + void* arg, + void (*handle_result)(void* arg, const Slice& k, const Slice& v)); + + + void ReadMeta(const Footer& footer); + void ReadFilter(const Slice& filter_handle_value); + + // No copying allowed + Table(const Table&); + void operator=(const Table&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_H_ diff --git a/include/leveldb/table_builder.h b/include/leveldb/table_builder.h new file mode 100644 index 0000000000..5fd1dc71f1 --- /dev/null +++ b/include/leveldb/table_builder.h @@ -0,0 +1,92 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// TableBuilder provides the interface used to build a Table +// (an immutable and sorted map from keys to values). +// +// Multiple threads can invoke const methods on a TableBuilder without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same TableBuilder must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ +#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ + +#include +#include "leveldb/options.h" +#include "leveldb/status.h" + +namespace leveldb { + +class BlockBuilder; +class BlockHandle; +class WritableFile; + +class TableBuilder { + public: + // Create a builder that will store the contents of the table it is + // building in *file. Does not close the file. It is up to the + // caller to close the file after calling Finish(). + TableBuilder(const Options& options, WritableFile* file); + + // REQUIRES: Either Finish() or Abandon() has been called. + ~TableBuilder(); + + // Change the options used by this builder. Note: only some of the + // option fields can be changed after construction. If a field is + // not allowed to change dynamically and its value in the structure + // passed to the constructor is different from its value in the + // structure passed to this method, this method will return an error + // without changing any fields. + Status ChangeOptions(const Options& options); + + // Add key,value to the table being constructed. + // REQUIRES: key is after any previously added key according to comparator. + // REQUIRES: Finish(), Abandon() have not been called + void Add(const Slice& key, const Slice& value); + + // Advanced operation: flush any buffered key/value pairs to file. + // Can be used to ensure that two adjacent entries never live in + // the same data block. Most clients should not need to use this method. + // REQUIRES: Finish(), Abandon() have not been called + void Flush(); + + // Return non-ok iff some error has been detected. + Status status() const; + + // Finish building the table. Stops using the file passed to the + // constructor after this function returns. + // REQUIRES: Finish(), Abandon() have not been called + Status Finish(); + + // Indicate that the contents of this builder should be abandoned. Stops + // using the file passed to the constructor after this function returns. + // If the caller is not going to call Finish(), it must call Abandon() + // before destroying this builder. + // REQUIRES: Finish(), Abandon() have not been called + void Abandon(); + + // Number of calls to Add() so far. + uint64_t NumEntries() const; + + // Size of the file generated so far. If invoked after a successful + // Finish() call, returns the size of the final generated file. + uint64_t FileSize() const; + + private: + bool ok() const { return status().ok(); } + void WriteBlock(BlockBuilder* block, BlockHandle* handle); + void WriteRawBlock(const Slice& data, CompressionType, BlockHandle* handle); + + struct Rep; + Rep* rep_; + + // No copying allowed + TableBuilder(const TableBuilder&); + void operator=(const TableBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_ diff --git a/include/leveldb/write_batch.h b/include/leveldb/write_batch.h new file mode 100644 index 0000000000..ee9aab68e0 --- /dev/null +++ b/include/leveldb/write_batch.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// WriteBatch holds a collection of updates to apply atomically to a DB. +// +// The updates are applied in the order in which they are added +// to the WriteBatch. For example, the value of "key" will be "v3" +// after the following batch is written: +// +// batch.Put("key", "v1"); +// batch.Delete("key"); +// batch.Put("key", "v2"); +// batch.Put("key", "v3"); +// +// Multiple threads can invoke const methods on a WriteBatch without +// external synchronization, but if any of the threads may call a +// non-const method, all threads accessing the same WriteBatch must use +// external synchronization. + +#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ +#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ + +#include +#include "leveldb/status.h" + +namespace leveldb { + +class Slice; + +class WriteBatch { + public: + WriteBatch(); + ~WriteBatch(); + + // Store the mapping "key->value" in the database. + void Put(const Slice& key, const Slice& value); + + // If the database contains a mapping for "key", erase it. Else do nothing. + void Delete(const Slice& key); + + // Clear all updates buffered in this batch. + void Clear(); + + // Support for iterating over the contents of a batch. + class Handler { + public: + virtual ~Handler(); + virtual void Put(const Slice& key, const Slice& value) = 0; + virtual void Delete(const Slice& key) = 0; + }; + Status Iterate(Handler* handler) const; + + private: + friend class WriteBatchInternal; + + std::string rep_; // See comment in write_batch.cc for the format of rep_ + + // Intentionally copyable +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_ diff --git a/issues/issue178_test.cc b/issues/issue178_test.cc new file mode 100644 index 0000000000..1b1cf8bb28 --- /dev/null +++ b/issues/issue178_test.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// Test for issue 178: a manual compaction causes deleted data to reappear. +#include +#include +#include + +#include "leveldb/db.h" +#include "leveldb/write_batch.h" +#include "util/testharness.h" + +namespace { + +const int kNumKeys = 1100000; + +std::string Key1(int i) { + char buf[100]; + snprintf(buf, sizeof(buf), "my_key_%d", i); + return buf; +} + +std::string Key2(int i) { + return Key1(i) + "_xxx"; +} + +class Issue178 { }; + +TEST(Issue178, Test) { + // Get rid of any state from an old run. + std::string dbpath = leveldb::test::TmpDir() + "/leveldb_cbug_test"; + DestroyDB(dbpath, leveldb::Options()); + + // Open database. Disable compression since it affects the creation + // of layers and the code below is trying to test against a very + // specific scenario. + leveldb::DB* db; + leveldb::Options db_options; + db_options.create_if_missing = true; + db_options.compression = leveldb::kNoCompression; + ASSERT_OK(leveldb::DB::Open(db_options, dbpath, &db)); + + // create first key range + leveldb::WriteBatch batch; + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key1(i), "value for range 1 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // create second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Put(Key2(i), "value for range 2 key"); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // delete second key range + batch.Clear(); + for (size_t i = 0; i < kNumKeys; i++) { + batch.Delete(Key2(i)); + } + ASSERT_OK(db->Write(leveldb::WriteOptions(), &batch)); + + // compact database + std::string start_key = Key1(0); + std::string end_key = Key1(kNumKeys - 1); + leveldb::Slice least(start_key.data(), start_key.size()); + leveldb::Slice greatest(end_key.data(), end_key.size()); + + // commenting out the line below causes the example to work correctly + db->CompactRange(&least, &greatest); + + // count the keys + leveldb::Iterator* iter = db->NewIterator(leveldb::ReadOptions()); + size_t num_keys = 0; + for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { + num_keys++; + } + delete iter; + ASSERT_EQ(kNumKeys, num_keys) << "Bad number of keys"; + + // close database + delete db; + DestroyDB(dbpath, leveldb::Options()); +} + +} // anonymous namespace + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/issues/issue200_test.cc b/issues/issue200_test.cc new file mode 100644 index 0000000000..1cec79f443 --- /dev/null +++ b/issues/issue200_test.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2013 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// Test for issue 200: when iterator switches direction from backward +// to forward, the current key can be yielded unexpectedly if a new +// mutation has been added just before the current key. + +#include "leveldb/db.h" +#include "util/testharness.h" + +namespace leveldb { + +class Issue200 { }; + +TEST(Issue200, Test) { + // Get rid of any state from an old run. + std::string dbpath = test::TmpDir() + "/leveldb_issue200_test"; + DestroyDB(dbpath, Options()); + + DB *db; + Options options; + options.create_if_missing = true; + ASSERT_OK(DB::Open(options, dbpath, &db)); + + WriteOptions write_options; + ASSERT_OK(db->Put(write_options, "1", "b")); + ASSERT_OK(db->Put(write_options, "2", "c")); + ASSERT_OK(db->Put(write_options, "3", "d")); + ASSERT_OK(db->Put(write_options, "4", "e")); + ASSERT_OK(db->Put(write_options, "5", "f")); + + ReadOptions read_options; + Iterator *iter = db->NewIterator(read_options); + + // Add an element that should not be reflected in the iterator. + ASSERT_OK(db->Put(write_options, "25", "cd")); + + iter->Seek("5"); + ASSERT_EQ(iter->key().ToString(), "5"); + iter->Prev(); + ASSERT_EQ(iter->key().ToString(), "4"); + iter->Prev(); + ASSERT_EQ(iter->key().ToString(), "3"); + iter->Next(); + ASSERT_EQ(iter->key().ToString(), "4"); + iter->Next(); + ASSERT_EQ(iter->key().ToString(), "5"); + + delete iter; + delete db; + DestroyDB(dbpath, options); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/port/README b/port/README new file mode 100644 index 0000000000..422563e25c --- /dev/null +++ b/port/README @@ -0,0 +1,10 @@ +This directory contains interfaces and implementations that isolate the +rest of the package from platform details. + +Code in the rest of the package includes "port.h" from this directory. +"port.h" in turn includes a platform specific "port_.h" file +that provides the platform specific implementation. + +See port_posix.h for an example of what must be provided in a platform +specific header file. + diff --git a/port/atomic_pointer.h b/port/atomic_pointer.h new file mode 100644 index 0000000000..d79a02230d --- /dev/null +++ b/port/atomic_pointer.h @@ -0,0 +1,245 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// AtomicPointer provides storage for a lock-free pointer. +// Platform-dependent implementation of AtomicPointer: +// - If the platform provides a cheap barrier, we use it with raw pointers +// - If is present (on newer versions of gcc, it is), we use +// a -based AtomicPointer. However we prefer the memory +// barrier based version, because at least on a gcc 4.4 32-bit build +// on linux, we have encountered a buggy implementation. +// Also, some implementations are much slower than a memory-barrier +// based implementation (~16ns for based acquire-load vs. ~1ns for +// a barrier based acquire-load). +// This code is based on atomicops-internals-* in Google's perftools: +// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase + +#ifndef PORT_ATOMIC_POINTER_H_ +#define PORT_ATOMIC_POINTER_H_ + +#include +#ifdef LEVELDB_ATOMIC_PRESENT +#include +#endif +#ifdef OS_WIN +#include +#endif +#ifdef OS_MACOSX +#include +#endif + +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#elif defined(__aarch64__) +#define ARCH_CPU_ARM64_FAMILY 1 +#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) +#define ARCH_CPU_PPC_FAMILY 1 +#elif defined(__mips__) +#define ARCH_CPU_MIPS_FAMILY 1 +#endif + +namespace leveldb { +namespace port { + +// AtomicPointer based on if available +#if defined(LEVELDB_ATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +#else + +// Define MemoryBarrier() if available +// Windows on x86 +#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +// windows.h already provides a MemoryBarrier(void) macro +// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Gcc on x86 +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + __asm__ __volatile__("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Sun Studio +#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + asm volatile("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM Linux +#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__) +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +// The Linux ARM kernel provides a highly optimized device-specific memory +// barrier function at a fixed memory address that is mapped in every +// user-level process. +// +// This beats using CPU-specific instructions which are, on single-core +// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more +// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking +// shows that the extra function call cost is completely negligible on +// multi-core devices. +// +inline void MemoryBarrier() { + (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM64 +#elif defined(ARCH_CPU_ARM64_FAMILY) +inline void MemoryBarrier() { + asm volatile("dmb sy" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// PPC +#elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + // TODO for some powerpc expert: is there a cheaper suitable variant? + // Perhaps by having separate barriers for acquire and release ops. + asm volatile("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// MIPS +#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(__GNUC__) +inline void MemoryBarrier() { + __asm__ __volatile__("sync" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +#endif + +// AtomicPointer built using platform-specific MemoryBarrier() +#if defined(LEVELDB_HAVE_MEMORY_BARRIER) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* p) : rep_(p) {} + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } + inline void* Acquire_Load() const { + void* result = rep_; + MemoryBarrier(); + return result; + } + inline void Release_Store(void* v) { + MemoryBarrier(); + rep_ = v; + } +}; + +// Atomic pointer based on sparc memory barriers +#elif defined(__sparcv9) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val; + __asm__ __volatile__ ( + "ldx [%[rep_]], %[val] \n\t" + "membar #LoadLoad|#LoadStore \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory"); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "membar #LoadStore|#StoreStore \n\t" + "stx %[v], [%[rep_]] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory"); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// Atomic pointer based on ia64 acq/rel +#elif defined(__ia64) && defined(__GNUC__) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + void* val ; + __asm__ __volatile__ ( + "ld8.acq %[val] = [%[rep_]] \n\t" + : [val] "=r" (val) + : [rep_] "r" (&rep_) + : "memory" + ); + return val; + } + inline void Release_Store(void* v) { + __asm__ __volatile__ ( + "st8.rel [%[rep_]] = %[v] \n\t" + : + : [rep_] "r" (&rep_), [v] "r" (v) + : "memory" + ); + } + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } +}; + +// We have neither MemoryBarrier(), nor +#else +#error Please implement AtomicPointer for this platform. + +#endif +#endif + +#undef LEVELDB_HAVE_MEMORY_BARRIER +#undef ARCH_CPU_X86_FAMILY +#undef ARCH_CPU_ARM_FAMILY +#undef ARCH_CPU_ARM64_FAMILY +#undef ARCH_CPU_PPC_FAMILY + +} // namespace port +} // namespace leveldb + +#endif // PORT_ATOMIC_POINTER_H_ diff --git a/port/port.h b/port/port.h new file mode 100644 index 0000000000..4baafa8e22 --- /dev/null +++ b/port/port.h @@ -0,0 +1,21 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_H_ +#define STORAGE_LEVELDB_PORT_PORT_H_ + +#include + +// Include the appropriate platform specific file below. If you are +// porting to a new platform, see "port_example.h" for documentation +// of what the new port_.h file must provide. +#if defined(LEVELDB_PLATFORM_POSIX) +# include "port/port_posix.h" +#elif defined(LEVELDB_PLATFORM_CHROMIUM) +# include "port/port_chromium.h" +#elif defined(LEVELDB_PLATFORM_WINDOWS) +# include "port/port_win.h" +#endif + +#endif // STORAGE_LEVELDB_PORT_PORT_H_ diff --git a/port/port_example.h b/port/port_example.h new file mode 100644 index 0000000000..5b1d027de5 --- /dev/null +++ b/port/port_example.h @@ -0,0 +1,145 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// This file contains the specification, but not the implementations, +// of the types/operations/etc. that should be defined by a platform +// specific port_.h file. Use this file as a reference for +// how to port this package to a new platform. + +#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ +#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ + +namespace leveldb { +namespace port { + +// TODO(jorlow): Many of these belong more in the environment class rather than +// here. We should try moving them and see if it affects perf. + +// The following boolean constant must be true on a little-endian machine +// and false otherwise. +static const bool kLittleEndian = true /* or some other expression */; + +// ------------------ Threading ------------------- + +// A Mutex represents an exclusive lock. +class Mutex { + public: + Mutex(); + ~Mutex(); + + // Lock the mutex. Waits until other lockers have exited. + // Will deadlock if the mutex is already locked by this thread. + void Lock(); + + // Unlock the mutex. + // REQUIRES: This mutex was locked by this thread. + void Unlock(); + + // Optionally crash if this thread does not hold this mutex. + // The implementation must be fast, especially if NDEBUG is + // defined. The implementation is allowed to skip all checks. + void AssertHeld(); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + + // Atomically release *mu and block on this condition variable until + // either a call to SignalAll(), or a call to Signal() that picks + // this thread to wakeup. + // REQUIRES: this thread holds *mu + void Wait(); + + // If there are some threads waiting, wake up at least one of them. + void Signal(); + + // Wake up all waiting threads. + void SignallAll(); +}; + +// Thread-safe initialization. +// Used as follows: +// static port::OnceType init_control = LEVELDB_ONCE_INIT; +// static void Initializer() { ... do something ...; } +// ... +// port::InitOnce(&init_control, &Initializer); +typedef intptr_t OnceType; +#define LEVELDB_ONCE_INIT 0 +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// A type that holds a pointer that can be read or written atomically +// (i.e., without word-tearing.) +class AtomicPointer { + private: + intptr_t rep_; + public: + // Initialize to arbitrary value + AtomicPointer(); + + // Initialize to hold v + explicit AtomicPointer(void* v) : rep_(v) { } + + // Read and return the stored pointer with the guarantee that no + // later memory access (read or write) by this thread can be + // reordered ahead of this read. + void* Acquire_Load() const; + + // Set v as the stored pointer with the guarantee that no earlier + // memory access (read or write) by this thread can be reordered + // after this store. + void Release_Store(void* v); + + // Read the stored pointer with no ordering guarantees. + void* NoBarrier_Load() const; + + // Set va as the stored pointer with no ordering guarantees. + void NoBarrier_Store(void* v); +}; + +// ------------------ Compression ------------------- + +// Store the snappy compression of "input[0,input_length-1]" in *output. +// Returns false if snappy is not supported by this port. +extern bool Snappy_Compress(const char* input, size_t input_length, + std::string* output); + +// If input[0,input_length-1] looks like a valid snappy compressed +// buffer, store the size of the uncompressed data in *result and +// return true. Else return false. +extern bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result); + +// Attempt to snappy uncompress input[0,input_length-1] into *output. +// Returns true if successful, false if the input is invalid lightweight +// compressed data. +// +// REQUIRES: at least the first "n" bytes of output[] must be writable +// where "n" is the result of a successful call to +// Snappy_GetUncompressedLength. +extern bool Snappy_Uncompress(const char* input_data, size_t input_length, + char* output); + +// ------------------ Miscellaneous ------------------- + +// If heap profiling is not supported, returns false. +// Else repeatedly calls (*func)(arg, data, n) and then returns true. +// The concatenation of all "data[0,n-1]" fragments is the heap profile. +extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); + +// Determine whether a working accelerated crc32 implementation exists +// Returns true if AcceleratedCRC32C is safe to call +bool HasAcceleratedCRC32C(); + +// Extend the CRC to include the first n bytes of buf. +// +// Returns zero if the CRC cannot be extended using acceleration, else returns +// the newly extended CRC value (which may also be zero). +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_ diff --git a/port/port_posix.cc b/port/port_posix.cc new file mode 100644 index 0000000000..ec39e92195 --- /dev/null +++ b/port/port_posix.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "port/port_posix.h" + +#include +#include +#include + +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) +#include +#endif + +namespace leveldb { +namespace port { + +static void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } +} + +Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); } + +Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } + +void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } + +void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } + +CondVar::CondVar(Mutex* mu) + : mu_(mu) { + PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); +} + +CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } + +void CondVar::Wait() { + PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); +} + +void CondVar::Signal() { + PthreadCall("signal", pthread_cond_signal(&cv_)); +} + +void CondVar::SignalAll() { + PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + PthreadCall("once", pthread_once(once, initializer)); +} + +bool HasAcceleratedCRC32C() { +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) + unsigned int eax, ebx, ecx, edx; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + return (ecx & (1 << 20)) != 0; +#else + return false; +#endif +} + +} // namespace port +} // namespace leveldb diff --git a/port/port_posix.h b/port/port_posix.h new file mode 100644 index 0000000000..d85fa5d63f --- /dev/null +++ b/port/port_posix.h @@ -0,0 +1,161 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ +#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ + +#undef PLATFORM_IS_LITTLE_ENDIAN +#if defined(OS_MACOSX) + #include + #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER) + #define PLATFORM_IS_LITTLE_ENDIAN \ + (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN) + #endif +#elif defined(OS_SOLARIS) + #include + #ifdef _LITTLE_ENDIAN + #define PLATFORM_IS_LITTLE_ENDIAN true + #else + #define PLATFORM_IS_LITTLE_ENDIAN false + #endif +#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) ||\ + defined(OS_NETBSD) || defined(OS_DRAGONFLYBSD) + #include + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#elif defined(OS_HPUX) + #define PLATFORM_IS_LITTLE_ENDIAN false +#elif defined(OS_ANDROID) + // Due to a bug in the NDK x86 definition, + // _BYTE_ORDER must be used instead of __BYTE_ORDER on Android. + // See http://code.google.com/p/android/issues/detail?id=39824 + #include + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#else + #include +#endif + +#include +#ifdef SNAPPY +#include +#endif +#include +#include +#include "port/atomic_pointer.h" + +#ifndef PLATFORM_IS_LITTLE_ENDIAN +#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) +#endif + +#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ + defined(OS_ANDROID) || defined(OS_HPUX) || defined(CYGWIN) +// Use fread/fwrite/fflush on platforms without _unlocked variants +#define fread_unlocked fread +#define fwrite_unlocked fwrite +#define fflush_unlocked fflush +#endif + +#if defined(OS_FREEBSD) ||\ + defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) +// Use fsync() on platforms without fdatasync() +#define fdatasync fsync +#endif + +#if defined(OS_MACOSX) +#define fdatasync(fd) fcntl(fd, F_FULLFSYNC, 0) +#endif + +#if defined(OS_ANDROID) && __ANDROID_API__ < 9 +// fdatasync() was only introduced in API level 9 on Android. Use fsync() +// when targetting older platforms. +#define fdatasync fsync +#endif + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN; +#undef PLATFORM_IS_LITTLE_ENDIAN + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld() { } + + private: + friend class CondVar; + pthread_mutex_t mu_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + pthread_cond_t cv_; + Mutex* mu_; +}; + +typedef pthread_once_t OnceType; +#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT +extern void InitOnce(OnceType* once, void (*initializer)()); + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +bool HasAcceleratedCRC32C(); +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/port/port_posix_sse.cc b/port/port_posix_sse.cc new file mode 100644 index 0000000000..2d49c21dd8 --- /dev/null +++ b/port/port_posix_sse.cc @@ -0,0 +1,110 @@ +// Copyright 2016 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. +// +// In a separate source file to allow this accelerated CRC32C function to be +// compiled with the appropriate compiler flags to enable x86 SSE 4.2 +// instructions. + +#include +#include +#include "port/port.h" + +#if defined(LEVELDB_PLATFORM_POSIX_SSE) + +#if defined(_MSC_VER) +#include +#elif defined(__GNUC__) && defined(__SSE4_2__) +#include +#endif + +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) + +namespace leveldb { +namespace port { + +#if defined(LEVELDB_PLATFORM_POSIX_SSE) + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + // SSE is x86 only, so ensured that |p| is always little-endian. + uint32_t word; + memcpy(&word, p, sizeof(word)); + return word; +} + +#if defined(_M_X64) || defined(__x86_64__) // LE_LOAD64 is only used on x64. + +// Used to fetch a naturally-aligned 64-bit word in little endian byte-order +static inline uint64_t LE_LOAD64(const uint8_t *p) { + uint64_t dword; + memcpy(&dword, p, sizeof(dword)); + return dword; +} + +#endif // defined(_M_X64) || defined(__x86_64__) + +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) + +// For further improvements see Intel publication at: +// http://download.intel.com/design/intarch/papers/323405.pdf +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { +#if !defined(LEVELDB_PLATFORM_POSIX_SSE) + return 0; +#else + + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + l = _mm_crc32_u8(l, *p++); \ +} while (0) +#define STEP4 do { \ + l = _mm_crc32_u32(l, LE_LOAD32(p)); \ + p += 4; \ +} while (0) +#define STEP8 do { \ + l = _mm_crc32_u64(l, LE_LOAD64(p)); \ + p += 8; \ +} while (0) + + if (size > 16) { + // Process unaligned bytes + for (unsigned int i = reinterpret_cast(p) % 8; i; --i) { + STEP1; + } + + // _mm_crc32_u64 is only available on x64. +#if defined(_M_X64) || defined(__x86_64__) + // Process 8 bytes at a time + while ((e-p) >= 8) { + STEP8; + } + // Process 4 bytes at a time + if ((e-p) >= 4) { + STEP4; + } +#else // !(defined(_M_X64) || defined(__x86_64__)) + // Process 4 bytes at a time + while ((e-p) >= 4) { + STEP4; + } +#endif // defined(_M_X64) || defined(__x86_64__) + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP8 +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +#endif // defined(LEVELDB_PLATFORM_POSIX_SSE) +} + +} // namespace port +} // namespace leveldb diff --git a/port/port_win.cc b/port/port_win.cc new file mode 100644 index 0000000000..1be9e8d5b0 --- /dev/null +++ b/port/port_win.cc @@ -0,0 +1,158 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "port/port_win.h" + +#include +#include +#include + +namespace leveldb { +namespace port { + +Mutex::Mutex() : + cs_(NULL) { + assert(!cs_); + cs_ = static_cast(new CRITICAL_SECTION()); + ::InitializeCriticalSection(static_cast(cs_)); + assert(cs_); +} + +Mutex::~Mutex() { + assert(cs_); + ::DeleteCriticalSection(static_cast(cs_)); + delete static_cast(cs_); + cs_ = NULL; + assert(!cs_); +} + +void Mutex::Lock() { + assert(cs_); + ::EnterCriticalSection(static_cast(cs_)); +} + +void Mutex::Unlock() { + assert(cs_); + ::LeaveCriticalSection(static_cast(cs_)); +} + +void Mutex::AssertHeld() { + assert(cs_); + assert(1); +} + +CondVar::CondVar(Mutex* mu) : + waiting_(0), + mu_(mu), + sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)), + sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) { + assert(mu_); +} + +CondVar::~CondVar() { + ::CloseHandle(sem1_); + ::CloseHandle(sem2_); +} + +void CondVar::Wait() { + mu_->AssertHeld(); + + wait_mtx_.Lock(); + ++waiting_; + wait_mtx_.Unlock(); + + mu_->Unlock(); + + // initiate handshake + ::WaitForSingleObject(sem1_, INFINITE); + ::ReleaseSemaphore(sem2_, 1, NULL); + mu_->Lock(); +} + +void CondVar::Signal() { + wait_mtx_.Lock(); + if (waiting_ > 0) { + --waiting_; + + // finalize handshake + ::ReleaseSemaphore(sem1_, 1, NULL); + ::WaitForSingleObject(sem2_, INFINITE); + } + wait_mtx_.Unlock(); +} + +void CondVar::SignalAll() { + wait_mtx_.Lock(); + ::ReleaseSemaphore(sem1_, waiting_, NULL); + while(waiting_ > 0) { + --waiting_; + ::WaitForSingleObject(sem2_, INFINITE); + } + wait_mtx_.Unlock(); +} + +AtomicPointer::AtomicPointer(void* v) { + Release_Store(v); +} + +void InitOnce(OnceType* once, void (*initializer)()) { + once->InitOnce(initializer); +} + +void* AtomicPointer::Acquire_Load() const { + void * p = NULL; + InterlockedExchangePointer(&p, rep_); + return p; +} + +void AtomicPointer::Release_Store(void* v) { + InterlockedExchangePointer(&rep_, v); +} + +void* AtomicPointer::NoBarrier_Load() const { + return rep_; +} + +void AtomicPointer::NoBarrier_Store(void* v) { + rep_ = v; +} + +bool HasAcceleratedCRC32C() { +#if defined(__x86_64__) || defined(__i386__) + int cpu_info[4]; + __cpuid(cpu_info, 1); + return (cpu_info[2] & (1 << 20)) != 0; +#else + return false; +#endif +} + +} +} diff --git a/port/port_win.h b/port/port_win.h new file mode 100644 index 0000000000..e8bf46ef27 --- /dev/null +++ b/port/port_win.h @@ -0,0 +1,177 @@ +// LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// See port_example.h for documentation for the following types/functions. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the University of California, Berkeley nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ +#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ + +#ifdef _MSC_VER +#define snprintf _snprintf +#define close _close +#define fread_unlocked _fread_nolock +#endif + +#include +#include +#ifdef SNAPPY +#include +#endif + +namespace leveldb { +namespace port { + +// Windows is little endian (for now :p) +static const bool kLittleEndian = true; + +class CondVar; + +class Mutex { + public: + Mutex(); + ~Mutex(); + + void Lock(); + void Unlock(); + void AssertHeld(); + + private: + friend class CondVar; + // critical sections are more efficient than mutexes + // but they are not recursive and can only be used to synchronize threads within the same process + // we use opaque void * to avoid including windows.h in port_win.h + void * cs_; + + // No copying + Mutex(const Mutex&); + void operator=(const Mutex&); +}; + +// the Win32 API offers a dependable condition variable mechanism, but only starting with +// Windows 2008 and Vista +// no matter what we will implement our own condition variable with a semaphore +// implementation as described in a paper written by Andrew D. Birrell in 2003 +class CondVar { + public: + explicit CondVar(Mutex* mu); + ~CondVar(); + void Wait(); + void Signal(); + void SignalAll(); + private: + Mutex* mu_; + + Mutex wait_mtx_; + long waiting_; + + void * sem1_; + void * sem2_; + + +}; + +class OnceType { +public: +// OnceType() : init_(false) {} + OnceType(const OnceType &once) : init_(once.init_) {} + OnceType(bool f) : init_(f) {} + void InitOnce(void (*initializer)()) { + mutex_.Lock(); + if (!init_) { + init_ = true; + initializer(); + } + mutex_.Unlock(); + } + +private: + bool init_; + Mutex mutex_; +}; + +#define LEVELDB_ONCE_INIT false +extern void InitOnce(port::OnceType*, void (*initializer)()); + +// Storage for a lock-free pointer +class AtomicPointer { + private: + void * rep_; + public: + AtomicPointer() : rep_(NULL) { } + explicit AtomicPointer(void* v); + void* Acquire_Load() const; + + void Release_Store(void* v); + + void* NoBarrier_Load() const; + + void NoBarrier_Store(void* v); +}; + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#ifdef SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#ifdef SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif +} + +inline bool Snappy_Uncompress(const char* input, size_t length, + char* output) { +#ifdef SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +bool HasAcceleratedCRC32C(); +uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); + +} +} + +#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/port/thread_annotations.h b/port/thread_annotations.h new file mode 100644 index 0000000000..9470ef587c --- /dev/null +++ b/port/thread_annotations.h @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ +#define STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ + +// Some environments provide custom macros to aid in static thread-safety +// analysis. Provide empty definitions of such macros unless they are already +// defined. + +#ifndef EXCLUSIVE_LOCKS_REQUIRED +#define EXCLUSIVE_LOCKS_REQUIRED(...) +#endif + +#ifndef SHARED_LOCKS_REQUIRED +#define SHARED_LOCKS_REQUIRED(...) +#endif + +#ifndef LOCKS_EXCLUDED +#define LOCKS_EXCLUDED(...) +#endif + +#ifndef LOCK_RETURNED +#define LOCK_RETURNED(x) +#endif + +#ifndef LOCKABLE +#define LOCKABLE +#endif + +#ifndef SCOPED_LOCKABLE +#define SCOPED_LOCKABLE +#endif + +#ifndef EXCLUSIVE_LOCK_FUNCTION +#define EXCLUSIVE_LOCK_FUNCTION(...) +#endif + +#ifndef SHARED_LOCK_FUNCTION +#define SHARED_LOCK_FUNCTION(...) +#endif + +#ifndef EXCLUSIVE_TRYLOCK_FUNCTION +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) +#endif + +#ifndef SHARED_TRYLOCK_FUNCTION +#define SHARED_TRYLOCK_FUNCTION(...) +#endif + +#ifndef UNLOCK_FUNCTION +#define UNLOCK_FUNCTION(...) +#endif + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS +#endif + +#endif // STORAGE_LEVELDB_PORT_THREAD_ANNOTATIONS_H_ diff --git a/port/win/stdint.h b/port/win/stdint.h new file mode 100644 index 0000000000..39edd0db13 --- /dev/null +++ b/port/win/stdint.h @@ -0,0 +1,24 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +// MSVC didn't ship with this file until the 2010 version. + +#ifndef STORAGE_LEVELDB_PORT_WIN_STDINT_H_ +#define STORAGE_LEVELDB_PORT_WIN_STDINT_H_ + +#if !defined(_MSC_VER) +#error This file should only be included when compiling with MSVC. +#endif + +// Define C99 equivalent types. +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif // STORAGE_LEVELDB_PORT_WIN_STDINT_H_ diff --git a/table/block.cc b/table/block.cc new file mode 100644 index 0000000000..43e402c9c0 --- /dev/null +++ b/table/block.cc @@ -0,0 +1,268 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Decodes the blocks generated by block_builder.cc. + +#include "table/block.h" + +#include +#include +#include "leveldb/comparator.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/logging.h" + +namespace leveldb { + +inline uint32_t Block::NumRestarts() const { + assert(size_ >= sizeof(uint32_t)); + return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); +} + +Block::Block(const BlockContents& contents) + : data_(contents.data.data()), + size_(contents.data.size()), + owned_(contents.heap_allocated) { + if (size_ < sizeof(uint32_t)) { + size_ = 0; // Error marker + } else { + size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t); + if (NumRestarts() > max_restarts_allowed) { + // The size is too small for NumRestarts() + size_ = 0; + } else { + restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t); + } + } +} + +Block::~Block() { + if (owned_) { + delete[] data_; + } +} + +// Helper routine: decode the next block entry starting at "p", +// storing the number of shared key bytes, non_shared key bytes, +// and the length of the value in "*shared", "*non_shared", and +// "*value_length", respectively. Will not dereference past "limit". +// +// If any errors are detected, returns NULL. Otherwise, returns a +// pointer to the key delta (just past the three decoded values). +static inline const char* DecodeEntry(const char* p, const char* limit, + uint32_t* shared, + uint32_t* non_shared, + uint32_t* value_length) { + if (limit - p < 3) return NULL; + *shared = reinterpret_cast(p)[0]; + *non_shared = reinterpret_cast(p)[1]; + *value_length = reinterpret_cast(p)[2]; + if ((*shared | *non_shared | *value_length) < 128) { + // Fast path: all three values are encoded in one byte each + p += 3; + } else { + if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL; + if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL; + } + + if (static_cast(limit - p) < (*non_shared + *value_length)) { + return NULL; + } + return p; +} + +class Block::Iter : public Iterator { + private: + const Comparator* const comparator_; + const char* const data_; // underlying block contents + uint32_t const restarts_; // Offset of restart array (list of fixed32) + uint32_t const num_restarts_; // Number of uint32_t entries in restart array + + // current_ is offset in data_ of current entry. >= restarts_ if !Valid + uint32_t current_; + uint32_t restart_index_; // Index of restart block in which current_ falls + std::string key_; + Slice value_; + Status status_; + + inline int Compare(const Slice& a, const Slice& b) const { + return comparator_->Compare(a, b); + } + + // Return the offset in data_ just past the end of the current entry. + inline uint32_t NextEntryOffset() const { + return (value_.data() + value_.size()) - data_; + } + + uint32_t GetRestartPoint(uint32_t index) { + assert(index < num_restarts_); + return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t)); + } + + void SeekToRestartPoint(uint32_t index) { + key_.clear(); + restart_index_ = index; + // current_ will be fixed by ParseNextKey(); + + // ParseNextKey() starts at the end of value_, so set value_ accordingly + uint32_t offset = GetRestartPoint(index); + value_ = Slice(data_ + offset, 0); + } + + public: + Iter(const Comparator* comparator, + const char* data, + uint32_t restarts, + uint32_t num_restarts) + : comparator_(comparator), + data_(data), + restarts_(restarts), + num_restarts_(num_restarts), + current_(restarts_), + restart_index_(num_restarts_) { + assert(num_restarts_ > 0); + } + + virtual bool Valid() const { return current_ < restarts_; } + virtual Status status() const { return status_; } + virtual Slice key() const { + assert(Valid()); + return key_; + } + virtual Slice value() const { + assert(Valid()); + return value_; + } + + virtual void Next() { + assert(Valid()); + ParseNextKey(); + } + + virtual void Prev() { + assert(Valid()); + + // Scan backwards to a restart point before current_ + const uint32_t original = current_; + while (GetRestartPoint(restart_index_) >= original) { + if (restart_index_ == 0) { + // No more entries + current_ = restarts_; + restart_index_ = num_restarts_; + return; + } + restart_index_--; + } + + SeekToRestartPoint(restart_index_); + do { + // Loop until end of current entry hits the start of original entry + } while (ParseNextKey() && NextEntryOffset() < original); + } + + virtual void Seek(const Slice& target) { + // Binary search in restart array to find the last restart point + // with a key < target + uint32_t left = 0; + uint32_t right = num_restarts_ - 1; + while (left < right) { + uint32_t mid = (left + right + 1) / 2; + uint32_t region_offset = GetRestartPoint(mid); + uint32_t shared, non_shared, value_length; + const char* key_ptr = DecodeEntry(data_ + region_offset, + data_ + restarts_, + &shared, &non_shared, &value_length); + if (key_ptr == NULL || (shared != 0)) { + CorruptionError(); + return; + } + Slice mid_key(key_ptr, non_shared); + if (Compare(mid_key, target) < 0) { + // Key at "mid" is smaller than "target". Therefore all + // blocks before "mid" are uninteresting. + left = mid; + } else { + // Key at "mid" is >= "target". Therefore all blocks at or + // after "mid" are uninteresting. + right = mid - 1; + } + } + + // Linear search (within restart block) for first key >= target + SeekToRestartPoint(left); + while (true) { + if (!ParseNextKey()) { + return; + } + if (Compare(key_, target) >= 0) { + return; + } + } + } + + virtual void SeekToFirst() { + SeekToRestartPoint(0); + ParseNextKey(); + } + + virtual void SeekToLast() { + SeekToRestartPoint(num_restarts_ - 1); + while (ParseNextKey() && NextEntryOffset() < restarts_) { + // Keep skipping + } + } + + private: + void CorruptionError() { + current_ = restarts_; + restart_index_ = num_restarts_; + status_ = Status::Corruption("bad entry in block"); + key_.clear(); + value_.clear(); + } + + bool ParseNextKey() { + current_ = NextEntryOffset(); + const char* p = data_ + current_; + const char* limit = data_ + restarts_; // Restarts come right after data + if (p >= limit) { + // No more entries to return. Mark as invalid. + current_ = restarts_; + restart_index_ = num_restarts_; + return false; + } + + // Decode next entry + uint32_t shared, non_shared, value_length; + p = DecodeEntry(p, limit, &shared, &non_shared, &value_length); + if (p == NULL || key_.size() < shared) { + CorruptionError(); + return false; + } else { + key_.resize(shared); + key_.append(p, non_shared); + value_ = Slice(p + non_shared, value_length); + while (restart_index_ + 1 < num_restarts_ && + GetRestartPoint(restart_index_ + 1) < current_) { + ++restart_index_; + } + return true; + } + } +}; + +Iterator* Block::NewIterator(const Comparator* cmp) { + if (size_ < sizeof(uint32_t)) { + return NewErrorIterator(Status::Corruption("bad block contents")); + } + const uint32_t num_restarts = NumRestarts(); + if (num_restarts == 0) { + return NewEmptyIterator(); + } else { + return new Iter(cmp, data_, restart_offset_, num_restarts); + } +} + +} // namespace leveldb diff --git a/table/block.h b/table/block.h new file mode 100644 index 0000000000..2493eb9f9f --- /dev/null +++ b/table/block.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_H_ + +#include +#include +#include "leveldb/iterator.h" + +namespace leveldb { + +struct BlockContents; +class Comparator; + +class Block { + public: + // Initialize the block with the specified contents. + explicit Block(const BlockContents& contents); + + ~Block(); + + size_t size() const { return size_; } + Iterator* NewIterator(const Comparator* comparator); + + private: + uint32_t NumRestarts() const; + + const char* data_; + size_t size_; + uint32_t restart_offset_; // Offset in data_ of restart array + bool owned_; // Block owns data_[] + + // No copying allowed + Block(const Block&); + void operator=(const Block&); + + class Iter; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_H_ diff --git a/table/block_builder.cc b/table/block_builder.cc new file mode 100644 index 0000000000..db660cd07c --- /dev/null +++ b/table/block_builder.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// BlockBuilder generates blocks where keys are prefix-compressed: +// +// When we store a key, we drop the prefix shared with the previous +// string. This helps reduce the space requirement significantly. +// Furthermore, once every K keys, we do not apply the prefix +// compression and store the entire key. We call this a "restart +// point". The tail end of the block stores the offsets of all of the +// restart points, and can be used to do a binary search when looking +// for a particular key. Values are stored as-is (without compression) +// immediately following the corresponding key. +// +// An entry for a particular key-value pair has the form: +// shared_bytes: varint32 +// unshared_bytes: varint32 +// value_length: varint32 +// key_delta: char[unshared_bytes] +// value: char[value_length] +// shared_bytes == 0 for restart points. +// +// The trailer of the block has the form: +// restarts: uint32[num_restarts] +// num_restarts: uint32 +// restarts[i] contains the offset within the block of the ith restart point. + +#include "table/block_builder.h" + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/table_builder.h" +#include "util/coding.h" + +namespace leveldb { + +BlockBuilder::BlockBuilder(const Options* options) + : options_(options), + restarts_(), + counter_(0), + finished_(false) { + assert(options->block_restart_interval >= 1); + restarts_.push_back(0); // First restart point is at offset 0 +} + +void BlockBuilder::Reset() { + buffer_.clear(); + restarts_.clear(); + restarts_.push_back(0); // First restart point is at offset 0 + counter_ = 0; + finished_ = false; + last_key_.clear(); +} + +size_t BlockBuilder::CurrentSizeEstimate() const { + return (buffer_.size() + // Raw data buffer + restarts_.size() * sizeof(uint32_t) + // Restart array + sizeof(uint32_t)); // Restart array length +} + +Slice BlockBuilder::Finish() { + // Append restart array + for (size_t i = 0; i < restarts_.size(); i++) { + PutFixed32(&buffer_, restarts_[i]); + } + PutFixed32(&buffer_, restarts_.size()); + finished_ = true; + return Slice(buffer_); +} + +void BlockBuilder::Add(const Slice& key, const Slice& value) { + Slice last_key_piece(last_key_); + assert(!finished_); + assert(counter_ <= options_->block_restart_interval); + assert(buffer_.empty() // No values yet? + || options_->comparator->Compare(key, last_key_piece) > 0); + size_t shared = 0; + if (counter_ < options_->block_restart_interval) { + // See how much sharing to do with previous string + const size_t min_length = std::min(last_key_piece.size(), key.size()); + while ((shared < min_length) && (last_key_piece[shared] == key[shared])) { + shared++; + } + } else { + // Restart compression + restarts_.push_back(buffer_.size()); + counter_ = 0; + } + const size_t non_shared = key.size() - shared; + + // Add "" to buffer_ + PutVarint32(&buffer_, shared); + PutVarint32(&buffer_, non_shared); + PutVarint32(&buffer_, value.size()); + + // Add string delta to buffer_ followed by value + buffer_.append(key.data() + shared, non_shared); + buffer_.append(value.data(), value.size()); + + // Update state + last_key_.resize(shared); + last_key_.append(key.data() + shared, non_shared); + assert(Slice(last_key_) == key); + counter_++; +} + +} // namespace leveldb diff --git a/table/block_builder.h b/table/block_builder.h new file mode 100644 index 0000000000..4fbcb33972 --- /dev/null +++ b/table/block_builder.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ +#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ + +#include + +#include +#include "leveldb/slice.h" + +namespace leveldb { + +struct Options; + +class BlockBuilder { + public: + explicit BlockBuilder(const Options* options); + + // Reset the contents as if the BlockBuilder was just constructed. + void Reset(); + + // REQUIRES: Finish() has not been called since the last call to Reset(). + // REQUIRES: key is larger than any previously added key + void Add(const Slice& key, const Slice& value); + + // Finish building the block and return a slice that refers to the + // block contents. The returned slice will remain valid for the + // lifetime of this builder or until Reset() is called. + Slice Finish(); + + // Returns an estimate of the current (uncompressed) size of the block + // we are building. + size_t CurrentSizeEstimate() const; + + // Return true iff no entries have been added since the last Reset() + bool empty() const { + return buffer_.empty(); + } + + private: + const Options* options_; + std::string buffer_; // Destination buffer + std::vector restarts_; // Restart points + int counter_; // Number of entries emitted since restart + bool finished_; // Has Finish() been called? + std::string last_key_; + + // No copying allowed + BlockBuilder(const BlockBuilder&); + void operator=(const BlockBuilder&); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_ diff --git a/table/filter_block.cc b/table/filter_block.cc new file mode 100644 index 0000000000..1ed5134170 --- /dev/null +++ b/table/filter_block.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" + +namespace leveldb { + +// See doc/table_format.md for an explanation of the filter block format. + +// Generate new filter every 2KB of data +static const size_t kFilterBaseLg = 11; +static const size_t kFilterBase = 1 << kFilterBaseLg; + +FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy) + : policy_(policy) { +} + +void FilterBlockBuilder::StartBlock(uint64_t block_offset) { + uint64_t filter_index = (block_offset / kFilterBase); + assert(filter_index >= filter_offsets_.size()); + while (filter_index > filter_offsets_.size()) { + GenerateFilter(); + } +} + +void FilterBlockBuilder::AddKey(const Slice& key) { + Slice k = key; + start_.push_back(keys_.size()); + keys_.append(k.data(), k.size()); +} + +Slice FilterBlockBuilder::Finish() { + if (!start_.empty()) { + GenerateFilter(); + } + + // Append array of per-filter offsets + const uint32_t array_offset = result_.size(); + for (size_t i = 0; i < filter_offsets_.size(); i++) { + PutFixed32(&result_, filter_offsets_[i]); + } + + PutFixed32(&result_, array_offset); + result_.push_back(kFilterBaseLg); // Save encoding parameter in result + return Slice(result_); +} + +void FilterBlockBuilder::GenerateFilter() { + const size_t num_keys = start_.size(); + if (num_keys == 0) { + // Fast path if there are no keys for this filter + filter_offsets_.push_back(result_.size()); + return; + } + + // Make list of keys from flattened key structure + start_.push_back(keys_.size()); // Simplify length computation + tmp_keys_.resize(num_keys); + for (size_t i = 0; i < num_keys; i++) { + const char* base = keys_.data() + start_[i]; + size_t length = start_[i+1] - start_[i]; + tmp_keys_[i] = Slice(base, length); + } + + // Generate filter for current set of keys and append to result_. + filter_offsets_.push_back(result_.size()); + policy_->CreateFilter(&tmp_keys_[0], static_cast(num_keys), &result_); + + tmp_keys_.clear(); + keys_.clear(); + start_.clear(); +} + +FilterBlockReader::FilterBlockReader(const FilterPolicy* policy, + const Slice& contents) + : policy_(policy), + data_(NULL), + offset_(NULL), + num_(0), + base_lg_(0) { + size_t n = contents.size(); + if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array + base_lg_ = contents[n-1]; + uint32_t last_word = DecodeFixed32(contents.data() + n - 5); + if (last_word > n - 5) return; + data_ = contents.data(); + offset_ = data_ + last_word; + num_ = (n - 5 - last_word) / 4; +} + +bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) { + uint64_t index = block_offset >> base_lg_; + if (index < num_) { + uint32_t start = DecodeFixed32(offset_ + index*4); + uint32_t limit = DecodeFixed32(offset_ + index*4 + 4); + if (start <= limit && limit <= static_cast(offset_ - data_)) { + Slice filter = Slice(data_ + start, limit - start); + return policy_->KeyMayMatch(key, filter); + } else if (start == limit) { + // Empty filters do not match any keys + return false; + } + } + return true; // Errors are treated as potential matches +} + +} diff --git a/table/filter_block.h b/table/filter_block.h new file mode 100644 index 0000000000..c67d010bd1 --- /dev/null +++ b/table/filter_block.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A filter block is stored near the end of a Table file. It contains +// filters (e.g., bloom filters) for all data blocks in the table combined +// into a single filter block. + +#ifndef STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ +#define STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ + +#include +#include +#include +#include +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +class FilterPolicy; + +// A FilterBlockBuilder is used to construct all of the filters for a +// particular Table. It generates a single string which is stored as +// a special block in the Table. +// +// The sequence of calls to FilterBlockBuilder must match the regexp: +// (StartBlock AddKey*)* Finish +class FilterBlockBuilder { + public: + explicit FilterBlockBuilder(const FilterPolicy*); + + void StartBlock(uint64_t block_offset); + void AddKey(const Slice& key); + Slice Finish(); + + private: + void GenerateFilter(); + + const FilterPolicy* policy_; + std::string keys_; // Flattened key contents + std::vector start_; // Starting index in keys_ of each key + std::string result_; // Filter data computed so far + std::vector tmp_keys_; // policy_->CreateFilter() argument + std::vector filter_offsets_; + + // No copying allowed + FilterBlockBuilder(const FilterBlockBuilder&); + void operator=(const FilterBlockBuilder&); +}; + +class FilterBlockReader { + public: + // REQUIRES: "contents" and *policy must stay live while *this is live. + FilterBlockReader(const FilterPolicy* policy, const Slice& contents); + bool KeyMayMatch(uint64_t block_offset, const Slice& key); + + private: + const FilterPolicy* policy_; + const char* data_; // Pointer to filter data (at block-start) + const char* offset_; // Pointer to beginning of offset array (at block-end) + size_t num_; // Number of entries in offset array + size_t base_lg_; // Encoding parameter (see kFilterBaseLg in .cc file) +}; + +} + +#endif // STORAGE_LEVELDB_TABLE_FILTER_BLOCK_H_ diff --git a/table/filter_block_test.cc b/table/filter_block_test.cc new file mode 100644 index 0000000000..8c4a4741f2 --- /dev/null +++ b/table/filter_block_test.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/filter_block.h" + +#include "leveldb/filter_policy.h" +#include "util/coding.h" +#include "util/hash.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// For testing: emit an array with one hash value per key +class TestHashFilter : public FilterPolicy { + public: + virtual const char* Name() const { + return "TestHashFilter"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + for (int i = 0; i < n; i++) { + uint32_t h = Hash(keys[i].data(), keys[i].size(), 1); + PutFixed32(dst, h); + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { + uint32_t h = Hash(key.data(), key.size(), 1); + for (size_t i = 0; i + 4 <= filter.size(); i += 4) { + if (h == DecodeFixed32(filter.data() + i)) { + return true; + } + } + return false; + } +}; + +class FilterBlockTest { + public: + TestHashFilter policy_; +}; + +TEST(FilterBlockTest, EmptyBuilder) { + FilterBlockBuilder builder(&policy_); + Slice block = builder.Finish(); + ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block)); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100000, "foo")); +} + +TEST(FilterBlockTest, SingleChunk) { + FilterBlockBuilder builder(&policy_); + builder.StartBlock(100); + builder.AddKey("foo"); + builder.AddKey("bar"); + builder.AddKey("box"); + builder.StartBlock(200); + builder.AddKey("box"); + builder.StartBlock(300); + builder.AddKey("hello"); + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(100, "bar")); + ASSERT_TRUE(reader.KeyMayMatch(100, "box")); + ASSERT_TRUE(reader.KeyMayMatch(100, "hello")); + ASSERT_TRUE(reader.KeyMayMatch(100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "missing")); + ASSERT_TRUE(! reader.KeyMayMatch(100, "other")); +} + +TEST(FilterBlockTest, MultiChunk) { + FilterBlockBuilder builder(&policy_); + + // First filter + builder.StartBlock(0); + builder.AddKey("foo"); + builder.StartBlock(2000); + builder.AddKey("bar"); + + // Second filter + builder.StartBlock(3100); + builder.AddKey("box"); + + // Third filter is empty + + // Last filter + builder.StartBlock(9000); + builder.AddKey("box"); + builder.AddKey("hello"); + + Slice block = builder.Finish(); + FilterBlockReader reader(&policy_, block); + + // Check first filter + ASSERT_TRUE(reader.KeyMayMatch(0, "foo")); + ASSERT_TRUE(reader.KeyMayMatch(2000, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(0, "hello")); + + // Check second filter + ASSERT_TRUE(reader.KeyMayMatch(3100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(3100, "hello")); + + // Check third filter (empty) + ASSERT_TRUE(! reader.KeyMayMatch(4100, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "bar")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "box")); + ASSERT_TRUE(! reader.KeyMayMatch(4100, "hello")); + + // Check last filter + ASSERT_TRUE(reader.KeyMayMatch(9000, "box")); + ASSERT_TRUE(reader.KeyMayMatch(9000, "hello")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "foo")); + ASSERT_TRUE(! reader.KeyMayMatch(9000, "bar")); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/table/format.cc b/table/format.cc new file mode 100644 index 0000000000..285e1c0de3 --- /dev/null +++ b/table/format.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/format.h" + +#include "leveldb/env.h" +#include "port/port.h" +#include "table/block.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +void BlockHandle::EncodeTo(std::string* dst) const { + // Sanity check that all fields have been set + assert(offset_ != ~static_cast(0)); + assert(size_ != ~static_cast(0)); + PutVarint64(dst, offset_); + PutVarint64(dst, size_); +} + +Status BlockHandle::DecodeFrom(Slice* input) { + if (GetVarint64(input, &offset_) && + GetVarint64(input, &size_)) { + return Status::OK(); + } else { + return Status::Corruption("bad block handle"); + } +} + +void Footer::EncodeTo(std::string* dst) const { + const size_t original_size = dst->size(); + metaindex_handle_.EncodeTo(dst); + index_handle_.EncodeTo(dst); + dst->resize(2 * BlockHandle::kMaxEncodedLength); // Padding + PutFixed32(dst, static_cast(kTableMagicNumber & 0xffffffffu)); + PutFixed32(dst, static_cast(kTableMagicNumber >> 32)); + assert(dst->size() == original_size + kEncodedLength); + (void)original_size; // Disable unused variable warning. +} + +Status Footer::DecodeFrom(Slice* input) { + const char* magic_ptr = input->data() + kEncodedLength - 8; + const uint32_t magic_lo = DecodeFixed32(magic_ptr); + const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4); + const uint64_t magic = ((static_cast(magic_hi) << 32) | + (static_cast(magic_lo))); + if (magic != kTableMagicNumber) { + return Status::Corruption("not an sstable (bad magic number)"); + } + + Status result = metaindex_handle_.DecodeFrom(input); + if (result.ok()) { + result = index_handle_.DecodeFrom(input); + } + if (result.ok()) { + // We skip over any leftover data (just padding for now) in "input" + const char* end = magic_ptr + 8; + *input = Slice(end, input->data() + input->size() - end); + } + return result; +} + +Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result) { + result->data = Slice(); + result->cachable = false; + result->heap_allocated = false; + + // Read the block contents as well as the type/crc footer. + // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); + char* buf = new char[n + kBlockTrailerSize]; + Slice contents; + Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + if (!s.ok()) { + delete[] buf; + return s; + } + if (contents.size() != n + kBlockTrailerSize) { + delete[] buf; + return Status::Corruption("truncated block read", file->GetName()); + } + + // Check the crc of the type and the block contents + const char* data = contents.data(); // Pointer to where Read put the data + if (options.verify_checksums) { + const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1)); + const uint32_t actual = crc32c::Value(data, n + 1); + if (actual != crc) { + delete[] buf; + s = Status::Corruption("block checksum mismatch", file->GetName()); + return s; + } + } + + switch (data[n]) { + case kNoCompression: + if (data != buf) { + // File implementation gave us pointer to some other data. + // Use it directly under the assumption that it will be live + // while the file is open. + delete[] buf; + result->data = Slice(data, n); + result->heap_allocated = false; + result->cachable = false; // Do not double-cache + } else { + result->data = Slice(buf, n); + result->heap_allocated = true; + result->cachable = true; + } + + // Ok + break; + case kSnappyCompression: { + size_t ulength = 0; + if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) { + delete[] buf; + return Status::Corruption("corrupted compressed block contents", file->GetName()); + } + char* ubuf = new char[ulength]; + if (!port::Snappy_Uncompress(data, n, ubuf)) { + delete[] buf; + delete[] ubuf; + return Status::Corruption("corrupted compressed block contents", file->GetName()); + } + delete[] buf; + result->data = Slice(ubuf, ulength); + result->heap_allocated = true; + result->cachable = true; + break; + } + default: + delete[] buf; + return Status::Corruption("bad block type", file->GetName()); + } + + return Status::OK(); +} + +} // namespace leveldb diff --git a/table/format.h b/table/format.h new file mode 100644 index 0000000000..6c0b80c017 --- /dev/null +++ b/table/format.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_ +#define STORAGE_LEVELDB_TABLE_FORMAT_H_ + +#include +#include +#include "leveldb/slice.h" +#include "leveldb/status.h" +#include "leveldb/table_builder.h" + +namespace leveldb { + +class Block; +class RandomAccessFile; +struct ReadOptions; + +// BlockHandle is a pointer to the extent of a file that stores a data +// block or a meta block. +class BlockHandle { + public: + BlockHandle(); + + // The offset of the block in the file. + uint64_t offset() const { return offset_; } + void set_offset(uint64_t offset) { offset_ = offset; } + + // The size of the stored block + uint64_t size() const { return size_; } + void set_size(uint64_t size) { size_ = size; } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Maximum encoding length of a BlockHandle + enum { kMaxEncodedLength = 10 + 10 }; + + private: + uint64_t offset_; + uint64_t size_; +}; + +// Footer encapsulates the fixed information stored at the tail +// end of every table file. +class Footer { + public: + Footer() { } + + // The block handle for the metaindex block of the table + const BlockHandle& metaindex_handle() const { return metaindex_handle_; } + void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; } + + // The block handle for the index block of the table + const BlockHandle& index_handle() const { + return index_handle_; + } + void set_index_handle(const BlockHandle& h) { + index_handle_ = h; + } + + void EncodeTo(std::string* dst) const; + Status DecodeFrom(Slice* input); + + // Encoded length of a Footer. Note that the serialization of a + // Footer will always occupy exactly this many bytes. It consists + // of two block handles and a magic number. + enum { + kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8 + }; + + private: + BlockHandle metaindex_handle_; + BlockHandle index_handle_; +}; + +// kTableMagicNumber was picked by running +// echo http://code.google.com/p/leveldb/ | sha1sum +// and taking the leading 64 bits. +static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull; + +// 1-byte type + 32-bit crc +static const size_t kBlockTrailerSize = 5; + +struct BlockContents { + Slice data; // Actual contents of data + bool cachable; // True iff data can be cached + bool heap_allocated; // True iff caller should delete[] data.data() +}; + +// Read the block identified by "handle" from "file". On failure +// return non-OK. On success fill *result and return OK. +extern Status ReadBlock(RandomAccessFile* file, + const ReadOptions& options, + const BlockHandle& handle, + BlockContents* result); + +// Implementation details follow. Clients should ignore, + +inline BlockHandle::BlockHandle() + : offset_(~static_cast(0)), + size_(~static_cast(0)) { +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_FORMAT_H_ diff --git a/table/iterator.cc b/table/iterator.cc new file mode 100644 index 0000000000..3d1c87fdec --- /dev/null +++ b/table/iterator.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/iterator.h" + +namespace leveldb { + +Iterator::Iterator() { + cleanup_.function = NULL; + cleanup_.next = NULL; +} + +Iterator::~Iterator() { + if (cleanup_.function != NULL) { + (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2); + for (Cleanup* c = cleanup_.next; c != NULL; ) { + (*c->function)(c->arg1, c->arg2); + Cleanup* next = c->next; + delete c; + c = next; + } + } +} + +void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) { + assert(func != NULL); + Cleanup* c; + if (cleanup_.function == NULL) { + c = &cleanup_; + } else { + c = new Cleanup; + c->next = cleanup_.next; + cleanup_.next = c; + } + c->function = func; + c->arg1 = arg1; + c->arg2 = arg2; +} + +namespace { +class EmptyIterator : public Iterator { + public: + EmptyIterator(const Status& s) : status_(s) { } + virtual bool Valid() const { return false; } + virtual void Seek(const Slice& target) { } + virtual void SeekToFirst() { } + virtual void SeekToLast() { } + virtual void Next() { assert(false); } + virtual void Prev() { assert(false); } + Slice key() const { assert(false); return Slice(); } + Slice value() const { assert(false); return Slice(); } + virtual Status status() const { return status_; } + private: + Status status_; +}; +} // namespace + +Iterator* NewEmptyIterator() { + return new EmptyIterator(Status::OK()); +} + +Iterator* NewErrorIterator(const Status& status) { + return new EmptyIterator(status); +} + +} // namespace leveldb diff --git a/table/iterator_wrapper.h b/table/iterator_wrapper.h new file mode 100644 index 0000000000..f410c3fabe --- /dev/null +++ b/table/iterator_wrapper.h @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ +#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ + +#include "leveldb/iterator.h" +#include "leveldb/slice.h" + +namespace leveldb { + +// A internal wrapper class with an interface similar to Iterator that +// caches the valid() and key() results for an underlying iterator. +// This can help avoid virtual function calls and also gives better +// cache locality. +class IteratorWrapper { + public: + IteratorWrapper(): iter_(NULL), valid_(false) { } + explicit IteratorWrapper(Iterator* iter): iter_(NULL) { + Set(iter); + } + ~IteratorWrapper() { delete iter_; } + Iterator* iter() const { return iter_; } + + // Takes ownership of "iter" and will delete it when destroyed, or + // when Set() is invoked again. + void Set(Iterator* iter) { + delete iter_; + iter_ = iter; + if (iter_ == NULL) { + valid_ = false; + } else { + Update(); + } + } + + + // Iterator interface methods + bool Valid() const { return valid_; } + Slice key() const { assert(Valid()); return key_; } + Slice value() const { assert(Valid()); return iter_->value(); } + // Methods below require iter() != NULL + Status status() const { assert(iter_); return iter_->status(); } + void Next() { assert(iter_); iter_->Next(); Update(); } + void Prev() { assert(iter_); iter_->Prev(); Update(); } + void Seek(const Slice& k) { assert(iter_); iter_->Seek(k); Update(); } + void SeekToFirst() { assert(iter_); iter_->SeekToFirst(); Update(); } + void SeekToLast() { assert(iter_); iter_->SeekToLast(); Update(); } + + private: + void Update() { + valid_ = iter_->Valid(); + if (valid_) { + key_ = iter_->key(); + } + } + + Iterator* iter_; + bool valid_; + Slice key_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_ diff --git a/table/merger.cc b/table/merger.cc new file mode 100644 index 0000000000..2dde4dc21f --- /dev/null +++ b/table/merger.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/merger.h" + +#include "leveldb/comparator.h" +#include "leveldb/iterator.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { +class MergingIterator : public Iterator { + public: + MergingIterator(const Comparator* comparator, Iterator** children, int n) + : comparator_(comparator), + children_(new IteratorWrapper[n]), + n_(n), + current_(NULL), + direction_(kForward) { + for (int i = 0; i < n; i++) { + children_[i].Set(children[i]); + } + } + + virtual ~MergingIterator() { + delete[] children_; + } + + virtual bool Valid() const { + return (current_ != NULL); + } + + virtual void SeekToFirst() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToFirst(); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void SeekToLast() { + for (int i = 0; i < n_; i++) { + children_[i].SeekToLast(); + } + FindLargest(); + direction_ = kReverse; + } + + virtual void Seek(const Slice& target) { + for (int i = 0; i < n_; i++) { + children_[i].Seek(target); + } + FindSmallest(); + direction_ = kForward; + } + + virtual void Next() { + assert(Valid()); + + // Ensure that all children are positioned after key(). + // If we are moving in the forward direction, it is already + // true for all of the non-current_ children since current_ is + // the smallest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kForward) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid() && + comparator_->Compare(key(), child->key()) == 0) { + child->Next(); + } + } + } + direction_ = kForward; + } + + current_->Next(); + FindSmallest(); + } + + virtual void Prev() { + assert(Valid()); + + // Ensure that all children are positioned before key(). + // If we are moving in the reverse direction, it is already + // true for all of the non-current_ children since current_ is + // the largest child and key() == current_->key(). Otherwise, + // we explicitly position the non-current_ children. + if (direction_ != kReverse) { + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child != current_) { + child->Seek(key()); + if (child->Valid()) { + // Child is at first entry >= key(). Step back one to be < key() + child->Prev(); + } else { + // Child has no entries >= key(). Position at last entry. + child->SeekToLast(); + } + } + } + direction_ = kReverse; + } + + current_->Prev(); + FindLargest(); + } + + virtual Slice key() const { + assert(Valid()); + return current_->key(); + } + + virtual Slice value() const { + assert(Valid()); + return current_->value(); + } + + virtual Status status() const { + Status status; + for (int i = 0; i < n_; i++) { + status = children_[i].status(); + if (!status.ok()) { + break; + } + } + return status; + } + + private: + void FindSmallest(); + void FindLargest(); + + // We might want to use a heap in case there are lots of children. + // For now we use a simple array since we expect a very small number + // of children in leveldb. + const Comparator* comparator_; + IteratorWrapper* children_; + int n_; + IteratorWrapper* current_; + + // Which direction is the iterator moving? + enum Direction { + kForward, + kReverse + }; + Direction direction_; +}; + +void MergingIterator::FindSmallest() { + IteratorWrapper* smallest = NULL; + for (int i = 0; i < n_; i++) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (smallest == NULL) { + smallest = child; + } else if (comparator_->Compare(child->key(), smallest->key()) < 0) { + smallest = child; + } + } + } + current_ = smallest; +} + +void MergingIterator::FindLargest() { + IteratorWrapper* largest = NULL; + for (int i = n_-1; i >= 0; i--) { + IteratorWrapper* child = &children_[i]; + if (child->Valid()) { + if (largest == NULL) { + largest = child; + } else if (comparator_->Compare(child->key(), largest->key()) > 0) { + largest = child; + } + } + } + current_ = largest; +} +} // namespace + +Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) { + assert(n >= 0); + if (n == 0) { + return NewEmptyIterator(); + } else if (n == 1) { + return list[0]; + } else { + return new MergingIterator(cmp, list, n); + } +} + +} // namespace leveldb diff --git a/table/merger.h b/table/merger.h new file mode 100644 index 0000000000..91ddd80faa --- /dev/null +++ b/table/merger.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_ +#define STORAGE_LEVELDB_TABLE_MERGER_H_ + +namespace leveldb { + +class Comparator; +class Iterator; + +// Return an iterator that provided the union of the data in +// children[0,n-1]. Takes ownership of the child iterators and +// will delete them when the result iterator is deleted. +// +// The result does no duplicate suppression. I.e., if a particular +// key is present in K child iterators, it will be yielded K times. +// +// REQUIRES: n >= 0 +extern Iterator* NewMergingIterator( + const Comparator* comparator, Iterator** children, int n); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_MERGER_H_ diff --git a/table/table.cc b/table/table.cc new file mode 100644 index 0000000000..decf8082cc --- /dev/null +++ b/table/table.cc @@ -0,0 +1,285 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include "leveldb/cache.h" +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "table/two_level_iterator.h" +#include "util/coding.h" + +namespace leveldb { + +struct Table::Rep { + ~Rep() { + delete filter; + delete [] filter_data; + delete index_block; + } + + Options options; + Status status; + RandomAccessFile* file; + uint64_t cache_id; + FilterBlockReader* filter; + const char* filter_data; + + BlockHandle metaindex_handle; // Handle to metaindex_block: saved from footer + Block* index_block; +}; + +Status Table::Open(const Options& options, + RandomAccessFile* file, + uint64_t size, + Table** table) { + *table = NULL; + if (size < Footer::kEncodedLength) { + return Status::Corruption("file is too short to be an sstable"); + } + + char footer_space[Footer::kEncodedLength]; + Slice footer_input; + Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength, + &footer_input, footer_space); + if (!s.ok()) return s; + + Footer footer; + s = footer.DecodeFrom(&footer_input); + if (!s.ok()) return s; + + // Read the index block + BlockContents contents; + Block* index_block = NULL; + if (s.ok()) { + ReadOptions opt; + if (options.paranoid_checks) { + opt.verify_checksums = true; + } + s = ReadBlock(file, opt, footer.index_handle(), &contents); + if (s.ok()) { + index_block = new Block(contents); + } + } + + if (s.ok()) { + // We've successfully read the footer and the index block: we're + // ready to serve requests. + Rep* rep = new Table::Rep; + rep->options = options; + rep->file = file; + rep->metaindex_handle = footer.metaindex_handle(); + rep->index_block = index_block; + rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0); + rep->filter_data = NULL; + rep->filter = NULL; + *table = new Table(rep); + (*table)->ReadMeta(footer); + } else { + delete index_block; + } + + return s; +} + +void Table::ReadMeta(const Footer& footer) { + if (rep_->options.filter_policy == NULL) { + return; // Do not need any metadata + } + + // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates + // it is an empty block. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents contents; + if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) { + // Do not propagate errors since meta info is not needed for operation + return; + } + Block* meta = new Block(contents); + + Iterator* iter = meta->NewIterator(BytewiseComparator()); + std::string key = "filter."; + key.append(rep_->options.filter_policy->Name()); + iter->Seek(key); + if (iter->Valid() && iter->key() == Slice(key)) { + ReadFilter(iter->value()); + } + delete iter; + delete meta; +} + +void Table::ReadFilter(const Slice& filter_handle_value) { + Slice v = filter_handle_value; + BlockHandle filter_handle; + if (!filter_handle.DecodeFrom(&v).ok()) { + return; + } + + // We might want to unify with ReadBlock() if we start + // requiring checksum verification in Table::Open. + ReadOptions opt; + if (rep_->options.paranoid_checks) { + opt.verify_checksums = true; + } + BlockContents block; + if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) { + return; + } + if (block.heap_allocated) { + rep_->filter_data = block.data.data(); // Will need to delete later + } + rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data); +} + +Table::~Table() { + delete rep_; +} + +static void DeleteBlock(void* arg, void* ignored) { + delete reinterpret_cast(arg); +} + +static void DeleteCachedBlock(const Slice& key, void* value) { + Block* block = reinterpret_cast(value); + delete block; +} + +static void ReleaseBlock(void* arg, void* h) { + Cache* cache = reinterpret_cast(arg); + Cache::Handle* handle = reinterpret_cast(h); + cache->Release(handle); +} + +// Convert an index iterator value (i.e., an encoded BlockHandle) +// into an iterator over the contents of the corresponding block. +Iterator* Table::BlockReader(void* arg, + const ReadOptions& options, + const Slice& index_value) { + Table* table = reinterpret_cast(arg); + Cache* block_cache = table->rep_->options.block_cache; + Block* block = NULL; + Cache::Handle* cache_handle = NULL; + + BlockHandle handle; + Slice input = index_value; + Status s = handle.DecodeFrom(&input); + // We intentionally allow extra stuff in index_value so that we + // can add more features in the future. + + if (s.ok()) { + BlockContents contents; + if (block_cache != NULL) { + char cache_key_buffer[16]; + EncodeFixed64(cache_key_buffer, table->rep_->cache_id); + EncodeFixed64(cache_key_buffer+8, handle.offset()); + Slice key(cache_key_buffer, sizeof(cache_key_buffer)); + cache_handle = block_cache->Lookup(key); + if (cache_handle != NULL) { + block = reinterpret_cast(block_cache->Value(cache_handle)); + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + if (contents.cachable && options.fill_cache) { + cache_handle = block_cache->Insert( + key, block, block->size(), &DeleteCachedBlock); + } + } + } + } else { + s = ReadBlock(table->rep_->file, options, handle, &contents); + if (s.ok()) { + block = new Block(contents); + } + } + } + + Iterator* iter; + if (block != NULL) { + iter = block->NewIterator(table->rep_->options.comparator); + if (cache_handle == NULL) { + iter->RegisterCleanup(&DeleteBlock, block, NULL); + } else { + iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle); + } + } else { + iter = NewErrorIterator(s); + } + return iter; +} + +Iterator* Table::NewIterator(const ReadOptions& options) const { + return NewTwoLevelIterator( + rep_->index_block->NewIterator(rep_->options.comparator), + &Table::BlockReader, const_cast(this), options); +} + +Status Table::InternalGet(const ReadOptions& options, const Slice& k, + void* arg, + void (*saver)(void*, const Slice&, const Slice&)) { + Status s; + Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator); + iiter->Seek(k); + if (iiter->Valid()) { + Slice handle_value = iiter->value(); + FilterBlockReader* filter = rep_->filter; + BlockHandle handle; + if (filter != NULL && + handle.DecodeFrom(&handle_value).ok() && + !filter->KeyMayMatch(handle.offset(), k)) { + // Not found + } else { + Iterator* block_iter = BlockReader(this, options, iiter->value()); + block_iter->Seek(k); + if (block_iter->Valid()) { + (*saver)(arg, block_iter->key(), block_iter->value()); + } + s = block_iter->status(); + delete block_iter; + } + } + if (s.ok()) { + s = iiter->status(); + } + delete iiter; + return s; +} + + +uint64_t Table::ApproximateOffsetOf(const Slice& key) const { + Iterator* index_iter = + rep_->index_block->NewIterator(rep_->options.comparator); + index_iter->Seek(key); + uint64_t result; + if (index_iter->Valid()) { + BlockHandle handle; + Slice input = index_iter->value(); + Status s = handle.DecodeFrom(&input); + if (s.ok()) { + result = handle.offset(); + } else { + // Strange: we can't decode the block handle in the index block. + // We'll just return the offset of the metaindex block, which is + // close to the whole file size for this case. + result = rep_->metaindex_handle.offset(); + } + } else { + // key is past the last key in the file. Approximate the offset + // by returning the offset of the metaindex block (which is + // right near the end of the file). + result = rep_->metaindex_handle.offset(); + } + delete index_iter; + return result; +} + +} // namespace leveldb diff --git a/table/table_builder.cc b/table/table_builder.cc new file mode 100644 index 0000000000..62002c84f2 --- /dev/null +++ b/table/table_builder.cc @@ -0,0 +1,270 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table_builder.h" + +#include +#include "leveldb/comparator.h" +#include "leveldb/env.h" +#include "leveldb/filter_policy.h" +#include "leveldb/options.h" +#include "table/block_builder.h" +#include "table/filter_block.h" +#include "table/format.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { + +struct TableBuilder::Rep { + Options options; + Options index_block_options; + WritableFile* file; + uint64_t offset; + Status status; + BlockBuilder data_block; + BlockBuilder index_block; + std::string last_key; + int64_t num_entries; + bool closed; // Either Finish() or Abandon() has been called. + FilterBlockBuilder* filter_block; + + // We do not emit the index entry for a block until we have seen the + // first key for the next data block. This allows us to use shorter + // keys in the index block. For example, consider a block boundary + // between the keys "the quick brown fox" and "the who". We can use + // "the r" as the key for the index block entry since it is >= all + // entries in the first block and < all entries in subsequent + // blocks. + // + // Invariant: r->pending_index_entry is true only if data_block is empty. + bool pending_index_entry; + BlockHandle pending_handle; // Handle to add to index block + + std::string compressed_output; + + Rep(const Options& opt, WritableFile* f) + : options(opt), + index_block_options(opt), + file(f), + offset(0), + data_block(&options), + index_block(&index_block_options), + num_entries(0), + closed(false), + filter_block(opt.filter_policy == NULL ? NULL + : new FilterBlockBuilder(opt.filter_policy)), + pending_index_entry(false) { + index_block_options.block_restart_interval = 1; + } +}; + +TableBuilder::TableBuilder(const Options& options, WritableFile* file) + : rep_(new Rep(options, file)) { + if (rep_->filter_block != NULL) { + rep_->filter_block->StartBlock(0); + } +} + +TableBuilder::~TableBuilder() { + assert(rep_->closed); // Catch errors where caller forgot to call Finish() + delete rep_->filter_block; + delete rep_; +} + +Status TableBuilder::ChangeOptions(const Options& options) { + // Note: if more fields are added to Options, update + // this function to catch changes that should not be allowed to + // change in the middle of building a Table. + if (options.comparator != rep_->options.comparator) { + return Status::InvalidArgument("changing comparator while building table"); + } + + // Note that any live BlockBuilders point to rep_->options and therefore + // will automatically pick up the updated options. + rep_->options = options; + rep_->index_block_options = options; + rep_->index_block_options.block_restart_interval = 1; + return Status::OK(); +} + +void TableBuilder::Add(const Slice& key, const Slice& value) { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->num_entries > 0) { + assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0); + } + + if (r->pending_index_entry) { + assert(r->data_block.empty()); + r->options.comparator->FindShortestSeparator(&r->last_key, key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + + if (r->filter_block != NULL) { + r->filter_block->AddKey(key); + } + + r->last_key.assign(key.data(), key.size()); + r->num_entries++; + r->data_block.Add(key, value); + + const size_t estimated_block_size = r->data_block.CurrentSizeEstimate(); + if (estimated_block_size >= r->options.block_size) { + Flush(); + } +} + +void TableBuilder::Flush() { + Rep* r = rep_; + assert(!r->closed); + if (!ok()) return; + if (r->data_block.empty()) return; + assert(!r->pending_index_entry); + WriteBlock(&r->data_block, &r->pending_handle); + if (ok()) { + r->pending_index_entry = true; + r->status = r->file->Flush(); + } + if (r->filter_block != NULL) { + r->filter_block->StartBlock(r->offset); + } +} + +void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) { + // File format contains a sequence of blocks where each block has: + // block_data: uint8[n] + // type: uint8 + // crc: uint32 + assert(ok()); + Rep* r = rep_; + Slice raw = block->Finish(); + + Slice block_contents; + CompressionType type = r->options.compression; + // TODO(postrelease): Support more compression options: zlib? + switch (type) { + case kNoCompression: + block_contents = raw; + break; + + case kSnappyCompression: { + std::string* compressed = &r->compressed_output; + if (port::Snappy_Compress(raw.data(), raw.size(), compressed) && + compressed->size() < raw.size() - (raw.size() / 8u)) { + block_contents = *compressed; + } else { + // Snappy not supported, or compressed less than 12.5%, so just + // store uncompressed form + block_contents = raw; + type = kNoCompression; + } + break; + } + } + WriteRawBlock(block_contents, type, handle); + r->compressed_output.clear(); + block->Reset(); +} + +void TableBuilder::WriteRawBlock(const Slice& block_contents, + CompressionType type, + BlockHandle* handle) { + Rep* r = rep_; + handle->set_offset(r->offset); + handle->set_size(block_contents.size()); + r->status = r->file->Append(block_contents); + if (r->status.ok()) { + char trailer[kBlockTrailerSize]; + trailer[0] = type; + uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size()); + crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type + EncodeFixed32(trailer+1, crc32c::Mask(crc)); + r->status = r->file->Append(Slice(trailer, kBlockTrailerSize)); + if (r->status.ok()) { + r->offset += block_contents.size() + kBlockTrailerSize; + } + } +} + +Status TableBuilder::status() const { + return rep_->status; +} + +Status TableBuilder::Finish() { + Rep* r = rep_; + Flush(); + assert(!r->closed); + r->closed = true; + + BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle; + + // Write filter block + if (ok() && r->filter_block != NULL) { + WriteRawBlock(r->filter_block->Finish(), kNoCompression, + &filter_block_handle); + } + + // Write metaindex block + if (ok()) { + BlockBuilder meta_index_block(&r->options); + if (r->filter_block != NULL) { + // Add mapping from "filter.Name" to location of filter data + std::string key = "filter."; + key.append(r->options.filter_policy->Name()); + std::string handle_encoding; + filter_block_handle.EncodeTo(&handle_encoding); + meta_index_block.Add(key, handle_encoding); + } + + // TODO(postrelease): Add stats and other meta blocks + WriteBlock(&meta_index_block, &metaindex_block_handle); + } + + // Write index block + if (ok()) { + if (r->pending_index_entry) { + r->options.comparator->FindShortSuccessor(&r->last_key); + std::string handle_encoding; + r->pending_handle.EncodeTo(&handle_encoding); + r->index_block.Add(r->last_key, Slice(handle_encoding)); + r->pending_index_entry = false; + } + WriteBlock(&r->index_block, &index_block_handle); + } + + // Write footer + if (ok()) { + Footer footer; + footer.set_metaindex_handle(metaindex_block_handle); + footer.set_index_handle(index_block_handle); + std::string footer_encoding; + footer.EncodeTo(&footer_encoding); + r->status = r->file->Append(footer_encoding); + if (r->status.ok()) { + r->offset += footer_encoding.size(); + } + } + return r->status; +} + +void TableBuilder::Abandon() { + Rep* r = rep_; + assert(!r->closed); + r->closed = true; +} + +uint64_t TableBuilder::NumEntries() const { + return rep_->num_entries; +} + +uint64_t TableBuilder::FileSize() const { + return rep_->offset; +} + +} // namespace leveldb diff --git a/table/table_test.cc b/table/table_test.cc new file mode 100644 index 0000000000..abf6e246ff --- /dev/null +++ b/table/table_test.cc @@ -0,0 +1,876 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/table.h" + +#include +#include +#include "db/dbformat.h" +#include "db/memtable.h" +#include "db/write_batch_internal.h" +#include "leveldb/db.h" +#include "leveldb/env.h" +#include "leveldb/iterator.h" +#include "leveldb/table_builder.h" +#include "table/block.h" +#include "table/block_builder.h" +#include "table/format.h" +#include "util/random.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +// Return reverse of "key". +// Used to test non-lexicographic comparators. +static std::string Reverse(const Slice& key) { + std::string str(key.ToString()); + std::string rev(""); + for (std::string::reverse_iterator rit = str.rbegin(); + rit != str.rend(); ++rit) { + rev.push_back(*rit); + } + return rev; +} + +namespace { +class ReverseKeyComparator : public Comparator { + public: + virtual const char* Name() const { + return "leveldb.ReverseBytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return BytewiseComparator()->Compare(Reverse(a), Reverse(b)); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + std::string s = Reverse(*start); + std::string l = Reverse(limit); + BytewiseComparator()->FindShortestSeparator(&s, l); + *start = Reverse(s); + } + + virtual void FindShortSuccessor(std::string* key) const { + std::string s = Reverse(*key); + BytewiseComparator()->FindShortSuccessor(&s); + *key = Reverse(s); + } +}; +} // namespace +static ReverseKeyComparator reverse_key_comparator; + +static void Increment(const Comparator* cmp, std::string* key) { + if (cmp == BytewiseComparator()) { + key->push_back('\0'); + } else { + assert(cmp == &reverse_key_comparator); + std::string rev = Reverse(*key); + rev.push_back('\0'); + *key = Reverse(rev); + } +} + +// An STL comparator that uses a Comparator +namespace { +struct STLLessThan { + const Comparator* cmp; + + STLLessThan() : cmp(BytewiseComparator()) { } + STLLessThan(const Comparator* c) : cmp(c) { } + bool operator()(const std::string& a, const std::string& b) const { + return cmp->Compare(Slice(a), Slice(b)) < 0; + } +}; +} // namespace + +class StringSink: public WritableFile { + public: + ~StringSink() { } + + const std::string& contents() const { return contents_; } + + virtual Status Close() { return Status::OK(); } + virtual Status Flush() { return Status::OK(); } + virtual Status Sync() { return Status::OK(); } + + virtual Status Append(const Slice& data) { + contents_.append(data.data(), data.size()); + return Status::OK(); + } + + private: + std::string contents_; +}; + + +class StringSource: public RandomAccessFile { + public: + StringSource(const Slice& contents) + : contents_(contents.data(), contents.size()) { + } + + virtual ~StringSource() { } + + uint64_t Size() const { return contents_.size(); } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + if (offset > contents_.size()) { + return Status::InvalidArgument("invalid Read offset"); + } + if (offset + n > contents_.size()) { + n = contents_.size() - offset; + } + memcpy(scratch, &contents_[offset], n); + *result = Slice(scratch, n); + return Status::OK(); + } + + private: + std::string contents_; +}; + +typedef std::map KVMap; + +// Helper class for tests to unify the interface between +// BlockBuilder/TableBuilder and Block/Table. +class Constructor { + public: + explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { } + virtual ~Constructor() { } + + void Add(const std::string& key, const Slice& value) { + data_[key] = value.ToString(); + } + + // Finish constructing the data structure with all the keys that have + // been added so far. Returns the keys in sorted order in "*keys" + // and stores the key/value pairs in "*kvmap" + void Finish(const Options& options, + std::vector* keys, + KVMap* kvmap) { + *kvmap = data_; + keys->clear(); + for (KVMap::const_iterator it = data_.begin(); + it != data_.end(); + ++it) { + keys->push_back(it->first); + } + data_.clear(); + Status s = FinishImpl(options, *kvmap); + ASSERT_TRUE(s.ok()) << s.ToString(); + } + + // Construct the data structure from the data in "data" + virtual Status FinishImpl(const Options& options, const KVMap& data) = 0; + + virtual Iterator* NewIterator() const = 0; + + virtual const KVMap& data() { return data_; } + + virtual DB* db() const { return NULL; } // Overridden in DBConstructor + + private: + KVMap data_; +}; + +class BlockConstructor: public Constructor { + public: + explicit BlockConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp), + block_(NULL) { } + ~BlockConstructor() { + delete block_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete block_; + block_ = NULL; + BlockBuilder builder(&options); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + } + // Open the block + data_ = builder.Finish().ToString(); + BlockContents contents; + contents.data = data_; + contents.cachable = false; + contents.heap_allocated = false; + block_ = new Block(contents); + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return block_->NewIterator(comparator_); + } + + private: + const Comparator* comparator_; + std::string data_; + Block* block_; + + BlockConstructor(); +}; + +class TableConstructor: public Constructor { + public: + TableConstructor(const Comparator* cmp) + : Constructor(cmp), + source_(NULL), table_(NULL) { + } + ~TableConstructor() { + Reset(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + Reset(); + StringSink sink; + TableBuilder builder(options, &sink); + + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + builder.Add(it->first, it->second); + ASSERT_TRUE(builder.status().ok()); + } + Status s = builder.Finish(); + ASSERT_TRUE(s.ok()) << s.ToString(); + + ASSERT_EQ(sink.contents().size(), builder.FileSize()); + + // Open the table + source_ = new StringSource(sink.contents()); + Options table_options; + table_options.comparator = options.comparator; + return Table::Open(table_options, source_, sink.contents().size(), &table_); + } + + virtual Iterator* NewIterator() const { + return table_->NewIterator(ReadOptions()); + } + + uint64_t ApproximateOffsetOf(const Slice& key) const { + return table_->ApproximateOffsetOf(key); + } + + private: + void Reset() { + delete table_; + delete source_; + table_ = NULL; + source_ = NULL; + } + + StringSource* source_; + Table* table_; + + TableConstructor(); +}; + +// A helper class that converts internal format keys into user keys +class KeyConvertingIterator: public Iterator { + public: + explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { } + virtual ~KeyConvertingIterator() { delete iter_; } + virtual bool Valid() const { return iter_->Valid(); } + virtual void Seek(const Slice& target) { + ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue); + std::string encoded; + AppendInternalKey(&encoded, ikey); + iter_->Seek(encoded); + } + virtual void SeekToFirst() { iter_->SeekToFirst(); } + virtual void SeekToLast() { iter_->SeekToLast(); } + virtual void Next() { iter_->Next(); } + virtual void Prev() { iter_->Prev(); } + + virtual Slice key() const { + assert(Valid()); + ParsedInternalKey key; + if (!ParseInternalKey(iter_->key(), &key)) { + status_ = Status::Corruption("malformed internal key"); + return Slice("corrupted key"); + } + return key.user_key; + } + + virtual Slice value() const { return iter_->value(); } + virtual Status status() const { + return status_.ok() ? iter_->status() : status_; + } + + private: + mutable Status status_; + Iterator* iter_; + + // No copying allowed + KeyConvertingIterator(const KeyConvertingIterator&); + void operator=(const KeyConvertingIterator&); +}; + +class MemTableConstructor: public Constructor { + public: + explicit MemTableConstructor(const Comparator* cmp) + : Constructor(cmp), + internal_comparator_(cmp) { + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + } + ~MemTableConstructor() { + memtable_->Unref(); + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + memtable_->Unref(); + memtable_ = new MemTable(internal_comparator_); + memtable_->Ref(); + int seq = 1; + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + memtable_->Add(seq, kTypeValue, it->first, it->second); + seq++; + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return new KeyConvertingIterator(memtable_->NewIterator()); + } + + private: + InternalKeyComparator internal_comparator_; + MemTable* memtable_; +}; + +class DBConstructor: public Constructor { + public: + explicit DBConstructor(const Comparator* cmp) + : Constructor(cmp), + comparator_(cmp) { + db_ = NULL; + NewDB(); + } + ~DBConstructor() { + delete db_; + } + virtual Status FinishImpl(const Options& options, const KVMap& data) { + delete db_; + db_ = NULL; + NewDB(); + for (KVMap::const_iterator it = data.begin(); + it != data.end(); + ++it) { + WriteBatch batch; + batch.Put(it->first, it->second); + ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok()); + } + return Status::OK(); + } + virtual Iterator* NewIterator() const { + return db_->NewIterator(ReadOptions()); + } + + virtual DB* db() const { return db_; } + + private: + void NewDB() { + std::string name = test::TmpDir() + "/table_testdb"; + + Options options; + options.comparator = comparator_; + Status status = DestroyDB(name, options); + ASSERT_TRUE(status.ok()) << status.ToString(); + + options.create_if_missing = true; + options.error_if_exists = true; + options.write_buffer_size = 10000; // Something small to force merging + status = DB::Open(options, name, &db_); + ASSERT_TRUE(status.ok()) << status.ToString(); + } + + const Comparator* comparator_; + DB* db_; +}; + +enum TestType { + TABLE_TEST, + BLOCK_TEST, + MEMTABLE_TEST, + DB_TEST +}; + +struct TestArgs { + TestType type; + bool reverse_compare; + int restart_interval; +}; + +static const TestArgs kTestArgList[] = { + { TABLE_TEST, false, 16 }, + { TABLE_TEST, false, 1 }, + { TABLE_TEST, false, 1024 }, + { TABLE_TEST, true, 16 }, + { TABLE_TEST, true, 1 }, + { TABLE_TEST, true, 1024 }, + + { BLOCK_TEST, false, 16 }, + { BLOCK_TEST, false, 1 }, + { BLOCK_TEST, false, 1024 }, + { BLOCK_TEST, true, 16 }, + { BLOCK_TEST, true, 1 }, + { BLOCK_TEST, true, 1024 }, + + // Restart interval does not matter for memtables + { MEMTABLE_TEST, false, 16 }, + { MEMTABLE_TEST, true, 16 }, + + // Do not bother with restart interval variations for DB + { DB_TEST, false, 16 }, + { DB_TEST, true, 16 }, +}; +static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]); + +class Harness { + public: + Harness() : constructor_(NULL) { } + + void Init(const TestArgs& args) { + delete constructor_; + constructor_ = NULL; + options_ = Options(); + + options_.block_restart_interval = args.restart_interval; + // Use shorter block size for tests to exercise block boundary + // conditions more. + options_.block_size = 256; + if (args.reverse_compare) { + options_.comparator = &reverse_key_comparator; + } + switch (args.type) { + case TABLE_TEST: + constructor_ = new TableConstructor(options_.comparator); + break; + case BLOCK_TEST: + constructor_ = new BlockConstructor(options_.comparator); + break; + case MEMTABLE_TEST: + constructor_ = new MemTableConstructor(options_.comparator); + break; + case DB_TEST: + constructor_ = new DBConstructor(options_.comparator); + break; + } + } + + ~Harness() { + delete constructor_; + } + + void Add(const std::string& key, const std::string& value) { + constructor_->Add(key, value); + } + + void Test(Random* rnd) { + std::vector keys; + KVMap data; + constructor_->Finish(options_, &keys, &data); + + TestForwardScan(keys, data); + TestBackwardScan(keys, data); + TestRandomAccess(rnd, keys, data); + } + + void TestForwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToFirst(); + for (KVMap::const_iterator model_iter = data.begin(); + model_iter != data.end(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Next(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestBackwardScan(const std::vector& keys, + const KVMap& data) { + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + for (KVMap::const_reverse_iterator model_iter = data.rbegin(); + model_iter != data.rend(); + ++model_iter) { + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + iter->Prev(); + } + ASSERT_TRUE(!iter->Valid()); + delete iter; + } + + void TestRandomAccess(Random* rnd, + const std::vector& keys, + const KVMap& data) { + static const bool kVerbose = false; + Iterator* iter = constructor_->NewIterator(); + ASSERT_TRUE(!iter->Valid()); + KVMap::const_iterator model_iter = data.begin(); + if (kVerbose) fprintf(stderr, "---\n"); + for (int i = 0; i < 200; i++) { + const int toss = rnd->Uniform(5); + switch (toss) { + case 0: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Next\n"); + iter->Next(); + ++model_iter; + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 1: { + if (kVerbose) fprintf(stderr, "SeekToFirst\n"); + iter->SeekToFirst(); + model_iter = data.begin(); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 2: { + std::string key = PickRandomKey(rnd, keys); + model_iter = data.lower_bound(key); + if (kVerbose) fprintf(stderr, "Seek '%s'\n", + EscapeString(key).c_str()); + iter->Seek(Slice(key)); + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + + case 3: { + if (iter->Valid()) { + if (kVerbose) fprintf(stderr, "Prev\n"); + iter->Prev(); + if (model_iter == data.begin()) { + model_iter = data.end(); // Wrap around to invalid value + } else { + --model_iter; + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + } + break; + } + + case 4: { + if (kVerbose) fprintf(stderr, "SeekToLast\n"); + iter->SeekToLast(); + if (keys.empty()) { + model_iter = data.end(); + } else { + std::string last = data.rbegin()->first; + model_iter = data.lower_bound(last); + } + ASSERT_EQ(ToString(data, model_iter), ToString(iter)); + break; + } + } + } + delete iter; + } + + std::string ToString(const KVMap& data, const KVMap::const_iterator& it) { + if (it == data.end()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const KVMap& data, + const KVMap::const_reverse_iterator& it) { + if (it == data.rend()) { + return "END"; + } else { + return "'" + it->first + "->" + it->second + "'"; + } + } + + std::string ToString(const Iterator* it) { + if (!it->Valid()) { + return "END"; + } else { + return "'" + it->key().ToString() + "->" + it->value().ToString() + "'"; + } + } + + std::string PickRandomKey(Random* rnd, const std::vector& keys) { + if (keys.empty()) { + return "foo"; + } else { + const int index = rnd->Uniform(keys.size()); + std::string result = keys[index]; + switch (rnd->Uniform(3)) { + case 0: + // Return an existing key + break; + case 1: { + // Attempt to return something smaller than an existing key + if (result.size() > 0 && result[result.size()-1] > '\0') { + result[result.size()-1]--; + } + break; + } + case 2: { + // Return something larger than an existing key + Increment(options_.comparator, &result); + break; + } + } + return result; + } + } + + // Returns NULL if not running against a DB + DB* db() const { return constructor_->db(); } + + private: + Options options_; + Constructor* constructor_; +}; + +// Test empty table/block. +TEST(Harness, Empty) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Test(&rnd); + } +} + +// Special test for a block with no restart entries. The C++ leveldb +// code never generates such blocks, but the Java version of leveldb +// seems to. +TEST(Harness, ZeroRestartPointsInBlock) { + char data[sizeof(uint32_t)]; + memset(data, 0, sizeof(data)); + BlockContents contents; + contents.data = Slice(data, sizeof(data)); + contents.cachable = false; + contents.heap_allocated = false; + Block block(contents); + Iterator* iter = block.NewIterator(BytewiseComparator()); + iter->SeekToFirst(); + ASSERT_TRUE(!iter->Valid()); + iter->SeekToLast(); + ASSERT_TRUE(!iter->Valid()); + iter->Seek("foo"); + ASSERT_TRUE(!iter->Valid()); + delete iter; +} + +// Test the empty key +TEST(Harness, SimpleEmptyKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 1); + Add("", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSingle) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 2); + Add("abc", "v"); + Test(&rnd); + } +} + +TEST(Harness, SimpleMulti) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 3); + Add("abc", "v"); + Add("abcd", "v"); + Add("ac", "v2"); + Test(&rnd); + } +} + +TEST(Harness, SimpleSpecialKey) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 4); + Add("\xff\xff", "v3"); + Test(&rnd); + } +} + +TEST(Harness, Randomized) { + for (int i = 0; i < kNumTestArgs; i++) { + Init(kTestArgList[i]); + Random rnd(test::RandomSeed() + 5); + for (int num_entries = 0; num_entries < 2000; + num_entries += (num_entries < 50 ? 1 : 200)) { + if ((num_entries % 10) == 0) { + fprintf(stderr, "case %d of %d: num_entries = %d\n", + (i + 1), int(kNumTestArgs), num_entries); + } + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + } + } +} + +TEST(Harness, RandomizedLongDB) { + Random rnd(test::RandomSeed()); + TestArgs args = { DB_TEST, false, 16 }; + Init(args); + int num_entries = 100000; + for (int e = 0; e < num_entries; e++) { + std::string v; + Add(test::RandomKey(&rnd, rnd.Skewed(4)), + test::RandomString(&rnd, rnd.Skewed(5), &v).ToString()); + } + Test(&rnd); + + // We must have created enough data to force merging + int files = 0; + for (int level = 0; level < config::kNumLevels; level++) { + std::string value; + char name[100]; + snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level); + ASSERT_TRUE(db()->GetProperty(name, &value)); + files += atoi(value.c_str()); + } + ASSERT_GT(files, 0); +} + +class MemTableTest { }; + +TEST(MemTableTest, Simple) { + InternalKeyComparator cmp(BytewiseComparator()); + MemTable* memtable = new MemTable(cmp); + memtable->Ref(); + WriteBatch batch; + WriteBatchInternal::SetSequence(&batch, 100); + batch.Put(std::string("k1"), std::string("v1")); + batch.Put(std::string("k2"), std::string("v2")); + batch.Put(std::string("k3"), std::string("v3")); + batch.Put(std::string("largekey"), std::string("vlarge")); + ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok()); + + Iterator* iter = memtable->NewIterator(); + iter->SeekToFirst(); + while (iter->Valid()) { + fprintf(stderr, "key: '%s' -> '%s'\n", + iter->key().ToString().c_str(), + iter->value().ToString().c_str()); + iter->Next(); + } + + delete iter; + memtable->Unref(); +} + +static bool Between(uint64_t val, uint64_t low, uint64_t high) { + bool result = (val >= low) && (val <= high); + if (!result) { + fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n", + (unsigned long long)(val), + (unsigned long long)(low), + (unsigned long long)(high)); + } + return result; +} + +class TableTest { }; + +TEST(TableTest, ApproximateOffsetOfPlain) { + TableConstructor c(BytewiseComparator()); + c.Add("k01", "hello"); + c.Add("k02", "hello2"); + c.Add("k03", std::string(10000, 'x')); + c.Add("k04", std::string(200000, 'x')); + c.Add("k05", std::string(300000, 'x')); + c.Add("k06", "hello3"); + c.Add("k07", std::string(100000, 'x')); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kNoCompression; + c.Finish(options, &keys, &kvmap); + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000)); + +} + +static bool SnappyCompressionSupported() { + std::string out; + Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + return port::Snappy_Compress(in.data(), in.size(), &out); +} + +TEST(TableTest, ApproximateOffsetOfCompressed) { + if (!SnappyCompressionSupported()) { + fprintf(stderr, "skipping compression tests\n"); + return; + } + + Random rnd(301); + TableConstructor c(BytewiseComparator()); + std::string tmp; + c.Add("k01", "hello"); + c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + c.Add("k03", "hello3"); + c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp)); + std::vector keys; + KVMap kvmap; + Options options; + options.block_size = 1024; + options.compression = kSnappyCompression; + c.Finish(options, &keys, &kvmap); + + // Expected upper and lower bounds of space used by compressible strings. + static const int kSlop = 1000; // Compressor effectiveness varies. + const int expected = 2500; // 10000 * compression ratio (0.25) + const int min_z = expected - kSlop; + const int max_z = expected + kSlop; + + ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, kSlop)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, kSlop)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, kSlop)); + // Have now emitted a large compressible string, so adjust expected offset. + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), min_z, max_z)); + ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), min_z, max_z)); + // Have now emitted two large compressible strings, so adjust expected offset. + ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 2 * min_z, 2 * max_z)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/table/two_level_iterator.cc b/table/two_level_iterator.cc new file mode 100644 index 0000000000..7822ebab9c --- /dev/null +++ b/table/two_level_iterator.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "table/two_level_iterator.h" + +#include "leveldb/table.h" +#include "table/block.h" +#include "table/format.h" +#include "table/iterator_wrapper.h" + +namespace leveldb { + +namespace { + +typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&); + +class TwoLevelIterator: public Iterator { + public: + TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options); + + virtual ~TwoLevelIterator(); + + virtual void Seek(const Slice& target); + virtual void SeekToFirst(); + virtual void SeekToLast(); + virtual void Next(); + virtual void Prev(); + + virtual bool Valid() const { + return data_iter_.Valid(); + } + virtual Slice key() const { + assert(Valid()); + return data_iter_.key(); + } + virtual Slice value() const { + assert(Valid()); + return data_iter_.value(); + } + virtual Status status() const { + // It'd be nice if status() returned a const Status& instead of a Status + if (!index_iter_.status().ok()) { + return index_iter_.status(); + } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) { + return data_iter_.status(); + } else { + return status_; + } + } + + private: + void SaveError(const Status& s) { + if (status_.ok() && !s.ok()) status_ = s; + } + void SkipEmptyDataBlocksForward(); + void SkipEmptyDataBlocksBackward(); + void SetDataIterator(Iterator* data_iter); + void InitDataBlock(); + + BlockFunction block_function_; + void* arg_; + const ReadOptions options_; + Status status_; + IteratorWrapper index_iter_; + IteratorWrapper data_iter_; // May be NULL + // If data_iter_ is non-NULL, then "data_block_handle_" holds the + // "index_value" passed to block_function_ to create the data_iter_. + std::string data_block_handle_; +}; + +TwoLevelIterator::TwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) + : block_function_(block_function), + arg_(arg), + options_(options), + index_iter_(index_iter), + data_iter_(NULL) { +} + +TwoLevelIterator::~TwoLevelIterator() { +} + +void TwoLevelIterator::Seek(const Slice& target) { + index_iter_.Seek(target); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.Seek(target); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToFirst() { + index_iter_.SeekToFirst(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::SeekToLast() { + index_iter_.SeekToLast(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + SkipEmptyDataBlocksBackward(); +} + +void TwoLevelIterator::Next() { + assert(Valid()); + data_iter_.Next(); + SkipEmptyDataBlocksForward(); +} + +void TwoLevelIterator::Prev() { + assert(Valid()); + data_iter_.Prev(); + SkipEmptyDataBlocksBackward(); +} + + +void TwoLevelIterator::SkipEmptyDataBlocksForward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Next(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToFirst(); + } +} + +void TwoLevelIterator::SkipEmptyDataBlocksBackward() { + while (data_iter_.iter() == NULL || !data_iter_.Valid()) { + // Move to next block + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + return; + } + index_iter_.Prev(); + InitDataBlock(); + if (data_iter_.iter() != NULL) data_iter_.SeekToLast(); + } +} + +void TwoLevelIterator::SetDataIterator(Iterator* data_iter) { + if (data_iter_.iter() != NULL) SaveError(data_iter_.status()); + data_iter_.Set(data_iter); +} + +void TwoLevelIterator::InitDataBlock() { + if (!index_iter_.Valid()) { + SetDataIterator(NULL); + } else { + Slice handle = index_iter_.value(); + if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) { + // data_iter_ is already constructed with this iterator, so + // no need to change anything + } else { + Iterator* iter = (*block_function_)(arg_, options_, handle); + data_block_handle_.assign(handle.data(), handle.size()); + SetDataIterator(iter); + } + } +} + +} // namespace + +Iterator* NewTwoLevelIterator( + Iterator* index_iter, + BlockFunction block_function, + void* arg, + const ReadOptions& options) { + return new TwoLevelIterator(index_iter, block_function, arg, options); +} + +} // namespace leveldb diff --git a/table/two_level_iterator.h b/table/two_level_iterator.h new file mode 100644 index 0000000000..629ca34525 --- /dev/null +++ b/table/two_level_iterator.h @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ +#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ + +#include "leveldb/iterator.h" + +namespace leveldb { + +struct ReadOptions; + +// Return a new two level iterator. A two-level iterator contains an +// index iterator whose values point to a sequence of blocks where +// each block is itself a sequence of key,value pairs. The returned +// two-level iterator yields the concatenation of all key/value pairs +// in the sequence of blocks. Takes ownership of "index_iter" and +// will delete it when no longer needed. +// +// Uses a supplied function to convert an index_iter value into +// an iterator over the contents of the corresponding block. +extern Iterator* NewTwoLevelIterator( + Iterator* index_iter, + Iterator* (*block_function)( + void* arg, + const ReadOptions& options, + const Slice& index_value), + void* arg, + const ReadOptions& options); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_ diff --git a/util/arena.cc b/util/arena.cc new file mode 100644 index 0000000000..74078213ee --- /dev/null +++ b/util/arena.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" +#include + +namespace leveldb { + +static const int kBlockSize = 4096; + +Arena::Arena() : memory_usage_(0) { + alloc_ptr_ = NULL; // First allocation will allocate a block + alloc_bytes_remaining_ = 0; +} + +Arena::~Arena() { + for (size_t i = 0; i < blocks_.size(); i++) { + delete[] blocks_[i]; + } +} + +char* Arena::AllocateFallback(size_t bytes) { + if (bytes > kBlockSize / 4) { + // Object is more than a quarter of our block size. Allocate it separately + // to avoid wasting too much space in leftover bytes. + char* result = AllocateNewBlock(bytes); + return result; + } + + // We waste the remaining space in the current block. + alloc_ptr_ = AllocateNewBlock(kBlockSize); + alloc_bytes_remaining_ = kBlockSize; + + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; +} + +char* Arena::AllocateAligned(size_t bytes) { + const int align = (sizeof(void*) > 8) ? sizeof(void*) : 8; + assert((align & (align-1)) == 0); // Pointer size should be a power of 2 + size_t current_mod = reinterpret_cast(alloc_ptr_) & (align-1); + size_t slop = (current_mod == 0 ? 0 : align - current_mod); + size_t needed = bytes + slop; + char* result; + if (needed <= alloc_bytes_remaining_) { + result = alloc_ptr_ + slop; + alloc_ptr_ += needed; + alloc_bytes_remaining_ -= needed; + } else { + // AllocateFallback always returned aligned memory + result = AllocateFallback(bytes); + } + assert((reinterpret_cast(result) & (align-1)) == 0); + return result; +} + +char* Arena::AllocateNewBlock(size_t block_bytes) { + char* result = new char[block_bytes]; + blocks_.push_back(result); + memory_usage_.NoBarrier_Store( + reinterpret_cast(MemoryUsage() + block_bytes + sizeof(char*))); + return result; +} + +} // namespace leveldb diff --git a/util/arena.h b/util/arena.h new file mode 100644 index 0000000000..48bab33741 --- /dev/null +++ b/util/arena.h @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_ +#define STORAGE_LEVELDB_UTIL_ARENA_H_ + +#include +#include +#include +#include +#include "port/port.h" + +namespace leveldb { + +class Arena { + public: + Arena(); + ~Arena(); + + // Return a pointer to a newly allocated memory block of "bytes" bytes. + char* Allocate(size_t bytes); + + // Allocate memory with the normal alignment guarantees provided by malloc + char* AllocateAligned(size_t bytes); + + // Returns an estimate of the total memory usage of data allocated + // by the arena. + size_t MemoryUsage() const { + return reinterpret_cast(memory_usage_.NoBarrier_Load()); + } + + private: + char* AllocateFallback(size_t bytes); + char* AllocateNewBlock(size_t block_bytes); + + // Allocation state + char* alloc_ptr_; + size_t alloc_bytes_remaining_; + + // Array of new[] allocated memory blocks + std::vector blocks_; + + // Total memory usage of the arena. + port::AtomicPointer memory_usage_; + + // No copying allowed + Arena(const Arena&); + void operator=(const Arena&); +}; + +inline char* Arena::Allocate(size_t bytes) { + // The semantics of what to return are a bit messy if we allow + // 0-byte allocations, so we disallow them here (we don't need + // them for our internal use). + assert(bytes > 0); + if (bytes <= alloc_bytes_remaining_) { + char* result = alloc_ptr_; + alloc_ptr_ += bytes; + alloc_bytes_remaining_ -= bytes; + return result; + } + return AllocateFallback(bytes); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ARENA_H_ diff --git a/util/arena_test.cc b/util/arena_test.cc new file mode 100644 index 0000000000..58e870ec44 --- /dev/null +++ b/util/arena_test.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/arena.h" + +#include "util/random.h" +#include "util/testharness.h" + +namespace leveldb { + +class ArenaTest { }; + +TEST(ArenaTest, Empty) { + Arena arena; +} + +TEST(ArenaTest, Simple) { + std::vector > allocated; + Arena arena; + const int N = 100000; + size_t bytes = 0; + Random rnd(301); + for (int i = 0; i < N; i++) { + size_t s; + if (i % (N / 10) == 0) { + s = i; + } else { + s = rnd.OneIn(4000) ? rnd.Uniform(6000) : + (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20)); + } + if (s == 0) { + // Our arena disallows size 0 allocations. + s = 1; + } + char* r; + if (rnd.OneIn(10)) { + r = arena.AllocateAligned(s); + } else { + r = arena.Allocate(s); + } + + for (size_t b = 0; b < s; b++) { + // Fill the "i"th allocation with a known bit pattern + r[b] = i % 256; + } + bytes += s; + allocated.push_back(std::make_pair(s, r)); + ASSERT_GE(arena.MemoryUsage(), bytes); + if (i > N/10) { + ASSERT_LE(arena.MemoryUsage(), bytes * 1.10); + } + } + for (size_t i = 0; i < allocated.size(); i++) { + size_t num_bytes = allocated[i].first; + const char* p = allocated[i].second; + for (size_t b = 0; b < num_bytes; b++) { + // Check the "i"th allocation for the known bit pattern + ASSERT_EQ(int(p[b]) & 0xff, i % 256); + } + } +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/bloom.cc b/util/bloom.cc new file mode 100644 index 0000000000..bf3e4ca6e9 --- /dev/null +++ b/util/bloom.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "leveldb/slice.h" +#include "util/hash.h" + +namespace leveldb { + +namespace { +static uint32_t BloomHash(const Slice& key) { + return Hash(key.data(), key.size(), 0xbc9f1d34); +} + +class BloomFilterPolicy : public FilterPolicy { + private: + size_t bits_per_key_; + size_t k_; + + public: + explicit BloomFilterPolicy(int bits_per_key) + : bits_per_key_(bits_per_key) { + // We intentionally round down to reduce probing cost a little bit + k_ = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) + if (k_ < 1) k_ = 1; + if (k_ > 30) k_ = 30; + } + + virtual const char* Name() const { + return "leveldb.BuiltinBloomFilter2"; + } + + virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { + // Compute bloom filter size (in both bits and bytes) + size_t bits = n * bits_per_key_; + + // For small n, we can see a very high false positive rate. Fix it + // by enforcing a minimum bloom filter length. + if (bits < 64) bits = 64; + + size_t bytes = (bits + 7) / 8; + bits = bytes * 8; + + const size_t init_size = dst->size(); + dst->resize(init_size + bytes, 0); + dst->push_back(static_cast(k_)); // Remember # of probes in filter + char* array = &(*dst)[init_size]; + for (int i = 0; i < n; i++) { + // Use double-hashing to generate a sequence of hash values. + // See analysis in [Kirsch,Mitzenmacher 2006]. + uint32_t h = BloomHash(keys[i]); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k_; j++) { + const uint32_t bitpos = h % bits; + array[bitpos/8] |= (1 << (bitpos % 8)); + h += delta; + } + } + } + + virtual bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const { + const size_t len = bloom_filter.size(); + if (len < 2) return false; + + const char* array = bloom_filter.data(); + const size_t bits = (len - 1) * 8; + + // Use the encoded k so that we can read filters generated by + // bloom filters created using different parameters. + const size_t k = array[len-1]; + if (k > 30) { + // Reserved for potentially new encodings for short bloom filters. + // Consider it a match. + return true; + } + + uint32_t h = BloomHash(key); + const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits + for (size_t j = 0; j < k; j++) { + const uint32_t bitpos = h % bits; + if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false; + h += delta; + } + return true; + } +}; +} + +const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) { + return new BloomFilterPolicy(bits_per_key); +} + +} // namespace leveldb diff --git a/util/bloom_test.cc b/util/bloom_test.cc new file mode 100644 index 0000000000..1b87a2be3f --- /dev/null +++ b/util/bloom_test.cc @@ -0,0 +1,162 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +#include "util/coding.h" +#include "util/logging.h" +#include "util/testharness.h" +#include "util/testutil.h" + +namespace leveldb { + +static const int kVerbose = 1; + +static Slice Key(int i, char* buffer) { + EncodeFixed32(buffer, i); + return Slice(buffer, sizeof(uint32_t)); +} + +class BloomTest { + private: + const FilterPolicy* policy_; + std::string filter_; + std::vector keys_; + + public: + BloomTest() : policy_(NewBloomFilterPolicy(10)) { } + + ~BloomTest() { + delete policy_; + } + + void Reset() { + keys_.clear(); + filter_.clear(); + } + + void Add(const Slice& s) { + keys_.push_back(s.ToString()); + } + + void Build() { + std::vector key_slices; + for (size_t i = 0; i < keys_.size(); i++) { + key_slices.push_back(Slice(keys_[i])); + } + filter_.clear(); + policy_->CreateFilter(&key_slices[0], static_cast(key_slices.size()), + &filter_); + keys_.clear(); + if (kVerbose >= 2) DumpFilter(); + } + + size_t FilterSize() const { + return filter_.size(); + } + + void DumpFilter() { + fprintf(stderr, "F("); + for (size_t i = 0; i+1 < filter_.size(); i++) { + const unsigned int c = static_cast(filter_[i]); + for (int j = 0; j < 8; j++) { + fprintf(stderr, "%c", (c & (1 <KeyMayMatch(s, filter_); + } + + double FalsePositiveRate() { + char buffer[sizeof(int)]; + int result = 0; + for (int i = 0; i < 10000; i++) { + if (Matches(Key(i + 1000000000, buffer))) { + result++; + } + } + return result / 10000.0; + } +}; + +TEST(BloomTest, EmptyFilter) { + ASSERT_TRUE(! Matches("hello")); + ASSERT_TRUE(! Matches("world")); +} + +TEST(BloomTest, Small) { + Add("hello"); + Add("world"); + ASSERT_TRUE(Matches("hello")); + ASSERT_TRUE(Matches("world")); + ASSERT_TRUE(! Matches("x")); + ASSERT_TRUE(! Matches("foo")); +} + +static int NextLength(int length) { + if (length < 10) { + length += 1; + } else if (length < 100) { + length += 10; + } else if (length < 1000) { + length += 100; + } else { + length += 1000; + } + return length; +} + +TEST(BloomTest, VaryingLengths) { + char buffer[sizeof(int)]; + + // Count number of filters that significantly exceed the false positive rate + int mediocre_filters = 0; + int good_filters = 0; + + for (int length = 1; length <= 10000; length = NextLength(length)) { + Reset(); + for (int i = 0; i < length; i++) { + Add(Key(i, buffer)); + } + Build(); + + ASSERT_LE(FilterSize(), static_cast((length * 10 / 8) + 40)) + << length; + + // All added keys must match + for (int i = 0; i < length; i++) { + ASSERT_TRUE(Matches(Key(i, buffer))) + << "Length " << length << "; key " << i; + } + + // Check false positive rate + double rate = FalsePositiveRate(); + if (kVerbose >= 1) { + fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate*100.0, length, static_cast(FilterSize())); + } + ASSERT_LE(rate, 0.02); // Must not be over 2% + if (rate > 0.0125) mediocre_filters++; // Allowed, but not too often + else good_filters++; + } + if (kVerbose >= 1) { + fprintf(stderr, "Filters: %d good, %d mediocre\n", + good_filters, mediocre_filters); + } + ASSERT_LE(mediocre_filters, good_filters/5); +} + +// Different bits-per-byte + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/cache.cc b/util/cache.cc new file mode 100644 index 0000000000..ce46886171 --- /dev/null +++ b/util/cache.cc @@ -0,0 +1,405 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include + +#include "leveldb/cache.h" +#include "port/port.h" +#include "util/hash.h" +#include "util/mutexlock.h" + +namespace leveldb { + +Cache::~Cache() { +} + +namespace { + +// LRU cache implementation +// +// Cache entries have an "in_cache" boolean indicating whether the cache has a +// reference on the entry. The only ways that this can become false without the +// entry being passed to its "deleter" are via Erase(), via Insert() when +// an element with a duplicate key is inserted, or on destruction of the cache. +// +// The cache keeps two linked lists of items in the cache. All items in the +// cache are in one list or the other, and never both. Items still referenced +// by clients but erased from the cache are in neither list. The lists are: +// - in-use: contains the items currently referenced by clients, in no +// particular order. (This list is used for invariant checking. If we +// removed the check, elements that would otherwise be on this list could be +// left as disconnected singleton lists.) +// - LRU: contains the items not currently referenced by clients, in LRU order +// Elements are moved between these lists by the Ref() and Unref() methods, +// when they detect an element in the cache acquiring or losing its only +// external reference. + +// An entry is a variable length heap-allocated structure. Entries +// are kept in a circular doubly linked list ordered by access time. +struct LRUHandle { + void* value; + void (*deleter)(const Slice&, void* value); + LRUHandle* next_hash; + LRUHandle* next; + LRUHandle* prev; + size_t charge; // TODO(opt): Only allow uint32_t? + size_t key_length; + bool in_cache; // Whether entry is in the cache. + uint32_t refs; // References, including cache reference, if present. + uint32_t hash; // Hash of key(); used for fast sharding and comparisons + char key_data[1]; // Beginning of key + + Slice key() const { + // For cheaper lookups, we allow a temporary Handle object + // to store a pointer to a key in "value". + if (next == this) { + return *(reinterpret_cast(value)); + } else { + return Slice(key_data, key_length); + } + } +}; + +// We provide our own simple hash table since it removes a whole bunch +// of porting hacks and is also faster than some of the built-in hash +// table implementations in some of the compiler/runtime combinations +// we have tested. E.g., readrandom speeds up by ~5% over the g++ +// 4.4.3's builtin hashtable. +class HandleTable { + public: + HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); } + ~HandleTable() { delete[] list_; } + + LRUHandle* Lookup(const Slice& key, uint32_t hash) { + return *FindPointer(key, hash); + } + + LRUHandle* Insert(LRUHandle* h) { + LRUHandle** ptr = FindPointer(h->key(), h->hash); + LRUHandle* old = *ptr; + h->next_hash = (old == NULL ? NULL : old->next_hash); + *ptr = h; + if (old == NULL) { + ++elems_; + if (elems_ > length_) { + // Since each cache entry is fairly large, we aim for a small + // average linked list length (<= 1). + Resize(); + } + } + return old; + } + + LRUHandle* Remove(const Slice& key, uint32_t hash) { + LRUHandle** ptr = FindPointer(key, hash); + LRUHandle* result = *ptr; + if (result != NULL) { + *ptr = result->next_hash; + --elems_; + } + return result; + } + + private: + // The table consists of an array of buckets where each bucket is + // a linked list of cache entries that hash into the bucket. + uint32_t length_; + uint32_t elems_; + LRUHandle** list_; + + // Return a pointer to slot that points to a cache entry that + // matches key/hash. If there is no such cache entry, return a + // pointer to the trailing slot in the corresponding linked list. + LRUHandle** FindPointer(const Slice& key, uint32_t hash) { + LRUHandle** ptr = &list_[hash & (length_ - 1)]; + while (*ptr != NULL && + ((*ptr)->hash != hash || key != (*ptr)->key())) { + ptr = &(*ptr)->next_hash; + } + return ptr; + } + + void Resize() { + uint32_t new_length = 4; + while (new_length < elems_) { + new_length *= 2; + } + LRUHandle** new_list = new LRUHandle*[new_length]; + memset(new_list, 0, sizeof(new_list[0]) * new_length); + uint32_t count = 0; + for (uint32_t i = 0; i < length_; i++) { + LRUHandle* h = list_[i]; + while (h != NULL) { + LRUHandle* next = h->next_hash; + uint32_t hash = h->hash; + LRUHandle** ptr = &new_list[hash & (new_length - 1)]; + h->next_hash = *ptr; + *ptr = h; + h = next; + count++; + } + } + assert(elems_ == count); + delete[] list_; + list_ = new_list; + length_ = new_length; + } +}; + +// A single shard of sharded cache. +class LRUCache { + public: + LRUCache(); + ~LRUCache(); + + // Separate from constructor so caller can easily make an array of LRUCache + void SetCapacity(size_t capacity) { capacity_ = capacity; } + + // Like Cache methods, but with an extra "hash" parameter. + Cache::Handle* Insert(const Slice& key, uint32_t hash, + void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)); + Cache::Handle* Lookup(const Slice& key, uint32_t hash); + void Release(Cache::Handle* handle); + void Erase(const Slice& key, uint32_t hash); + void Prune(); + size_t TotalCharge() const { + MutexLock l(&mutex_); + return usage_; + } + + private: + void LRU_Remove(LRUHandle* e); + void LRU_Append(LRUHandle*list, LRUHandle* e); + void Ref(LRUHandle* e); + void Unref(LRUHandle* e); + bool FinishErase(LRUHandle* e); + + // Initialized before use. + size_t capacity_; + + // mutex_ protects the following state. + mutable port::Mutex mutex_; + size_t usage_; + + // Dummy head of LRU list. + // lru.prev is newest entry, lru.next is oldest entry. + // Entries have refs==1 and in_cache==true. + LRUHandle lru_; + + // Dummy head of in-use list. + // Entries are in use by clients, and have refs >= 2 and in_cache==true. + LRUHandle in_use_; + + HandleTable table_; +}; + +LRUCache::LRUCache() + : usage_(0) { + // Make empty circular linked lists. + lru_.next = &lru_; + lru_.prev = &lru_; + in_use_.next = &in_use_; + in_use_.prev = &in_use_; +} + +LRUCache::~LRUCache() { + assert(in_use_.next == &in_use_); // Error if caller has an unreleased handle + for (LRUHandle* e = lru_.next; e != &lru_; ) { + LRUHandle* next = e->next; + assert(e->in_cache); + e->in_cache = false; + assert(e->refs == 1); // Invariant of lru_ list. + Unref(e); + e = next; + } +} + +void LRUCache::Ref(LRUHandle* e) { + if (e->refs == 1 && e->in_cache) { // If on lru_ list, move to in_use_ list. + LRU_Remove(e); + LRU_Append(&in_use_, e); + } + e->refs++; +} + +void LRUCache::Unref(LRUHandle* e) { + assert(e->refs > 0); + e->refs--; + if (e->refs == 0) { // Deallocate. + assert(!e->in_cache); + (*e->deleter)(e->key(), e->value); + free(e); + } else if (e->in_cache && e->refs == 1) { // No longer in use; move to lru_ list. + LRU_Remove(e); + LRU_Append(&lru_, e); + } +} + +void LRUCache::LRU_Remove(LRUHandle* e) { + e->next->prev = e->prev; + e->prev->next = e->next; +} + +void LRUCache::LRU_Append(LRUHandle* list, LRUHandle* e) { + // Make "e" newest entry by inserting just before *list + e->next = list; + e->prev = list->prev; + e->prev->next = e; + e->next->prev = e; +} + +Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + LRUHandle* e = table_.Lookup(key, hash); + if (e != NULL) { + Ref(e); + } + return reinterpret_cast(e); +} + +void LRUCache::Release(Cache::Handle* handle) { + MutexLock l(&mutex_); + Unref(reinterpret_cast(handle)); +} + +Cache::Handle* LRUCache::Insert( + const Slice& key, uint32_t hash, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + MutexLock l(&mutex_); + + LRUHandle* e = reinterpret_cast( + malloc(sizeof(LRUHandle)-1 + key.size())); + e->value = value; + e->deleter = deleter; + e->charge = charge; + e->key_length = key.size(); + e->hash = hash; + e->in_cache = false; + e->refs = 1; // for the returned handle. + memcpy(e->key_data, key.data(), key.size()); + + if (capacity_ > 0) { + e->refs++; // for the cache's reference. + e->in_cache = true; + LRU_Append(&in_use_, e); + usage_ += charge; + FinishErase(table_.Insert(e)); + } // else don't cache. (Tests use capacity_==0 to turn off caching.) + + while (usage_ > capacity_ && lru_.next != &lru_) { + LRUHandle* old = lru_.next; + assert(old->refs == 1); + bool erased = FinishErase(table_.Remove(old->key(), old->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } + } + + return reinterpret_cast(e); +} + +// If e != NULL, finish removing *e from the cache; it has already been removed +// from the hash table. Return whether e != NULL. Requires mutex_ held. +bool LRUCache::FinishErase(LRUHandle* e) { + if (e != NULL) { + assert(e->in_cache); + LRU_Remove(e); + e->in_cache = false; + usage_ -= e->charge; + Unref(e); + } + return e != NULL; +} + +void LRUCache::Erase(const Slice& key, uint32_t hash) { + MutexLock l(&mutex_); + FinishErase(table_.Remove(key, hash)); +} + +void LRUCache::Prune() { + MutexLock l(&mutex_); + while (lru_.next != &lru_) { + LRUHandle* e = lru_.next; + assert(e->refs == 1); + bool erased = FinishErase(table_.Remove(e->key(), e->hash)); + if (!erased) { // to avoid unused variable when compiled NDEBUG + assert(erased); + } + } +} + +static const int kNumShardBits = 4; +static const int kNumShards = 1 << kNumShardBits; + +class ShardedLRUCache : public Cache { + private: + LRUCache shard_[kNumShards]; + port::Mutex id_mutex_; + uint64_t last_id_; + + static inline uint32_t HashSlice(const Slice& s) { + return Hash(s.data(), s.size(), 0); + } + + static uint32_t Shard(uint32_t hash) { + return hash >> (32 - kNumShardBits); + } + + public: + explicit ShardedLRUCache(size_t capacity) + : last_id_(0) { + const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards; + for (int s = 0; s < kNumShards; s++) { + shard_[s].SetCapacity(per_shard); + } + } + virtual ~ShardedLRUCache() { } + virtual Handle* Insert(const Slice& key, void* value, size_t charge, + void (*deleter)(const Slice& key, void* value)) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter); + } + virtual Handle* Lookup(const Slice& key) { + const uint32_t hash = HashSlice(key); + return shard_[Shard(hash)].Lookup(key, hash); + } + virtual void Release(Handle* handle) { + LRUHandle* h = reinterpret_cast(handle); + shard_[Shard(h->hash)].Release(handle); + } + virtual void Erase(const Slice& key) { + const uint32_t hash = HashSlice(key); + shard_[Shard(hash)].Erase(key, hash); + } + virtual void* Value(Handle* handle) { + return reinterpret_cast(handle)->value; + } + virtual uint64_t NewId() { + MutexLock l(&id_mutex_); + return ++(last_id_); + } + virtual void Prune() { + for (int s = 0; s < kNumShards; s++) { + shard_[s].Prune(); + } + } + virtual size_t TotalCharge() const { + size_t total = 0; + for (int s = 0; s < kNumShards; s++) { + total += shard_[s].TotalCharge(); + } + return total; + } +}; + +} // end anonymous namespace + +Cache* NewLRUCache(size_t capacity) { + return new ShardedLRUCache(capacity); +} + +} // namespace leveldb diff --git a/util/cache_test.cc b/util/cache_test.cc new file mode 100644 index 0000000000..468f7a6425 --- /dev/null +++ b/util/cache_test.cc @@ -0,0 +1,226 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/cache.h" + +#include +#include "util/coding.h" +#include "util/testharness.h" + +namespace leveldb { + +// Conversions between numeric keys/values and the types expected by Cache. +static std::string EncodeKey(int k) { + std::string result; + PutFixed32(&result, k); + return result; +} +static int DecodeKey(const Slice& k) { + assert(k.size() == 4); + return DecodeFixed32(k.data()); +} +static void* EncodeValue(uintptr_t v) { return reinterpret_cast(v); } +static int DecodeValue(void* v) { return reinterpret_cast(v); } + +class CacheTest { + public: + static CacheTest* current_; + + static void Deleter(const Slice& key, void* v) { + current_->deleted_keys_.push_back(DecodeKey(key)); + current_->deleted_values_.push_back(DecodeValue(v)); + } + + static const int kCacheSize = 1000; + std::vector deleted_keys_; + std::vector deleted_values_; + Cache* cache_; + + CacheTest() : cache_(NewLRUCache(kCacheSize)) { + current_ = this; + } + + ~CacheTest() { + delete cache_; + } + + int Lookup(int key) { + Cache::Handle* handle = cache_->Lookup(EncodeKey(key)); + const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle)); + if (handle != NULL) { + cache_->Release(handle); + } + return r; + } + + void Insert(int key, int value, int charge = 1) { + cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter)); + } + + Cache::Handle* InsertAndReturnHandle(int key, int value, int charge = 1) { + return cache_->Insert(EncodeKey(key), EncodeValue(value), charge, + &CacheTest::Deleter); + } + + void Erase(int key) { + cache_->Erase(EncodeKey(key)); + } +}; +CacheTest* CacheTest::current_; + +TEST(CacheTest, HitAndMiss) { + ASSERT_EQ(-1, Lookup(100)); + + Insert(100, 101); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(200, 201); + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + Insert(100, 102); + ASSERT_EQ(102, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(-1, Lookup(300)); + + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); +} + +TEST(CacheTest, Erase) { + Erase(200); + ASSERT_EQ(0, deleted_keys_.size()); + + Insert(100, 101); + Insert(200, 201); + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(201, Lookup(200)); + ASSERT_EQ(1, deleted_keys_.size()); +} + +TEST(CacheTest, EntriesArePinned) { + Insert(100, 101); + Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); + + Insert(100, 102); + Cache::Handle* h2 = cache_->Lookup(EncodeKey(100)); + ASSERT_EQ(102, DecodeValue(cache_->Value(h2))); + ASSERT_EQ(0, deleted_keys_.size()); + + cache_->Release(h1); + ASSERT_EQ(1, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[0]); + ASSERT_EQ(101, deleted_values_[0]); + + Erase(100); + ASSERT_EQ(-1, Lookup(100)); + ASSERT_EQ(1, deleted_keys_.size()); + + cache_->Release(h2); + ASSERT_EQ(2, deleted_keys_.size()); + ASSERT_EQ(100, deleted_keys_[1]); + ASSERT_EQ(102, deleted_values_[1]); +} + +TEST(CacheTest, EvictionPolicy) { + Insert(100, 101); + Insert(200, 201); + Insert(300, 301); + Cache::Handle* h = cache_->Lookup(EncodeKey(300)); + + // Frequently used entry must be kept around, + // as must things that are still in use. + for (int i = 0; i < kCacheSize + 100; i++) { + Insert(1000+i, 2000+i); + ASSERT_EQ(2000+i, Lookup(1000+i)); + ASSERT_EQ(101, Lookup(100)); + } + ASSERT_EQ(101, Lookup(100)); + ASSERT_EQ(-1, Lookup(200)); + ASSERT_EQ(301, Lookup(300)); + cache_->Release(h); +} + +TEST(CacheTest, UseExceedsCacheSize) { + // Overfill the cache, keeping handles on all inserted entries. + std::vector h; + for (int i = 0; i < kCacheSize + 100; i++) { + h.push_back(InsertAndReturnHandle(1000+i, 2000+i)); + } + + // Check that all the entries can be found in the cache. + for (int i = 0; i < h.size(); i++) { + ASSERT_EQ(2000+i, Lookup(1000+i)); + } + + for (int i = 0; i < h.size(); i++) { + cache_->Release(h[i]); + } +} + +TEST(CacheTest, HeavyEntries) { + // Add a bunch of light and heavy entries and then count the combined + // size of items still in the cache, which must be approximately the + // same as the total capacity. + const int kLight = 1; + const int kHeavy = 10; + int added = 0; + int index = 0; + while (added < 2*kCacheSize) { + const int weight = (index & 1) ? kLight : kHeavy; + Insert(index, 1000+index, weight); + added += weight; + index++; + } + + int cached_weight = 0; + for (int i = 0; i < index; i++) { + const int weight = (i & 1 ? kLight : kHeavy); + int r = Lookup(i); + if (r >= 0) { + cached_weight += weight; + ASSERT_EQ(1000+i, r); + } + } + ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10); +} + +TEST(CacheTest, NewId) { + uint64_t a = cache_->NewId(); + uint64_t b = cache_->NewId(); + ASSERT_NE(a, b); +} + +TEST(CacheTest, Prune) { + Insert(1, 100); + Insert(2, 200); + + Cache::Handle* handle = cache_->Lookup(EncodeKey(1)); + ASSERT_TRUE(handle); + cache_->Prune(); + cache_->Release(handle); + + ASSERT_EQ(100, Lookup(1)); + ASSERT_EQ(-1, Lookup(2)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/coding.cc b/util/coding.cc new file mode 100644 index 0000000000..21e3186d5d --- /dev/null +++ b/util/coding.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +namespace leveldb { + +void EncodeFixed32(char* buf, uint32_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + } +} + +void EncodeFixed64(char* buf, uint64_t value) { + if (port::kLittleEndian) { + memcpy(buf, &value, sizeof(value)); + } else { + buf[0] = value & 0xff; + buf[1] = (value >> 8) & 0xff; + buf[2] = (value >> 16) & 0xff; + buf[3] = (value >> 24) & 0xff; + buf[4] = (value >> 32) & 0xff; + buf[5] = (value >> 40) & 0xff; + buf[6] = (value >> 48) & 0xff; + buf[7] = (value >> 56) & 0xff; + } +} + +void PutFixed32(std::string* dst, uint32_t value) { + char buf[sizeof(value)]; + EncodeFixed32(buf, value); + dst->append(buf, sizeof(buf)); +} + +void PutFixed64(std::string* dst, uint64_t value) { + char buf[sizeof(value)]; + EncodeFixed64(buf, value); + dst->append(buf, sizeof(buf)); +} + +char* EncodeVarint32(char* dst, uint32_t v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(dst); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +void PutVarint32(std::string* dst, uint32_t v) { + char buf[5]; + char* ptr = EncodeVarint32(buf, v); + dst->append(buf, ptr - buf); +} + +char* EncodeVarint64(char* dst, uint64_t v) { + static const int B = 128; + unsigned char* ptr = reinterpret_cast(dst); + while (v >= B) { + *(ptr++) = (v & (B-1)) | B; + v >>= 7; + } + *(ptr++) = static_cast(v); + return reinterpret_cast(ptr); +} + +void PutVarint64(std::string* dst, uint64_t v) { + char buf[10]; + char* ptr = EncodeVarint64(buf, v); + dst->append(buf, ptr - buf); +} + +void PutLengthPrefixedSlice(std::string* dst, const Slice& value) { + PutVarint32(dst, value.size()); + dst->append(value.data(), value.size()); +} + +int VarintLength(uint64_t v) { + int len = 1; + while (v >= 128) { + v >>= 7; + len++; + } + return len; +} + +const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value) { + uint32_t result = 0; + for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) { + uint32_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint32(Slice* input, uint32_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint32Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) { + uint64_t result = 0; + for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) { + uint64_t byte = *(reinterpret_cast(p)); + p++; + if (byte & 128) { + // More bytes are present + result |= ((byte & 127) << shift); + } else { + result |= (byte << shift); + *value = result; + return reinterpret_cast(p); + } + } + return NULL; +} + +bool GetVarint64(Slice* input, uint64_t* value) { + const char* p = input->data(); + const char* limit = p + input->size(); + const char* q = GetVarint64Ptr(p, limit, value); + if (q == NULL) { + return false; + } else { + *input = Slice(q, limit - q); + return true; + } +} + +const char* GetLengthPrefixedSlice(const char* p, const char* limit, + Slice* result) { + uint32_t len; + p = GetVarint32Ptr(p, limit, &len); + if (p == NULL) return NULL; + if (p + len > limit) return NULL; + *result = Slice(p, len); + return p + len; +} + +bool GetLengthPrefixedSlice(Slice* input, Slice* result) { + uint32_t len; + if (GetVarint32(input, &len) && + input->size() >= len) { + *result = Slice(input->data(), len); + input->remove_prefix(len); + return true; + } else { + return false; + } +} + +} // namespace leveldb diff --git a/util/coding.h b/util/coding.h new file mode 100644 index 0000000000..3993c4a755 --- /dev/null +++ b/util/coding.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Endian-neutral encoding: +// * Fixed-length numbers are encoded with least-significant byte first +// * In addition we support variable length "varint" encoding +// * Strings are encoded prefixed by their length in varint format + +#ifndef STORAGE_LEVELDB_UTIL_CODING_H_ +#define STORAGE_LEVELDB_UTIL_CODING_H_ + +#include +#include +#include +#include "leveldb/slice.h" +#include "port/port.h" + +namespace leveldb { + +// Standard Put... routines append to a string +extern void PutFixed32(std::string* dst, uint32_t value); +extern void PutFixed64(std::string* dst, uint64_t value); +extern void PutVarint32(std::string* dst, uint32_t value); +extern void PutVarint64(std::string* dst, uint64_t value); +extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value); + +// Standard Get... routines parse a value from the beginning of a Slice +// and advance the slice past the parsed value. +extern bool GetVarint32(Slice* input, uint32_t* value); +extern bool GetVarint64(Slice* input, uint64_t* value); +extern bool GetLengthPrefixedSlice(Slice* input, Slice* result); + +// Pointer-based variants of GetVarint... These either store a value +// in *v and return a pointer just past the parsed value, or return +// NULL on error. These routines only look at bytes in the range +// [p..limit-1] +extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v); +extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v); + +// Returns the length of the varint32 or varint64 encoding of "v" +extern int VarintLength(uint64_t v); + +// Lower-level versions of Put... that write directly into a character buffer +// REQUIRES: dst has enough space for the value being written +extern void EncodeFixed32(char* dst, uint32_t value); +extern void EncodeFixed64(char* dst, uint64_t value); + +// Lower-level versions of Put... that write directly into a character buffer +// and return a pointer just past the last byte written. +// REQUIRES: dst has enough space for the value being written +extern char* EncodeVarint32(char* dst, uint32_t value); +extern char* EncodeVarint64(char* dst, uint64_t value); + +// Lower-level versions of Get... that read directly from a character buffer +// without any bounds checking. + +inline uint32_t DecodeFixed32(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint32_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + return ((static_cast(static_cast(ptr[0]))) + | (static_cast(static_cast(ptr[1])) << 8) + | (static_cast(static_cast(ptr[2])) << 16) + | (static_cast(static_cast(ptr[3])) << 24)); + } +} + +inline uint64_t DecodeFixed64(const char* ptr) { + if (port::kLittleEndian) { + // Load the raw bytes + uint64_t result; + memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load + return result; + } else { + uint64_t lo = DecodeFixed32(ptr); + uint64_t hi = DecodeFixed32(ptr + 4); + return (hi << 32) | lo; + } +} + +// Internal routine for use by fallback path of GetVarint32Ptr +extern const char* GetVarint32PtrFallback(const char* p, + const char* limit, + uint32_t* value); +inline const char* GetVarint32Ptr(const char* p, + const char* limit, + uint32_t* value) { + if (p < limit) { + uint32_t result = *(reinterpret_cast(p)); + if ((result & 128) == 0) { + *value = result; + return p + 1; + } + } + return GetVarint32PtrFallback(p, limit, value); +} + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CODING_H_ diff --git a/util/coding_test.cc b/util/coding_test.cc new file mode 100644 index 0000000000..521541ea61 --- /dev/null +++ b/util/coding_test.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/coding.h" + +#include "util/testharness.h" + +namespace leveldb { + +class Coding { }; + +TEST(Coding, Fixed32) { + std::string s; + for (uint32_t v = 0; v < 100000; v++) { + PutFixed32(&s, v); + } + + const char* p = s.data(); + for (uint32_t v = 0; v < 100000; v++) { + uint32_t actual = DecodeFixed32(p); + ASSERT_EQ(v, actual); + p += sizeof(uint32_t); + } +} + +TEST(Coding, Fixed64) { + std::string s; + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + PutFixed64(&s, v - 1); + PutFixed64(&s, v + 0); + PutFixed64(&s, v + 1); + } + + const char* p = s.data(); + for (int power = 0; power <= 63; power++) { + uint64_t v = static_cast(1) << power; + uint64_t actual; + actual = DecodeFixed64(p); + ASSERT_EQ(v-1, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+0, actual); + p += sizeof(uint64_t); + + actual = DecodeFixed64(p); + ASSERT_EQ(v+1, actual); + p += sizeof(uint64_t); + } +} + +// Test that encoding routines generate little-endian encodings +TEST(Coding, EncodingOutput) { + std::string dst; + PutFixed32(&dst, 0x04030201); + ASSERT_EQ(4, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + + dst.clear(); + PutFixed64(&dst, 0x0807060504030201ull); + ASSERT_EQ(8, dst.size()); + ASSERT_EQ(0x01, static_cast(dst[0])); + ASSERT_EQ(0x02, static_cast(dst[1])); + ASSERT_EQ(0x03, static_cast(dst[2])); + ASSERT_EQ(0x04, static_cast(dst[3])); + ASSERT_EQ(0x05, static_cast(dst[4])); + ASSERT_EQ(0x06, static_cast(dst[5])); + ASSERT_EQ(0x07, static_cast(dst[6])); + ASSERT_EQ(0x08, static_cast(dst[7])); +} + +TEST(Coding, Varint32) { + std::string s; + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t v = (i / 32) << (i % 32); + PutVarint32(&s, v); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (uint32_t i = 0; i < (32 * 32); i++) { + uint32_t expected = (i / 32) << (i % 32); + uint32_t actual; + const char* start = p; + p = GetVarint32Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(expected, actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, s.data() + s.size()); +} + +TEST(Coding, Varint64) { + // Construct the list of values to check + std::vector values; + // Some special values + values.push_back(0); + values.push_back(100); + values.push_back(~static_cast(0)); + values.push_back(~static_cast(0) - 1); + for (uint32_t k = 0; k < 64; k++) { + // Test values near powers of two + const uint64_t power = 1ull << k; + values.push_back(power); + values.push_back(power-1); + values.push_back(power+1); + } + + std::string s; + for (size_t i = 0; i < values.size(); i++) { + PutVarint64(&s, values[i]); + } + + const char* p = s.data(); + const char* limit = p + s.size(); + for (size_t i = 0; i < values.size(); i++) { + ASSERT_TRUE(p < limit); + uint64_t actual; + const char* start = p; + p = GetVarint64Ptr(p, limit, &actual); + ASSERT_TRUE(p != NULL); + ASSERT_EQ(values[i], actual); + ASSERT_EQ(VarintLength(actual), p - start); + } + ASSERT_EQ(p, limit); + +} + +TEST(Coding, Varint32Overflow) { + uint32_t result; + std::string input("\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint32Truncation) { + uint32_t large_value = (1u << 31) + 100; + std::string s; + PutVarint32(&s, large_value); + uint32_t result; + for (size_t len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Varint64Overflow) { + uint64_t result; + std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11"); + ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result) + == NULL); +} + +TEST(Coding, Varint64Truncation) { + uint64_t large_value = (1ull << 63) + 100ull; + std::string s; + PutVarint64(&s, large_value); + uint64_t result; + for (size_t len = 0; len < s.size() - 1; len++) { + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL); + } + ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL); + ASSERT_EQ(large_value, result); +} + +TEST(Coding, Strings) { + std::string s; + PutLengthPrefixedSlice(&s, Slice("")); + PutLengthPrefixedSlice(&s, Slice("foo")); + PutLengthPrefixedSlice(&s, Slice("bar")); + PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x'))); + + Slice input(s); + Slice v; + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("foo", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ("bar", v.ToString()); + ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v)); + ASSERT_EQ(std::string(200, 'x'), v.ToString()); + ASSERT_EQ("", input.ToString()); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/comparator.cc b/util/comparator.cc new file mode 100644 index 0000000000..4b7b5724ef --- /dev/null +++ b/util/comparator.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "leveldb/comparator.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" + +namespace leveldb { + +Comparator::~Comparator() { } + +namespace { +class BytewiseComparatorImpl : public Comparator { + public: + BytewiseComparatorImpl() { } + + virtual const char* Name() const { + return "leveldb.BytewiseComparator"; + } + + virtual int Compare(const Slice& a, const Slice& b) const { + return a.compare(b); + } + + virtual void FindShortestSeparator( + std::string* start, + const Slice& limit) const { + // Find length of common prefix + size_t min_length = std::min(start->size(), limit.size()); + size_t diff_index = 0; + while ((diff_index < min_length) && + ((*start)[diff_index] == limit[diff_index])) { + diff_index++; + } + + if (diff_index >= min_length) { + // Do not shorten if one string is a prefix of the other + } else { + uint8_t diff_byte = static_cast((*start)[diff_index]); + if (diff_byte < static_cast(0xff) && + diff_byte + 1 < static_cast(limit[diff_index])) { + (*start)[diff_index]++; + start->resize(diff_index + 1); + assert(Compare(*start, limit) < 0); + } + } + } + + virtual void FindShortSuccessor(std::string* key) const { + // Find first character that can be incremented + size_t n = key->size(); + for (size_t i = 0; i < n; i++) { + const uint8_t byte = (*key)[i]; + if (byte != static_cast(0xff)) { + (*key)[i] = byte + 1; + key->resize(i+1); + return; + } + } + // *key is a run of 0xffs. Leave it alone. + } +}; +} // namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static const Comparator* bytewise; + +static void InitModule() { + bytewise = new BytewiseComparatorImpl; +} + +const Comparator* BytewiseComparator() { + port::InitOnce(&once, InitModule); + return bytewise; +} + +} // namespace leveldb diff --git a/util/crc32c.cc b/util/crc32c.cc new file mode 100644 index 0000000000..b3f40eeeed --- /dev/null +++ b/util/crc32c.cc @@ -0,0 +1,354 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. + +#include "util/crc32c.h" + +#include + +#include "port/port.h" +#include "util/coding.h" + +namespace leveldb { +namespace crc32c { + +static const uint32_t table0_[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; +static const uint32_t table1_[256] = { + 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, + 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, + 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, + 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, + 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, + 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, + 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, + 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, + 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, + 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, + 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, + 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, + 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, + 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, + 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, + 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, + 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, + 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, + 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, + 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, + 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, + 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, + 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, + 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, + 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, + 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, + 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, + 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, + 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, + 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, + 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, + 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, + 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 +}; +static const uint32_t table2_[256] = { + 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, + 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, + 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, + 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, + 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, + 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, + 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, + 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, + 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, + 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, + 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, + 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, + 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, + 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, + 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, + 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, + 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, + 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, + 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, + 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, + 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, + 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, + 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, + 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, + 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, + 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, + 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, + 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, + 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, + 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, + 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, + 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, + 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, + 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, + 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 +}; +static const uint32_t table3_[256] = { + 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, + 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, + 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, + 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, + 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, + 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, + 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, + 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, + 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, + 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, + 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, + 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, + 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, + 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, + 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, + 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, + 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, + 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, + 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, + 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, + 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, + 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, + 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, + 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, + 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, + 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, + 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, + 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, + 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, + 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, + 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, + 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, + 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, + 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 +}; + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + return DecodeFixed32(reinterpret_cast(p)); +} + +// Determine if the CPU running this program can accelerate the CRC32C +// calculation. +static bool CanAccelerateCRC32C() { + if (!port::HasAcceleratedCRC32C()) + return false; + + // Double-check that the accelerated implementation functions correctly. + // port::AcceleretedCRC32C returns zero when unable to accelerate. + static const char kTestCRCBuffer[] = "TestCRCBuffer"; + static const char kBufSize = sizeof(kTestCRCBuffer) - 1; + static const uint32_t kTestCRCValue = 0xdcbc59fa; + + return port::AcceleratedCRC32C(0, kTestCRCBuffer, kBufSize) == kTestCRCValue; +} + +uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + static bool accelerate = CanAccelerateCRC32C(); + if (accelerate) { + return port::AcceleratedCRC32C(crc, buf, size); + } + + const uint8_t *p = reinterpret_cast(buf); + const uint8_t *e = p + size; + uint32_t l = crc ^ 0xffffffffu; + +#define STEP1 do { \ + int c = (l & 0xff) ^ *p++; \ + l = table0_[c] ^ (l >> 8); \ +} while (0) +#define STEP4 do { \ + uint32_t c = l ^ LE_LOAD32(p); \ + p += 4; \ + l = table3_[c & 0xff] ^ \ + table2_[(c >> 8) & 0xff] ^ \ + table1_[(c >> 16) & 0xff] ^ \ + table0_[c >> 24]; \ +} while (0) + + // Point x at first 4-byte aligned byte in string. This might be + // just past the end of the string. + const uintptr_t pval = reinterpret_cast(p); + const uint8_t* x = reinterpret_cast(((pval + 3) >> 2) << 2); + if (x <= e) { + // Process bytes until finished or p is 4-byte aligned + while (p != x) { + STEP1; + } + } + // Process bytes 16 at a time + while ((e-p) >= 16) { + STEP4; STEP4; STEP4; STEP4; + } + // Process bytes 4 at a time + while ((e-p) >= 4) { + STEP4; + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP4 +#undef STEP1 + return l ^ 0xffffffffu; +} + +} // namespace crc32c +} // namespace leveldb diff --git a/util/crc32c.h b/util/crc32c.h new file mode 100644 index 0000000000..1d7e5c075d --- /dev/null +++ b/util/crc32c.h @@ -0,0 +1,45 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ +#define STORAGE_LEVELDB_UTIL_CRC32C_H_ + +#include +#include + +namespace leveldb { +namespace crc32c { + +// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the +// crc32c of some string A. Extend() is often used to maintain the +// crc32c of a stream of data. +extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n); + +// Return the crc32c of data[0,n-1] +inline uint32_t Value(const char* data, size_t n) { + return Extend(0, data, n); +} + +static const uint32_t kMaskDelta = 0xa282ead8ul; + +// Return a masked representation of crc. +// +// Motivation: it is problematic to compute the CRC of a string that +// contains embedded CRCs. Therefore we recommend that CRCs stored +// somewhere (e.g., in files) should be masked before being stored. +inline uint32_t Mask(uint32_t crc) { + // Rotate right by 15 bits and add a constant. + return ((crc >> 15) | (crc << 17)) + kMaskDelta; +} + +// Return the crc whose masked representation is masked_crc. +inline uint32_t Unmask(uint32_t masked_crc) { + uint32_t rot = masked_crc - kMaskDelta; + return ((rot >> 17) | (rot << 15)); +} + +} // namespace crc32c +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_CRC32C_H_ diff --git a/util/crc32c_test.cc b/util/crc32c_test.cc new file mode 100644 index 0000000000..4b957ee120 --- /dev/null +++ b/util/crc32c_test.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/crc32c.h" +#include "util/testharness.h" + +namespace leveldb { +namespace crc32c { + +class CRC { }; + +TEST(CRC, StandardResults) { + // From rfc3720 section B.4. + char buf[32]; + + memset(buf, 0, sizeof(buf)); + ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf))); + + memset(buf, 0xff, sizeof(buf)); + ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = i; + } + ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf))); + + for (int i = 0; i < 32; i++) { + buf[i] = 31 - i; + } + ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf))); + + unsigned char data[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + ASSERT_EQ(0xd9963a56, Value(reinterpret_cast(data), sizeof(data))); +} + +TEST(CRC, Values) { + ASSERT_NE(Value("a", 1), Value("foo", 3)); +} + +TEST(CRC, Extend) { + ASSERT_EQ(Value("hello world", 11), + Extend(Value("hello ", 6), "world", 5)); +} + +TEST(CRC, Mask) { + uint32_t crc = Value("foo", 3); + ASSERT_NE(crc, Mask(crc)); + ASSERT_NE(crc, Mask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Mask(crc))); + ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc))))); +} + +} // namespace crc32c +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/env.cc b/util/env.cc new file mode 100644 index 0000000000..c58a0821ef --- /dev/null +++ b/util/env.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +namespace leveldb { + +Env::~Env() { +} + +Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) { + return Status::NotSupported("NewAppendableFile", fname); +} + +SequentialFile::~SequentialFile() { +} + +RandomAccessFile::~RandomAccessFile() { +} + +WritableFile::~WritableFile() { +} + +Logger::~Logger() { +} + +FileLock::~FileLock() { +} + +void Log(Logger* info_log, const char* format, ...) { + if (info_log != NULL) { + va_list ap; + va_start(ap, format); + info_log->Logv(format, ap); + va_end(ap); + } +} + +static Status DoWriteStringToFile(Env* env, const Slice& data, + const std::string& fname, + bool should_sync) { + WritableFile* file; + Status s = env->NewWritableFile(fname, &file); + if (!s.ok()) { + return s; + } + s = file->Append(data); + if (s.ok() && should_sync) { + s = file->Sync(); + } + if (s.ok()) { + s = file->Close(); + } + delete file; // Will auto-close if we did not close above + if (!s.ok()) { + env->DeleteFile(fname); + } + return s; +} + +Status WriteStringToFile(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, false); +} + +Status WriteStringToFileSync(Env* env, const Slice& data, + const std::string& fname) { + return DoWriteStringToFile(env, data, fname, true); +} + +Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { + data->clear(); + SequentialFile* file; + Status s = env->NewSequentialFile(fname, &file); + if (!s.ok()) { + return s; + } + static const int kBufferSize = 8192; + char* space = new char[kBufferSize]; + while (true) { + Slice fragment; + s = file->Read(kBufferSize, &fragment, space); + if (!s.ok()) { + break; + } + data->append(fragment.data(), fragment.size()); + if (fragment.empty()) { + break; + } + } + delete[] space; + delete file; + return s; +} + +EnvWrapper::~EnvWrapper() { +} + +} // namespace leveldb diff --git a/util/env_posix.cc b/util/env_posix.cc new file mode 100644 index 0000000000..4676bc2240 --- /dev/null +++ b/util/env_posix.cc @@ -0,0 +1,706 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +#if !defined(LEVELDB_PLATFORM_WINDOWS) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "port/port.h" +#include "util/logging.h" +#include "util/mutexlock.h" +#include "util/posix_logger.h" +#include "util/env_posix_test_helper.h" + +namespace leveldb { + +namespace { + +static int open_read_only_file_limit = -1; +static int mmap_limit = -1; + +static Status IOError(const std::string& context, int err_number) { + return Status::IOError(context, strerror(err_number)); +} + +// Helper class to limit resource usage to avoid exhaustion. +// Currently used to limit read-only file descriptors and mmap file usage +// so that we do not end up running out of file descriptors, virtual memory, +// or running into kernel performance problems for very large databases. +class Limiter { + public: + // Limit maximum number of resources to |n|. + Limiter(intptr_t n) { + SetAllowed(n); + } + + // If another resource is available, acquire it and return true. + // Else return false. + bool Acquire() { + if (GetAllowed() <= 0) { + return false; + } + MutexLock l(&mu_); + intptr_t x = GetAllowed(); + if (x <= 0) { + return false; + } else { + SetAllowed(x - 1); + return true; + } + } + + // Release a resource acquired by a previous call to Acquire() that returned + // true. + void Release() { + MutexLock l(&mu_); + SetAllowed(GetAllowed() + 1); + } + + private: + port::Mutex mu_; + port::AtomicPointer allowed_; + + intptr_t GetAllowed() const { + return reinterpret_cast(allowed_.Acquire_Load()); + } + + // REQUIRES: mu_ must be held + void SetAllowed(intptr_t v) { + allowed_.Release_Store(reinterpret_cast(v)); + } + + Limiter(const Limiter&); + void operator=(const Limiter&); +}; + +class PosixSequentialFile: public SequentialFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixSequentialFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + virtual ~PosixSequentialFile() { fclose(file_); } + + virtual Status Read(size_t n, Slice* result, char* scratch) { + Status s; + size_t r = fread_unlocked(scratch, 1, n, file_); + *result = Slice(scratch, r); + if (r < n) { + if (feof(file_)) { + // We leave status as ok if we hit the end of the file + } else { + // A partial read with an error: return a non-ok status + s = IOError(filename_, errno); + } + } + return s; + } + + virtual Status Skip(uint64_t n) { + if (fseek(file_, n, SEEK_CUR)) { + return IOError(filename_, errno); + } + return Status::OK(); + } + + virtual std::string GetName() const { return filename_; } +}; + +// pread() based random-access +class PosixRandomAccessFile: public RandomAccessFile { + private: + std::string filename_; + bool temporary_fd_; // If true, fd_ is -1 and we open on every read. + int fd_; + Limiter* limiter_; + + public: + PosixRandomAccessFile(const std::string& fname, int fd, Limiter* limiter) + : filename_(fname), fd_(fd), limiter_(limiter) { + temporary_fd_ = !limiter->Acquire(); + if (temporary_fd_) { + // Open file on every access. + close(fd_); + fd_ = -1; + } + } + + virtual ~PosixRandomAccessFile() { + if (!temporary_fd_) { + close(fd_); + limiter_->Release(); + } + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + int fd = fd_; + if (temporary_fd_) { + fd = open(filename_.c_str(), O_RDONLY); + if (fd < 0) { + return IOError(filename_, errno); + } + } + + Status s; + ssize_t r = pread(fd, scratch, n, static_cast(offset)); + *result = Slice(scratch, (r < 0) ? 0 : r); + if (r < 0) { + // An error: return a non-ok status + s = IOError(filename_, errno); + } + if (temporary_fd_) { + // Close the temporary file descriptor opened earlier. + close(fd); + } + return s; + } + + virtual std::string GetName() const { return filename_; } +}; + +// mmap() based random-access +class PosixMmapReadableFile: public RandomAccessFile { + private: + std::string filename_; + void* mmapped_region_; + size_t length_; + Limiter* limiter_; + + public: + // base[0,length-1] contains the mmapped contents of the file. + PosixMmapReadableFile(const std::string& fname, void* base, size_t length, + Limiter* limiter) + : filename_(fname), mmapped_region_(base), length_(length), + limiter_(limiter) { + } + + virtual ~PosixMmapReadableFile() { + munmap(mmapped_region_, length_); + limiter_->Release(); + } + + virtual Status Read(uint64_t offset, size_t n, Slice* result, + char* scratch) const { + Status s; + if (offset + n > length_) { + *result = Slice(); + s = IOError(filename_, EINVAL); + } else { + *result = Slice(reinterpret_cast(mmapped_region_) + offset, n); + } + return s; + } + + virtual std::string GetName() const { return filename_; } +}; + +class PosixWritableFile : public WritableFile { + private: + std::string filename_; + FILE* file_; + + public: + PosixWritableFile(const std::string& fname, FILE* f) + : filename_(fname), file_(f) { } + + ~PosixWritableFile() { + if (file_ != NULL) { + // Ignoring any potential errors + fclose(file_); + } + } + + virtual Status Append(const Slice& data) { + size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); + if (r != data.size()) { + return IOError(filename_, errno); + } + return Status::OK(); + } + + virtual Status Close() { + Status result; + if (fclose(file_) != 0) { + result = IOError(filename_, errno); + } + file_ = NULL; + return result; + } + + virtual Status Flush() { + if (fflush_unlocked(file_) != 0) { + return IOError(filename_, errno); + } + return Status::OK(); + } + + Status SyncDirIfManifest() { + const char* f = filename_.c_str(); + const char* sep = strrchr(f, '/'); + Slice basename; + std::string dir; + if (sep == NULL) { + dir = "."; + basename = f; + } else { + dir = std::string(f, sep - f); + basename = sep + 1; + } + Status s; + if (basename.starts_with("MANIFEST")) { + int fd = open(dir.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(dir, errno); + } else { + if (fsync(fd) < 0 && errno != EINVAL) { + s = IOError(dir, errno); + } + close(fd); + } + } + return s; + } + + virtual Status Sync() { + // Ensure new files referred to by the manifest are in the filesystem. + Status s = SyncDirIfManifest(); + if (!s.ok()) { + return s; + } + if (fflush_unlocked(file_) != 0 || + fdatasync(fileno(file_)) != 0) { + s = Status::IOError(filename_, strerror(errno)); + } + return s; + } + + virtual std::string GetName() const { return filename_; } +}; + +static int LockOrUnlock(int fd, bool lock) { + errno = 0; + struct flock f; + memset(&f, 0, sizeof(f)); + f.l_type = (lock ? F_WRLCK : F_UNLCK); + f.l_whence = SEEK_SET; + f.l_start = 0; + f.l_len = 0; // Lock/unlock entire file + return fcntl(fd, F_SETLK, &f); +} + +class PosixFileLock : public FileLock { + public: + int fd_; + std::string name_; +}; + +// Set of locked files. We keep a separate set instead of just +// relying on fcntrl(F_SETLK) since fcntl(F_SETLK) does not provide +// any protection against multiple uses from the same process. +class PosixLockTable { + private: + port::Mutex mu_; + std::set locked_files_; + public: + bool Insert(const std::string& fname) { + MutexLock l(&mu_); + return locked_files_.insert(fname).second; + } + void Remove(const std::string& fname) { + MutexLock l(&mu_); + locked_files_.erase(fname); + } +}; + +class PosixEnv : public Env { + public: + PosixEnv(); + virtual ~PosixEnv() { + char msg[] = "Destroying Env::Default()\n"; + fwrite(msg, 1, sizeof(msg), stderr); + abort(); + } + + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result) { + FILE* f = fopen(fname.c_str(), "r"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixSequentialFile(fname, f); + return Status::OK(); + } + } + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result) { + *result = NULL; + Status s; + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + s = IOError(fname, errno); + } else if (mmap_limit_.Acquire()) { + uint64_t size; + s = GetFileSize(fname, &size); + if (s.ok()) { + void* base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (base != MAP_FAILED) { + *result = new PosixMmapReadableFile(fname, base, size, &mmap_limit_); + } else { + s = IOError(fname, errno); + } + } + close(fd); + if (!s.ok()) { + mmap_limit_.Release(); + } + } else { + *result = new PosixRandomAccessFile(fname, fd, &fd_limit_); + } + return s; + } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + Status s; + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + s = IOError(fname, errno); + } else { + *result = new PosixWritableFile(fname, f); + } + return s; + } + + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + Status s; + FILE* f = fopen(fname.c_str(), "a"); + if (f == NULL) { + *result = NULL; + s = IOError(fname, errno); + } else { + *result = new PosixWritableFile(fname, f); + } + return s; + } + + virtual bool FileExists(const std::string& fname) { + return access(fname.c_str(), F_OK) == 0; + } + + virtual Status GetChildren(const std::string& dir, + std::vector* result) { + result->clear(); + DIR* d = opendir(dir.c_str()); + if (d == NULL) { + return IOError(dir, errno); + } + struct dirent* entry; + while ((entry = readdir(d)) != NULL) { + result->push_back(entry->d_name); + } + closedir(d); + return Status::OK(); + } + + virtual Status DeleteFile(const std::string& fname) { + Status result; + if (unlink(fname.c_str()) != 0) { + result = IOError(fname, errno); + } + return result; + } + + virtual Status CreateDir(const std::string& name) { + Status result; + if (mkdir(name.c_str(), 0755) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status DeleteDir(const std::string& name) { + Status result; + if (rmdir(name.c_str()) != 0) { + result = IOError(name, errno); + } + return result; + } + + virtual Status GetFileSize(const std::string& fname, uint64_t* size) { + Status s; + struct stat sbuf; + if (stat(fname.c_str(), &sbuf) != 0) { + *size = 0; + s = IOError(fname, errno); + } else { + *size = sbuf.st_size; + } + return s; + } + + virtual Status RenameFile(const std::string& src, const std::string& target) { + Status result; + if (rename(src.c_str(), target.c_str()) != 0) { + result = IOError(src, errno); + } + return result; + } + + virtual Status LockFile(const std::string& fname, FileLock** lock) { + *lock = NULL; + Status result; + int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644); + if (fd < 0) { + result = IOError(fname, errno); + } else if (!locks_.Insert(fname)) { + close(fd); + result = Status::IOError("lock " + fname, "already held by process"); + } else if (LockOrUnlock(fd, true) == -1) { + result = IOError("lock " + fname, errno); + close(fd); + locks_.Remove(fname); + } else { + PosixFileLock* my_lock = new PosixFileLock; + my_lock->fd_ = fd; + my_lock->name_ = fname; + *lock = my_lock; + } + return result; + } + + virtual Status UnlockFile(FileLock* lock) { + PosixFileLock* my_lock = reinterpret_cast(lock); + Status result; + if (LockOrUnlock(my_lock->fd_, false) == -1) { + result = IOError("unlock", errno); + } + locks_.Remove(my_lock->name_); + close(my_lock->fd_); + delete my_lock; + return result; + } + + virtual void Schedule(void (*function)(void*), void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* result) { + const char* env = getenv("TEST_TMPDIR"); + if (env && env[0] != '\0') { + *result = env; + } else { + char buf[100]; + snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); + *result = buf; + } + // Directory may already exist + CreateDir(*result); + return Status::OK(); + } + + static uint64_t gettid() { + pthread_t tid = pthread_self(); + uint64_t thread_id = 0; + memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid))); + return thread_id; + } + + virtual Status NewLogger(const std::string& fname, Logger** result) { + FILE* f = fopen(fname.c_str(), "w"); + if (f == NULL) { + *result = NULL; + return IOError(fname, errno); + } else { + *result = new PosixLogger(f, &PosixEnv::gettid); + return Status::OK(); + } + } + + virtual uint64_t NowMicros() { + struct timeval tv; + gettimeofday(&tv, NULL); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + } + + virtual void SleepForMicroseconds(int micros) { + usleep(micros); + } + + private: + void PthreadCall(const char* label, int result) { + if (result != 0) { + fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); + abort(); + } + } + + // BGThread() is the body of the background thread + void BGThread(); + static void* BGThreadWrapper(void* arg) { + reinterpret_cast(arg)->BGThread(); + return NULL; + } + + pthread_mutex_t mu_; + pthread_cond_t bgsignal_; + pthread_t bgthread_; + bool started_bgthread_; + + // Entry per Schedule() call + struct BGItem { void* arg; void (*function)(void*); }; + typedef std::deque BGQueue; + BGQueue queue_; + + PosixLockTable locks_; + Limiter mmap_limit_; + Limiter fd_limit_; +}; + +// Return the maximum number of concurrent mmaps. +static int MaxMmaps() { + if (mmap_limit >= 0) { + return mmap_limit; + } + // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes. + mmap_limit = sizeof(void*) >= 8 ? 1000 : 0; + return mmap_limit; +} + +// Return the maximum number of read-only files to keep open. +static intptr_t MaxOpenFiles() { + if (open_read_only_file_limit >= 0) { + return open_read_only_file_limit; + } + struct rlimit rlim; + if (getrlimit(RLIMIT_NOFILE, &rlim)) { + // getrlimit failed, fallback to hard-coded default. + open_read_only_file_limit = 50; + } else if (rlim.rlim_cur == RLIM_INFINITY) { + open_read_only_file_limit = std::numeric_limits::max(); + } else { + // Allow use of 20% of available file descriptors for read-only files. + open_read_only_file_limit = rlim.rlim_cur / 5; + } + return open_read_only_file_limit; +} + +PosixEnv::PosixEnv() + : started_bgthread_(false), + mmap_limit_(MaxMmaps()), + fd_limit_(MaxOpenFiles()) { + PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL)); + PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL)); +} + +void PosixEnv::Schedule(void (*function)(void*), void* arg) { + PthreadCall("lock", pthread_mutex_lock(&mu_)); + + // Start background thread if necessary + if (!started_bgthread_) { + started_bgthread_ = true; + PthreadCall( + "create thread", + pthread_create(&bgthread_, NULL, &PosixEnv::BGThreadWrapper, this)); + } + + // If the queue is currently empty, the background thread may currently be + // waiting. + if (queue_.empty()) { + PthreadCall("signal", pthread_cond_signal(&bgsignal_)); + } + + // Add to priority queue + queue_.push_back(BGItem()); + queue_.back().function = function; + queue_.back().arg = arg; + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); +} + +void PosixEnv::BGThread() { + while (true) { + // Wait until there is an item that is ready to run + PthreadCall("lock", pthread_mutex_lock(&mu_)); + while (queue_.empty()) { + PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_)); + } + + void (*function)(void*) = queue_.front().function; + void* arg = queue_.front().arg; + queue_.pop_front(); + + PthreadCall("unlock", pthread_mutex_unlock(&mu_)); + (*function)(arg); + } +} + +namespace { +struct StartThreadState { + void (*user_function)(void*); + void* arg; +}; +} +static void* StartThreadWrapper(void* arg) { + StartThreadState* state = reinterpret_cast(arg); + state->user_function(state->arg); + delete state; + return NULL; +} + +void PosixEnv::StartThread(void (*function)(void* arg), void* arg) { + pthread_t t; + StartThreadState* state = new StartThreadState; + state->user_function = function; + state->arg = arg; + PthreadCall("start thread", + pthread_create(&t, NULL, &StartThreadWrapper, state)); +} + +} // namespace + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new PosixEnv; } + +void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) { + assert(default_env == NULL); + open_read_only_file_limit = limit; +} + +void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) { + assert(default_env == NULL); + mmap_limit = limit; +} + +Env* Env::Default() { + pthread_once(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif diff --git a/util/env_posix_test.cc b/util/env_posix_test.cc new file mode 100644 index 0000000000..295f8ae440 --- /dev/null +++ b/util/env_posix_test.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" +#include "util/env_posix_test_helper.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; +static const int kReadOnlyFileLimit = 4; +static const int kMMapLimit = 4; + +class EnvPosixTest { + public: + Env* env_; + EnvPosixTest() : env_(Env::Default()) { } + + static void SetFileLimits(int read_only_file_limit, int mmap_limit) { + EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit); + EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit); + } +}; + +TEST(EnvPosixTest, TestOpenOnRead) { + // Write some test data to a single file that will be opened |n| times. + std::string test_dir; + ASSERT_OK(env_->GetTestDirectory(&test_dir)); + std::string test_file = test_dir + "/open_on_read.txt"; + + FILE* f = fopen(test_file.c_str(), "w"); + ASSERT_TRUE(f != NULL); + const char kFileData[] = "abcdefghijklmnopqrstuvwxyz"; + fputs(kFileData, f); + fclose(f); + + // Open test file some number above the sum of the two limits to force + // open-on-read behavior of POSIX Env leveldb::RandomAccessFile. + const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5; + leveldb::RandomAccessFile* files[kNumFiles] = {0}; + for (int i = 0; i < kNumFiles; i++) { + ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i])); + } + char scratch; + Slice read_result; + for (int i = 0; i < kNumFiles; i++) { + ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch)); + ASSERT_EQ(kFileData[i], read_result[0]); + } + for (int i = 0; i < kNumFiles; i++) { + delete files[i]; + } + ASSERT_OK(env_->DeleteFile(test_file)); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + // All tests currently run with the same read-only file limits. + leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit, + leveldb::kMMapLimit); + return leveldb::test::RunAllTests(); +} diff --git a/util/env_posix_test_helper.h b/util/env_posix_test_helper.h new file mode 100644 index 0000000000..0386960598 --- /dev/null +++ b/util/env_posix_test_helper.h @@ -0,0 +1,28 @@ +// Copyright 2017 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ +#define STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ + +namespace leveldb { + +class EnvPosixTest; + +// A helper for the POSIX Env to facilitate testing. +class EnvPosixTestHelper { + private: + friend class EnvPosixTest; + + // Set the maximum number of read-only files that will be opened. + // Must be called before creating an Env. + static void SetReadOnlyFDLimit(int limit); + + // Set the maximum number of read-only files that will be mapped via mmap. + // Must be called before creating an Env. + static void SetReadOnlyMMapLimit(int limit); +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_ENV_POSIX_TEST_HELPER_H_ diff --git a/util/env_test.cc b/util/env_test.cc new file mode 100644 index 0000000000..839ae56a1a --- /dev/null +++ b/util/env_test.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/env.h" + +#include "port/port.h" +#include "util/testharness.h" + +namespace leveldb { + +static const int kDelayMicros = 100000; +static const int kReadOnlyFileLimit = 4; +static const int kMMapLimit = 4; + +class EnvTest { + private: + port::Mutex mu_; + std::string events_; + + public: + Env* env_; + EnvTest() : env_(Env::Default()) { } +}; + +static void SetBool(void* ptr) { + reinterpret_cast(ptr)->NoBarrier_Store(ptr); +} + +TEST(EnvTest, RunImmediately) { + port::AtomicPointer called (NULL); + env_->Schedule(&SetBool, &called); + env_->SleepForMicroseconds(kDelayMicros); + ASSERT_TRUE(called.NoBarrier_Load() != NULL); +} + +TEST(EnvTest, RunMany) { + port::AtomicPointer last_id (NULL); + + struct CB { + port::AtomicPointer* last_id_ptr; // Pointer to shared slot + uintptr_t id; // Order# for the execution of this callback + + CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { } + + static void Run(void* v) { + CB* cb = reinterpret_cast(v); + void* cur = cb->last_id_ptr->NoBarrier_Load(); + ASSERT_EQ(cb->id-1, reinterpret_cast(cur)); + cb->last_id_ptr->Release_Store(reinterpret_cast(cb->id)); + } + }; + + // Schedule in different order than start time + CB cb1(&last_id, 1); + CB cb2(&last_id, 2); + CB cb3(&last_id, 3); + CB cb4(&last_id, 4); + env_->Schedule(&CB::Run, &cb1); + env_->Schedule(&CB::Run, &cb2); + env_->Schedule(&CB::Run, &cb3); + env_->Schedule(&CB::Run, &cb4); + + env_->SleepForMicroseconds(kDelayMicros); + void* cur = last_id.Acquire_Load(); + ASSERT_EQ(4, reinterpret_cast(cur)); +} + +struct State { + port::Mutex mu; + int val; + int num_running; +}; + +static void ThreadBody(void* arg) { + State* s = reinterpret_cast(arg); + s->mu.Lock(); + s->val += 1; + s->num_running -= 1; + s->mu.Unlock(); +} + +TEST(EnvTest, StartThread) { + State state; + state.val = 0; + state.num_running = 3; + for (int i = 0; i < 3; i++) { + env_->StartThread(&ThreadBody, &state); + } + while (true) { + state.mu.Lock(); + int num = state.num_running; + state.mu.Unlock(); + if (num == 0) { + break; + } + env_->SleepForMicroseconds(kDelayMicros); + } + ASSERT_EQ(state.val, 3); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/env_win.cc b/util/env_win.cc new file mode 100644 index 0000000000..81380216bb --- /dev/null +++ b/util/env_win.cc @@ -0,0 +1,901 @@ +// This file contains source that originates from: +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h +// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc +// Those files don't have any explicit license headers but the +// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' +// as the license. +#if defined(LEVELDB_PLATFORM_WINDOWS) +#include + + +#include "leveldb/env.h" + +#include "port/port.h" +#include "leveldb/slice.h" +#include "util/logging.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef max +#undef max +#endif + +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +#if defined DeleteFile +#undef DeleteFile +#endif + +//Declarations +namespace leveldb +{ + +namespace Win32 +{ + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +std::string GetCurrentDir(); +std::wstring GetCurrentDirW(); + +static const std::string CurrentDir = GetCurrentDir(); +static const std::wstring CurrentDirW = GetCurrentDirW(); + +std::string& ModifyPath(std::string& path); +std::wstring& ModifyPath(std::wstring& path); + +std::string GetLastErrSz(); +std::wstring GetLastErrSzW(); + +size_t GetPageSize(); + +typedef void (*ScheduleProc)(void*) ; + +struct WorkItemWrapper +{ + WorkItemWrapper(ScheduleProc proc_,void* content_); + ScheduleProc proc; + void* pContent; +}; + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); + +class Win32SequentialFile : public SequentialFile +{ +public: + friend class Win32Env; + virtual ~Win32SequentialFile(); + virtual Status Read(size_t n, Slice* result, char* scratch); + virtual Status Skip(uint64_t n); + BOOL isEnable(); + virtual std::string GetName() const { return _filename; } +private: + BOOL _Init(); + void _CleanUp(); + Win32SequentialFile(const std::string& fname); + std::string _filename; + ::HANDLE _hFile; + DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); +}; + +class Win32RandomAccessFile : public RandomAccessFile +{ +public: + friend class Win32Env; + virtual ~Win32RandomAccessFile(); + virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; + BOOL isEnable(); + virtual std::string GetName() const { return _filename; } +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32RandomAccessFile(const std::string& fname); + HANDLE _hFile; + const std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); +}; + +class Win32WritableFile : public WritableFile +{ +public: + Win32WritableFile(const std::string& fname, bool append); + ~Win32WritableFile(); + + virtual Status Append(const Slice& data); + virtual Status Close(); + virtual Status Flush(); + virtual Status Sync(); + BOOL isEnable(); + virtual std::string GetName() const { return filename_; } +private: + std::string filename_; + ::HANDLE _hFile; +}; + +class Win32FileLock : public FileLock +{ +public: + friend class Win32Env; + virtual ~Win32FileLock(); + BOOL isEnable(); +private: + BOOL _Init(LPCWSTR path); + void _CleanUp(); + Win32FileLock(const std::string& fname); + HANDLE _hFile; + std::string _filename; + DISALLOW_COPY_AND_ASSIGN(Win32FileLock); +}; + +class Win32Logger : public Logger +{ +public: + friend class Win32Env; + virtual ~Win32Logger(); + virtual void Logv(const char* format, va_list ap); +private: + explicit Win32Logger(WritableFile* pFile); + WritableFile* _pFileProxy; + DISALLOW_COPY_AND_ASSIGN(Win32Logger); +}; + +class Win32Env : public Env +{ +public: + Win32Env(); + virtual ~Win32Env(); + virtual Status NewSequentialFile(const std::string& fname, + SequentialFile** result); + + virtual Status NewRandomAccessFile(const std::string& fname, + RandomAccessFile** result); + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result); + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result); + + virtual bool FileExists(const std::string& fname); + + virtual Status GetChildren(const std::string& dir, + std::vector* result); + + virtual Status DeleteFile(const std::string& fname); + + virtual Status CreateDir(const std::string& dirname); + + virtual Status DeleteDir(const std::string& dirname); + + virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); + + virtual Status RenameFile(const std::string& src, + const std::string& target); + + virtual Status LockFile(const std::string& fname, FileLock** lock); + + virtual Status UnlockFile(FileLock* lock); + + virtual void Schedule( + void (*function)(void* arg), + void* arg); + + virtual void StartThread(void (*function)(void* arg), void* arg); + + virtual Status GetTestDirectory(std::string* path); + + //virtual void Logv(WritableFile* log, const char* format, va_list ap); + + virtual Status NewLogger(const std::string& fname, Logger** result); + + virtual uint64_t NowMicros(); + + virtual void SleepForMicroseconds(int micros); +}; + +void ToWidePath(const std::string& value, std::wstring& target) { + wchar_t buffer[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); + target = buffer; +} + +void ToNarrowPath(const std::wstring& value, std::string& target) { + char buffer[MAX_PATH]; + WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); + target = buffer; +} + +std::string GetCurrentDir() +{ + CHAR path[MAX_PATH]; + ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); + *strrchr(path,'\\') = 0; + return std::string(path); +} + +std::wstring GetCurrentDirW() +{ + WCHAR path[MAX_PATH]; + ::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); + *wcsrchr(path,L'\\') = 0; + return std::wstring(path); +} + +std::string& ModifyPath(std::string& path) +{ + if(path[0] == '/' || path[0] == '\\'){ + path = CurrentDir + path; + } + std::replace(path.begin(),path.end(),'/','\\'); + + return path; +} + +std::wstring& ModifyPath(std::wstring& path) +{ + if(path[0] == L'/' || path[0] == L'\\'){ + path = CurrentDirW + path; + } + std::replace(path.begin(),path.end(),L'/',L'\\'); + return path; +} + +std::string GetLastErrSz() +{ + LPWSTR lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::string Err; + ToNarrowPath(lpMsgBuf, Err); + LocalFree( lpMsgBuf ); + return Err; +} + +std::wstring GetLastErrSzW() +{ + LPVOID lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + std::wstring Err = (LPCWSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + return Err; +} + +WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : + proc(proc_),pContent(content_) +{ + +} + +DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) +{ + WorkItemWrapper* item = static_cast(pContent); + ScheduleProc TempProc = item->proc; + void* arg = item->pContent; + delete item; + TempProc(arg); + return 0; +} + +size_t GetPageSize() +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return std::max(si.dwPageSize,si.dwAllocationGranularity); +} + +const size_t g_PageSize = GetPageSize(); + + +Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + _Init(); +} + +Win32SequentialFile::~Win32SequentialFile() +{ + _CleanUp(); +} + +Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) +{ + Status sRet; + DWORD hasRead = 0; + if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ + *result = Slice(scratch,hasRead); + } else { + sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); + } + return sRet; +} + +Status Win32SequentialFile::Skip( uint64_t n ) +{ + Status sRet; + LARGE_INTEGER Move,NowPointer; + Move.QuadPart = n; + if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + } + return sRet; +} + +BOOL Win32SequentialFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +BOOL Win32SequentialFile::_Init() +{ + std::wstring path; + ToWidePath(_filename, path); + _hFile = CreateFileW(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (_hFile == INVALID_HANDLE_VALUE) + _hFile = NULL; + return _hFile ? TRUE : FALSE; +} + +void Win32SequentialFile::_CleanUp() +{ + if(_hFile){ + CloseHandle(_hFile); + _hFile = NULL; + } +} + +Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : + _filename(fname),_hFile(NULL) +{ + std::wstring path; + ToWidePath(fname, path); + _Init( path.c_str() ); +} + +Win32RandomAccessFile::~Win32RandomAccessFile() +{ + _CleanUp(); +} + +Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const +{ + Status sRet; + OVERLAPPED ol = {0}; + ZeroMemory(&ol,sizeof(ol)); + ol.Offset = (DWORD)offset; + ol.OffsetHigh = (DWORD)(offset >> 32); + DWORD hasRead = 0; + if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) + sRet = Status::IOError(_filename,Win32::GetLastErrSz()); + else + *result = Slice(scratch,hasRead); + return sRet; +} + +BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) + _hFile = NULL; + else + bRet = TRUE; + return bRet; +} + +BOOL Win32RandomAccessFile::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +void Win32RandomAccessFile::_CleanUp() +{ + if(_hFile){ + ::CloseHandle(_hFile); + _hFile = NULL; + } +} + +Win32WritableFile::Win32WritableFile(const std::string& fname, bool append) + : filename_(fname) +{ + std::wstring path; + ToWidePath(fname, path); + // NewAppendableFile: append to an existing file, or create a new one + // if none exists - this is OPEN_ALWAYS behavior, with + // FILE_APPEND_DATA to avoid having to manually position the file + // pointer at the end of the file. + // NewWritableFile: create a new file, delete if it exists - this is + // CREATE_ALWAYS behavior. This file is used for writing only so + // use GENERIC_WRITE. + _hFile = CreateFileW(path.c_str(), + append ? FILE_APPEND_DATA : GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use +} + +Win32WritableFile::~Win32WritableFile() +{ + if (_hFile != INVALID_HANDLE_VALUE) + Close(); +} + +Status Win32WritableFile::Append(const Slice& data) +{ + DWORD r = 0; + if (!WriteFile(_hFile, data.data(), data.size(), &r, NULL) || r != data.size()) { + return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_, Win32::GetLastErrSz()); + } + return Status::OK(); +} + +Status Win32WritableFile::Close() +{ + if (!CloseHandle(_hFile)) { + return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_, Win32::GetLastErrSz()); + } + _hFile = INVALID_HANDLE_VALUE; + return Status::OK(); +} + +Status Win32WritableFile::Flush() +{ + // Nothing to do here, there are no application-side buffers + return Status::OK(); +} + +Status Win32WritableFile::Sync() +{ + if (!FlushFileBuffers(_hFile)) { + return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_, Win32::GetLastErrSz()); + } + return Status::OK(); +} + +BOOL Win32WritableFile::isEnable() +{ + return _hFile != INVALID_HANDLE_VALUE; +} + +Win32FileLock::Win32FileLock( const std::string& fname ) : + _hFile(NULL),_filename(fname) +{ + std::wstring path; + ToWidePath(fname, path); + _Init(path.c_str()); +} + +Win32FileLock::~Win32FileLock() +{ + _CleanUp(); +} + +BOOL Win32FileLock::_Init( LPCWSTR path ) +{ + BOOL bRet = FALSE; + if(!_hFile) + _hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ + _hFile = NULL; + } + else + bRet = TRUE; + return bRet; +} + +void Win32FileLock::_CleanUp() +{ + ::CloseHandle(_hFile); + _hFile = NULL; +} + +BOOL Win32FileLock::isEnable() +{ + return _hFile ? TRUE : FALSE; +} + +Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) +{ + assert(_pFileProxy); +} + +Win32Logger::~Win32Logger() +{ + if(_pFileProxy) + delete _pFileProxy; +} + +void Win32Logger::Logv( const char* format, va_list ap ) +{ + uint64_t thread_id = ::GetCurrentThreadId(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + SYSTEMTIME st; + GetLocalTime(&st); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + int(st.wYear), + int(st.wMonth), + int(st.wDay), + int(st.wHour), + int(st.wMinute), + int(st.wMinute), + int(st.wMilliseconds), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + DWORD hasWritten = 0; + if(_pFileProxy){ + _pFileProxy->Append(Slice(base, p - base)); + _pFileProxy->Flush(); + } + if (base != buffer) { + delete[] base; + } + break; + } +} + +bool Win32Env::FileExists(const std::string& fname) +{ + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + return ::PathFileExistsW(wpath.c_str()) ? true : false; +} + +Status Win32Env::GetChildren(const std::string& dir, std::vector* result) +{ + Status sRet; + ::WIN32_FIND_DATAW wfd; + std::string path = dir; + ModifyPath(path); + path += "\\*.*"; + std::wstring wpath; + ToWidePath(path, wpath); + + ::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); + if(hFind && hFind != INVALID_HANDLE_VALUE){ + BOOL hasNext = TRUE; + std::string child; + while(hasNext){ + ToNarrowPath(wfd.cFileName, child); + if(child != ".." && child != ".") { + result->push_back(child); + } + hasNext = ::FindNextFileW(hFind,&wfd); + } + ::FindClose(hFind); + } + else + sRet = Status::IOError(dir,"Could not get children."); + return sRet; +} + +void Win32Env::SleepForMicroseconds( int micros ) +{ + ::Sleep((micros + 999) /1000); +} + + +Status Win32Env::DeleteFile( const std::string& fname ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + if(!::DeleteFileW(wpath.c_str())) { + sRet = Status::IOError(path, "Could not delete file."); + } + return sRet; +} + +Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) +{ + Status sRet; + std::string path = fname; + std::wstring wpath; + ToWidePath(ModifyPath(path), wpath); + + HANDLE file = ::CreateFileW(wpath.c_str(), + GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + LARGE_INTEGER li; + if(::GetFileSizeEx(file,&li)){ + *file_size = (uint64_t)li.QuadPart; + }else + sRet = Status::IOError(path,"Could not get the file size."); + CloseHandle(file); + return sRet; +} + +Status Win32Env::RenameFile( const std::string& src, const std::string& target ) +{ + Status sRet; + std::string src_path = src; + std::wstring wsrc_path; + ToWidePath(ModifyPath(src_path), wsrc_path); + std::string target_path = target; + std::wstring wtarget_path; + ToWidePath(ModifyPath(target_path), wtarget_path); + + if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ + DWORD err = GetLastError(); + if(err == 0x000000b7){ + if(!::DeleteFileW(wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + else if(!::MoveFileW(wsrc_path.c_str(), + wtarget_path.c_str() ) ) + sRet = Status::IOError(src, "Could not rename file."); + } + } + return sRet; +} + +Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32FileLock* _lock = new Win32FileLock(path); + if(!_lock->isEnable()){ + delete _lock; + *lock = NULL; + sRet = Status::IOError(path, "Could not lock file."); + } + else + *lock = _lock; + return sRet; +} + +Status Win32Env::UnlockFile( FileLock* lock ) +{ + Status sRet; + delete lock; + return sRet; +} + +void Win32Env::Schedule( void (*function)(void* arg), void* arg ) +{ + QueueUserWorkItem(Win32::WorkItemWrapperProc, + new Win32::WorkItemWrapper(function,arg), + WT_EXECUTEDEFAULT); +} + +void Win32Env::StartThread( void (*function)(void* arg), void* arg ) +{ + ::_beginthread(function,0,arg); +} + +Status Win32Env::GetTestDirectory( std::string* path ) +{ + Status sRet; + WCHAR TempPath[MAX_PATH]; + ::GetTempPathW(MAX_PATH,TempPath); + ToNarrowPath(TempPath, *path); + path->append("leveldb\\test\\"); + ModifyPath(*path); + return sRet; +} + +uint64_t Win32Env::NowMicros() +{ +#ifndef USE_VISTA_API +#define GetTickCount64 GetTickCount +#endif + return (uint64_t)(GetTickCount64()*1000); +} + +static Status CreateDirInner( const std::string& dirname ) +{ + Status sRet; + DWORD attr = ::GetFileAttributes(dirname.c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: + std::size_t slash = dirname.find_last_of("\\"); + if (slash != std::string::npos){ + sRet = CreateDirInner(dirname.substr(0, slash)); + if (!sRet.ok()) return sRet; + } + BOOL result = ::CreateDirectory(dirname.c_str(), NULL); + if (result == FALSE) { + sRet = Status::IOError(dirname, "Could not create directory."); + return sRet; + } + } + return sRet; +} + +Status Win32Env::CreateDir( const std::string& dirname ) +{ + std::string path = dirname; + if(path[path.length() - 1] != '\\'){ + path += '\\'; + } + ModifyPath(path); + + return CreateDirInner(path); +} + +Status Win32Env::DeleteDir( const std::string& dirname ) +{ + Status sRet; + std::wstring path; + ToWidePath(dirname, path); + ModifyPath(path); + if(!::RemoveDirectoryW( path.c_str() ) ){ + sRet = Status::IOError(dirname, "Could not delete directory."); + } + return sRet; +} + +Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) +{ + Status sRet; + std::string path = fname; + ModifyPath(path); + Win32SequentialFile* pFile = new Win32SequentialFile(path); + if(pFile->isEnable()){ + *result = pFile; + }else { + delete pFile; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + } + return sRet; +} + +Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) +{ + Status sRet; + std::string path = fname; + Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); + if(!pFile->isEnable()){ + delete pFile; + *result = NULL; + sRet = Status::IOError(path, Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Status Win32Env::NewLogger( const std::string& fname, Logger** result ) +{ + Status sRet; + std::string path = fname; + // Logs are opened with write semantics, not with append semantics + // (see PosixEnv::NewLogger) + Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path), false); + if(!pMapFile->isEnable()){ + delete pMapFile; + *result = NULL; + sRet = Status::IOError(path,"could not create a logger."); + }else + *result = new Win32Logger(pMapFile); + return sRet; +} + +Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) +{ + Status sRet; + std::string path = fname; + Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), false); + if(!pFile->isEnable()){ + *result = NULL; + sRet = Status::IOError(fname,Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Status Win32Env::NewAppendableFile( const std::string& fname, WritableFile** result ) +{ + Status sRet; + std::string path = fname; + Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), true); + if(!pFile->isEnable()){ + *result = NULL; + sRet = Status::IOError(fname,Win32::GetLastErrSz()); + }else + *result = pFile; + return sRet; +} + +Win32Env::Win32Env() +{ + +} + +Win32Env::~Win32Env() +{ + +} + + +} // Win32 namespace + +static port::OnceType once = LEVELDB_ONCE_INIT; +static Env* default_env; +static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } + +Env* Env::Default() { + port::InitOnce(&once, InitDefaultEnv); + return default_env; +} + +} // namespace leveldb + +#endif // defined(LEVELDB_PLATFORM_WINDOWS) diff --git a/util/filter_policy.cc b/util/filter_policy.cc new file mode 100644 index 0000000000..7b045c8c91 --- /dev/null +++ b/util/filter_policy.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/filter_policy.h" + +namespace leveldb { + +FilterPolicy::~FilterPolicy() { } + +} // namespace leveldb diff --git a/util/hash.cc b/util/hash.cc new file mode 100644 index 0000000000..ed439ce7a2 --- /dev/null +++ b/util/hash.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "util/coding.h" +#include "util/hash.h" + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels. The real definition should be provided externally. +// This one is a fallback version for unsupported compilers. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED do { } while (0) +#endif + +namespace leveldb { + +uint32_t Hash(const char* data, size_t n, uint32_t seed) { + // Similar to murmur hash + const uint32_t m = 0xc6a4a793; + const uint32_t r = 24; + const char* limit = data + n; + uint32_t h = seed ^ (n * m); + + // Pick up four bytes at a time + while (data + 4 <= limit) { + uint32_t w = DecodeFixed32(data); + data += 4; + h += w; + h *= m; + h ^= (h >> 16); + } + + // Pick up remaining bytes + switch (limit - data) { + case 3: + h += static_cast(data[2]) << 16; + FALLTHROUGH_INTENDED; + case 2: + h += static_cast(data[1]) << 8; + FALLTHROUGH_INTENDED; + case 1: + h += static_cast(data[0]); + h *= m; + h ^= (h >> r); + break; + } + return h; +} + + +} // namespace leveldb diff --git a/util/hash.h b/util/hash.h new file mode 100644 index 0000000000..8889d56be8 --- /dev/null +++ b/util/hash.h @@ -0,0 +1,19 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Simple hash function used for internal data structures + +#ifndef STORAGE_LEVELDB_UTIL_HASH_H_ +#define STORAGE_LEVELDB_UTIL_HASH_H_ + +#include +#include + +namespace leveldb { + +extern uint32_t Hash(const char* data, size_t n, uint32_t seed); + +} + +#endif // STORAGE_LEVELDB_UTIL_HASH_H_ diff --git a/util/hash_test.cc b/util/hash_test.cc new file mode 100644 index 0000000000..eaa1c92c23 --- /dev/null +++ b/util/hash_test.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/hash.h" +#include "util/testharness.h" + +namespace leveldb { + +class HASH { }; + +TEST(HASH, SignedUnsignedIssue) { + const unsigned char data1[1] = {0x62}; + const unsigned char data2[2] = {0xc3, 0x97}; + const unsigned char data3[3] = {0xe2, 0x99, 0xa5}; + const unsigned char data4[4] = {0xe1, 0x80, 0xb9, 0x32}; + const unsigned char data5[48] = { + 0x01, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x18, + 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + ASSERT_EQ(Hash(0, 0, 0xbc9f1d34), 0xbc9f1d34); + ASSERT_EQ( + Hash(reinterpret_cast(data1), sizeof(data1), 0xbc9f1d34), + 0xef1345c4); + ASSERT_EQ( + Hash(reinterpret_cast(data2), sizeof(data2), 0xbc9f1d34), + 0x5b663814); + ASSERT_EQ( + Hash(reinterpret_cast(data3), sizeof(data3), 0xbc9f1d34), + 0x323c078f); + ASSERT_EQ( + Hash(reinterpret_cast(data4), sizeof(data4), 0xbc9f1d34), + 0xed21633a); + ASSERT_EQ( + Hash(reinterpret_cast(data5), sizeof(data5), 0x12345678), + 0xf333dabb); +} + +} // namespace leveldb + +int main(int argc, char** argv) { + return leveldb::test::RunAllTests(); +} diff --git a/util/histogram.cc b/util/histogram.cc new file mode 100644 index 0000000000..bb95f583ea --- /dev/null +++ b/util/histogram.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include +#include "port/port.h" +#include "util/histogram.h" + +namespace leveldb { + +const double Histogram::kBucketLimit[kNumBuckets] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45, + 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450, + 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000, + 16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000, + 70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000, + 250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000, + 3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000, + 9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000, + 25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000, + 70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000, + 180000000, 200000000, 250000000, 300000000, 350000000, 400000000, + 450000000, 500000000, 600000000, 700000000, 800000000, 900000000, + 1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000, + 2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0, + 5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0, + 1e200, +}; + +void Histogram::Clear() { + min_ = kBucketLimit[kNumBuckets-1]; + max_ = 0; + num_ = 0; + sum_ = 0; + sum_squares_ = 0; + for (int i = 0; i < kNumBuckets; i++) { + buckets_[i] = 0; + } +} + +void Histogram::Add(double value) { + // Linear search is fast enough for our usage in db_bench + int b = 0; + while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) { + b++; + } + buckets_[b] += 1.0; + if (min_ > value) min_ = value; + if (max_ < value) max_ = value; + num_++; + sum_ += value; + sum_squares_ += (value * value); +} + +void Histogram::Merge(const Histogram& other) { + if (other.min_ < min_) min_ = other.min_; + if (other.max_ > max_) max_ = other.max_; + num_ += other.num_; + sum_ += other.sum_; + sum_squares_ += other.sum_squares_; + for (int b = 0; b < kNumBuckets; b++) { + buckets_[b] += other.buckets_[b]; + } +} + +double Histogram::Median() const { + return Percentile(50.0); +} + +double Histogram::Percentile(double p) const { + double threshold = num_ * (p / 100.0); + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + sum += buckets_[b]; + if (sum >= threshold) { + // Scale linearly within this bucket + double left_point = (b == 0) ? 0 : kBucketLimit[b-1]; + double right_point = kBucketLimit[b]; + double left_sum = sum - buckets_[b]; + double right_sum = sum; + double pos = (threshold - left_sum) / (right_sum - left_sum); + double r = left_point + (right_point - left_point) * pos; + if (r < min_) r = min_; + if (r > max_) r = max_; + return r; + } + } + return max_; +} + +double Histogram::Average() const { + if (num_ == 0.0) return 0; + return sum_ / num_; +} + +double Histogram::StandardDeviation() const { + if (num_ == 0.0) return 0; + double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_); + return sqrt(variance); +} + +std::string Histogram::ToString() const { + std::string r; + char buf[200]; + snprintf(buf, sizeof(buf), + "Count: %.0f Average: %.4f StdDev: %.2f\n", + num_, Average(), StandardDeviation()); + r.append(buf); + snprintf(buf, sizeof(buf), + "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); + r.append(buf); + r.append("------------------------------------------------------\n"); + const double mult = 100.0 / num_; + double sum = 0; + for (int b = 0; b < kNumBuckets; b++) { + if (buckets_[b] <= 0.0) continue; + sum += buckets_[b]; + snprintf(buf, sizeof(buf), + "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b-1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage + r.append(buf); + + // Add hash marks based on percentage; 20 marks for 100%. + int marks = static_cast(20*(buckets_[b] / num_) + 0.5); + r.append(marks, '#'); + r.push_back('\n'); + } + return r; +} + +} // namespace leveldb diff --git a/util/histogram.h b/util/histogram.h new file mode 100644 index 0000000000..1ef9f3c8ab --- /dev/null +++ b/util/histogram.h @@ -0,0 +1,42 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ +#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ + +#include + +namespace leveldb { + +class Histogram { + public: + Histogram() { } + ~Histogram() { } + + void Clear(); + void Add(double value); + void Merge(const Histogram& other); + + std::string ToString() const; + + private: + double min_; + double max_; + double num_; + double sum_; + double sum_squares_; + + enum { kNumBuckets = 154 }; + static const double kBucketLimit[kNumBuckets]; + double buckets_[kNumBuckets]; + + double Median() const; + double Percentile(double p) const; + double Average() const; + double StandardDeviation() const; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_ diff --git a/util/logging.cc b/util/logging.cc new file mode 100644 index 0000000000..db6160c8f1 --- /dev/null +++ b/util/logging.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/logging.h" + +#include +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" + +namespace leveldb { + +void AppendNumberTo(std::string* str, uint64_t num) { + char buf[30]; + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num); + str->append(buf); +} + +void AppendEscapedStringTo(std::string* str, const Slice& value) { + for (size_t i = 0; i < value.size(); i++) { + char c = value[i]; + if (c >= ' ' && c <= '~') { + str->push_back(c); + } else { + char buf[10]; + snprintf(buf, sizeof(buf), "\\x%02x", + static_cast(c) & 0xff); + str->append(buf); + } + } +} + +std::string NumberToString(uint64_t num) { + std::string r; + AppendNumberTo(&r, num); + return r; +} + +std::string EscapeString(const Slice& value) { + std::string r; + AppendEscapedStringTo(&r, value); + return r; +} + +bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { + uint64_t v = 0; + int digits = 0; + while (!in->empty()) { + unsigned char c = (*in)[0]; + if (c >= '0' && c <= '9') { + ++digits; + const int delta = (c - '0'); + static const uint64_t kMaxUint64 = ~static_cast(0); + if (v > kMaxUint64/10 || + (v == kMaxUint64/10 && delta > kMaxUint64%10)) { + // Overflow + return false; + } + v = (v * 10) + delta; + in->remove_prefix(1); + } else { + break; + } + } + *val = v; + return (digits > 0); +} + +} // namespace leveldb diff --git a/util/logging.h b/util/logging.h new file mode 100644 index 0000000000..1b450d2480 --- /dev/null +++ b/util/logging.h @@ -0,0 +1,43 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Must not be included from any .h files to avoid polluting the namespace +// with macros. + +#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ +#define STORAGE_LEVELDB_UTIL_LOGGING_H_ + +#include +#include +#include +#include "port/port.h" + +namespace leveldb { + +class Slice; +class WritableFile; + +// Append a human-readable printout of "num" to *str +extern void AppendNumberTo(std::string* str, uint64_t num); + +// Append a human-readable printout of "value" to *str. +// Escapes any non-printable characters found in "value". +extern void AppendEscapedStringTo(std::string* str, const Slice& value); + +// Return a human-readable printout of "num" +extern std::string NumberToString(uint64_t num); + +// Return a human-readable version of "value". +// Escapes any non-printable characters found in "value". +extern std::string EscapeString(const Slice& value); + +// Parse a human-readable number from "*in" into *value. On success, +// advances "*in" past the consumed number and sets "*val" to the +// numeric value. Otherwise, returns false and leaves *in in an +// unspecified state. +extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val); + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_LOGGING_H_ diff --git a/util/mutexlock.h b/util/mutexlock.h new file mode 100644 index 0000000000..1ff5a9efa1 --- /dev/null +++ b/util/mutexlock.h @@ -0,0 +1,41 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ +#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ + +#include "port/port.h" +#include "port/thread_annotations.h" + +namespace leveldb { + +// Helper class that locks a mutex on construction and unlocks the mutex when +// the destructor of the MutexLock object is invoked. +// +// Typical usage: +// +// void MyClass::MyMethod() { +// MutexLock l(&mu_); // mu_ is an instance variable +// ... some complex code, possibly with multiple return paths ... +// } + +class SCOPED_LOCKABLE MutexLock { + public: + explicit MutexLock(port::Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) + : mu_(mu) { + this->mu_->Lock(); + } + ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } + + private: + port::Mutex *const mu_; + // No copying allowed + MutexLock(const MutexLock&); + void operator=(const MutexLock&); +}; + +} // namespace leveldb + + +#endif // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_ diff --git a/util/options.cc b/util/options.cc new file mode 100644 index 0000000000..b5e6227613 --- /dev/null +++ b/util/options.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "leveldb/options.h" + +#include "leveldb/comparator.h" +#include "leveldb/env.h" + +namespace leveldb { + +Options::Options() + : comparator(BytewiseComparator()), + create_if_missing(false), + error_if_exists(false), + paranoid_checks(false), + env(Env::Default()), + info_log(NULL), + write_buffer_size(4<<20), + max_open_files(1000), + block_cache(NULL), + block_size(4096), + block_restart_interval(16), + max_file_size(2<<20), + compression(kSnappyCompression), + reuse_logs(false), + filter_policy(NULL) { +} + +} // namespace leveldb diff --git a/util/posix_logger.h b/util/posix_logger.h new file mode 100644 index 0000000000..c063c2b7cb --- /dev/null +++ b/util/posix_logger.h @@ -0,0 +1,98 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// Logger implementation that can be shared by all environments +// where enough Posix functionality is available. + +#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ +#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ + +#include +#include +#include +#include +#include "leveldb/env.h" + +namespace leveldb { + +class PosixLogger : public Logger { + private: + FILE* file_; + uint64_t (*gettid_)(); // Return the thread id for the current thread + public: + PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { } + virtual ~PosixLogger() { + fclose(file_); + } + virtual void Logv(const char* format, va_list ap) { + const uint64_t thread_id = (*gettid_)(); + + // We try twice: the first time with a fixed-size stack allocated buffer, + // and the second time with a much larger dynamically allocated buffer. + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + struct timeval now_tv; + gettimeofday(&now_tv, NULL); + const time_t seconds = now_tv.tv_sec; + struct tm t; + localtime_r(&seconds, &t); + p += snprintf(p, limit - p, + "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", + t.tm_year + 1900, + t.tm_mon + 1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + static_cast(now_tv.tv_usec), + static_cast(thread_id)); + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + fwrite(base, 1, p - base, file_); + fflush(file_); + if (base != buffer) { + delete[] base; + } + break; + } + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_ diff --git a/util/random.h b/util/random.h new file mode 100644 index 0000000000..ddd51b1c7b --- /dev/null +++ b/util/random.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ +#define STORAGE_LEVELDB_UTIL_RANDOM_H_ + +#include + +namespace leveldb { + +// A very simple random number generator. Not especially good at +// generating truly random bits, but good enough for our needs in this +// package. +class Random { + private: + uint32_t seed_; + public: + explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { + // Avoid bad seeds. + if (seed_ == 0 || seed_ == 2147483647L) { + seed_ = 1; + } + } + uint32_t Next() { + static const uint32_t M = 2147483647L; // 2^31-1 + static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 + // We are computing + // seed_ = (seed_ * A) % M, where M = 2^31-1 + // + // seed_ must not be zero or M, or else all subsequent computed values + // will be zero or M respectively. For all other values, seed_ will end + // up cycling through every number in [1,M-1] + uint64_t product = seed_ * A; + + // Compute (product % M) using the fact that ((x << 31) % M) == x. + seed_ = static_cast((product >> 31) + (product & M)); + // The first reduction may overflow by 1 bit, so we may need to + // repeat. mod == M is not possible; using > allows the faster + // sign-bit-based test. + if (seed_ > M) { + seed_ -= M; + } + return seed_; + } + // Returns a uniformly distributed value in the range [0..n-1] + // REQUIRES: n > 0 + uint32_t Uniform(int n) { return Next() % n; } + + // Randomly returns true ~"1/n" of the time, and false otherwise. + // REQUIRES: n > 0 + bool OneIn(int n) { return (Next() % n) == 0; } + + // Skewed: pick "base" uniformly from range [0,max_log] and then + // return "base" random bits. The effect is to pick a number in the + // range [0,2^max_log-1] with exponential bias towards smaller numbers. + uint32_t Skewed(int max_log) { + return Uniform(1 << Uniform(max_log + 1)); + } +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ diff --git a/util/status.cc b/util/status.cc new file mode 100644 index 0000000000..a44f35b314 --- /dev/null +++ b/util/status.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include +#include "port/port.h" +#include "leveldb/status.h" + +namespace leveldb { + +const char* Status::CopyState(const char* state) { + uint32_t size; + memcpy(&size, state, sizeof(size)); + char* result = new char[size + 5]; + memcpy(result, state, size + 5); + return result; +} + +Status::Status(Code code, const Slice& msg, const Slice& msg2) { + assert(code != kOk); + const uint32_t len1 = msg.size(); + const uint32_t len2 = msg2.size(); + const uint32_t size = len1 + (len2 ? (2 + len2) : 0); + char* result = new char[size + 5]; + memcpy(result, &size, sizeof(size)); + result[4] = static_cast(code); + memcpy(result + 5, msg.data(), len1); + if (len2) { + result[5 + len1] = ':'; + result[6 + len1] = ' '; + memcpy(result + 7 + len1, msg2.data(), len2); + } + state_ = result; +} + +std::string Status::ToString() const { + if (state_ == NULL) { + return "OK"; + } else { + char tmp[30]; + const char* type; + switch (code()) { + case kOk: + type = "OK"; + break; + case kNotFound: + type = "NotFound: "; + break; + case kCorruption: + type = "Corruption: "; + break; + case kNotSupported: + type = "Not implemented: "; + break; + case kInvalidArgument: + type = "Invalid argument: "; + break; + case kIOError: + type = "IO error: "; + break; + default: + snprintf(tmp, sizeof(tmp), "Unknown code(%d): ", + static_cast(code())); + type = tmp; + break; + } + std::string result(type); + uint32_t length; + memcpy(&length, state_, sizeof(length)); + result.append(state_ + 5, length); + return result; + } +} + +} // namespace leveldb diff --git a/util/testharness.cc b/util/testharness.cc new file mode 100644 index 0000000000..402fab34d7 --- /dev/null +++ b/util/testharness.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testharness.h" + +#include +#include +#include +#include + +namespace leveldb { +namespace test { + +namespace { +struct Test { + const char* base; + const char* name; + void (*func)(); +}; +std::vector* tests; +} + +bool RegisterTest(const char* base, const char* name, void (*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + Test t; + t.base = base; + t.name = name; + t.func = func; + tests->push_back(t); + return true; +} + +int RunAllTests() { + const char* matcher = getenv("LEVELDB_TESTS"); + + int num = 0; + if (tests != NULL) { + for (size_t i = 0; i < tests->size(); i++) { + const Test& t = (*tests)[i]; + if (matcher != NULL) { + std::string name = t.base; + name.push_back('.'); + name.append(t.name); + if (strstr(name.c_str(), matcher) == NULL) { + continue; + } + } + fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); + (*t.func)(); + ++num; + } + } + fprintf(stderr, "==== PASSED %d tests\n", num); + return 0; +} + +std::string TmpDir() { + std::string dir; + Status s = Env::Default()->GetTestDirectory(&dir); + ASSERT_TRUE(s.ok()) << s.ToString(); + return dir; +} + +int RandomSeed() { + const char* env = getenv("TEST_RANDOM_SEED"); + int result = (env != NULL ? atoi(env) : 301); + if (result <= 0) { + result = 301; + } + return result; +} + +} // namespace test +} // namespace leveldb diff --git a/util/testharness.h b/util/testharness.h new file mode 100644 index 0000000000..da4fe68bb4 --- /dev/null +++ b/util/testharness.h @@ -0,0 +1,138 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ +#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ + +#include +#include +#include +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Run some of the tests registered by the TEST() macro. If the +// environment variable "LEVELDB_TESTS" is not set, runs all tests. +// Otherwise, runs only the tests whose name contains the value of +// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: +// TEST(Foo, Hello) { ... } +// TEST(Foo, World) { ... } +// LEVELDB_TESTS=Hello will run the first test +// LEVELDB_TESTS=o will run both tests +// LEVELDB_TESTS=Junk will run no tests +// +// Returns 0 if all tests pass. +// Dies or returns a non-zero value if some test fails. +extern int RunAllTests(); + +// Return the directory to use for temporary storage. +extern std::string TmpDir(); + +// Return a randomization seed for this run. Typically returns the +// same number on repeated invocations of this binary, but automated +// runs may be able to vary the seed. +extern int RandomSeed(); + +// An instance of Tester is allocated to hold temporary state during +// the execution of an assertion. +class Tester { + private: + bool ok_; + const char* fname_; + int line_; + std::stringstream ss_; + + public: + Tester(const char* f, int l) + : ok_(true), fname_(f), line_(l) { + } + + ~Tester() { + if (!ok_) { + fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); + exit(1); + } + } + + Tester& Is(bool b, const char* msg) { + if (!b) { + ss_ << " Assertion failure " << msg; + ok_ = false; + } + return *this; + } + + Tester& IsOk(const Status& s) { + if (!s.ok()) { + ss_ << " " << s.ToString(); + ok_ = false; + } + return *this; + } + +#define BINARY_OP(name,op) \ + template \ + Tester& name(const X& x, const Y& y) { \ + if (! (x op y)) { \ + ss_ << " failed: " << x << (" " #op " ") << y; \ + ok_ = false; \ + } \ + return *this; \ + } + + BINARY_OP(IsEq, ==) + BINARY_OP(IsNe, !=) + BINARY_OP(IsGe, >=) + BINARY_OP(IsGt, >) + BINARY_OP(IsLe, <=) + BINARY_OP(IsLt, <) +#undef BINARY_OP + + // Attach the specified value to the error message if an error has occurred + template + Tester& operator<<(const V& value) { + if (!ok_) { + ss_ << " " << value; + } + return *this; + } +}; + +#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) +#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) +#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) +#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) +#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) +#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) +#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) +#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) + +#define TCONCAT(a,b) TCONCAT1(a,b) +#define TCONCAT1(a,b) a##b + +#define TEST(base,name) \ +class TCONCAT(_Test_,name) : public base { \ + public: \ + void _Run(); \ + static void _RunIt() { \ + TCONCAT(_Test_,name) t; \ + t._Run(); \ + } \ +}; \ +bool TCONCAT(_Test_ignored_,name) = \ + ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \ +void TCONCAT(_Test_,name)::_Run() + +// Register the specified test. Typically not used directly, but +// invoked via the macro expansion of TEST. +extern bool RegisterTest(const char* base, const char* name, void (*func)()); + + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/util/testutil.cc b/util/testutil.cc new file mode 100644 index 0000000000..bee56bf75f --- /dev/null +++ b/util/testutil.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "util/testutil.h" + +#include "util/random.h" + +namespace leveldb { +namespace test { + +Slice RandomString(Random* rnd, int len, std::string* dst) { + dst->resize(len); + for (int i = 0; i < len; i++) { + (*dst)[i] = static_cast(' ' + rnd->Uniform(95)); // ' ' .. '~' + } + return Slice(*dst); +} + +std::string RandomKey(Random* rnd, int len) { + // Make sure to generate a wide variety of characters so we + // test the boundary conditions for short-key optimizations. + static const char kTestChars[] = { + '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff' + }; + std::string result; + for (int i = 0; i < len; i++) { + result += kTestChars[rnd->Uniform(sizeof(kTestChars))]; + } + return result; +} + + +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + size_t len, std::string* dst) { + int raw = static_cast(len * compressed_fraction); + if (raw < 1) raw = 1; + std::string raw_data; + RandomString(rnd, raw, &raw_data); + + // Duplicate the random data until we have filled "len" bytes + dst->clear(); + while (dst->size() < len) { + dst->append(raw_data); + } + dst->resize(len); + return Slice(*dst); +} + +} // namespace test +} // namespace leveldb diff --git a/util/testutil.h b/util/testutil.h new file mode 100644 index 0000000000..d7e4583702 --- /dev/null +++ b/util/testutil.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ +#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ + +#include "leveldb/env.h" +#include "leveldb/slice.h" +#include "util/random.h" + +namespace leveldb { +namespace test { + +// Store in *dst a random string of length "len" and return a Slice that +// references the generated data. +extern Slice RandomString(Random* rnd, int len, std::string* dst); + +// Return a random key with the specified length that may contain interesting +// characters (e.g. \x00, \xff, etc.). +extern std::string RandomKey(Random* rnd, int len); + +// Store in *dst a string of length "len" that will compress to +// "N*compressed_fraction" bytes and return a Slice that references +// the generated data. +extern Slice CompressibleString(Random* rnd, double compressed_fraction, + size_t len, std::string* dst); + +// A wrapper that allows injection of errors. +class ErrorEnv : public EnvWrapper { + public: + bool writable_file_error_; + int num_writable_file_errors_; + + ErrorEnv() : EnvWrapper(Env::Default()), + writable_file_error_(false), + num_writable_file_errors_(0) { } + + virtual Status NewWritableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewWritableFile(fname, result); + } + + virtual Status NewAppendableFile(const std::string& fname, + WritableFile** result) { + if (writable_file_error_) { + ++num_writable_file_errors_; + *result = NULL; + return Status::IOError(fname, "fake error"); + } + return target()->NewAppendableFile(fname, result); + } +}; + +} // namespace test +} // namespace leveldb + +#endif // STORAGE_LEVELDB_UTIL_TESTUTIL_H_ From 720328aaaedfe174d1b28db54d7c3d816f33da78 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Nov 2020 13:25:52 -0500 Subject: [PATCH 0514/1888] build: update build system for new leveldb (cherry picked from commit ffee03c) --- configure.ac | 43 +++++++++++++++++++++++++++++++++++-- src/Makefile.am | 20 +++++------------ src/Makefile.qttest.include | 2 +- src/Makefile.test.include | 4 ++-- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 781e38194a..24c17d5968 100644 --- a/configure.ac +++ b/configure.ac @@ -234,6 +234,33 @@ if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[CXXFLAGS="$CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) fi +# Check for optional instruction set support. Enabling these does _not_ imply that all code will +# be compiled with them, rather that specific objects/libs may use them after checking for runtime +# compatibility. +AX_CHECK_COMPILE_FLAG([-msse4.2],[[SSE42_CXXFLAGS="-msse4.2"]],,[[$CXXFLAG_WERROR]]) + +TEMP_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $SSE42_CXXFLAGS" +AC_MSG_CHECKING(for assembler crc32 support) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #if defined(_MSC_VER) + #include + #elif defined(__GNUC__) && defined(__SSE4_2__) + #include + #endif + ]],[[ + uint64_t l = 0; + l = _mm_crc32_u8(l, 0); + l = _mm_crc32_u32(l, 0); + l = _mm_crc32_u64(l, 0); + return l; + ]])], + [ AC_MSG_RESULT(yes); enable_hwcrc32=yes], + [ AC_MSG_RESULT(no)] +) +CXXFLAGS="$TEMP_CXXFLAGS" + CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], @@ -299,7 +326,7 @@ case $host in fi CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB" - LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE" + LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -w" fi @@ -321,7 +348,7 @@ case $host in ;; *darwin*) TARGET_OS=darwin - LEVELDB_TARGET_FLAGS="TARGET_OS=Darwin" + LEVELDB_TARGET_FLAGS="-DOS_MACOSX" if test x$cross_compiling != xyes; then BUILD_OS=darwin AC_CHECK_PROG([PORT],port, port) @@ -393,8 +420,18 @@ case $host in ;; *linux*) TARGET_OS=linux + LEVELDB_TARGET_FLAGS="-DOS_LINUX" + ;; + *freebsd*) + LEVELDB_TARGET_FLAGS="-DOS_FREEBSD" + ;; + *openbsd*) + LEVELDB_TARGET_FLAGS="-DOS_OPENBSD" ;; *) + OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'` + AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.]) + LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}" ;; esac @@ -1106,6 +1143,7 @@ AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) AM_CONDITIONAL([USE_LIBSECP256K1],[test x$use_libsecp256k1 = xyes]) +AM_CONDITIONAL([ENABLE_HWCRC32],[test x$enable_hwcrc32 = xyes]) AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version]) AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version]) @@ -1131,6 +1169,7 @@ AC_SUBST(HARDENED_CPPFLAGS) AC_SUBST(HARDENED_LDFLAGS) AC_SUBST(PIC_FLAGS) AC_SUBST(PIE_FLAGS) +AC_SUBST(SSE42_CXXFLAGS) AC_SUBST(COMPAT_LDFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) diff --git a/src/Makefile.am b/src/Makefile.am index 1e5c75b4c2..de1ba1d048 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,21 +18,6 @@ else LIBUNIVALUE = $(UNIVALUE_LIBS) endif -if EMBEDDED_LEVELDB -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include -LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv -LIBLEVELDB += $(builddir)/leveldb/libleveldb.a -LIBMEMENV += $(builddir)/leveldb/libmemenv.a - -# NOTE: This dependency is not strictly necessary, but without it make may try to build both in parallel, which breaks the LevelDB build system in a race -$(LIBLEVELDB): $(LIBMEMENV) - -$(LIBLEVELDB) $(LIBMEMENV): - @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ - CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ - OPT="$(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS" -endif - BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BITCOIN_CONFIG_INCLUDES) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) @@ -409,6 +394,7 @@ dapscoind_LDADD = \ $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ + $(LIBLEVELDB_SSE42) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ $(LIBSECP256K1_2) @@ -532,6 +518,10 @@ clean-local: @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$( Date: Sun, 29 Nov 2020 13:52:15 -0500 Subject: [PATCH 0515/1888] Add missing files to Makefile.am --- src/Makefile.am | 20 +++++++++++++++++++- src/Makefile.qt.include | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 82f538abf3..d7a05610b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,9 +97,12 @@ BITCOIN_CORE_H = \ allocators.h \ amount.h \ base58.h \ + bignum.h \ bip38.h \ bip39.h \ bip39_english.h \ + ecdhutil.h \ + enum.h \ hdchain.h \ bloom.h \ chain.h \ @@ -127,6 +130,7 @@ BITCOIN_CORE_H = \ httprpc.h \ httpserver.h \ init.h \ + invalid.h \ kernel.h \ swifttx.h \ key.h \ @@ -173,6 +177,7 @@ BITCOIN_CORE_H = \ txmempool.h \ guiinterface.h \ uint256.h \ + uint512.h \ undo.h \ util.h \ util/macros.h \ @@ -255,7 +260,20 @@ libbitcoin_zxcvbn_a_SOURCES = \ zxcvbn/scoring.cpp \ zxcvbn/time_estimates.cpp \ zxcvbn/util.cpp \ - zxcvbn/zxcvbn.cpp + zxcvbn/zxcvbn.cpp \ + zxcvbn/adjacency_graphs.hpp \ + zxcvbn/common.hpp \ + zxcvbn/feedback.hpp \ + zxcvbn/frequency_lists_common.hpp \ + zxcvbn/_frequency_lists.hpp \ + zxcvbn/frequency_lists.hpp \ + zxcvbn/matching.hpp \ + zxcvbn/optional.hpp \ + zxcvbn/scoring.hpp \ + zxcvbn/time_estimates.hpp \ + zxcvbn/util.hpp \ + zxcvbn/zxcvbn.hpp \ + zxcvbn/zxcvbn.h # wallet: shared between dapscoind and dapscoin-qt, but only linked diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 2072e83030..28a5c127ad 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -241,6 +241,7 @@ RES_ICONS = \ qt/res/icons/connect2_16.png \ qt/res/icons/connect3_16.png \ qt/res/icons/connect4_16.png \ + qt/res/icons/dapsico.png \ qt/res/icons/debugwindow.png \ qt/res/icons/edit.png \ qt/res/icons/editcopy.png \ From c9fcb08b55b6e6e8a998d055d22b0a764bbb9699 Mon Sep 17 00:00:00 2001 From: volbil Date: Mon, 30 Nov 2020 22:58:06 +0200 Subject: [PATCH 0516/1888] PaymentID in listtransactions --- src/wallet/rpcwallet.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fc5186c8bb..6609bc8b82 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -65,6 +65,11 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("walletconflicts", conflicts)); entry.push_back(Pair("time", wtx.GetTxTime())); entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); + + if (wtx.hasPaymentID) { + entry.push_back(Pair("paymentid", wtx.paymentID)); + } + for (const PAIRTYPE(string, string) & item : wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } From c0550b60cb9c9895d4cd6b77c50a3707873b80b0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Nov 2020 13:52:28 -0500 Subject: [PATCH 0517/1888] Remove unused files --- contrib/dapscoin-qt.pro | 7 - src/Makefile.am | 1 - src/arith_uint256.cpp | 316 ----------------- src/arith_uint256.h | 334 ------------------ src/mintpool.cpp | 110 ------ src/mintpool.h | 53 --- src/stakeinput.cpp | 111 ------ src/stakeinput.h | 53 --- src/test/arith_uint256_tests.cpp | 569 ------------------------------- src/uint512.h | 40 --- 10 files changed, 1594 deletions(-) delete mode 100644 src/arith_uint256.cpp delete mode 100644 src/arith_uint256.h delete mode 100644 src/mintpool.cpp delete mode 100644 src/mintpool.h delete mode 100644 src/stakeinput.cpp delete mode 100644 src/stakeinput.h delete mode 100644 src/test/arith_uint256_tests.cpp delete mode 100644 src/uint512.h diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index 1dabddfd33..9644f02515 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -65,7 +65,6 @@ HEADERS += src/activemasternode.h \ src/addrman.h \ src/allocators.h \ src/amount.h \ - src/arith_uint256.h \ src/base58.h \ src/bignum.h \ src/bip38.h \ @@ -111,7 +110,6 @@ HEADERS += src/activemasternode.h \ src/masternodeman.h \ src/merkleblock.h \ src/miner.h \ - src/mintpool.h \ src/mruset.h \ src/net.h \ src/netbase.h \ @@ -126,7 +124,6 @@ HEADERS += src/activemasternode.h \ src/reverse_iterate.h \ src/scheduler.h \ src/serialize.h \ - src/stakeinput.h \ src/streams.h \ src/swifttx.h \ src/sync.h \ @@ -137,7 +134,6 @@ HEADERS += src/activemasternode.h \ src/txdb.h \ src/txmempool.h \ src/uint256.h \ - src/uint512.h \ src/undo.h \ src/util.h \ src/utilmoneystr.h \ @@ -400,7 +396,6 @@ SOURCES += src/activemasternode.cpp \ src/addrman.cpp \ src/allocators.cpp \ src/amount.cpp \ - src/arith_uint256.cpp \ src/base58.cpp \ src/bip38.cpp \ src/bip39.cpp \ @@ -441,7 +436,6 @@ SOURCES += src/activemasternode.cpp \ src/masternodeman.cpp \ src/merkleblock.cpp \ src/miner.cpp \ - src/mintpool.cpp \ src/net.cpp \ src/netbase.cpp \ src/noui.cpp \ @@ -453,7 +447,6 @@ SOURCES += src/activemasternode.cpp \ src/random.cpp \ src/rest.cpp \ src/scheduler.cpp \ - src/stakeinput.cpp \ src/swifttx.cpp \ src/sync.cpp \ src/timedata.cpp \ diff --git a/src/Makefile.am b/src/Makefile.am index d7a05610b1..5b736c831b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -177,7 +177,6 @@ BITCOIN_CORE_H = \ txmempool.h \ guiinterface.h \ uint256.h \ - uint512.h \ undo.h \ util.h \ util/macros.h \ diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp deleted file mode 100644 index 1c0b1764b0..0000000000 --- a/src/arith_uint256.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "arith_uint256.h" - -#include "crypto/common.h" -#include "uint256.h" -#include "uint512.h" -#include "utilstrencodings.h" - -#include -#include - - -template <> -std::string base_uint<256>::GetHex() const -{ - return ArithToUint256(*this).GetHex(); -} - -template <> -void base_uint<256>::SetHex(const char* psz) -{ - *this = UintToArith256(uint256S(psz)); -} - -template <> -std::string base_uint<512>::GetHex() const -{ - return ArithToUint512(*this).GetHex(); -} - - -template <> -void base_uint<512>::SetHex(const char* psz) -{ - *this = UintToArith512(uint512S(psz)); -} - - -template -base_uint::base_uint(const std::string& str) -{ - SetHex(str); -} - -template -base_uint::base_uint(const std::vector& vch) -{ - if (vch.size() != sizeof(pn)) - throw uint_error("Converting vector of wrong size to base_uint"); - memcpy(pn, &vch[0], sizeof(pn)); -} - -template -base_uint& 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; -} - -template -base_uint& 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; -} - -template -base_uint& base_uint::operator*=(uint32_t b32) -{ - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) { - uint64_t n = carry + (uint64_t)b32 * pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; -} - -template -base_uint& base_uint::operator*=(const base_uint& b) -{ - base_uint a = *this; - *this = 0; - for (int j = 0; j < WIDTH; j++) { - uint64_t carry = 0; - for (int i = 0; i + j < WIDTH; i++) { - uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; - pn[i + j] = n & 0xffffffff; - carry = n >> 32; - } - } - return *this; -} - -template -base_uint& base_uint::operator/=(const base_uint& b) -{ - base_uint div = b; // make a copy, so we can shift. - base_uint num = *this; // make a copy, so we can subtract. - *this = 0; // the quotient. - int num_bits = num.bits(); - int div_bits = div.bits(); - if (div_bits == 0) - throw uint_error("Division by zero"); - if (div_bits > num_bits) // the result is certainly 0. - return *this; - int shift = num_bits - div_bits; - div <<= shift; // shift so that div and num align. - while (shift >= 0) { - if (num >= div) { - num -= div; - pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. - } - div >>= 1; // shift back. - shift--; - } - // num now contains the remainder of the division. - return *this; -} - -template -int base_uint::CompareTo(const base_uint& b) const -{ - for (int i = WIDTH - 1; i >= 0; i--) { - if (pn[i] < b.pn[i]) - return -1; - if (pn[i] > b.pn[i]) - return 1; - } - return 0; -} - -template -bool base_uint::EqualTo(uint64_t b) const -{ - for (int i = WIDTH - 1; i >= 2; i--) { - if (pn[i]) - return false; - } - if (pn[1] != (b >> 32)) - return false; - if (pn[0] != (b & 0xfffffffful)) - return false; - return true; -} - -template -double base_uint::getdouble() const -{ - double ret = 0.0; - double fact = 1.0; - for (int i = 0; i < WIDTH; i++) { - ret += fact * pn[i]; - fact *= 4294967296.0; - } - return ret; -} - -template -void base_uint::SetHex(const std::string& str) -{ - SetHex(str.c_str()); -} - -template -std::string base_uint::ToString() const -{ - return (GetHex()); -} - -template -unsigned int base_uint::bits() const -{ - for (int pos = WIDTH - 1; pos >= 0; pos--) { - if (pn[pos]) { - for (int bits = 31; bits > 0; bits--) { - if (pn[pos] & 1 << bits) - return 32 * pos + bits + 1; - } - return 32 * pos + 1; - } - } - return 0; -} - -// Explicit instantiations for base_uint<256> -template base_uint<256>::base_uint(const std::string&); -template base_uint<256>::base_uint(const std::vector&); -template base_uint<256>& base_uint<256>::operator<<=(unsigned int); -template base_uint<256>& base_uint<256>::operator>>=(unsigned int); -template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); -template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); -template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); -template int base_uint<256>::CompareTo(const base_uint<256>&) const; -template bool base_uint<256>::EqualTo(uint64_t) const; -template double base_uint<256>::getdouble() const; -template std::string base_uint<256>::ToString() const; -template void base_uint<256>::SetHex(const char*); -template void base_uint<256>::SetHex(const std::string&); -template unsigned int base_uint<256>::bits() const; - -// Explicit instantiations for base_uint<512> -template base_uint<512>::base_uint(const std::string&); -template base_uint<512>::base_uint(const std::vector&); -template base_uint<512>& base_uint<512>::operator<<=(unsigned int); -template base_uint<512>& base_uint<512>::operator>>=(unsigned int); -template base_uint<512>& base_uint<512>::operator*=(uint32_t b32); -template base_uint<512>& base_uint<512>::operator*=(const base_uint<512>& b); -template base_uint<512>& base_uint<512>::operator/=(const base_uint<512>& b); -template int base_uint<512>::CompareTo(const base_uint<512>&) const; -template bool base_uint<512>::EqualTo(uint64_t) const; -template double base_uint<512>::getdouble() const; -template std::string base_uint<512>::ToString() const; -//template void base_uint<512>::SetHex(const char*); -template void base_uint<512>::SetHex(const std::string&); -template unsigned int base_uint<512>::bits() const; - -// This implementation directly uses shifts instead of going -// through an intermediate MPI representation. -arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow) -{ - int nSize = nCompact >> 24; - uint32_t nWord = nCompact & 0x007fffff; - if (nSize <= 3) { - nWord >>= 8 * (3 - nSize); - *this = nWord; - } else { - *this = nWord; - *this <<= 8 * (nSize - 3); - } - if (pfNegative) - *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; - if (pfOverflow) - *pfOverflow = nWord != 0 && ((nSize > 34) || - (nWord > 0xff && nSize > 33) || - (nWord > 0xffff && nSize > 32)); - return *this; -} - -uint32_t arith_uint256::GetCompact(bool fNegative) const -{ - int nSize = (bits() + 7) / 8; - uint32_t nCompact = 0; - if (nSize <= 3) { - nCompact = GetLow64() << 8 * (3 - nSize); - } else { - arith_uint256 bn = *this >> 8 * (nSize - 3); - nCompact = bn.GetLow64(); - } - // The 0x00800000 bit denotes the sign. - // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. - if (nCompact & 0x00800000) { - nCompact >>= 8; - nSize++; - } - assert((nCompact & ~0x007fffff) == 0); - assert(nSize < 256); - nCompact |= nSize << 24; - nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); - return nCompact; -} - -uint256 ArithToUint256(const arith_uint256& a) -{ - uint256 b; - for (int x = 0; x < a.WIDTH; ++x) - WriteLE32(b.begin() + x * 4, a.pn[x]); - return b; -} -arith_uint256 UintToArith256(const uint256& a) -{ - arith_uint256 b; - for (int x = 0; x < b.WIDTH; ++x) - b.pn[x] = ReadLE32(a.begin() + x * 4); - return b; -} - -uint512 ArithToUint512(const arith_uint512& a) -{ - uint512 b; - for (int x = 0; x < a.WIDTH; ++x) - WriteLE32(b.begin() + x * 4, a.pn[x]); - return b; -} - -arith_uint512 UintToArith512(const uint512& a) -{ - arith_uint512 b; - for (int x = 0; x < b.WIDTH; ++x) - b.pn[x] = ReadLE32(a.begin() + x * 4); - return b; -} diff --git a/src/arith_uint256.h b/src/arith_uint256.h deleted file mode 100644 index 8768be2471..0000000000 --- a/src/arith_uint256.h +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_ARITH_UINT256_H -#define BITCOIN_ARITH_UINT256_H - -#include -#include -#include -#include -#include -#include - -class uint512; -class uint256; - -class uint_error : public std::runtime_error -{ -public: - explicit uint_error(const std::string& str) : std::runtime_error(str) {} -}; - -/** Template base class for unsigned big integers. */ -template -class base_uint -{ -protected: - enum { WIDTH = BITS / 32 }; - uint32_t pn[WIDTH]; - -public: - base_uint() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - base_uint(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - base_uint& operator=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - base_uint(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - explicit base_uint(const std::string& str); - explicit base_uint(const std::vector& vch); - - 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; - } - - double getdouble() const; - - 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<<=(unsigned int shift); - base_uint& operator>>=(unsigned int shift); - - 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*=(uint32_t b32); - base_uint& operator*=(const base_uint& b); - base_uint& operator/=(const base_uint& b); - - 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] == (uint32_t)-1 && i < WIDTH - 1) - i++; - return *this; - } - - const base_uint operator--(int) - { - // postfix operator - const base_uint ret = *this; - --(*this); - return ret; - } - - int CompareTo(const base_uint& b) const; - bool EqualTo(uint64_t b) const; - - friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } - friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } - friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } - friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } - friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } - friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } - friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } - friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } - friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } - friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } - friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } - friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } - friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } - friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } - friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } - friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } - friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } - friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } - - std::string GetHex() const; - void SetHex(const char* psz); - void SetHex(const std::string& str); - std::string ToString() const; - - unsigned char* begin() - { - return (unsigned char*)&pn[0]; - } - - unsigned char* end() - { - return (unsigned char*)&pn[WIDTH]; - } - - const unsigned char* begin() const - { - return (unsigned char*)&pn[0]; - } - - const unsigned char* end() const - { - return (unsigned char*)&pn[WIDTH]; - } - - unsigned int size() const - { - return sizeof(pn); - } - - /** - * Returns the position of the highest bit set plus one, or zero if the - * value is zero. - */ - unsigned int bits() const; - - uint64_t GetLow64() const - { - assert(WIDTH >= 2); - return pn[0] | (uint64_t)pn[1] << 32; - } -}; - -/** 256-bit unsigned big integer. */ -class arith_uint256 : public base_uint<256> -{ -public: - arith_uint256() {} - arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} - arith_uint256(uint64_t b) : base_uint<256>(b) {} - explicit arith_uint256(const std::string& str) : base_uint<256>(str) {} - explicit arith_uint256(const std::vector& vch) : base_uint<256>(vch) {} - - /** - * The "compact" format is a representation of a whole - * number N using an unsigned 32bit number similar to a - * floating point format. - * The most significant 8 bits are the unsigned exponent of base 256. - * This exponent can be thought of as "number of bytes of N". - * The lower 23 bits are the mantissa. - * Bit number 24 (0x800000) represents the sign of N. - * N = (-1^sign) * mantissa * 256^(exponent-3) - * - * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). - * MPI uses the most significant bit of the first byte as sign. - * Thus 0x1234560000 is compact (0x05123456) - * and 0xc0de000000 is compact (0x0600c0de) - * - * Bitcoin only uses this "compact" format for encoding difficulty - * targets, which are unsigned 256bit quantities. Thus, all the - * complexities of the sign bit and using base 256 are probably an - * implementation accident. - */ - arith_uint256& SetCompact(uint32_t nCompact, bool* pfNegative = NULL, bool* pfOverflow = NULL); - uint32_t GetCompact(bool fNegative = false) const; - - friend uint256 ArithToUint256(const arith_uint256&); - friend arith_uint256 UintToArith256(const uint256&); - uint64_t GetHash(const arith_uint256& salt) const; -}; - - -/** 512-bit unsigned big integer. */ -class arith_uint512 : public base_uint<512> -{ -public: - arith_uint512() {} - arith_uint512(const base_uint<512>& b) : base_uint<512>(b) {} - arith_uint512(uint64_t b) : base_uint<512>(b) {} - explicit arith_uint512(const std::string& str) : base_uint<512>(str) {} - explicit arith_uint512(const std::vector& vch) : base_uint<512>(vch) {} - - uint64_t GetHash(const arith_uint256& salt) const; - - friend arith_uint512 UintToArith512(const uint512& a); - friend uint512 ArithToUint512(const arith_uint512& a); -}; - -uint256 ArithToUint256(const arith_uint256&); -arith_uint256 UintToArith256(const uint256&); -uint512 ArithToUint512(const arith_uint512&); -arith_uint512 UintToArith512(const uint512&); - -#endif // BITCOIN_UINT256_H diff --git a/src/mintpool.cpp b/src/mintpool.cpp deleted file mode 100644 index e5533bef30..0000000000 --- a/src/mintpool.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "mintpool.h" -#include "util.h" - -using namespace std; - -CMintPool::CMintPool() -{ - this->nCountLastGenerated = 0; - this->nCountLastRemoved = 0; -} - -CMintPool::CMintPool(uint32_t nCount) -{ - this->nCountLastRemoved = nCount; - this->nCountLastGenerated = nCount; -} - -void CMintPool::Add(const CBigNum& bnValue, const uint32_t& nCount) -{ - uint256 hash = GetPubCoinHash(bnValue); - Add(make_pair(hash, nCount)); - LogPrintf("%s : add %s to mint pool, nCountLastGenerated=%d\n", __func__, bnValue.GetHex().substr(0, 6), nCountLastGenerated); -} - -void CMintPool::Add(const pair& pMint, bool fVerbose) -{ - insert(pMint); - if (pMint.second > nCountLastGenerated) - nCountLastGenerated = pMint.second; - - if (fVerbose) - LogPrintf("%s : add %s count %d to mint pool\n", __func__, pMint.first.GetHex().substr(0, 6), pMint.second); -} - -bool CMintPool::Has(const CBigNum& bnValue) -{ - return static_cast(count(GetPubCoinHash(bnValue))); -} - -std::pair CMintPool::Get(const CBigNum& bnValue) -{ - auto it = find(GetPubCoinHash(bnValue)); - return *it; -} - -bool SortSmallest(const pair& a, const pair& b) -{ - return a.second < b.second; -} - -std::list > CMintPool::List() -{ - list > listMints; - for (auto pMint : *(this)) { - listMints.emplace_back(pMint); - } - - listMints.sort(SortSmallest); - - return listMints; -} - -void CMintPool::Reset() -{ - clear(); - nCountLastGenerated = 0; - nCountLastRemoved = 0; -} - -bool CMintPool::Front(std::pair& pMint) -{ - if (empty()) - return false; - pMint = *begin(); - return true; -} - -bool CMintPool::Next(pair& pMint) -{ - auto it = find(pMint.first); - if (it == end() || ++it == end()) - return false; - - pMint = *it; - return true; -} - -void CMintPool::Remove(const CBigNum& bnValue) -{ - Remove(GetPubCoinHash(bnValue)); - LogPrintf("%s : remove %s from mint pool\n", __func__, bnValue.GetHex().substr(0, 6)); -} - -void CMintPool::Remove(const uint256& hashPubcoin) -{ - auto it = find(hashPubcoin); - if (it == end()) - return; - - nCountLastRemoved = it->second; - erase(it); -} - - - diff --git a/src/mintpool.h b/src/mintpool.h deleted file mode 100644 index 8f6eb72c07..0000000000 --- a/src/mintpool.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef DAPScoin_MINTPOOL_H -#define DAPScoin_MINTPOOL_H - -#include -#include - -#include "bignum.h" -#include "uint256.h" - -/** - * The MintPool only contains mint values that have not been added to the blockchain yet. - * When a mint is generated by the wallet, or found while syncing, the mint will be removed - * from the MintPool. - * - * The MintPool provides a convenient way to check whether mints in the blockchain belong to a - * wallet's deterministic seed. - */ -class CMintPool : public std::map //pubcoin hash, count -{ -private: - uint32_t nCountLastGenerated; - uint32_t nCountLastRemoved; - -public: - CMintPool(); - explicit CMintPool(uint32_t nCount); - void Add(const CBigNum& bnValue, const uint32_t& nCount); - void Add(const std::pair& pMint, bool fVerbose = false); - bool Has(const CBigNum& bnValue); - void Remove(const CBigNum& bnValue); - void Remove(const uint256& hashPubcoin); - std::pair Get(const CBigNum& bnValue); - std::list > List(); - void Reset(); - - bool Front(std::pair& pMint); - bool Next(std::pair& pMint); - - //The count of the next mint to generate will have be a mint that is already in the pool - //therefore need to return the next value that has not been removed from the pool yet - uint32_t CountOfLastRemoved() { return nCountLastRemoved; } - - //The next pool count returns the next count that will be added to the pool - uint32_t CountOfLastGenerated() { return nCountLastGenerated; } -}; - - -#endif //DAPScoin_MINTPOOL_H diff --git a/src/stakeinput.cpp b/src/stakeinput.cpp deleted file mode 100644 index 2b44c9a873..0000000000 --- a/src/stakeinput.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "chain.h" -#include "primitives/deterministicmint.h" -#include "main.h" -#include "stakeinput.h" -#include "wallet/wallet.h" - -//!DAPS Stake -bool CDapsStake::SetInput(CTransaction txPrev, unsigned int n) -{ - this->txFrom = txPrev; - this->nPosition = n; - return true; -} - -bool CDapsStake::GetTxFrom(CTransaction& tx) -{ - tx = txFrom; - return true; -} - -bool CDapsStake::CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut) -{ - txIn = CTxIn(txFrom.GetHash(), nPosition); - return true; -} - -CAmount CDapsStake::GetValue() -{ - return txFrom.vout[nPosition].nValue; -} - -bool CDapsStake::CreateTxOuts(CWallet* pwallet, vector& vout, CAmount nTotal) -{ - vector vSolutions; - txnouttype whichType; - CScript scriptPubKeyKernel = txFrom.vout[nPosition].scriptPubKey; - if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) { - LogPrintf("CreateCoinStake : failed to parse kernel\n"); - return false; - } - - if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH) - return false; // only support pay to public key and pay to address - - CScript scriptPubKey; - if (whichType == TX_PUBKEYHASH) // pay to address type - { - //convert to pay to public key type - CKey key; - CKeyID keyID = CKeyID(uint160(vSolutions[0])); - if (!pwallet->GetKey(keyID, key)) - return false; - - scriptPubKey << key.GetPubKey() << OP_CHECKSIG; - } else - scriptPubKey = scriptPubKeyKernel; - - vout.emplace_back(CTxOut(0, scriptPubKey)); - - // Calculate if we need to split the output - if (nTotal / 2 > (CAmount)(pwallet->nStakeSplitThreshold * COIN)) - vout.emplace_back(CTxOut(0, scriptPubKey)); - - return true; -} - -bool CDapsStake::GetModifier(uint64_t& nStakeModifier) -{ - int nStakeModifierHeight = 0; - int64_t nStakeModifierTime = 0; - GetIndexFrom(); - if (!pindexFrom) - return error("%s: failed to get index from", __func__); - - if (!GetKernelStakeModifier(pindexFrom->GetBlockHash(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, false)) - return error("CheckStakeKernelHash(): failed to get kernel stake modifier \n"); - - return true; -} - -CDataStream CDapsStake::GetUniqueness() -{ - //The unique identifier for a DAPS stake is the outpoint - CDataStream ss(SER_NETWORK, 0); - ss << nPosition << txFrom.GetHash(); - return ss; -} - -//The block that the UTXO was added to the chain -CBlockIndex* CDapsStake::GetIndexFrom() -{ - uint256 hashBlock = 0; - CTransaction tx; - if (GetTransaction(txFrom.GetHash(), tx, hashBlock, true)) { - // If the index is in the chain, then set it as the "index from" - if (mapBlockIndex.count(hashBlock)) { - CBlockIndex* pindex = mapBlockIndex.at(hashBlock); - if (chainActive.Contains(pindex)) - pindexFrom = pindex; - } - } else { - LogPrintf("%s : failed to find tx %s\n", __func__, txFrom.GetHash().GetHex()); - } - - return pindexFrom; -} diff --git a/src/stakeinput.h b/src/stakeinput.h deleted file mode 100644 index 7c9899471f..0000000000 --- a/src/stakeinput.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef DAPScoin_STAKEINPUT_H -#define DAPScoin_STAKEINPUT_H - -class CKeyStore; -class CWallet; -class CWalletTx; - -class CStakeInput -{ -protected: - CBlockIndex* pindexFrom; - -public: - virtual ~CStakeInput(){}; - virtual CBlockIndex* GetIndexFrom() = 0; - virtual bool CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut = 0) = 0; - virtual bool GetTxFrom(CTransaction& tx) = 0; - virtual CAmount GetValue() = 0; - virtual bool CreateTxOuts(CWallet* pwallet, vector& vout, CAmount nTotal) = 0; - virtual bool GetModifier(uint64_t& nStakeModifier) = 0; - virtual CDataStream GetUniqueness() = 0; -}; - - -class CDapsStake : public CStakeInput -{ -private: - CTransaction txFrom; - unsigned int nPosition; -public: - CDapsStake() - { - this->pindexFrom = nullptr; - } - - bool SetInput(CTransaction txPrev, unsigned int n); - - CBlockIndex* GetIndexFrom() override; - bool GetTxFrom(CTransaction& tx) override; - CAmount GetValue() override; - bool GetModifier(uint64_t& nStakeModifier) override; - CDataStream GetUniqueness() override; - bool CreateTxIn(CWallet* pwallet, CTxIn& txIn, uint256 hashTxOut = 0) override; - bool CreateTxOuts(CWallet* pwallet, vector& vout, CAmount nTotal) override; -}; - - -#endif //DAPScoin_STAKEINPUT_H diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp deleted file mode 100644 index f5e437458d..0000000000 --- a/src/test/arith_uint256_tests.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright (c) 2011-2013 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include "uint256.h" -#include "arith_uint256.h" -#include -#include "version.h" - -#ifdef DISABLE_PASSED_TEST -BOOST_AUTO_TEST_SUITE(arith_uint256_tests) -///BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) - -/// Convert vector to arith_uint256, via uint256 blob -inline arith_uint256 arith_uint256V(const std::vector& vch) -{ - return UintToArith256(uint256(vch)); -} - -const unsigned char R1Array[] = - "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" - "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; -const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; -const double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256 -const arith_uint256 R1L = arith_uint256V(std::vector(R1Array,R1Array+32)); -const uint64_t R1LLow64 = 0x121156cfdb4a529cULL; - -const unsigned char R2Array[] = - "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" - "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; -const arith_uint256 R2L = arith_uint256V(std::vector(R2Array,R2Array+32)); - -const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; - -const unsigned char ZeroArray[] = - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; -const arith_uint256 ZeroL = arith_uint256V(std::vector(ZeroArray,ZeroArray+32)); - -const unsigned char OneArray[] = - "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; -const arith_uint256 OneL = arith_uint256V(std::vector(OneArray,OneArray+32)); - -const unsigned char MaxArray[] = - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; -const arith_uint256 MaxL = arith_uint256V(std::vector(MaxArray,MaxArray+32)); - -const arith_uint256 HalfL = (OneL << 255); -std::string ArrayToString(const unsigned char A[], unsigned int width) -{ - std::stringstream Stream; - Stream << std::hex; - for (unsigned int i = 0; i < width; ++i) - { - Stream<): - BOOST_CHECK(R1L.ToString() == ArrayToString(R1Array,32)); - BOOST_CHECK(R2L.ToString() == ArrayToString(R2Array,32)); - BOOST_CHECK(ZeroL.ToString() == ArrayToString(ZeroArray,32)); - BOOST_CHECK(OneL.ToString() == ArrayToString(OneArray,32)); - BOOST_CHECK(MaxL.ToString() == ArrayToString(MaxArray,32)); - BOOST_CHECK(OneL.ToString() != ArrayToString(ZeroArray,32)); - - // == and != - BOOST_CHECK(R1L != R2L); - BOOST_CHECK(ZeroL != OneL); - BOOST_CHECK(OneL != ZeroL); - BOOST_CHECK(MaxL != ZeroL); - BOOST_CHECK(~MaxL == ZeroL); - BOOST_CHECK( ((R1L ^ R2L) ^ R1L) == R2L); - - uint64_t Tmp64 = 0xc4dab720d9c7acaaULL; - for (unsigned int i = 0; i < 256; ++i) - { - BOOST_CHECK(ZeroL != (OneL << i)); - BOOST_CHECK((OneL << i) != ZeroL); - BOOST_CHECK(R1L != (R1L ^ (OneL << i))); - BOOST_CHECK(((arith_uint256(Tmp64) ^ (OneL << i) ) != Tmp64 )); - } - BOOST_CHECK(ZeroL == (OneL << 256)); - - // String Constructor and Copy Constructor - BOOST_CHECK(arith_uint256("0x"+R1L.ToString()) == R1L); - BOOST_CHECK(arith_uint256("0x"+R2L.ToString()) == R2L); - BOOST_CHECK(arith_uint256("0x"+ZeroL.ToString()) == ZeroL); - BOOST_CHECK(arith_uint256("0x"+OneL.ToString()) == OneL); - BOOST_CHECK(arith_uint256("0x"+MaxL.ToString()) == MaxL); - BOOST_CHECK(arith_uint256(R1L.ToString()) == R1L); - BOOST_CHECK(arith_uint256(" 0x"+R1L.ToString()+" ") == R1L); - BOOST_CHECK(arith_uint256("") == ZeroL); - BOOST_CHECK(R1L == arith_uint256(R1ArrayHex)); - BOOST_CHECK(arith_uint256(R1L) == R1L); - BOOST_CHECK((arith_uint256(R1L^R2L)^R2L) == R1L); - BOOST_CHECK(arith_uint256(ZeroL) == ZeroL); - BOOST_CHECK(arith_uint256(OneL) == OneL); - - // uint64_t constructor - BOOST_CHECK( (R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64)); - BOOST_CHECK(ZeroL == arith_uint256(0)); - BOOST_CHECK(OneL == arith_uint256(1)); - BOOST_CHECK(arith_uint256("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL)); - - // Assignment (from base_uint) - arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL); - tmpL = ~OneL; BOOST_CHECK(tmpL == ~OneL); - tmpL = ~R1L; BOOST_CHECK(tmpL == ~R1L); - tmpL = ~R2L; BOOST_CHECK(tmpL == ~R2L); - tmpL = ~MaxL; BOOST_CHECK(tmpL == ~MaxL); -} - -void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) -{ - for (unsigned int T=0; T < arrayLength; ++T) - { - unsigned int F = (T+bitsToShift/8); - if (F < arrayLength) - to[T] = from[F] >> (bitsToShift%8); - else - to[T] = 0; - if (F + 1 < arrayLength) - to[T] |= from[(F+1)] << (8-bitsToShift%8); - } -} - -void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) -{ - for (unsigned int T=0; T < arrayLength; ++T) - { - if (T >= bitsToShift/8) - { - unsigned int F = T-bitsToShift/8; - to[T] = from[F] << (bitsToShift%8); - if (T >= bitsToShift/8+1) - to[T] |= from[F-1] >> (8-bitsToShift%8); - } - else { - to[T] = 0; - } - } -} - -BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>=" - unsigned char TmpArray[32]; - arith_uint256 TmpL; - for (unsigned int i = 0; i < 256; ++i) - { - shiftArrayLeft(TmpArray, OneArray, 32, i); - BOOST_CHECK(arith_uint256V(std::vector(TmpArray,TmpArray+32)) == (OneL << i)); - TmpL = OneL; TmpL <<= i; - BOOST_CHECK(TmpL == (OneL << i)); - BOOST_CHECK((HalfL >> (255-i)) == (OneL << i)); - TmpL = HalfL; TmpL >>= (255-i); - BOOST_CHECK(TmpL == (OneL << i)); - - shiftArrayLeft(TmpArray, R1Array, 32, i); - BOOST_CHECK(arith_uint256V(std::vector(TmpArray,TmpArray+32)) == (R1L << i)); - TmpL = R1L; TmpL <<= i; - BOOST_CHECK(TmpL == (R1L << i)); - - shiftArrayRight(TmpArray, R1Array, 32, i); - BOOST_CHECK(arith_uint256V(std::vector(TmpArray,TmpArray+32)) == (R1L >> i)); - TmpL = R1L; TmpL >>= i; - BOOST_CHECK(TmpL == (R1L >> i)); - - shiftArrayLeft(TmpArray, MaxArray, 32, i); - BOOST_CHECK(arith_uint256V(std::vector(TmpArray,TmpArray+32)) == (MaxL << i)); - TmpL = MaxL; TmpL <<= i; - BOOST_CHECK(TmpL == (MaxL << i)); - - shiftArrayRight(TmpArray, MaxArray, 32, i); - BOOST_CHECK(arith_uint256V(std::vector(TmpArray,TmpArray+32)) == (MaxL >> i)); - TmpL = MaxL; TmpL >>= i; - BOOST_CHECK(TmpL == (MaxL >> i)); - } - arith_uint256 c1L = arith_uint256(0x0123456789abcdefULL); - arith_uint256 c2L = c1L << 128; - for (unsigned int i = 0; i < 128; ++i) { - BOOST_CHECK((c1L << i) == (c2L >> (128-i))); - } - for (unsigned int i = 128; i < 256; ++i) { - BOOST_CHECK((c1L << i) == (c2L << (i-128))); - } -} - -BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ - -{ - BOOST_CHECK(!ZeroL); - BOOST_CHECK(!(!OneL)); - for (unsigned int i = 0; i < 256; ++i) - BOOST_CHECK(!(!(OneL<(TmpArray,TmpArray+32)) == (~R1L)); - - BOOST_CHECK(-ZeroL == ZeroL); - BOOST_CHECK(-R1L == (~R1L)+1); - for (unsigned int i = 0; i < 256; ++i) - BOOST_CHECK(-(OneL<(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L)); - -#define CHECKASSIGNMENTOPERATOR(_A_,_B_,_OP_) \ - TmpL = _A_##L; TmpL _OP_##= _B_##L; BOOST_CHECK(TmpL == (_A_##L _OP_ _B_##L)); - -BOOST_AUTO_TEST_CASE( bitwiseOperators ) -{ - unsigned char TmpArray[32]; - - CHECKBITWISEOPERATOR(R1,R2,|) - CHECKBITWISEOPERATOR(R1,R2,^) - CHECKBITWISEOPERATOR(R1,R2,&) - CHECKBITWISEOPERATOR(R1,Zero,|) - CHECKBITWISEOPERATOR(R1,Zero,^) - CHECKBITWISEOPERATOR(R1,Zero,&) - CHECKBITWISEOPERATOR(R1,Max,|) - CHECKBITWISEOPERATOR(R1,Max,^) - CHECKBITWISEOPERATOR(R1,Max,&) - CHECKBITWISEOPERATOR(Zero,R1,|) - CHECKBITWISEOPERATOR(Zero,R1,^) - CHECKBITWISEOPERATOR(Zero,R1,&) - CHECKBITWISEOPERATOR(Max,R1,|) - CHECKBITWISEOPERATOR(Max,R1,^) - CHECKBITWISEOPERATOR(Max,R1,&) - - arith_uint256 TmpL; - CHECKASSIGNMENTOPERATOR(R1,R2,|) - CHECKASSIGNMENTOPERATOR(R1,R2,^) - CHECKASSIGNMENTOPERATOR(R1,R2,&) - CHECKASSIGNMENTOPERATOR(R1,Zero,|) - CHECKASSIGNMENTOPERATOR(R1,Zero,^) - CHECKASSIGNMENTOPERATOR(R1,Zero,&) - CHECKASSIGNMENTOPERATOR(R1,Max,|) - CHECKASSIGNMENTOPERATOR(R1,Max,^) - CHECKASSIGNMENTOPERATOR(R1,Max,&) - CHECKASSIGNMENTOPERATOR(Zero,R1,|) - CHECKASSIGNMENTOPERATOR(Zero,R1,^) - CHECKASSIGNMENTOPERATOR(Zero,R1,&) - CHECKASSIGNMENTOPERATOR(Max,R1,|) - CHECKASSIGNMENTOPERATOR(Max,R1,^) - CHECKASSIGNMENTOPERATOR(Max,R1,&) - - uint64_t Tmp64 = 0xe1db685c9a0b47a2ULL; - TmpL = R1L; TmpL |= Tmp64; BOOST_CHECK(TmpL == (R1L | arith_uint256(Tmp64))); - TmpL = R1L; TmpL |= 0; BOOST_CHECK(TmpL == R1L); - TmpL ^= 0; BOOST_CHECK(TmpL == R1L); - TmpL ^= Tmp64; BOOST_CHECK(TmpL == (R1L ^ arith_uint256(Tmp64))); -} - -BOOST_AUTO_TEST_CASE( comparison ) // <= >= < > -{ - arith_uint256 TmpL; - for (unsigned int i = 0; i < 256; ++i) { - TmpL= OneL<< i; - BOOST_CHECK( TmpL >= ZeroL && TmpL > ZeroL && ZeroL < TmpL && ZeroL <= TmpL); - BOOST_CHECK( TmpL >= 0 && TmpL > 0 && 0 < TmpL && 0 <= TmpL); - TmpL |= R1L; - BOOST_CHECK( TmpL >= R1L ); BOOST_CHECK( (TmpL == R1L) != (TmpL > R1L)); BOOST_CHECK( (TmpL == R1L) || !( TmpL <= R1L)); - BOOST_CHECK( R1L <= TmpL ); BOOST_CHECK( (R1L == TmpL) != (R1L < TmpL)); BOOST_CHECK( (TmpL == R1L) || !( R1L >= TmpL)); - BOOST_CHECK(! (TmpL < R1L)); BOOST_CHECK(! (R1L > TmpL)); - } -} - -BOOST_AUTO_TEST_CASE( plusMinus ) -{ - arith_uint256 TmpL = 0; - BOOST_CHECK(R1L+R2L == arith_uint256(R1LplusR2L)); - TmpL += R1L; - BOOST_CHECK(TmpL == R1L); - TmpL += R2L; - BOOST_CHECK(TmpL == R1L + R2L); - BOOST_CHECK(OneL+MaxL == ZeroL); - BOOST_CHECK(MaxL+OneL == ZeroL); - for (unsigned int i = 1; i < 256; ++i) { - BOOST_CHECK( (MaxL >> i) + OneL == (HalfL >> (i-1)) ); - BOOST_CHECK( OneL + (MaxL >> i) == (HalfL >> (i-1)) ); - TmpL = (MaxL>>i); TmpL += OneL; - BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); - TmpL = (MaxL>>i); TmpL += 1; - BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); - TmpL = (MaxL>>i); - BOOST_CHECK( TmpL++ == (MaxL>>i) ); - BOOST_CHECK( TmpL == (HalfL >> (i-1))); - } - BOOST_CHECK(arith_uint256(0xbedc77e27940a7ULL) + 0xee8d836fce66fbULL == arith_uint256(0xbedc77e27940a7ULL + 0xee8d836fce66fbULL)); - TmpL = arith_uint256(0xbedc77e27940a7ULL); TmpL += 0xee8d836fce66fbULL; - BOOST_CHECK(TmpL == arith_uint256(0xbedc77e27940a7ULL+0xee8d836fce66fbULL)); - TmpL -= 0xee8d836fce66fbULL; BOOST_CHECK(TmpL == 0xbedc77e27940a7ULL); - TmpL = R1L; - BOOST_CHECK(++TmpL == R1L+1); - - BOOST_CHECK(R1L -(-R2L) == R1L+R2L); - BOOST_CHECK(R1L -(-OneL) == R1L+OneL); - BOOST_CHECK(R1L - OneL == R1L+(-OneL)); - for (unsigned int i = 1; i < 256; ++i) { - BOOST_CHECK((MaxL>>i) - (-OneL) == (HalfL >> (i-1))); - BOOST_CHECK((HalfL >> (i-1)) - OneL == (MaxL>>i)); - TmpL = (HalfL >> (i-1)); - BOOST_CHECK(TmpL-- == (HalfL >> (i-1))); - BOOST_CHECK(TmpL == (MaxL >> i)); - TmpL = (HalfL >> (i-1)); - BOOST_CHECK(--TmpL == (MaxL >> i)); - } - TmpL = R1L; - BOOST_CHECK(--TmpL == R1L-1); -} - -BOOST_AUTO_TEST_CASE( multiply ) -{ - BOOST_CHECK((R1L * R1L).ToString() == "62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10"); - BOOST_CHECK((R1L * R2L).ToString() == "de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40"); - BOOST_CHECK((R1L * ZeroL) == ZeroL); - BOOST_CHECK((R1L * OneL) == R1L); - BOOST_CHECK((R1L * MaxL) == -R1L); - BOOST_CHECK((R2L * R1L) == (R1L * R2L)); - BOOST_CHECK((R2L * R2L).ToString() == "ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100"); - BOOST_CHECK((R2L * ZeroL) == ZeroL); - BOOST_CHECK((R2L * OneL) == R2L); - BOOST_CHECK((R2L * MaxL) == -R2L); - - BOOST_CHECK(MaxL * MaxL == OneL); - - BOOST_CHECK((R1L * 0) == 0); - BOOST_CHECK((R1L * 1) == R1L); - BOOST_CHECK((R1L * 3).ToString() == "7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4"); - BOOST_CHECK((R2L * 0x87654321UL).ToString() == "23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070"); -} - -BOOST_AUTO_TEST_CASE( divide ) -{ - arith_uint256 D1L("AD7133AC1977FA2B7"); - arith_uint256 D2L("ECD751716"); - BOOST_CHECK((R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); - BOOST_CHECK((R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); - BOOST_CHECK(R1L / OneL == R1L); - BOOST_CHECK(R1L / MaxL == ZeroL); - BOOST_CHECK(MaxL / R1L == 2); - BOOST_CHECK_THROW(R1L / ZeroL, uint_error); - BOOST_CHECK((R2L / D1L).ToString() == "000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5"); - BOOST_CHECK((R2L / D2L).ToString() == "000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4"); - BOOST_CHECK(R2L / OneL == R2L); - BOOST_CHECK(R2L / MaxL == ZeroL); - BOOST_CHECK(MaxL / R2L == 1); - BOOST_CHECK_THROW(R2L / ZeroL, uint_error); -} - - -bool almostEqual(double d1, double d2) -{ - return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits::epsilon(); -} - -BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex size() GetLow64 GetSerializeSize, Serialize, Unserialize -{ - BOOST_CHECK(R1L.GetHex() == R1L.ToString()); - BOOST_CHECK(R2L.GetHex() == R2L.ToString()); - BOOST_CHECK(OneL.GetHex() == OneL.ToString()); - BOOST_CHECK(MaxL.GetHex() == MaxL.ToString()); - arith_uint256 TmpL(R1L); - BOOST_CHECK(TmpL == R1L); - TmpL.SetHex(R2L.ToString()); BOOST_CHECK(TmpL == R2L); - TmpL.SetHex(ZeroL.ToString()); BOOST_CHECK(TmpL == 0); - TmpL.SetHex(HalfL.ToString()); BOOST_CHECK(TmpL == HalfL); - - TmpL.SetHex(R1L.ToString()); - BOOST_CHECK(R1L.size() == 32); - BOOST_CHECK(R2L.size() == 32); - BOOST_CHECK(ZeroL.size() == 32); - BOOST_CHECK(MaxL.size() == 32); - BOOST_CHECK(R1L.GetLow64() == R1LLow64); - BOOST_CHECK(HalfL.GetLow64() ==0x0000000000000000ULL); - BOOST_CHECK(OneL.GetLow64() ==0x0000000000000001ULL); - - for (unsigned int i = 0; i < 255; ++i) - { - BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0,i)); - } - BOOST_CHECK(ZeroL.getdouble() == 0.0); - for (int i = 256; i > 53; --i) - BOOST_CHECK(almostEqual((R1L>>(256-i)).getdouble(), ldexp(R1Ldouble,i))); - uint64_t R1L64part = (R1L>>192).GetLow64(); - for (int i = 53; i > 0; --i) // doubles can store all integers in {0,...,2^54-1} exactly - { - BOOST_CHECK((R1L>>(256-i)).getdouble() == (double)(R1L64part >> (64-i))); - } -} - -BOOST_AUTO_TEST_CASE(bignum_SetCompact) -{ - arith_uint256 num; - bool fNegative; - bool fOverflow; - num.SetCompact(0, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x00123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x01003456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x02000056, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x03000000, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x04000000, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x00923456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x01803456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x02800056, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x03800000, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x04800000, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x01123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000012"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - // Make sure that we don't generate compacts with the 0x00800000 bit set - num = 0x80; - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); - - num.SetCompact(0x01fedcba, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "000000000000000000000000000000000000000000000000000000000000007e"); - BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U); - BOOST_CHECK_EQUAL(fNegative, true); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x02123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000001234"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x03123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000123456"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x04123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x04923456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); - BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U); - BOOST_CHECK_EQUAL(fNegative, true); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x05009234, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000092340000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0x20123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, false); - - num.SetCompact(0xff123456, &fNegative, &fOverflow); - BOOST_CHECK_EQUAL(fNegative, false); - BOOST_CHECK_EQUAL(fOverflow, true); -} - - -BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% coverage -{ - // ~R1L give a base_uint<256> - BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); - BOOST_CHECK((~~R1L << 10) == (R1L << 10)); - BOOST_CHECK(!(~~R1L < R1L)); - BOOST_CHECK(~~R1L <= R1L); - BOOST_CHECK(!(~~R1L > R1L)); - BOOST_CHECK(~~R1L >= R1L); - BOOST_CHECK(!(R1L < ~~R1L)); - BOOST_CHECK(R1L <= ~~R1L); - BOOST_CHECK(!(R1L > ~~R1L)); - BOOST_CHECK(R1L >= ~~R1L); - - BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L); - BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L); - BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); - unsigned char TmpArray[32]; - CHECKBITWISEOPERATOR(~R1,R2,|) - CHECKBITWISEOPERATOR(~R1,R2,^) - CHECKBITWISEOPERATOR(~R1,R2,&) - CHECKBITWISEOPERATOR(R1,~R2,|) - CHECKBITWISEOPERATOR(R1,~R2,^) - CHECKBITWISEOPERATOR(R1,~R2,&) -} - -BOOST_AUTO_TEST_SUITE_END() -#endif \ No newline at end of file diff --git a/src/uint512.h b/src/uint512.h deleted file mode 100644 index 8186c8961a..0000000000 --- a/src/uint512.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2020 The DAPS Project developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once -#include "arith_uint256.h" -#include "uint256.h" - -/** 512-bit unsigned big integer. */ -class uint512 : public base_blob<512> -{ -public: - uint512() {} - uint512(const base_blob<512>& b) : base_blob<512>(b) {} - explicit uint512(const std::vector& vch) : base_blob<512>(vch) {} - - uint256 trim256() const - { - std::vector vch; - const unsigned char* p = this->begin(); - for (unsigned int i = 0; i < 32; i++) { - vch.push_back(*p++); - } - uint256 retval(vch); - return retval; - } -}; - - -/* uint256 from const char *. - * This is a separate function because the constructor uint256(const char*) can result - * in dangerously catching uint256(0). - */ -inline uint512 uint512S(const char* str) -{ - uint512 rv; - rv.SetHex(str); - return rv; -} From ae8d913b47406ac71c7027d09d3b076c6b4a6c51 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 30 Nov 2020 14:44:38 -0500 Subject: [PATCH 0518/1888] Remove duplicate include --- src/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5b736c831b..737a2e41b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -192,8 +192,7 @@ BITCOIN_CORE_H = \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h \ zmq/zmqnotificationinterface.h \ - zmq/zmqpublishnotifier.h \ - compat/sanity.h + zmq/zmqpublishnotifier.h obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj From cdaba3445f794e6dc28a5f8024e76ae6da739212 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Nov 2020 17:34:27 -0500 Subject: [PATCH 0519/1888] Update Fix Date to December 12 --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4e74eeee68..7dcbe5a452 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -204,7 +204,7 @@ class CMainParams : public CChainParams nMaxNumPoSBlocks = 120; nSoftForkBlock = 125000; // Soft fork block for difficulty change nHardForkBlock = 670000; // Hard fork block for PoA updates - nPoAFixTime = 1606780800; // Hard fork time for PoA fix - Tuesday, December 1, 2020 12:00:00 AM (GMT) + nPoAFixTime = 1607731200; // Hard fork time for PoA fix - Saturday, December 12, 2020 12:00:00 AM (GMT) /** * Build the genesis block. Note that the output of the genesis coinbase cannot From 19ff6cfe500efcceac9bc1c5a4a9ca6fbb09aac0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 1 Dec 2020 15:49:37 -0500 Subject: [PATCH 0520/1888] Fix warning: '&&' within '||' --- src/poa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/poa.cpp b/src/poa.cpp index 99d8c80996..9f6d5ceec7 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -248,7 +248,7 @@ bool CheckPoAContainRecentHash(const CBlock& block) while(pIndexLoop && !pIndexLoop->IsProofOfStake()) { pIndexLoop = pIndexLoop->pprev; } - if (!pIndexLoop || pIndexLoop->GetBlockHash() != lastAuditedPoSHash && !IsFixedAudit(fixedPoSAuditedHash.GetHex())) { + if (!pIndexLoop || (pIndexLoop->GetBlockHash() != lastAuditedPoSHash && !IsFixedAudit(fixedPoSAuditedHash.GetHex()))) { return error("CheckPoAContainRecentHash(): Some PoS block between %s and %s is not audited\n", lastAuditedPoSHash.GetHex(), currentFirstPoSAuditedHash.GetHex()); } From d665b74c8c8fa879f0506dc6bc666bfba1221564 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 9 Dec 2020 09:38:33 -0500 Subject: [PATCH 0521/1888] Update Fix Date to December 29 To better align with exchanges and partners Tuesday, December 29, 2020 12:00:00 AM --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7dcbe5a452..1762d84c25 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -204,7 +204,7 @@ class CMainParams : public CChainParams nMaxNumPoSBlocks = 120; nSoftForkBlock = 125000; // Soft fork block for difficulty change nHardForkBlock = 670000; // Hard fork block for PoA updates - nPoAFixTime = 1607731200; // Hard fork time for PoA fix - Saturday, December 12, 2020 12:00:00 AM (GMT) + nPoAFixTime = 1609200000; // Hard fork time for PoA fix - Tuesday, December 29, 2020 12:00:00 AM (GMT) /** * Build the genesis block. Note that the output of the genesis coinbase cannot From be93f643107e4727b186eaa50aa2dc71d2f75413 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 10 Dec 2020 11:47:58 -0500 Subject: [PATCH 0522/1888] [Build] Add GitHub Action Script --- .github/workflows/daps-build-factory.yml | 332 +++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 .github/workflows/daps-build-factory.yml diff --git a/.github/workflows/daps-build-factory.yml b/.github/workflows/daps-build-factory.yml new file mode 100644 index 0000000000..f4c2175a4e --- /dev/null +++ b/.github/workflows/daps-build-factory.yml @@ -0,0 +1,332 @@ +# Copyright (c) 2018-2020 The Veil developers +# Copyright (c) 2020 The DAPS Project +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +name: Github Actions CI for DAPS +on: [push, pull_request] +env: + SOURCE_ARTIFACT: source +jobs: + create-source-distribution: + name: Create Source Distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: source + steps: + - name: Checkout + uses: actions/checkout@v2 + # May need qt and protobuf to configure qt and include dapscoin-qt.1 in distribution + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 + sudo apt-get install -y libssl1.0-dev libzmq5 libgmp-dev libevent-dev libboost-all-dev libsodium-dev cargo + sudo apt-get install -y libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libqrencode-dev + sudo apt-get install -y software-properties-common g++-multilib binutils-gold patch + sudo add-apt-repository ppa:pivx/pivx + sudo apt-get update + sudo apt-get install -y libdb4.8-dev libdb4.8++-dev + - name: Create Distribution Tarball + run: | + mkdir -p $ARTIFACT_DIR + touch dapscoin.tar.gz + tar -czf dapscoin.tar.gz --exclude=dapscoin.tar.gz . + - name: Download Dependencies + run: make -C depends download + - name: Create Dependencies Tarball + run: tar -czf depends.tar.gz depends + - name: Prepare Files for Artifact + run: | + mv depends.tar.gz dapscoin.tar.gz $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + path: ${{ env.ARTIFACT_DIR }} + build-x86_64-linux: + name: Build for x86 Linux 64bit + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: x86_64-linux-binaries + TEST_LOG_ARTIFACT_DIR: test-logs + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y python3-zmq + - name: Build Dependencies + run: make -C depends -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-pc-linux-gnu) + make -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} + mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-win64: + name: Build for Win64 + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: win64-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 nsis + - name: Switch MinGW GCC and G++ to POSIX Threading + run: | + sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix + sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix + - name: Build Dependencies + run: make -C depends -j$(nproc) HOST=x86_64-w64-mingw32 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-w64-mingw32) + make -j$(nproc) + make deploy -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{dapscoin-cli.exe,dapscoin-tx.exe,dapscoind.exe,qt/dapscoin-qt.exe} + mv $SOURCE_ARTIFACT/{dapscoin-*.exe,src/dapscoin-cli.exe,src/dapscoin-tx.exe,src/dapscoind.exe,src/qt/dapscoin-qt.exe} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-win32: + name: Build for Win32 + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: win32-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y g++-mingw-w64-i686 mingw-w64-i686-dev nsis + - name: Switch MinGW GCC and G++ to POSIX Threading + run: | + sudo update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix + - name: Build Dependencies + run: make -C depends -j$(nproc) HOST=i686-w64-mingw32 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/i686-w64-mingw32) + make -j$(nproc) + make deploy -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{dapscoin-cli.exe,dapscoin-tx.exe,dapscoind.exe,qt/dapscoin-qt.exe} + mv $SOURCE_ARTIFACT/{dapscoin-*.exe,src/dapscoin-cli.exe,src/dapscoin-tx.exe,src/dapscoind.exe,src/qt/dapscoin-qt.exe} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-osx64: + name: Build for MacOSX + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: macosx-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y python3-setuptools libcap-dev zlib1g-dev cmake librsvg2-bin libtiff-tools imagemagick libz-dev libbz2-dev libtinfo5 + - name: Get macOS SDK + run: | + mkdir -p depends/sdk-sources + mkdir -p depends/SDKs + curl https://bitcoincore.org/depends-sources/sdks/MacOSX10.11.sdk.tar.gz -o depends/sdk-sources/MacOSX10.11.sdk.tar.gz + tar -C depends/SDKs -xf depends/sdk-sources/MacOSX10.11.sdk.tar.gz + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build Dependencies + run: make -C depends HOST=x86_64-apple-darwin16 -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-apple-darwin16) + make -j$(nproc) + make deploy -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + mv $SOURCE_ARTIFACT/{*.dmg,src/dapscoin-cli,src/dapscoin-tx,src/dapscoind,src/qt/dapscoin-qt} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-aarch64-linux: + name: Build for ARM Linux 64bit + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: aarch64-linux-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y python3-zmq libcap-dev cmake g++-aarch64-linux-gnu + - name: Build Dependencies + run: make -C depends HOST=aarch64-linux-gnu -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/aarch64-linux-gnu) + make -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-arm-linux-gnueabihf: + name: Build for ARM Linux 32bit + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: arm32-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y g++-arm-linux-gnueabihf libzmq5 libgmp-dev + - name: Build Dependencies + run: make -C depends -j$(nproc) HOST=arm-linux-gnueabihf + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/arm-linux-gnueabihf) --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ + make -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} + build-riscv64-linux-gnu: + name: Build for RISC-V 64-bit + needs: create-source-distribution + runs-on: ubuntu-18.04 + env: + ARTIFACT_DIR: riscv64-binaries + steps: + - name: Getting Source + uses: actions/download-artifact@v1 + with: + name: ${{ env.SOURCE_ARTIFACT }} + - name: Extract Archives + run: | + tar -xzf depends.tar.gz + tar -xzf dapscoin.tar.gz --strip-components=1 + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Install Required Packages + run: | + sudo apt-get update + sudo apt-get install -y g++-riscv64-linux-gnu binutils-riscv64-linux-gnu + - name: Build Dependencies + run: make -C depends -j$(nproc) HOST=riscv64-linux-gnu + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Build DAPS + run: | + ./autogen.sh + ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/riscv64-linux-gnu) --enable-reduce-exports LDFLAGS=-static-libstdc++ + make -j$(nproc) + working-directory: ${{ env.SOURCE_ARTIFACT }} + - name: Prepare Files for Artifact + run: | + mkdir -p $ARTIFACT_DIR + mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + - name: Upload Artifact + uses: actions/upload-artifact@v1 + with: + name: ${{ env.ARTIFACT_DIR }} + path: ${{ env.ARTIFACT_DIR }} From c9a6616a97931b88b03d068b9f0a64114e8ecd0e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 15 Dec 2020 10:45:27 -0500 Subject: [PATCH 0523/1888] Remove PoAFixTime() No longer required after Dec 29 --- src/chainparams.cpp | 1 - src/chainparams.h | 2 -- src/net.cpp | 6 +----- src/poa.cpp | 7 +------ 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1762d84c25..a6acc5bb0b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -204,7 +204,6 @@ class CMainParams : public CChainParams nMaxNumPoSBlocks = 120; nSoftForkBlock = 125000; // Soft fork block for difficulty change nHardForkBlock = 670000; // Hard fork block for PoA updates - nPoAFixTime = 1609200000; // Hard fork time for PoA fix - Tuesday, December 29, 2020 12:00:00 AM (GMT) /** * Build the genesis block. Note that the output of the genesis coinbase cannot diff --git a/src/chainparams.h b/src/chainparams.h index 0cfe04252a..8f21203022 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -105,7 +105,6 @@ class CChainParams int Block_Enforce_Invalid() const { return nBlockEnforceInvalidUTXO; } int SoftFork() const { return nSoftForkBlock;} int HardFork() const { return nHardForkBlock;} - int PoAFixTime() const { return nPoAFixTime;} //For PoA block time int POA_BLOCK_TIME() const { return nPoABlockTime; } @@ -135,7 +134,6 @@ class CChainParams int nStartPOABlock; int nSoftForkBlock; int nHardForkBlock; - int nPoAFixTime; int nMasternodeCountDrift; int nMaturity; int nModifierUpdateBlock; diff --git a/src/net.cpp b/src/net.cpp index 9b2bef6815..a3751bfb42 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -126,11 +126,7 @@ unsigned short GetListenPort() { } bool IsUnsupportedVersion(std::string strSubVer) { - std::time_t banningTime = std::time(0); // t is an integer type - if (banningTime >= Params().PoAFixTime()) { - return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/" || strSubVer == "/DAPS:1.0.8/" || strSubVer == "/DAPS:1.0.8.1/" || strSubVer == "/DAPS:1.0.8.2/"); - } - return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/"); + return (strSubVer == "/DAPScoin:0.27.5.1/" || strSubVer == "/DAPScoin:1.0.0/" || strSubVer == "/DAPScoin:1.0.1/" || strSubVer == "/DAPS:1.0.1.3/" || strSubVer == "/DAPS:1.0.2/" || strSubVer == "/DAPS:1.0.3.4/" || strSubVer == "/DAPS:1.0.4.6/" || strSubVer == "/DAPS:1.0.5.7/" || strSubVer == "/DAPS:1.0.5.8/" || strSubVer == "/DAPS:1.0.6.5/" || strSubVer == "/DAPS:1.0.6.6/" || strSubVer == "/DAPS:1.0.7.1/" || strSubVer == "/DAPS:1.0.8/" || strSubVer == "/DAPS:1.0.8.1/" || strSubVer == "/DAPS:1.0.8.2/"); } // find 'best' local address for a particular peer diff --git a/src/poa.cpp b/src/poa.cpp index 9f6d5ceec7..c53fd255fa 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -472,10 +472,5 @@ bool CheckPoABlockRewardAmount(const CBlock& block, const CBlockIndex* pindex) } bool IsFixedAudit(std::string txid) { - std::time_t fixedTime = std::time(0); - if (fixedTime >= Params().PoAFixTime()) { - //Currently only one - return (txid == "ff67a6645a36a82a3885c989951680917c9e2de90f59665c8130701ccdcbb9f9"); - } - return (txid == ""); + return (txid == "ff67a6645a36a82a3885c989951680917c9e2de90f59665c8130701ccdcbb9f9"); } From eadb166c84a6e89275fe49c87991533627602fe0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 15 Dec 2020 20:58:07 -0500 Subject: [PATCH 0524/1888] Remove dead seeds --- src/chainparams.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1762d84c25..6487029868 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -274,10 +274,6 @@ class CMainParams : public CChainParams vSeeds.push_back(CDNSSeedData("seed3.dapscoin.com", "seed3.dapscoin.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed4.dapscoin.com", "seed4.dapscoin.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed5.dapscoin.com", "seed5.dapscoin.com")); // Single node address - vSeeds.push_back(CDNSSeedData("seed6.dapscoin.com", "seed6.dapscoin.com")); // Single node address - vSeeds.push_back(CDNSSeedData("seed7.dapscoin.com", "seed7.dapscoin.com")); // Single node address - vSeeds.push_back(CDNSSeedData("seed8.dapscoin.com", "seed8.dapscoin.com")); // Single node address - vSeeds.push_back(CDNSSeedData("seed9.dapscoin.com", "seed9.dapscoin.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed.dapscoin-seeds.com", "seed.dapscoin-seeds.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed1.dapscoin-seeds.com", "seed1.dapscoin-seeds.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed2.dapscoin-seeds.com", "seed2.dapscoin-seeds.com")); // Single node address From 0388b154e22a505bd264af7f743660ec1bd8e8a0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 20 Dec 2020 22:30:11 -0500 Subject: [PATCH 0525/1888] Bump version to v1.0.9.1 --- configure.ac | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 24c17d5968..34eab12f6b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 9) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/version.txt b/version.txt index c92efd02dc..1a68d8d3a4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.9.0 \ No newline at end of file +1.0.9.1 \ No newline at end of file From aa9b806847520f6ac3b14a9368233110d62c7196 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 19 Dec 2020 18:10:23 -0500 Subject: [PATCH 0526/1888] Add fAlwaysRequest2FA to request 2FA before each send --- src/qt/forms/optionspage.ui | 9 ++++++++- src/qt/optionspage.cpp | 23 +++++++++++++++++++++++ src/qt/optionspage.h | 1 + src/qt/sendcoinsdialog.cpp | 9 +++++++-- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index dc3fc21e2f..eb2106a7f1 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -34,7 +34,7 @@ 0 0 806 - 565 + 588 @@ -207,6 +207,13 @@ + + + + Request authentication code before sending any transactions + + + diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index ae6a3ceb0e..bf8171289e 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -153,10 +153,12 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->mapPortUpnp->setChecked(settings.value("fUseUPnP", false).toBool()); ui->minimizeToTray->setChecked(settings.value("fMinimizeToTray", false).toBool()); ui->minimizeOnClose->setChecked(settings.value("fMinimizeOnClose", false).toBool()); + ui->alwaysRequest2FA->setChecked(settings.value("fAlwaysRequest2FA", false).toBool()); connect(ui->addNewFunds, SIGNAL(stateChanged(int)), this, SLOT(setAutoConsolidate(int))); connect(ui->mapPortUpnp, SIGNAL(stateChanged(int)), this, SLOT(mapPortUpnp_clicked(int))); connect(ui->minimizeToTray, SIGNAL(stateChanged(int)), this, SLOT(minimizeToTray_clicked(int))); connect(ui->minimizeOnClose, SIGNAL(stateChanged(int)), this, SLOT(minimizeOnClose_clicked(int))); + connect(ui->alwaysRequest2FA, SIGNAL(stateChanged(int)), this, SLOT(alwaysRequest2FA_clicked(int))); } void OptionsPage::setStakingToggle() @@ -987,3 +989,24 @@ void OptionsPage::changeDigits(int digit) digit = ui->comboBox->currentText().toInt(); settings.setValue("2fadigits", digit); } + + +void OptionsPage::alwaysRequest2FA_clicked(int state) +{ + int status = model->getEncryptionStatus(); + if (status == WalletModel::Locked || status == WalletModel::UnlockedForAnonymizationOnly) { + QMessageBox msgBox; + msgBox.setWindowTitle("2FA Settings"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText("Please unlock the keychain wallet with your passphrase before attempting to change this setting."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); + return; + } + bool twofastatus = pwalletMain->Read2FA(); + if (twofastatus && ui->alwaysRequest2FA->isChecked()) { + settings.setValue("fAlwaysRequest2FA", true); + } else { + settings.setValue("fAlwaysRequest2FA", false); + } +} diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index d901a29321..dac4a971c8 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -100,6 +100,7 @@ private Q_SLOTS: void minimizeToTray_clicked(int); void minimizeOnClose_clicked(int); void changeDigits(int); + void alwaysRequest2FA_clicked(int); }; #endif // BITCOIN_QT_OPTIONSPAGE_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 08d4dd7791..169cc3465b 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -153,6 +153,7 @@ void SendCoinsDialog::on_sendButton_clicked(){ send_amount = recipient.amount; bool isValidAddresss = (regex_match(address.toStdString(), regex("[a-zA-z0-9]+")))&&(address.length()==99||address.length()==110); bool isValidAmount = ((recipient.amount>0) && (recipient.amount<=model->getBalance())); + bool fAlwaysRequest2FA = settings.value("fAlwaysRequest2FA").toBool(); form->errorAddress(isValidAddresss); form->errorAmount(isValidAmount); @@ -214,9 +215,13 @@ void SendCoinsDialog::on_sendButton_clicked(){ CAmount totalAmount = send_amount + txFee; // Show total amount + all alternative units - questionString.append(tr("Total Amount = %1

      ") + questionString.append(tr("Total Amount = %1
      ") .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + if (fAlwaysRequest2FA) { + questionString.append("

      Note: Request 2FA authentication code before sending any transactions is enabled.
      You will be asked for your 2FA code on the next screen.

      "); + } + // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm Send Coins"), questionString.arg(formatted.join("
      ")), @@ -260,7 +265,7 @@ void SendCoinsDialog::on_sendButton_clicked(){ uint period = pwalletMain->Read2FAPeriod(); QDateTime current = QDateTime::currentDateTime(); uint diffTime = current.toTime_t() - lastTime; - if (diffTime <= period * 24 * 60 * 60) + if (diffTime <= period * 24 * 60 * 60 || !fAlwaysRequest2FA) sendTx(); else { TwoFAConfirmDialog codedlg; From 5ae0c441bf57fdbbaa1d3bb8bc7efbdbf9690188 Mon Sep 17 00:00:00 2001 From: JD Date: Tue, 22 Dec 2020 10:17:42 -0500 Subject: [PATCH 0527/1888] Update COPYING --- COPYING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COPYING b/COPYING index 208fdac7e4..5d48200525 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ Copyright (c) 2009-2015 Bitcoin Developers Copyright (c) 2014-2015 Dash Developers Copyright (c) 2015-2018 PIVX Developers -Copyright (c) 2018-2019 DAPScoin Developers +Copyright (c) 2018-2020 DAPScoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From e3f405a01a57a48e84f61bbf60734c6006e3973d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 22 Dec 2020 17:10:56 -0500 Subject: [PATCH 0528/1888] Restore updated configure.ac from conflict --- configure.ac | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/configure.ac b/configure.ac index 24c17d5968..ab5f5a6850 100644 --- a/configure.ac +++ b/configure.ac @@ -655,6 +655,40 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ ) LDFLAGS="$TEMP_LDFLAGS" +# Check for different ways of gathering OS randomness +AC_MSG_CHECKING(for Linux getrandom syscall) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include + #include ]], + [[ syscall(SYS_getrandom, nullptr, 32, 0); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYS_GETRANDOM, 1,[Define this symbol if the Linux getrandom system call is available]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING(for getentropy) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ getentropy(nullptr, 32) ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY, 1,[Define this symbol if the BSD getentropy system call is available]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING(for getentropy via random.h) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[ getentropy(nullptr, 32) ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_GETENTROPY_RAND, 1,[Define this symbol if the BSD getentropy system call is available with sys/random.h]) ], + [ AC_MSG_RESULT(no)] +) + +AC_MSG_CHECKING(for sysctl KERN_ARND) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #include ]], + [[ static const int name[2] = {CTL_KERN, KERN_ARND}; + sysctl(name, 2, nullptr, nullptr, nullptr, 0); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SYSCTL_ARND, 1,[Define this symbol if the BSD sysctl(KERN_ARND) is available]) ], + [ AC_MSG_RESULT(no)] +) + # Check for reduced exports if test x$use_reduce_exports = xyes; then AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[RE_CXXFLAGS="-fvisibility=hidden"], From 34a515b889a0b2251e8abdae0635a29f1541d68f Mon Sep 17 00:00:00 2001 From: PRCYdev Date: Wed, 30 Dec 2020 21:42:54 +0100 Subject: [PATCH 0529/1888] convert to PRCY --- .github/FUNDING.yml | 2 +- ...ild-factory.yml => prcy-build-factory.yml} | 77 +- .gitignore | 34 +- .travis.yml | 2 +- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 20 +- COPYING | 1 + Dockerfile | 52 +- INSTALL | 6 +- Makefile.am | 36 +- README.md | 57 +- build-aux/m4/bitcoin_qt.m4 | 4 +- configure.ac | 36 +- contrib/bitrpc/bitrpc.py | 4 +- contrib/dapscoin-qt.desktop | 7 - contrib/debian/README.md | 16 +- contrib/debian/changelog | 4 +- contrib/debian/control | 22 +- contrib/debian/dapscoin-qt.desktop | 12 - contrib/debian/dapscoind.bash-completion | 1 - contrib/debian/dapscoind.examples | 1 - contrib/debian/dapscoind.install | 2 - contrib/debian/dapscoind.manpages | 2 - .../examples/{dapscoin.conf => prcycoin.conf} | 26 +- .../manpages/{dapscoin-qt.1 => prcycoin-qt.1} | 14 +- .../{dapscoin.conf.5 => prcycoin.conf.5} | 30 +- .../manpages/{dapscoind.1 => prcycoind.1} | 50 +- contrib/debian/prcycoin-qt.desktop | 12 + ...apscoin-qt.install => prcycoin-qt.install} | 6 +- ...verrides => prcycoin-qt.lintian-overrides} | 2 +- ...scoin-qt.protocol => prcycoin-qt.protocol} | 4 +- contrib/debian/prcycoind.bash-completion | 1 + contrib/debian/prcycoind.examples | 1 + contrib/debian/prcycoind.install | 2 + ...-overrides => prcycoind.lintian-overrides} | 2 +- contrib/debian/prcycoind.manpages | 2 + contrib/debian/rules | 6 +- contrib/devtools/README.md | 16 +- contrib/devtools/check-doc.py | 2 +- contrib/devtools/update-translations.py | 2 +- contrib/gitian-build.sh | 70 +- contrib/gitian-descriptors/README.md | 4 +- contrib/gitian-descriptors/gitian-aarch64.yml | 12 +- contrib/gitian-descriptors/gitian-linux.yml | 12 +- .../gitian-descriptors/gitian-osx-signer.yml | 12 +- contrib/gitian-descriptors/gitian-osx.yml | 12 +- .../gitian-descriptors/gitian-win-signer.yml | 8 +- contrib/gitian-descriptors/gitian-win.yml | 14 +- contrib/init/README.md | 10 +- contrib/init/dapscoind.openrcconf | 26 - contrib/init/dapscoind.service | 26 - .../init/{dapscoind.conf => prcycoind.conf} | 22 +- .../init/{dapscoind.init => prcycoind.init} | 24 +- .../{dapscoind.openrc => prcycoind.openrc} | 28 +- contrib/init/prcycoind.openrcconf | 26 + contrib/init/prcycoind.service | 26 + contrib/linearize/linearize-hashes.py | 2 +- contrib/macdeploy/README.md | 2 +- contrib/macdeploy/custom_dsstore.py | 2 +- contrib/macdeploy/detached-sig-apply.sh | 2 +- contrib/macdeploy/detached-sig-create.sh | 2 +- contrib/macdeploy/fancy.plist | 2 +- contrib/macdeploy/macdeployqtplus | 4 +- contrib/prcycoin-qt.desktop | 7 + contrib/{dapscoin-qt.pro => prcycoin-qt.pro} | 82 +- ...h-completion => prcycoind.bash-completion} | 38 +- contrib/qos/README.md | 4 +- contrib/qos/tc.sh | 6 +- contrib/seeds/README.md | 2 +- contrib/seeds/generate-seeds.py | 4 +- contrib/seeds/makeseeds.py | 2 +- contrib/spendfrom/README.md | 4 +- contrib/spendfrom/spendfrom.py | 78 +- dapscoin.conf | 15 - depends/README.md | 2 +- doc/Doxyfile.in | 6 +- doc/README.md | 28 +- doc/README_osx.md | 2 +- doc/README_windows.txt | 10 +- doc/REST-interface.md | 4 +- doc/build-osx.md | 38 +- doc/build-unix.md | 32 +- doc/build-windows.md | 26 +- doc/developer-notes.md | 14 +- doc/dnsseed-policy.md | 14 +- doc/files.md | 6 +- doc/gitian-building.md | 42 +- doc/guide-startmany.md | 32 +- doc/init.md | 60 +- doc/masternode-budget.md | 16 +- doc/masternode_conf.md | 12 +- doc/multiwallet-qt.md | 8 +- doc/release-notes.md | 18 +- doc/release-process.md | 126 +-- doc/swifttx.md | 10 +- doc/tor.md | 32 +- doc/translation_process.md | 34 +- doc/unit-tests.md | 8 +- doc/zmq.md | 20 +- prcycoin.conf | 10 + qa/pull-tester/run-bitcoind-for-test.sh.in | 4 +- qa/pull-tester/tests-config.sh.in | 4 +- qa/rpc-tests/proxy_test.py | 6 +- qa/rpc-tests/util.py | 20 +- qa/rpc-tests/util.sh | 4 +- qa/rpc-tests/wallet.py | 4 +- share/pixmaps/bitcoin-bc.ico | Bin 21090 -> 84494 bytes share/pixmaps/bitcoin.ico | Bin 21090 -> 84494 bytes share/pixmaps/bitcoin128.png | Bin 11950 -> 28533 bytes share/pixmaps/bitcoin128.xpm | 686 ++++++------ share/pixmaps/bitcoin16.png | Bin 848 -> 892 bytes share/pixmaps/bitcoin16.xpm | 345 +++---- share/pixmaps/bitcoin256.png | Bin 29623 -> 86775 bytes share/pixmaps/bitcoin256.xpm | 973 +++++++++--------- share/pixmaps/bitcoin32.png | Bin 1872 -> 2624 bytes share/pixmaps/bitcoin32.xpm | 394 ++++--- share/pixmaps/bitcoin64.png | Bin 4320 -> 8503 bytes share/pixmaps/bitcoin64.xpm | 525 ++++++---- share/pixmaps/favicon.ico | Bin 21090 -> 84494 bytes share/pixmaps/nsis-header.bmp | Bin 166398 -> 166398 bytes share/pixmaps/nsis-header.png | Bin 14081 -> 84116 bytes share/pixmaps/nsis-wizard.bmp | Bin 51014 -> 49206 bytes share/qt/Info.plist.in | 20 +- share/qt/extract_strings_qt.py | 6 +- share/qt/make_windows_icon.sh | 0 share/setup.nsi.in | 10 +- src/Makefile.am | 74 +- src/Makefile.qt.include | 138 +-- src/Makefile.qttest.include | 30 +- src/Makefile.test.include | 34 +- src/activemasternode.cpp | 10 +- src/activemasternode.h | 4 +- src/amount.cpp | 4 +- src/amount.h | 2 +- src/base58.h | 2 +- src/blocksignature.h | 6 +- src/chainparams.cpp | 225 ++-- src/chainparams.h | 14 +- src/chainparamsbase.cpp | 4 +- src/chainparamsbase.h | 4 +- src/chainparamsseeds.h | 10 +- src/clientversion.cpp | 4 +- src/clientversion.h | 8 +- src/coins.h | 2 +- src/compat.h | 2 +- src/compat/glibc_compat.cpp | 2 +- src/compat/glibc_sanity.cpp | 2 +- src/compat/strnlen.cpp | 2 +- src/ecdhutil.h | 6 +- src/enum.h | 6 +- src/init.cpp | 56 +- src/init.h | 2 +- src/invalid.h | 6 +- src/kernel.cpp | 2 +- src/key.cpp | 2 +- src/main.cpp | 166 ++- src/main.h | 10 +- src/masternode-budget.h | 2 +- src/masternode-payments.cpp | 4 +- src/masternode.cpp | 8 +- src/masternode.h | 2 +- src/masternodeconfig.cpp | 10 +- src/masternodeman.cpp | 10 +- src/miner.cpp | 40 +- src/miner.h | 4 +- src/net.cpp | 10 +- src/netbase.cpp | 2 +- src/netbase.h | 2 +- src/noui.cpp | 2 +- src/obfuscation.cpp | 8 +- src/obfuscation.h | 2 +- src/poa.cpp | 46 +- ...apscoin-cli-res.rc => prcycoin-cli-res.rc} | 10 +- src/{dapscoin-cli.cpp => prcycoin-cli.cpp} | 12 +- ...{dapscoin-tx-res.rc => prcycoin-tx-res.rc} | 10 +- src/{dapscoin-tx.cpp => prcycoin-tx.cpp} | 8 +- src/{dapscoind-res.rc => prcycoind-res.rc} | 10 +- src/{dapscoind.cpp => prcycoind.cpp} | 20 +- src/primitives/transaction.cpp | 2 +- src/primitives/transaction.h | 2 +- src/qt/2faqrdialog.cpp | 6 +- src/qt/addressbookpage.cpp | 6 +- src/qt/addresstablemodel.cpp | 2 +- src/qt/askpassphrasedialog.cpp | 8 +- src/qt/askpassphrasedialog.h | 2 +- src/qt/bitcoinaddressvalidator.cpp | 2 +- src/qt/bitcoinamountfield.cpp | 4 +- src/qt/bitcoingui.cpp | 92 +- src/qt/bitcoingui.h | 2 +- src/qt/bitcoinunits.cpp | 84 +- src/qt/bitcoinunits.h | 10 +- src/qt/blockexplorer.cpp | 6 +- src/qt/clientmodel.h | 2 +- src/qt/coincontroldialog.cpp | 4 +- src/qt/dapscoin_locale.qrc | 36 - src/qt/dapscoinstrings.cpp | 418 -------- src/qt/editaddressdialog.cpp | 2 +- src/qt/forms/2fadialog.ui | 2 +- src/qt/forms/2faqrdialog.ui | 4 +- src/qt/forms/addressbookpage.ui | 10 +- src/qt/forms/bip38tooldialog.ui | 26 +- src/qt/forms/blockexplorer.ui | 2 +- src/qt/forms/coincontroldialog.ui | 8 +- src/qt/forms/entermnemonics.ui | 2 +- src/qt/forms/helpmessagedialog.ui | 6 +- src/qt/forms/historypage.ui | 2 +- src/qt/forms/importorcreate.ui | 2 +- src/qt/forms/intro.ui | 6 +- src/qt/forms/multisenddialog.ui | 8 +- src/qt/forms/optionsdialog.ui | 12 +- src/qt/forms/optionspage.ui | 6 +- src/qt/forms/overviewpage.ui | 6 +- src/qt/forms/receivecoinsdialog.ui | 6 +- src/qt/forms/rpcconsole.ui | 6 +- src/qt/forms/sendcoinsdialog.ui | 12 +- src/qt/forms/sendcoinsentry.ui | 14 +- src/qt/forms/signverifymessagedialog.ui | 26 +- src/qt/guiconstants.h | 10 +- src/qt/guiutil.cpp | 28 +- src/qt/guiutil.h | 8 +- src/qt/intro.cpp | 6 +- .../locale/{dapscoin_bg.ts => prcycoin_bg.ts} | 286 ++--- .../locale/{dapscoin_ca.ts => prcycoin_ca.ts} | 98 +- .../locale/{dapscoin_cs.ts => prcycoin_cs.ts} | 162 +-- .../locale/{dapscoin_da.ts => prcycoin_da.ts} | 324 +++--- .../locale/{dapscoin_de.ts => prcycoin_de.ts} | 350 +++---- .../locale/{dapscoin_en.ts => prcycoin_en.ts} | 170 +-- .../{dapscoin_en_US.ts => prcycoin_en_US.ts} | 354 +++---- .../locale/{dapscoin_eo.ts => prcycoin_eo.ts} | 182 ++-- .../locale/{dapscoin_es.ts => prcycoin_es.ts} | 348 +++---- .../{dapscoin_es_ES.ts => prcycoin_es_ES.ts} | 348 +++---- .../locale/{dapscoin_fi.ts => prcycoin_fi.ts} | 186 ++-- .../{dapscoin_fr_FR.ts => prcycoin_fr_FR.ts} | 98 +- .../{dapscoin_hi_IN.ts => prcycoin_hi_IN.ts} | 2 +- .../locale/{dapscoin_hr.ts => prcycoin_hr.ts} | 38 +- .../{dapscoin_hr_HR.ts => prcycoin_hr_HR.ts} | 352 +++---- .../locale/{dapscoin_it.ts => prcycoin_it.ts} | 110 +- .../locale/{dapscoin_ja.ts => prcycoin_ja.ts} | 2 +- .../{dapscoin_ko_KR.ts => prcycoin_ko_KR.ts} | 350 +++---- .../{dapscoin_lt_LT.ts => prcycoin_lt_LT.ts} | 238 ++--- .../locale/{dapscoin_nl.ts => prcycoin_nl.ts} | 350 +++---- .../locale/{dapscoin_pl.ts => prcycoin_pl.ts} | 90 +- .../locale/{dapscoin_pt.ts => prcycoin_pt.ts} | 50 +- .../{dapscoin_pt_BR.ts => prcycoin_pt_BR.ts} | 282 ++--- .../{dapscoin_ro_RO.ts => prcycoin_ro_RO.ts} | 2 +- .../locale/{dapscoin_ru.ts => prcycoin_ru.ts} | 246 ++--- .../locale/{dapscoin_sk.ts => prcycoin_sk.ts} | 114 +- .../locale/{dapscoin_sv.ts => prcycoin_sv.ts} | 102 +- .../locale/{dapscoin_tr.ts => prcycoin_tr.ts} | 112 +- .../locale/{dapscoin_uk.ts => prcycoin_uk.ts} | 18 +- .../locale/{dapscoin_vi.ts => prcycoin_vi.ts} | 10 +- .../{dapscoin_zh_CN.ts => prcycoin_zh_CN.ts} | 164 +-- .../{dapscoin_zh_TW.ts => prcycoin_zh_TW.ts} | 114 +- src/qt/macnotificationhandler.mm | 2 +- src/qt/notificator.h | 2 +- src/qt/openuridialog.cpp | 4 +- src/qt/optionsdialog.cpp | 2 +- src/qt/optionsmodel.cpp | 6 +- src/qt/optionsmodel.h | 2 +- src/qt/optionspage.cpp | 22 +- src/qt/overviewpage.cpp | 16 +- src/qt/overviewpage.h | 2 +- src/qt/paymentserver.cpp | 30 +- src/qt/paymentserver.h | 2 +- src/qt/{dapscoin.cpp => prcycoin.cpp} | 36 +- src/qt/{dapscoin.qrc => prcycoin.qrc} | 14 +- src/qt/prcycoin_locale.qrc | 36 + src/qt/prcycoinstrings.cpp | 418 ++++++++ src/qt/receivecoinsdialog.cpp | 2 +- src/qt/receiverequestdialog.cpp | 2 +- src/qt/recentrequeststablemodel.h | 2 +- src/qt/res/css/Dark.css | 38 +- src/qt/res/icons/bitcoin.icns | Bin 373780 -> 328327 bytes src/qt/res/icons/bitcoin.ico | Bin 21090 -> 15086 bytes src/qt/res/icons/bitcoin.png | Bin 29623 -> 86775 bytes src/qt/res/icons/bitcoin_testnet.ico | Bin 21090 -> 15086 bytes src/qt/res/icons/bitcoin_testnet.png | Bin 29623 -> 86775 bytes src/qt/res/icons/dapsico.png | Bin 2503 -> 0 bytes src/qt/res/icons/prcyico.png | Bin 0 -> 86775 bytes ...{unit_mdapscoin.png => unit_mprcycoin.png} | Bin .../{unit_dapscoin.png => unit_prcycoin.png} | Bin ...nit_tmdapscoin.png => unit_tmprcycoin.png} | Bin ...{unit_tdapscoin.png => unit_tprcycoin.png} | Bin ...nit_tudapscoin.png => unit_tuprcycoin.png} | Bin ...{unit_udapscoin.png => unit_uprcycoin.png} | Bin src/qt/res/images/about.png | Bin 26193 -> 21514 bytes src/qt/res/images/background.png | Bin 588893 -> 1846432 bytes src/qt/res/images/overviewbackground.png | Bin 224876 -> 947531 bytes src/qt/res/images/splash.png | Bin 299496 -> 223030 bytes src/qt/res/images/splash_testnet.png | Bin 299496 -> 223030 bytes ...{dapscoin-qt-res.rc => prcycoin-qt-res.rc} | 10 +- src/qt/revealtxdialog.cpp | 3 +- src/qt/rpcconsole.cpp | 2 +- src/qt/rpcconsole.h | 2 +- src/qt/sendcoinsdialog.cpp | 2 +- src/qt/sendcoinsentry.cpp | 4 +- src/qt/splashscreen.cpp | 12 +- src/qt/test/test_main.cpp | 4 +- src/qt/test/uritests.cpp | 22 +- src/qt/transactiondesc.cpp | 2 +- src/qt/transactionrecord.cpp | 6 +- src/qt/utilitydialog.cpp | 8 +- src/qt/walletmodel.cpp | 11 +- src/qt/walletview.h | 2 +- src/rpc/blockchain.cpp | 8 +- src/rpc/budget.cpp | 28 +- src/rpc/masternode.cpp | 14 +- src/rpc/mining.cpp | 12 +- src/rpc/misc.cpp | 24 +- src/rpc/net.cpp | 10 +- src/rpc/protocol.cpp | 2 +- src/rpc/protocol.h | 4 +- src/rpc/rawtransaction.cpp | 22 +- src/rpc/server.cpp | 46 +- src/rpc/server.h | 2 +- src/script/bitcoinconsensus.h | 2 +- src/test/README.md | 4 +- src/test/data/bitcoin-util-test.json | 20 +- src/test/main_tests.cpp | 2 +- src/test/net_tests.cpp | 2 +- src/test/netbase_tests.cpp | 18 +- src/test/random_tests.cpp | 2 +- src/test/scheduler_tests.cpp | 2 +- .../{test_dapscoin.cpp => test_prcycoin.cpp} | 10 +- src/test/torcontrol_tests.cpp | 4 +- src/timedata.cpp | 2 +- src/util.cpp | 34 +- src/util.h | 6 +- src/util/threadnames.cpp | 2 +- src/utiltime.cpp | 2 +- src/version.h | 6 +- src/wallet/rpcdump.cpp | 26 +- src/wallet/rpcwallet.cpp | 152 +-- src/wallet/wallet.cpp | 87 +- src/wallet/wallet.h | 11 +- src/wallet/walletdb.cpp | 4 +- src/zmq/zmqconfig.h | 2 +- version.txt | 2 +- 338 files changed, 6957 insertions(+), 6745 deletions(-) rename .github/workflows/{daps-build-factory.yml => prcy-build-factory.yml} (81%) delete mode 100644 contrib/dapscoin-qt.desktop delete mode 100644 contrib/debian/dapscoin-qt.desktop delete mode 100644 contrib/debian/dapscoind.bash-completion delete mode 100644 contrib/debian/dapscoind.examples delete mode 100644 contrib/debian/dapscoind.install delete mode 100644 contrib/debian/dapscoind.manpages rename contrib/debian/examples/{dapscoin.conf => prcycoin.conf} (82%) rename contrib/debian/manpages/{dapscoin-qt.1 => prcycoin-qt.1} (92%) rename contrib/debian/manpages/{dapscoin.conf.5 => prcycoin.conf.5} (75%) rename contrib/debian/manpages/{dapscoind.1 => prcycoind.1} (82%) create mode 100644 contrib/debian/prcycoin-qt.desktop rename contrib/debian/{dapscoin-qt.install => prcycoin-qt.install} (50%) rename contrib/debian/{dapscoin-qt.lintian-overrides => prcycoin-qt.lintian-overrides} (52%) rename contrib/debian/{dapscoin-qt.protocol => prcycoin-qt.protocol} (73%) create mode 100644 contrib/debian/prcycoind.bash-completion create mode 100644 contrib/debian/prcycoind.examples create mode 100644 contrib/debian/prcycoind.install rename contrib/debian/{dapscoind.lintian-overrides => prcycoind.lintian-overrides} (53%) create mode 100644 contrib/debian/prcycoind.manpages delete mode 100644 contrib/init/dapscoind.openrcconf delete mode 100644 contrib/init/dapscoind.service rename contrib/init/{dapscoind.conf => prcycoind.conf} (76%) rename contrib/init/{dapscoind.init => prcycoind.init} (62%) rename contrib/init/{dapscoind.openrc => prcycoind.openrc} (71%) create mode 100644 contrib/init/prcycoind.openrcconf create mode 100644 contrib/init/prcycoind.service create mode 100644 contrib/prcycoin-qt.desktop rename contrib/{dapscoin-qt.pro => prcycoin-qt.pro} (93%) rename contrib/{dapscoind.bash-completion => prcycoind.bash-completion} (83%) delete mode 100644 dapscoin.conf create mode 100644 prcycoin.conf mode change 100644 => 100755 share/qt/make_windows_icon.sh rename src/{dapscoin-cli-res.rc => prcycoin-cli-res.rc} (81%) rename src/{dapscoin-cli.cpp => prcycoin-cli.cpp} (96%) rename src/{dapscoin-tx-res.rc => prcycoin-tx-res.rc} (82%) rename src/{dapscoin-tx.cpp => prcycoin-tx.cpp} (98%) rename src/{dapscoind-res.rc => prcycoind-res.rc} (82%) rename src/{dapscoind.cpp => prcycoind.cpp} (88%) delete mode 100644 src/qt/dapscoin_locale.qrc delete mode 100644 src/qt/dapscoinstrings.cpp rename src/qt/locale/{dapscoin_bg.ts => prcycoin_bg.ts} (94%) rename src/qt/locale/{dapscoin_ca.ts => prcycoin_ca.ts} (95%) rename src/qt/locale/{dapscoin_cs.ts => prcycoin_cs.ts} (94%) rename src/qt/locale/{dapscoin_da.ts => prcycoin_da.ts} (94%) rename src/qt/locale/{dapscoin_de.ts => prcycoin_de.ts} (94%) rename src/qt/locale/{dapscoin_en.ts => prcycoin_en.ts} (98%) rename src/qt/locale/{dapscoin_en_US.ts => prcycoin_en_US.ts} (94%) rename src/qt/locale/{dapscoin_eo.ts => prcycoin_eo.ts} (93%) rename src/qt/locale/{dapscoin_es.ts => prcycoin_es.ts} (94%) rename src/qt/locale/{dapscoin_es_ES.ts => prcycoin_es_ES.ts} (94%) rename src/qt/locale/{dapscoin_fi.ts => prcycoin_fi.ts} (94%) rename src/qt/locale/{dapscoin_fr_FR.ts => prcycoin_fr_FR.ts} (95%) rename src/qt/locale/{dapscoin_hi_IN.ts => prcycoin_hi_IN.ts} (99%) rename src/qt/locale/{dapscoin_hr.ts => prcycoin_hr.ts} (96%) rename src/qt/locale/{dapscoin_hr_HR.ts => prcycoin_hr_HR.ts} (95%) rename src/qt/locale/{dapscoin_it.ts => prcycoin_it.ts} (92%) rename src/qt/locale/{dapscoin_ja.ts => prcycoin_ja.ts} (99%) rename src/qt/locale/{dapscoin_ko_KR.ts => prcycoin_ko_KR.ts} (94%) rename src/qt/locale/{dapscoin_lt_LT.ts => prcycoin_lt_LT.ts} (93%) rename src/qt/locale/{dapscoin_nl.ts => prcycoin_nl.ts} (94%) rename src/qt/locale/{dapscoin_pl.ts => prcycoin_pl.ts} (95%) rename src/qt/locale/{dapscoin_pt.ts => prcycoin_pt.ts} (96%) rename src/qt/locale/{dapscoin_pt_BR.ts => prcycoin_pt_BR.ts} (94%) rename src/qt/locale/{dapscoin_ro_RO.ts => prcycoin_ro_RO.ts} (99%) rename src/qt/locale/{dapscoin_ru.ts => prcycoin_ru.ts} (94%) rename src/qt/locale/{dapscoin_sk.ts => prcycoin_sk.ts} (92%) rename src/qt/locale/{dapscoin_sv.ts => prcycoin_sv.ts} (94%) rename src/qt/locale/{dapscoin_tr.ts => prcycoin_tr.ts} (93%) rename src/qt/locale/{dapscoin_uk.ts => prcycoin_uk.ts} (95%) rename src/qt/locale/{dapscoin_vi.ts => prcycoin_vi.ts} (94%) rename src/qt/locale/{dapscoin_zh_CN.ts => prcycoin_zh_CN.ts} (91%) rename src/qt/locale/{dapscoin_zh_TW.ts => prcycoin_zh_TW.ts} (89%) rename src/qt/{dapscoin.cpp => prcycoin.cpp} (96%) rename src/qt/{dapscoin.qrc => prcycoin.qrc} (94%) create mode 100644 src/qt/prcycoin_locale.qrc create mode 100644 src/qt/prcycoinstrings.cpp delete mode 100644 src/qt/res/icons/dapsico.png create mode 100644 src/qt/res/icons/prcyico.png rename src/qt/res/icons/{unit_mdapscoin.png => unit_mprcycoin.png} (100%) rename src/qt/res/icons/{unit_dapscoin.png => unit_prcycoin.png} (100%) rename src/qt/res/icons/{unit_tmdapscoin.png => unit_tmprcycoin.png} (100%) rename src/qt/res/icons/{unit_tdapscoin.png => unit_tprcycoin.png} (100%) rename src/qt/res/icons/{unit_tudapscoin.png => unit_tuprcycoin.png} (100%) rename src/qt/res/icons/{unit_udapscoin.png => unit_uprcycoin.png} (100%) rename src/qt/res/{dapscoin-qt-res.rc => prcycoin-qt-res.rc} (83%) rename src/test/{test_dapscoin.cpp => test_prcycoin.cpp} (95%) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 8453c41218..520f226ea5 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: ["http://bit.ly/DAPScryptoDonations", dapscoin.com, "http://bit.ly/DAPSfiatDonations"] +custom: ["http://bit.ly/PRCYcryptoDonations", prcycoin.com, "http://bit.ly/PRCYfiatDonations"] diff --git a/.github/workflows/daps-build-factory.yml b/.github/workflows/prcy-build-factory.yml similarity index 81% rename from .github/workflows/daps-build-factory.yml rename to .github/workflows/prcy-build-factory.yml index f4c2175a4e..808dd727ec 100644 --- a/.github/workflows/daps-build-factory.yml +++ b/.github/workflows/prcy-build-factory.yml @@ -1,8 +1,9 @@ # Copyright (c) 2018-2020 The Veil developers # Copyright (c) 2020 The DAPS Project +# Copyright (c) 2020 The PRCY developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -name: Github Actions CI for DAPS +name: Github Actions CI for PRCY on: [push, pull_request] env: SOURCE_ARTIFACT: source @@ -15,7 +16,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - # May need qt and protobuf to configure qt and include dapscoin-qt.1 in distribution + # May need qt and protobuf to configure qt and include prcycoin-qt.1 in distribution - name: Install Required Packages run: | sudo apt-get update @@ -29,15 +30,15 @@ jobs: - name: Create Distribution Tarball run: | mkdir -p $ARTIFACT_DIR - touch dapscoin.tar.gz - tar -czf dapscoin.tar.gz --exclude=dapscoin.tar.gz . + touch prcycoin.tar.gz + tar -czf prcycoin.tar.gz --exclude=prcycoin.tar.gz . - name: Download Dependencies run: make -C depends download - name: Create Dependencies Tarball run: tar -czf depends.tar.gz depends - name: Prepare Files for Artifact run: | - mv depends.tar.gz dapscoin.tar.gz $ARTIFACT_DIR + mv depends.tar.gz prcycoin.tar.gz $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -48,7 +49,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: x86_64-linux-binaries + ARTIFACT_DIR: prcycoin-v-x86_64-linux TEST_LOG_ARTIFACT_DIR: test-logs steps: - name: Getting Source @@ -58,7 +59,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -67,7 +68,7 @@ jobs: - name: Build Dependencies run: make -C depends -j$(nproc) working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-pc-linux-gnu) @@ -76,8 +77,9 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - strip $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} - mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} + chmod +x $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} + mv $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -88,7 +90,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: win64-binaries + ARTIFACT_DIR: prcycoin-v-win64 steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -97,7 +99,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -110,7 +112,7 @@ jobs: - name: Build Dependencies run: make -C depends -j$(nproc) HOST=x86_64-w64-mingw32 working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-w64-mingw32) @@ -120,8 +122,8 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - strip $SOURCE_ARTIFACT/src/{dapscoin-cli.exe,dapscoin-tx.exe,dapscoind.exe,qt/dapscoin-qt.exe} - mv $SOURCE_ARTIFACT/{dapscoin-*.exe,src/dapscoin-cli.exe,src/dapscoin-tx.exe,src/dapscoind.exe,src/qt/dapscoin-qt.exe} $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{prcycoin-cli.exe,prcycoin-tx.exe,prcycoind.exe,qt/prcycoin-qt.exe} + mv $SOURCE_ARTIFACT/{prcycoin-*.exe,src/prcycoin-cli.exe,src/prcycoin-tx.exe,src/prcycoind.exe,src/qt/prcycoin-qt.exe} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -132,7 +134,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: win32-binaries + ARTIFACT_DIR: prcycoin-v-win32 steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -141,7 +143,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -153,7 +155,7 @@ jobs: - name: Build Dependencies run: make -C depends -j$(nproc) HOST=i686-w64-mingw32 working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/i686-w64-mingw32) @@ -163,8 +165,8 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - strip $SOURCE_ARTIFACT/src/{dapscoin-cli.exe,dapscoin-tx.exe,dapscoind.exe,qt/dapscoin-qt.exe} - mv $SOURCE_ARTIFACT/{dapscoin-*.exe,src/dapscoin-cli.exe,src/dapscoin-tx.exe,src/dapscoind.exe,src/qt/dapscoin-qt.exe} $ARTIFACT_DIR + strip $SOURCE_ARTIFACT/src/{prcycoin-cli.exe,prcycoin-tx.exe,prcycoind.exe,qt/prcycoin-qt.exe} + mv $SOURCE_ARTIFACT/{prcycoin-*.exe,src/prcycoin-cli.exe,src/prcycoin-tx.exe,src/prcycoind.exe,src/qt/prcycoin-qt.exe} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -175,7 +177,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: macosx-binaries + ARTIFACT_DIR: prcycoin-v-macosx steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -184,7 +186,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -200,7 +202,7 @@ jobs: - name: Build Dependencies run: make -C depends HOST=x86_64-apple-darwin16 -j$(nproc) working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/x86_64-apple-darwin16) @@ -210,7 +212,7 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - mv $SOURCE_ARTIFACT/{*.dmg,src/dapscoin-cli,src/dapscoin-tx,src/dapscoind,src/qt/dapscoin-qt} $ARTIFACT_DIR + mv $SOURCE_ARTIFACT/{*.dmg,src/prcycoin-cli,src/prcycoin-tx,src/prcycoind,src/qt/prcycoin-qt} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -221,7 +223,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: aarch64-linux-binaries + ARTIFACT_DIR: prcycoin-v-aarch64-linux steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -230,7 +232,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -239,7 +241,7 @@ jobs: - name: Build Dependencies run: make -C depends HOST=aarch64-linux-gnu -j$(nproc) working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/aarch64-linux-gnu) @@ -248,7 +250,8 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + chmod +x $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} + mv $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -259,7 +262,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: arm32-binaries + ARTIFACT_DIR: prcycoin-v-arm32 steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -268,7 +271,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -277,7 +280,7 @@ jobs: - name: Build Dependencies run: make -C depends -j$(nproc) HOST=arm-linux-gnueabihf working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/arm-linux-gnueabihf) --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ @@ -286,7 +289,8 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + chmod +x $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} + mv $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: @@ -297,7 +301,7 @@ jobs: needs: create-source-distribution runs-on: ubuntu-18.04 env: - ARTIFACT_DIR: riscv64-binaries + ARTIFACT_DIR: prcycoin-v-riscv64 steps: - name: Getting Source uses: actions/download-artifact@v1 @@ -306,7 +310,7 @@ jobs: - name: Extract Archives run: | tar -xzf depends.tar.gz - tar -xzf dapscoin.tar.gz --strip-components=1 + tar -xzf prcycoin.tar.gz --strip-components=1 working-directory: ${{ env.SOURCE_ARTIFACT }} - name: Install Required Packages run: | @@ -315,7 +319,7 @@ jobs: - name: Build Dependencies run: make -C depends -j$(nproc) HOST=riscv64-linux-gnu working-directory: ${{ env.SOURCE_ARTIFACT }} - - name: Build DAPS + - name: Build PRCY run: | ./autogen.sh ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench --prefix=$(realpath depends/riscv64-linux-gnu) --enable-reduce-exports LDFLAGS=-static-libstdc++ @@ -324,7 +328,8 @@ jobs: - name: Prepare Files for Artifact run: | mkdir -p $ARTIFACT_DIR - mv $SOURCE_ARTIFACT/src/{dapscoin-cli,dapscoin-tx,dapscoind,qt/dapscoin-qt} $ARTIFACT_DIR + chmod +x $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} + mv $SOURCE_ARTIFACT/src/{prcycoin-cli,prcycoin-tx,prcycoind,qt/prcycoin-qt} $ARTIFACT_DIR - name: Upload Artifact uses: actions/upload-artifact@v1 with: diff --git a/.gitignore b/.gitignore index aa4fca1689..f21a3bed6b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,12 +6,12 @@ reset-files.bash *.tar.gz *.exe -src/dapscoin -src/dapscoind -src/dapscoin-cli -src/dapscoin-tx -src/test/test_dapscoin -src/qt/test/test_dapscoin-qt +src/prcycoin +src/prcycoind +src/prcycoin-cli +src/prcycoin-tx +src/test/test_prcycoin +src/qt/test/test_prcycoin-qt # autoreconf Makefile.in @@ -37,8 +37,8 @@ confdefs.h conftest.cpp conftest.err libtool -src/config/dapscoin-config.h -src/config/dapscoin-config.h.in +src/config/prcycoin-config.h +src/config/prcycoin-config.h.in src/config/stamp-h1 src/secp256k1-mw/build-aux/compile src/secp256k1-mw/build-aux/config.guess @@ -56,8 +56,8 @@ share/setup.nsi share/qt/Info.plist contrib/devtools/split-debug.sh -src/qt/dapscoin-qt-multisig -src/qt/test/test_dapscoin-qt-multisig +src/qt/prcycoin-qt-multisig +src/qt/test/test_prcycoin-qt-multisig src/univalue/gen src/qt/*.moc @@ -79,7 +79,7 @@ src/qt/test/moc*.cpp *.o *.o-* *.patch -.dapscoin +.prcycoin *.a !libchilkat*.a *.pb.cc @@ -99,12 +99,12 @@ src/qt/test/moc*.cpp # Compilation and Qt preprocessor part *.qm Makefile -dapscoin-qt -DAPScoin-Qt.app +prcycoin-qt +PRCYcoin-Qt.app # Unit-tests Makefile.test -dapscoin-qt_test +prcycoin-qt_test src/test/buildenv.py # Resources cpp @@ -123,7 +123,7 @@ dist/ #lcov *.gcno /*.info -test_dapscoin.coverage/ +test_prcycoin.coverage/ total.coverage/ coverage_percent.txt @@ -150,5 +150,5 @@ CMakeLists.txt cmake-build-debug .vscode/* BackupWallet* -dapscoin-qt.pro -!contrib/dapscoin-qt.pro +prcycoin-qt.pro +!contrib/prcycoin-qt.pro diff --git a/.travis.yml b/.travis.yml index 3b6eb2cd9b..aa29adccea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ env: - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" PYZMQ=true # Win64 - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports" -# dapscoind +# prcycoind - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" PYZMQ=true # No wallet # - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 21f7258add..4e659e8a31 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at support@dapscoin.com. All +reported by contacting the project team at support@prcycoin.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b05f2bf105..328d43b5c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ -Contributing to DAPS +Contributing to PRCY ============================ -The DAPS project operates an open contributor model where anyone is +The PRCY Developers operates an open contributor model where anyone is welcome to contribute towards development in the form of peer review, testing and patches. This document explains the practical process and guidelines for contributing. @@ -57,12 +57,12 @@ the pull request affects. Valid areas as: - *Consensus* for changes to consensus critical code - *Docs* for changes to the documentation - - *Qt* for changes to dapscoin-qt + - *Qt* for changes to prcycoin-qt - *Minting* for changes to the minting code - *Net* or *P2P* for changes to the peer-to-peer network code - *RPC/REST* for changes to the RPC or REST APIs - *Scripts and tools* for changes to the scripts and tools - - *Tests* for changes to the dapscoin unit tests or QA tests + - *Tests* for changes to the prcycoin unit tests or QA tests - *Trivial* should **only** be used for PRs that do not change generated executable code. Notably, refactors (change of function arguments and code reorganization) and changes in behavior should **not** be marked as trivial. @@ -157,10 +157,10 @@ where possible keep them short, un-complex and easy to verify. "Decision Making" Process ------------------------- -The following applies to code changes to the DAPS project, and is not to be -confused with overall DAPS Network Protocol consensus changes. +The following applies to code changes to the PRCY project, and is not to be +confused with overall PRCY Network Protocol consensus changes. -Whether a pull request is merged into DAPS rests with the project merge +Whether a pull request is merged into PRCY rests with the project merge maintainers and ultimately the project lead. Maintainers will take into consideration if a patch is in line with the general @@ -174,7 +174,7 @@ In general, all pull requests must: - be well peer reviewed; - follow code style guidelines; -Patches that change DAPS consensus rules are considerably more involved than +Patches that change PRCY consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by extensive discussions and clear detailing. While each case will be different, one should be prepared to expend more time and effort than for other kinds of @@ -214,7 +214,7 @@ higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code. -Where a patch set proposes to change the DAPS consensus, it must have been +Where a patch set proposes to change the PRCY consensus, it must have been discussed extensively on the forums and Slack, be accompanied by a widely discussed Proposal and have a generally widely perceived technical consensus of being a worthwhile change based on the judgement of the maintainers. @@ -254,7 +254,7 @@ about: Release Policy -------------- -The project leader is the release manager for each DAPS release. +The project leader is the release manager for each PRCY release. Copyright --------- diff --git a/COPYING b/COPYING index 5d48200525..374ca7a905 100644 --- a/COPYING +++ b/COPYING @@ -2,6 +2,7 @@ Copyright (c) 2009-2015 Bitcoin Developers Copyright (c) 2014-2015 Dash Developers Copyright (c) 2015-2018 PIVX Developers Copyright (c) 2018-2020 DAPScoin Developers +Copyright (c) 2020-2021 PRCYcoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Dockerfile b/Dockerfile index d84cab7844..6a2c5ec2f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,38 +1,22 @@ - -# DAPS DEPS IMG +# PRCY DEPS IMG FROM ubuntu:18.04 -RUN apt-get update -RUN apt-get install gnupg software-properties-common debconf dialog apt-utils gcc-5 bsdmainutils curl git -y --fix-missing -RUN add-apt-repository ppa:bitcoin/bitcoin -y -RUN apt-get update - -RUN apt-get install autotools-dev build-essential autoconf make automake openssl -y --fix-missing - -RUN apt-get install libssl-dev libboost-dev libtool pkg-config -y --fix-missing -RUN apt-get install libminiupnpc-dev miniupnpc libdb4.8++-dev libdb4.8-dev libqrencode-dev libevent-dev -y --fix-missing - -RUN apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev libboost-all-dev protobuf-compiler -y --fix-missing -RUN apt-get install libqrencode-dev libzmq3-dev -y --fix-missing - -RUN apt-get install g++-5 libcurl4-openssl-dev libjansson-dev -y --fix-missing -RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 1 -#compile for windows -RUN apt-get install g++-mingw-w64-x86-64 -y --fix-missing -RUN update-alternatives --config x86_64-w64-mingw32-g++ -RUN PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var +COPY ./prcycoin.conf /root/.prcycoin/prcycoin.conf +COPY . /prcycoin +WORKDIR /prcycoin - - -RUN mkdir /DAPS/ -COPY . /DAPS/ - -RUN make -C DAPS/depends HOST=x86_64-w64-mingw32 -#RUN make -C /DAPS/depends - -RUN bash /DAPS/autogen.sh -RUN CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ -RUN bash /DAPS/configure - -RUN ls -a \ No newline at end of file +RUN apt-get update +RUN apt-get install -y build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 +RUN apt-get install -y libssl1.0-dev libzmq5 libgmp-dev libevent-dev libboost-all-dev libsodium-dev cargo +RUN apt-get install -y libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libqrencode-dev +RUN apt-get install -y software-properties-common g++-multilib binutils-gold patch +RUN add-apt-repository ppa:pivx/pivx +RUN apt-get update +RUN apt-get install -y libdb4.8-dev libdb4.8++-dev +RUN ./autogen.sh +RUN ./configure --disable-jni --disable-tests --disable-gui-tests --disable-bench +RUN make +RUN make install +EXPOSE 59682 59683 59684 59685s +CMD ["prcycoind", "--printtoconsole"] diff --git a/INSTALL b/INSTALL index c4918c9e76..d7ff9d48ef 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -Building DAPScoin +Building PRCYcoin Use the autogen script to prepare the build environment. @@ -8,6 +8,6 @@ Use the autogen script to prepare the build environment. Always verify the signatures and checksums. -See doc/build-*.md for instructions on building dapscoind, +See doc/build-*.md for instructions on building prcycoind, the intended-for-services, no-graphical-interface, reference -implementation of DAPScoin. +implementation of PRCYcoin. diff --git a/Makefile.am b/Makefile.am index 9914b005be..6ba2b71994 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,7 @@ BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EX empty := space := $(empty) $(empty) -OSX_APP=DAPScoin-Qt.app +OSX_APP=PRCYcoin-Qt.app OSX_VOLNAME = $(subst $(space),-,$(PACKAGE_NAME)) OSX_DMG = $(OSX_VOLNAME).dmg OSX_BACKGROUND_SVG=background.svg @@ -49,9 +49,9 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \ - leveldb_baseline.info test_dapscoin_filtered.info total_coverage.info \ + leveldb_baseline.info test_prcycoin_filtered.info total_coverage.info \ baseline_filtered.info block_test_filtered.info \ - leveldb_baseline_filtered.info test_dapscoin_coverage.info test_dapscoin.info + leveldb_baseline_filtered.info test_prcycoin_coverage.info test_prcycoin.info dist-hook: -$(MAKE) -C $(top_distdir)/src/leveldb clean @@ -92,7 +92,7 @@ $(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) $(MKDIR_P) $(@D) $(INSTALL_DATA) $< $@ -$(OSX_APP)/Contents/MacOS/DAPScoin-Qt: $(BITCOIN_QT_BIN) +$(OSX_APP)/Contents/MacOS/PRCYcoin-Qt: $(BITCOIN_QT_BIN) $(MKDIR_P) $(@D) STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ @@ -102,7 +102,7 @@ $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ - $(OSX_APP)/Contents/MacOS/DAPScoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings + $(OSX_APP)/Contents/MacOS/PRCYcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings osx_volname: echo $(OSX_VOLNAME) >$@ @@ -127,7 +127,7 @@ $(APP_DIST_DIR)/Applications: @rm -f $@ @cd $(@D); $(LN_S) /Applications $(@F) -$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/DAPScoin-Qt +$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/PRCYcoin-Qt $(OSX_DMG): $(APP_DIST_EXTRAS) $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -apple -o $@ dist @@ -142,7 +142,7 @@ $(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE_DPIF $(APP_DIST_DIR)/.DS_Store: $(OSX_DSSTORE_GEN) $(PYTHON) $< "$@" "$(OSX_VOLNAME)" -$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/DAPScoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) +$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/PRCYcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 deploydir: $(APP_DIST_EXTRAS) @@ -185,16 +185,16 @@ leveldb_baseline_filtered.info: leveldb_baseline.info baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info $(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@ -test_dapscoin.info: baseline_filtered_combined.info +test_prcycoin.info: baseline_filtered_combined.info $(MAKE) -C src/ check - $(LCOV) -c -d $(abs_builddir)/src -t test_dapscoin -o $@ + $(LCOV) -c -d $(abs_builddir)/src -t test_prcycoin -o $@ $(LCOV) -z -d $(abs_builddir)/src $(LCOV) -z -d $(abs_builddir)/src/leveldb -test_dapscoin_filtered.info: test_dapscoin.info +test_prcycoin_filtered.info: test_prcycoin.info $(LCOV) -r $< "/usr/include/*" -o $@ -block_test.info: test_dapscoin_filtered.info +block_test.info: test_prcycoin_filtered.info $(MKDIR_P) qa/tmp -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool 0 $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@ @@ -204,13 +204,13 @@ block_test.info: test_dapscoin_filtered.info block_test_filtered.info: block_test.info $(LCOV) -r $< "/usr/include/*" -o $@ -test_dapscoin_coverage.info: baseline_filtered_combined.info test_dapscoin_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_dapscoin_filtered.info -o $@ +test_prcycoin_coverage.info: baseline_filtered_combined.info test_prcycoin_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_prcycoin_filtered.info -o $@ -total_coverage.info: baseline_filtered_combined.info test_dapscoin_filtered.info block_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_dapscoin_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +total_coverage.info: baseline_filtered_combined.info test_prcycoin_filtered.info block_test_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_prcycoin_filtered.info -a block_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt -test_dapscoin.coverage/.dirstamp: test_dapscoin_coverage.info +test_prcycoin.coverage/.dirstamp: test_prcycoin_coverage.info $(GENHTML) -s $< -o $(@D) @touch $@ @@ -218,7 +218,7 @@ total.coverage/.dirstamp: total_coverage.info $(GENHTML) -s $< -o $(@D) @touch $@ -cov: test_dapscoin.coverage/.dirstamp total.coverage/.dirstamp +cov: test_prcycoin.coverage/.dirstamp total.coverage/.dirstamp endif @@ -231,5 +231,5 @@ CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) .INTERMEDIATE: $(COVERAGE_INFO) clean-local: - rm -rf test_dapscoin.coverage/ total.coverage/ $(OSX_APP) + rm -rf test_prcycoin.coverage/ total.coverage/ $(OSX_APP) rm -rf osx_volname dist/ dpi36.background.tiff dpi72.background.tiff diff --git a/README.md b/README.md index 28986b6450..b338f66c53 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,63 @@ -Welcome to DAPS +![Github Actions CI for PRCY](https://github.com/PRCYcoin/PRCYCoin-dev/workflows/Github%20Actions%20CI%20for%20PRCY/badge.svg?branch=master) + +Welcome to PRCY ===================================== ## Introduction -DAPScoin is a cutting edge cryptocurrency, with many features not available in most other cryptocurrencies. +PRCYcoin is a cutting edge cryptocurrency, with many features not available in most other cryptocurrencies. - Anonymized transactions using Stealth addresses, RingCT and Bulletproofs. -- Masternode is secured with a collateral of 1,000,000 DAPS. -DAPS is a cryptocurrency designed for corporate entities, traders, and individuals to have the autonomy to transactions business freely around the world safely and securely without the exposure to malicious actors that threaten financial transactions through traceability. - -DAPS is a privacy coin that aims to be the most private and secure privacy coin on the market in a hybrid chain of PoW, PoSv3 and PoA. We aim to set our protocol to become the new standard of privacy coins. +- Masternode is secured with a collateral of 5,000 PRCY +- Minimum Staking Amount is 2,500 PRCY +PRCY is a cryptocurrency designed for corporate entities, traders, and individuals to have the autonomy to transactions business freely around the world safely and securely without the exposure to malicious actors that threaten financial transactions through traceability. -What makes DAPS special is that DAPS is the first to solve the "trust problem" for fully private chains with our PoA (Proof of Audit) algorithm which audits the chain for any abnormalities without compromising the chain's anonymity features. +PRCY is a privacy coin that aims to be the most private and secure privacy coin on the market in a hybrid chain of PoW, PoSv3 and PoA. We aim to set our protocol to become the new standard of privacy coins. -DAPS is the world's first coin to implement Bulletproofs and RingCT & Ring Signatures in a staking chain. With DAPS it is possible to stake, run masternodes and mine PoA blocks. In 2019 DAPS completed two successful testnets, sponsored Consensus 2019 NYC and Futurist Conference in Canada, achieved and kept top 200 coin status, passed security audit by Red4Sec, launched mainnet and achieved over 3000 hosted masternodes in the first month, staying in the top 10. +The team of PRCY solves the trust issue of privacy coins and their management as follows: +- The community will get access to view the number of the PRCY project coins and their actions +- Each quarter the team explains their actions and displays their project balance of coins +- Upfront the allocation is published as a starting point ## About this Project -DAPS is a non-ICO community driven project. The project has funded itself to deliver ground-breaking technology in the privacy coin industry. - -DAPS Team -The team consists of a total of 20 members located worldwide. +PRCY is a non-ICO community driven project. The project has funded itself to deliver ground-breaking technology in the privacy coin industry. -## How we Compare to Other Privacy Projects +PRCY Team +The team consists of a total of 10 members located worldwide. -![Privacy Coin Chart](https://officialdapscoin.com/daps-coin-comparison-chart-2020/) +## How to Contribute to PRCY -## How to Contribute to DAPS - -We have an extensive [Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. +We have an extensive [Contributing.md](https://github.com/PRCYCoin/PRCYCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to PRCY source code. Please have a look at this first before deciding to contribute to our codebase. We welcome developers from all backgrounds to take a look at our code and welcome all suggestions and changes. ## Social -Facebook - (https://www.facebook.com/officialDAPScoin/) - -Twitter - (https://twitter.com/DAPScoin) +Facebook - (https://www.facebook.com/Prcycoin-101534778505838) -LinkedIn - (https://www.linkedin.com/company/daps-coin/) +Twitter - (https://twitter.com/PRCYcoin) -Reddit - (https://www.reddit.com/r/DAPSCoin/) +Reddit - (https://www.reddit.com/r/PRCYCoin/) -Forum - (https://forum.officialdapscoin.com/) +Telegram - (https://t.me/prcycoinofficial) -Telegram - (https://t.me/dapscoin) +Telegram - Tech Support - (https://t.me/prycSupport) -Discord - (https://discord.gg/hxfmWpR) +Medium - (https://prcycoin.medium.com/) -Bitcointalk - (https://bitcointalk.org/index.php?topic=5146718.0) +Bitcointalk - (https://bitcointalk.org/index.php?topic=5301128) +Instagram - (https://www.instagram.com/prcycoin/) -More information at [officialdapscoin.com](https://officialdapscoin.com) Visit our ANN thread at [BitcoinTalk](https://bitcointalk.org/index.php?topic=5146718) +More information at [prcycoin.com](https://prcycoin.com) Visit our ANN thread at [BitcoinTalk](https://bitcointalk.org/index.php?topic=5301128) ### Coin Specs - - + +
      AlgoPoW-PoA-PoS
      Block Time60 Seconds
      Difficulty RetargetingEvery Block
      Max Coin Supply70,000,000,000 DAPS
      Premine60 000 000 000 DAPS
      Max Coin Supply70,000,000 PRCY
      Premine60,000,000 PRCY
      diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index d2fdb303db..b1ebde2846 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -7,7 +7,7 @@ dnl Output: If qt version is auto, set bitcoin_enable_qt to false. Else, exit. AC_DEFUN([BITCOIN_QT_FAIL],[ if test "x$bitcoin_qt_want_version" = xauto && test "x$bitcoin_qt_force" != xyes; then if test "x$bitcoin_enable_qt" != xno; then - AC_MSG_WARN([$1; dapscoin-qt frontend will not be built]) + AC_MSG_WARN([$1; prcycoin-qt frontend will not be built]) fi bitcoin_enable_qt=no bitcoin_enable_qt_test=no @@ -54,7 +54,7 @@ AC_DEFUN([BITCOIN_QT_INIT],[ dnl enable qt support AC_ARG_WITH([gui], [AS_HELP_STRING([--with-gui@<:@=no|qt5|auto@:>@], - [build dapscoin-qt GUI (default=auto)])], + [build prcycoin-qt GUI (default=auto)])], [ bitcoin_qt_want_version=$withval if test "x$bitcoin_qt_want_version" = xyes; then diff --git a/configure.ac b/configure.ac index 1c13ed7de0..bcfd684436 100644 --- a/configure.ac +++ b/configure.ac @@ -2,21 +2,21 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 9) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2020) -AC_INIT([DAPScoin],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_REVISION, m4_if(_CLIENT_VERSION_BUILD, [0], [], _CLIENT_VERSION_BUILD))m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/DAPSCoin/DAPSCoin/issues],[dapscoin],[https://officialdapscoin.com]) +define(_COPYRIGHT_YEAR, 2021) +AC_INIT([PRCYcoin],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_REVISION, m4_if(_CLIENT_VERSION_BUILD, [0], [], _CLIENT_VERSION_BUILD))m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/PRCYCoin/PRCYCoin/issues],[prcycoin],[https://prcycoin.com]) AC_CONFIG_SRCDIR([src/main.cpp]) -AC_CONFIG_HEADERS([src/config/dapscoin-config.h]) +AC_CONFIG_HEADERS([src/config/prcycoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) -BITCOIN_DAEMON_NAME=dapscoind -BITCOIN_GUI_NAME=dapscoin-qt -BITCOIN_CLI_NAME=dapscoin-cli -BITCOIN_TX_NAME=dapscoin-tx +BITCOIN_DAEMON_NAME=prcycoind +BITCOIN_GUI_NAME=prcycoin-qt +BITCOIN_CLI_NAME=prcycoin-cli +BITCOIN_TX_NAME=prcycoin-tx dnl Unless the user specified ARFLAGS, force it to be cr AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to if not set]) @@ -26,9 +26,9 @@ fi AC_CANONICAL_HOST -AH_TOP([#ifndef DAPS_CONFIG_H]) -AH_TOP([#define DAPS_CONFIG_H]) -AH_BOTTOM([#endif //DAPS_CONFIG_H]) +AH_TOP([#ifndef PRCY_CONFIG_H]) +AH_TOP([#define PRCY_CONFIG_H]) +AH_BOTTOM([#endif //PRCY_CONFIG_H]) dnl faketime breaks configure and is only needed for make. Disable it here. unset FAKETIME @@ -265,7 +265,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], - [build dapscoin-cli dapscoin-tx (default=yes)])], + [build prcycoin-cli prcycoin-tx (default=yes)])], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) @@ -277,7 +277,7 @@ AC_ARG_WITH([libs], AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], - [build dapscoind daemon (default=yes)])], + [build prcycoind daemon (default=yes)])], [build_bitcoind=$withval], [build_bitcoind=yes]) @@ -486,7 +486,7 @@ AC_C_BIGENDIAN([AC_MSG_ERROR("Big Endian not supported")]) dnl Check for pthread compile/link requirements AX_PTHREAD -# The following macro will add the necessary defines to dapscoin-config.h, but +# The following macro will add the necessary defines to prcycoin-config.h, but # they also need to be passed down to any subprojects. Pull the results out of # the cache and add them to CPPFLAGS. AC_SYS_LARGEFILE @@ -1030,11 +1030,11 @@ LIBS="$LIBS_TEMP" BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) -AC_MSG_CHECKING([whether to build dapscoind]) +AC_MSG_CHECKING([whether to build prcycoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (dapscoin-cli dapscoin-tx)]) +AC_MSG_CHECKING([whether to build utils (prcycoin-cli prcycoin-tx)]) AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) AC_MSG_RESULT($build_bitcoin_utils) @@ -1134,7 +1134,7 @@ if test x$bitcoin_enable_qt != xno; then AC_MSG_WARN("xgettext is required to update qt translations") fi - AC_MSG_CHECKING([whether to build test_dapscoin-qt]) + AC_MSG_CHECKING([whether to build test_prcycoin-qt]) if test x$use_tests$bitcoin_enable_qt_test = xyesyes; then AC_MSG_RESULT([yes]) BUILD_TEST_QT="test" @@ -1145,7 +1145,7 @@ fi AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) -AC_MSG_CHECKING([whether to build test_dapscoin]) +AC_MSG_CHECKING([whether to build test_prcycoin]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) BUILD_TEST="test" diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py index 6facb48581..1a1cbe6c89 100644 --- a/contrib/bitrpc/bitrpc.py +++ b/contrib/bitrpc/bitrpc.py @@ -11,9 +11,9 @@ if rpcpass == "": - access = ServiceProxy("http://127.0.0.1:53573") + access = ServiceProxy("http://127.0.0.1:59683") else: - access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:53573") + access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:59683") cmd = sys.argv[1].lower() if cmd == "backupwallet": diff --git a/contrib/dapscoin-qt.desktop b/contrib/dapscoin-qt.desktop deleted file mode 100644 index d2b50d0df8..0000000000 --- a/contrib/dapscoin-qt.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Type=Application -Name=DAPScoin-qt -Comment=DAPScoin QT Wallet -Exec=dapscoin-qt -Icon=dapscoin -Categories=Utility; diff --git a/contrib/debian/README.md b/contrib/debian/README.md index e7ab96061c..daedfefd4f 100644 --- a/contrib/debian/README.md +++ b/contrib/debian/README.md @@ -1,21 +1,21 @@ Debian ==================== -This directory contains files used to package dapscoind/dapscoin-qt -for Debian-based Linux systems. If you compile dapscoind/dapscoin-qt yourself, there are some useful files here. +This directory contains files used to package prcycoind/prcycoin-qt +for Debian-based Linux systems. If you compile prcycoind/prcycoin-qt yourself, there are some useful files here. -## dapscoin: URI support ## +## prcycoin: URI support ## -dapscoin-qt.desktop (Gnome / Open Desktop) +prcycoin-qt.desktop (Gnome / Open Desktop) To install: - sudo desktop-file-install dapscoin-qt.desktop + sudo desktop-file-install prcycoin-qt.desktop sudo update-desktop-database If you build yourself, you will either need to modify the paths in -the .desktop file or copy or symlink your dapscoinqt binary to `/usr/bin` -and the `../../share/pixmaps/dapscoin128.png` to `/usr/share/pixmaps` +the .desktop file or copy or symlink your prcycoinqt binary to `/usr/bin` +and the `../../share/pixmaps/prcycoin128.png` to `/usr/share/pixmaps` -dapscoin-qt.protocol (KDE) +prcycoin-qt.protocol (KDE) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index a9a00c27f5..56d0bf4e3f 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -365,8 +365,8 @@ bitcoin (0.3.19~dfsg-5) unstable; urgency=low bitcoin (0.3.19~dfsg-4) unstable; urgency=low [ Micah Anderson ] - * Provide example dapscoin.conf. - * Add bitcoind(1) and dapscoin.conf(5) man pages. + * Provide example prcycoin.conf. + * Add bitcoind(1) and prcycoin.conf(5) man pages. [ Jonas Smedegaard ] * Ease backporting: diff --git a/contrib/debian/control b/contrib/debian/control index 5e444a92e9..3846d4d5a9 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,4 +1,4 @@ -Source: dapscoin +Source: prcycoin Section: utils Priority: optional Maintainer: Jonas Smedegaard ***TODO*** @@ -22,15 +22,15 @@ Build-Depends: debhelper, libqrencode-dev, libprotobuf-dev, protobuf-compiler Standards-Version: 3.9.2 -Homepage: http://www.dapscoin.org -Vcs-Git: git://github.com/DAPScoin-Project/DAPScoin.git -Vcs-Browser: http://github.com/DAPScoin-Project/DAPScoin +Homepage: http://www.prcycoin.org +Vcs-Git: git://github.com/PRCYcoin-Project/PRCYcoin.git +Vcs-Browser: http://github.com/PRCYcoin-Project/PRCYcoin -Package: dapscoind +Package: prcycoind Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - daemon - Dapscoin is a free open source peer-to-peer electronic cash system that + Prcycoin is a free open source peer-to-peer electronic cash system that is completely decentralized, without the need for a central server or trusted parties. Users hold the crypto keys to their own money and transact directly with each other, with the help of a P2P network to @@ -39,14 +39,14 @@ Description: peer-to-peer network based digital currency - daemon Full transaction history is stored locally at each client. This requires 1+ GB of space, slowly growing. . - This package provides the daemon, dapscoind, and the CLI tool - dapscoin-cli to interact with the daemon. + This package provides the daemon, prcycoind, and the CLI tool + prcycoin-cli to interact with the daemon. -Package: dapscoin-qt +Package: prcycoin-qt Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - Qt GUI - Dapscoin is a free open source peer-to-peer electronic cash system that + Prcycoin is a free open source peer-to-peer electronic cash system that is completely decentralized, without the need for a central server or trusted parties. Users hold the crypto keys to their own money and transact directly with each other, with the help of a P2P network to @@ -55,4 +55,4 @@ Description: peer-to-peer network based digital currency - Qt GUI Full transaction history is stored locally at each client. This requires 1+ GB of space, slowly growing. . - This package provides Dapscoin-Qt, a GUI for Dapscoin based on Qt. + This package provides Prcycoin-Qt, a GUI for Prcycoin based on Qt. diff --git a/contrib/debian/dapscoin-qt.desktop b/contrib/debian/dapscoin-qt.desktop deleted file mode 100644 index 3e9ac22d91..0000000000 --- a/contrib/debian/dapscoin-qt.desktop +++ /dev/null @@ -1,12 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Name=Dapscoin -Comment=Dapscoin P2P Cryptocurrency -Comment[fr]=Dapscoin, monnaie virtuelle cryptographique pair à pair -Comment[tr]=Dapscoin, eşten eşe kriptografik sanal para birimi -Exec=dapscoin-qt %u -Terminal=false -Type=Application -Icon=dapscoin128 -MimeType=x-scheme-handler/dapscoin; -Categories=Office;Finance; diff --git a/contrib/debian/dapscoind.bash-completion b/contrib/debian/dapscoind.bash-completion deleted file mode 100644 index 035fa21083..0000000000 --- a/contrib/debian/dapscoind.bash-completion +++ /dev/null @@ -1 +0,0 @@ -contrib/dapscoind.bash-completion dapscoind diff --git a/contrib/debian/dapscoind.examples b/contrib/debian/dapscoind.examples deleted file mode 100644 index dde3213db0..0000000000 --- a/contrib/debian/dapscoind.examples +++ /dev/null @@ -1 +0,0 @@ -debian/examples/dapscoin.conf diff --git a/contrib/debian/dapscoind.install b/contrib/debian/dapscoind.install deleted file mode 100644 index 719be311b9..0000000000 --- a/contrib/debian/dapscoind.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/local/bin/dapscoind usr/bin -usr/local/bin/dapscoin-cli usr/bin diff --git a/contrib/debian/dapscoind.manpages b/contrib/debian/dapscoind.manpages deleted file mode 100644 index fdd50a6e5c..0000000000 --- a/contrib/debian/dapscoind.manpages +++ /dev/null @@ -1,2 +0,0 @@ -debian/manpages/dapscoind.1 -debian/manpages/dapscoin.conf.5 diff --git a/contrib/debian/examples/dapscoin.conf b/contrib/debian/examples/prcycoin.conf similarity index 82% rename from contrib/debian/examples/dapscoin.conf rename to contrib/debian/examples/prcycoin.conf index 4a26ffb9b7..22bbfa7bc6 100644 --- a/contrib/debian/examples/dapscoin.conf +++ b/contrib/debian/examples/prcycoin.conf @@ -1,10 +1,10 @@ ## -## dapscoin.conf configuration file. Lines beginning with # are comments. +## prcycoin.conf configuration file. Lines beginning with # are comments. ## # Network-related settings: -# Run on the test network instead of the real dapscoin network. +# Run on the test network instead of the real prcycoin network. #testnet=0 # Run a regression test network @@ -38,11 +38,11 @@ # Use as many addnode= settings as you like to connect to specific peers #addnode=69.164.218.197 -#addnode=10.0.0.2:53572 +#addnode=10.0.0.2:59682 # Alternatively use as many connect= settings as you like to connect ONLY to specific peers #connect=69.164.218.197 -#connect=10.0.0.1:53572 +#connect=10.0.0.1:59682 # Listening mode, enabled by default except when 'connect' is being used #listen=1 @@ -51,17 +51,17 @@ #maxconnections= # -# JSON-RPC options (for controlling a running Dapscoin/dapscoind process) +# JSON-RPC options (for controlling a running Prcycoin/prcycoind process) # -# server=1 tells Dapscoin-QT and dapscoind to accept JSON-RPC commands +# server=1 tells Prcycoin-QT and prcycoind to accept JSON-RPC commands #server=0 # You must set rpcuser and rpcpassword to secure the JSON-RPC api #rpcuser=Ulysseys #rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593 -# How many seconds dapscoin will wait for a complete RPC HTTP request. +# How many seconds prcycoin will wait for a complete RPC HTTP request. # after the HTTP connection is established. #rpcclienttimeout=30 @@ -72,16 +72,16 @@ # NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED, # because the rpcpassword is transmitted over the network unencrypted. -# server=1 tells Dapscoin-QT to accept JSON-RPC commands. -# it is also read by dapscoind to determine if RPC should be enabled +# server=1 tells Prcycoin-QT to accept JSON-RPC commands. +# it is also read by prcycoind to determine if RPC should be enabled #rpcallowip=10.1.1.34/255.255.255.0 #rpcallowip=1.2.3.4/24 #rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96 # Listen for RPC connections on this TCP port: -#rpcport=53573 +#rpcport=59683 -# You can use Dapscoin or dapscoind to send commands to Dapscoin/dapscoind +# You can use Prcycoin or prcycoind to send commands to Prcycoin/prcycoind # running on another host using this option: #rpcconnect=127.0.0.1 @@ -91,14 +91,14 @@ # both prior transactions and several dozen future transactions. #keypool=100 -# Pay an optional transaction fee every time you send DAPSs. Transactions with fees +# Pay an optional transaction fee every time you send PRCYs. Transactions with fees # are more likely than free transactions to be included in generated blocks, so may # be validated sooner. #paytxfee=0.00 # User interface options -# Start Dapscoin minimized +# Start Prcycoin minimized #min=1 # Minimize to the system tray diff --git a/contrib/debian/manpages/dapscoin-qt.1 b/contrib/debian/manpages/prcycoin-qt.1 similarity index 92% rename from contrib/debian/manpages/dapscoin-qt.1 rename to contrib/debian/manpages/prcycoin-qt.1 index 9d40e331f4..5a000596be 100644 --- a/contrib/debian/manpages/dapscoin-qt.1 +++ b/contrib/debian/manpages/prcycoin-qt.1 @@ -1,20 +1,20 @@ -.TH DAPS-QT "1" "February 2017" "dapscoin-qt 1" +.TH PRCY-QT "1" "February 2017" "prcycoin-qt 1" .SH NAME -dapscoin-qt \- peer-to-peer network based digital currency +prcycoin-qt \- peer-to-peer network based digital currency .SH DESCRIPTION .SS "Usage:" .IP -dapscoin\-qt [command\-line options] +prcycoin\-qt [command\-line options] .SH OPTIONS .TP \-? This help message .TP \fB\-conf=\fR -Specify configuration file (default: dapscoin.conf) +Specify configuration file (default: prcycoin.conf) .TP \fB\-pid=\fR -Specify pid file (default: dapscoind.pid) +Specify pid file (default: prcycoind.pid) .TP \fB\-gen\fR Generate coins @@ -41,7 +41,7 @@ Use proxy to reach tor hidden services (default: same as \fB\-proxy\fR) Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR .TP \fB\-port=\fR -Listen for connections on (default: 53572 or testnet: 53574) +Listen for connections on (default: 59682 or testnet: 59684) .TP \fB\-maxconnections=\fR Maintain at most connections to peers (default: 125) @@ -122,7 +122,7 @@ Username for JSON\-RPC connections Password for JSON\-RPC connections .TP \fB\-rpcport=\fR -Listen for JSON\-RPC connections on (default: 53573 or testnet: 53575) +Listen for JSON\-RPC connections on (default: 59683 or testnet: 59685) .TP \fB\-rpcallowip=\fR Allow JSON\-RPC connections from specified IP address diff --git a/contrib/debian/manpages/dapscoin.conf.5 b/contrib/debian/manpages/prcycoin.conf.5 similarity index 75% rename from contrib/debian/manpages/dapscoin.conf.5 rename to contrib/debian/manpages/prcycoin.conf.5 index d7d297656b..9db0fcb0c6 100644 --- a/contrib/debian/manpages/dapscoin.conf.5 +++ b/contrib/debian/manpages/prcycoin.conf.5 @@ -1,27 +1,27 @@ -.TH DAPS.CONF "5" "January 2011" "dapscoin.conf 3.19" +.TH PRCY.CONF "5" "January 2011" "prcycoin.conf 3.19" .SH NAME -dapscoin.conf \- dapscoin configuration file +prcycoin.conf \- prcycoin configuration file .SH SYNOPSIS All command-line options (except for '\-conf') may be specified in a configuration file, and all configuration file options may also be specified on the command line. Command-line options override values set in the configuration file. .TP The configuration file is a list of 'setting=value' pairs, one per line, with optional comments starting with the '#' character. .TP -The configuration file is not automatically created; you can create it using your favorite plain-text editor. By default, dapscoind(1) will look for a file named dapscoin.conf(5) in the dapscoin data directory, but both the data directory and the configuration file path may be changed using the '\-datadir' and '\-conf' command-line arguments. +The configuration file is not automatically created; you can create it using your favorite plain-text editor. By default, prcycoind(1) will look for a file named prcycoin.conf(5) in the prcycoin data directory, but both the data directory and the configuration file path may be changed using the '\-datadir' and '\-conf' command-line arguments. .SH LOCATION -dapscoin.conf should be located in $HOME/.dapscoin +prcycoin.conf should be located in $HOME/.prcycoin .SH NETWORK-RELATED SETTINGS .TP .TP \fBtestnet=\fR[\fI'1'\fR|\fI'0'\fR] -Enable or disable run on the test network instead of the real *dapscoin* network. +Enable or disable run on the test network instead of the real *prcycoin* network. .TP \fBproxy=\fR\fI'127.0.0.1:9050'\fR Connect via a socks4 proxy. .TP -\fBaddnode=\fR\fI'10.0.0.2:53572'\fR +\fBaddnode=\fR\fI'10.0.0.2:59682'\fR Use as many *addnode=* settings as you like to connect to specific peers. .TP -\fBconnect=\fR\fI'10.0.0.1:53572'\fR +\fBconnect=\fR\fI'10.0.0.1:59682'\fR Use as many *connect=* settings as you like to connect ONLY to specific peers. .TP \fRmaxconnections=\fR\fI'value'\fR @@ -29,7 +29,7 @@ Maximum number of inbound+outbound connections. .SH JSON-RPC OPTIONS .TP \fBserver=\fR[\fI'1'\fR|\fI'0'\fR] -Tells *dapscoin* to accept or not accept JSON-RPC commands. +Tells *prcycoin* to accept or not accept JSON-RPC commands. .TP \fBrpcuser=\fR\fI'username'\fR You must set *rpcuser* to secure the JSON-RPC api. @@ -40,25 +40,25 @@ You must set *rpcpassword* to secure the JSON-RPC api. \fBrpcallowip=\fR\fI'192.168.1.*'\fR By default, only RPC connections from localhost are allowed. Specify as many *rpcallowip=* settings as you like to allow connections from other hosts (and you may use * as a wildcard character). .TP -\fBrpcport=\fR\fI'53573'\fR +\fBrpcport=\fR\fI'59683'\fR Listen for RPC connections on this TCP port. .TP \fBrpcconnect=\fR\fI'127.0.0.1'\fR -You can use *dapscoin* or *dapscoind(1)* to send commands to *dapscoin*/*dapscoind(1)* running on another host using this option. +You can use *prcycoin* or *prcycoind(1)* to send commands to *prcycoin*/*prcycoind(1)* running on another host using this option. .TP .SH MISCELLANEOUS OPTIONS .TP \fBgen=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable attempt to generate DAPSs. +Enable or disable attempt to generate PRCYs. .TP \fB4way=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable use SSE instructions to try to generate DAPSs faster. +Enable or disable use SSE instructions to try to generate PRCYs faster. .TP \fBkeypool=\fR\fI'100'\fR Pre-generate this many public/private key pairs, so wallet backups will be valid for both prior transactions and several dozen future transactions. .TP \fBpaytxfee=\fR\fI'0.00'\fR -Pay an optional transaction fee every time you send DAPSs. Transactions with fees are more likely than free transactions to be included in generated blocks, so may be validated sooner. +Pay an optional transaction fee every time you send PRCYs. Transactions with fees are more likely than free transactions to be included in generated blocks, so may be validated sooner. .TP \fBallowreceivebyip=\fR\fI'1'\fR Allow direct connections for the 'pay via IP address' feature. @@ -66,12 +66,12 @@ Allow direct connections for the 'pay via IP address' feature. .SH USER INTERFACE OPTIONS .TP \fBmin=\fR[\fI'0'\fR|\fI'1'\fR] -Enable or disable start dapscoind minimized. +Enable or disable start prcycoind minimized. .TP \fBminimizetotray=\fR[\fI'0'\fR|\fI'1'\fR] Enable or disable minimize to the system tray. .SH "SEE ALSO" -dapscoind(1) +prcycoind(1) .SH AUTHOR This manual page was written by Micah Anderson for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. diff --git a/contrib/debian/manpages/dapscoind.1 b/contrib/debian/manpages/prcycoind.1 similarity index 82% rename from contrib/debian/manpages/dapscoind.1 rename to contrib/debian/manpages/prcycoind.1 index d09c7ff5c2..c8840421a6 100644 --- a/contrib/debian/manpages/dapscoind.1 +++ b/contrib/debian/manpages/prcycoind.1 @@ -1,19 +1,19 @@ -.TH DAPSD "1" "February 2017" "dapscoind 2.1.4.1" +.TH PRCYD "1" "February 2017" "prcycoind 2.1.4.1" .SH NAME -Dapscoin \- peer-to-peer network based digital currency +Prcycoin \- peer-to-peer network based digital currency .SH SYNOPSIS -dapscoind [options] [params] +prcycoind [options] [params] .TP -dapscoind [options] help \- Get help for a command +prcycoind [options] help \- Get help for a command .SH DESCRIPTION -This manual page documents the dapscoind program. Dapscoin is a peer-to-peer digital currency. Peer-to-peer (P2P) means that there is no central authority to issue new money or keep track of transactions. Instead, these tasks are managed collectively by the nodes of the network. Advantages: +This manual page documents the prcycoind program. Prcycoin is a peer-to-peer digital currency. Peer-to-peer (P2P) means that there is no central authority to issue new money or keep track of transactions. Instead, these tasks are managed collectively by the nodes of the network. Advantages: -Dapscoin can be sent easily through the Internet, without having to trust middlemen. Transactions are designed to be irreversible. Be safe from instability caused by fractional reserve banking and central banks. The limited inflation of the Dapscoin system’s money supply is distributed evenly (by CPU power) throughout the network, not monopolized by banks. +Prcycoin can be sent easily through the Internet, without having to trust middlemen. Transactions are designed to be irreversible. Be safe from instability caused by fractional reserve banking and central banks. The limited inflation of the Prcycoin system’s money supply is distributed evenly (by CPU power) throughout the network, not monopolized by banks. .SH OPTIONS .TP \fB\-conf=\fR -Specify configuration file (default: dapscoin.conf) +Specify configuration file (default: prcycoin.conf) .TP \fB\-gen\fR Generate coins @@ -70,14 +70,14 @@ This help message \fBbackupwallet 'destination'\fR Safely copies *wallet.dat* to 'destination', which can be a directory or a path with filename. .TP -\fBgetaccount 'dapscoinaddress'\fR +\fBgetaccount 'prcycoinaddress'\fR Returns the account associated with the given address. .TP -\fBsetaccount 'dapscoinaddress' ['account']\fR +\fBsetaccount 'prcycoinaddress' ['account']\fR Sets the ['account'] associated with the given address. ['account'] may be omitted to remove an address from ['account']. .TP \fBgetaccountaddress 'account'\fR -Returns a new dapscoin address for 'account'. +Returns a new prcycoin address for 'account'. .TP \fBgetaddressesbyaccount 'account'\fR Returns the list of addresses associated with the given 'account'. @@ -98,7 +98,7 @@ Returns the number of connections to other nodes. Returns the proof-of-work difficulty as a multiple of the minimum difficulty. .TP \fBgetgenerate\fR -Returns boolean true if server is trying to generate DAPS, false otherwise. +Returns boolean true if server is trying to generate PRCY, false otherwise. .TP \fBsetgenerate 'generate' ['genproclimit']\fR Generation is limited to ['genproclimit'] processors, \-1 is unlimited. @@ -110,13 +110,13 @@ Returns a recent hashes per second performance measurement while generating. Returns an object containing server information. .TP \fBgetnewaddress 'account'\fR -Returns a new dapscoin address for receiving payments. If 'account' is specified (recommended), it is added to the address book so payments received with the address will be credited to 'account'. +Returns a new prcycoin address for receiving payments. If 'account' is specified (recommended), it is added to the address book so payments received with the address will be credited to 'account'. .TP \fBgetreceivedbyaccount 'account' ['minconf=1']\fR Returns the total amount received by addresses associated with 'account' in transactions with at least ['minconf'] confirmations. .TP -\fBgetreceivedbyaddress 'dapscoinaddress' ['minconf=1']\fR -Returns the total amount received by 'dapscoinaddress' in transactions with at least ['minconf'] confirmations. +\fBgetreceivedbyaddress 'prcycoinaddress' ['minconf=1']\fR +Returns the total amount received by 'prcycoinaddress' in transactions with at least ['minconf'] confirmations. .TP \fBgettransaction 'txid'\fR Returns information about a specific transaction, given hexadecimal transaction ID. @@ -134,7 +134,7 @@ List commands, or get help for a command. .TP \fBlistaccounts ['minconf=1']\fR List accounts and their current balances. - *note: requires dapscoin 1.0.2.1 or later. + *note: requires prcycoin 1.0.2.1 or later. .TP \fBlistreceivedbyaccount ['minconf=1'] ['includeempty=false']\fR ['minconf'] is the minimum number of confirmations before payments are included. ['includeempty'] whether to include addresses that haven't received any payments. Returns an array of objects containing: @@ -163,31 +163,31 @@ Returns a list of the last ['count'] transactions for 'account' \- for all accou "message" : message associated with transaction (only for send). "to" : message-to associated with transaction (only for send). - *note: requires dapscoin 1.0.2.1 or later. + *note: requires prcycoin 1.0.2.1 or later. .TP \fBmove <'fromaccount'> <'toaccount'> <'amount'> ['minconf=1'] ['comment']\fR Moves funds between accounts. .TP -\fBsendfrom* <'account'> <'dapscoinaddress'> <'amount'> ['minconf=1'] ['comment'] ['comment-to']\fR -Sends amount from account's balance to 'dapscoinaddress'. This method will fail if there is less than amount DAPS with ['minconf'] confirmations in the account's balance (unless account is the empty-string-named default account; it behaves like the *sendtoaddress* method). Returns transaction ID on success. +\fBsendfrom* <'account'> <'prcycoinaddress'> <'amount'> ['minconf=1'] ['comment'] ['comment-to']\fR +Sends amount from account's balance to 'prcycoinaddress'. This method will fail if there is less than amount PRCY with ['minconf'] confirmations in the account's balance (unless account is the empty-string-named default account; it behaves like the *sendtoaddress* method). Returns transaction ID on success. .TP -\fBsendtoaddress 'dapscoinaddress' 'amount' ['comment'] ['comment-to']\fR -Sends amount from the server's available balance to 'dapscoinaddress'. amount is a real and is rounded to the nearest 0.01. Returns transaction id on success. +\fBsendtoaddress 'prcycoinaddress' 'amount' ['comment'] ['comment-to']\fR +Sends amount from the server's available balance to 'prcycoinaddress'. amount is a real and is rounded to the nearest 0.01. Returns transaction id on success. .TP \fBstop\fR -Stops the dapscoin server. +Stops the prcycoin server. .TP -\fBvalidateaddress 'dapscoinaddress'\fR -Checks that 'dapscoinaddress' looks like a proper Dapscoin address. Returns an object containing: +\fBvalidateaddress 'prcycoinaddress'\fR +Checks that 'prcycoinaddress' looks like a proper Prcycoin address. Returns an object containing: "isvalid" : true or false. "ismine" : true if the address is in the server's wallet. - "address" : dapscoinaddress. + "address" : prcycoinaddress. *note: ismine and address are only returned if the address is valid. .SH "SEE ALSO" -dapscoin.conf(5) +prcycoin.conf(5) .SH AUTHOR This manual page was written by Micah Anderson for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. diff --git a/contrib/debian/prcycoin-qt.desktop b/contrib/debian/prcycoin-qt.desktop new file mode 100644 index 0000000000..d6d18ba61b --- /dev/null +++ b/contrib/debian/prcycoin-qt.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Prcycoin +Comment=Prcycoin P2P Cryptocurrency +Comment[fr]=Prcycoin, monnaie virtuelle cryptographique pair à pair +Comment[tr]=Prcycoin, eşten eşe kriptografik sanal para birimi +Exec=prcycoin-qt %u +Terminal=false +Type=Application +Icon=prcycoin128 +MimeType=x-scheme-handler/prcycoin; +Categories=Office;Finance; diff --git a/contrib/debian/dapscoin-qt.install b/contrib/debian/prcycoin-qt.install similarity index 50% rename from contrib/debian/dapscoin-qt.install rename to contrib/debian/prcycoin-qt.install index 9dba1727a4..42f64cae62 100644 --- a/contrib/debian/dapscoin-qt.install +++ b/contrib/debian/prcycoin-qt.install @@ -1,6 +1,6 @@ -usr/local/bin/dapscoin-qt usr/bin +usr/local/bin/prcycoin-qt usr/bin share/pixmaps/bitcoin32.xpm usr/share/pixmaps share/pixmaps/bitcoin16.xpm usr/share/pixmaps share/pixmaps/bitcoin128.png usr/share/pixmaps -debian/dapscoin-qt.desktop usr/share/applications -debian/dapscoin-qt.protocol usr/share/kde4/services/ +debian/prcycoin-qt.desktop usr/share/applications +debian/prcycoin-qt.protocol usr/share/kde4/services/ diff --git a/contrib/debian/dapscoin-qt.lintian-overrides b/contrib/debian/prcycoin-qt.lintian-overrides similarity index 52% rename from contrib/debian/dapscoin-qt.lintian-overrides rename to contrib/debian/prcycoin-qt.lintian-overrides index 777ee89790..f0bf230053 100644 --- a/contrib/debian/dapscoin-qt.lintian-overrides +++ b/contrib/debian/prcycoin-qt.lintian-overrides @@ -1,2 +1,2 @@ # Linked code is Expat - only Debian packaging is GPL-2+ -dapscoin-qt: possible-gpl-code-linked-with-openssl +prcycoin-qt: possible-gpl-code-linked-with-openssl diff --git a/contrib/debian/dapscoin-qt.protocol b/contrib/debian/prcycoin-qt.protocol similarity index 73% rename from contrib/debian/dapscoin-qt.protocol rename to contrib/debian/prcycoin-qt.protocol index 0543f911b7..1cf82a5582 100644 --- a/contrib/debian/dapscoin-qt.protocol +++ b/contrib/debian/prcycoin-qt.protocol @@ -1,6 +1,6 @@ [Protocol] -exec=dapscoin-qt '%u' -protocol=dapscoin +exec=prcycoin-qt '%u' +protocol=prcycoin input=none output=none helper=true diff --git a/contrib/debian/prcycoind.bash-completion b/contrib/debian/prcycoind.bash-completion new file mode 100644 index 0000000000..f49ab02746 --- /dev/null +++ b/contrib/debian/prcycoind.bash-completion @@ -0,0 +1 @@ +contrib/prcycoind.bash-completion prcycoind diff --git a/contrib/debian/prcycoind.examples b/contrib/debian/prcycoind.examples new file mode 100644 index 0000000000..8f9fcffba0 --- /dev/null +++ b/contrib/debian/prcycoind.examples @@ -0,0 +1 @@ +debian/examples/prcycoin.conf diff --git a/contrib/debian/prcycoind.install b/contrib/debian/prcycoind.install new file mode 100644 index 0000000000..a6f99cc4f6 --- /dev/null +++ b/contrib/debian/prcycoind.install @@ -0,0 +1,2 @@ +usr/local/bin/prcycoind usr/bin +usr/local/bin/prcycoin-cli usr/bin diff --git a/contrib/debian/dapscoind.lintian-overrides b/contrib/debian/prcycoind.lintian-overrides similarity index 53% rename from contrib/debian/dapscoind.lintian-overrides rename to contrib/debian/prcycoind.lintian-overrides index 4b0508d59b..3fa6c545e6 100644 --- a/contrib/debian/dapscoind.lintian-overrides +++ b/contrib/debian/prcycoind.lintian-overrides @@ -1,2 +1,2 @@ # Linked code is Expat - only Debian packaging is GPL-2+ -dapscoind: possible-gpl-code-linked-with-openssl +prcycoind: possible-gpl-code-linked-with-openssl diff --git a/contrib/debian/prcycoind.manpages b/contrib/debian/prcycoind.manpages new file mode 100644 index 0000000000..d72486ea25 --- /dev/null +++ b/contrib/debian/prcycoind.manpages @@ -0,0 +1,2 @@ +debian/manpages/prcycoind.1 +debian/manpages/prcycoin.conf.5 diff --git a/contrib/debian/rules b/contrib/debian/rules index 27b46bae3d..a4049ad72d 100644 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -1,9 +1,9 @@ #!/usr/bin/make -f # -*- mode: makefile; coding: utf-8 -*- -#DEB_MAKE_CHECK_TARGET = test_dapscoin +#DEB_MAKE_CHECK_TARGET = test_prcycoin #build/bitcoind:: -# $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_dapscoin) +# $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_prcycoin) DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/* DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/* @@ -13,7 +13,7 @@ DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/* override_dh_auto_clean: if [ -f Makefile ]; then $(MAKE) distclean; fi - rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/dapscoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in + rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/prcycoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in # Yea, autogen should be run on the source archive, but I like doing git archive override_dh_auto_configure: diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index afa0a90fd3..955108b593 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -18,7 +18,7 @@ For example: ./github-merge.py 3077 (in any git repository) will help you merge pull request #3077 for the -DAPScoin-Project/DAPS repository. +PRCYcoin-Project/PRCY repository. What it does: * Fetch master and the pull request. @@ -36,16 +36,16 @@ couldn't mess with the sources. Setup --------- -Configuring the github-merge tool for the DAPS repository is done in the following way: +Configuring the github-merge tool for the PRCY repository is done in the following way: - git config githubmerge.repository DAPScoin-Project/DAPScoin + git config githubmerge.repository PRCYcoin-Project/PRCYcoin git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) git config --global user.signingkey mykeyid (if you want to GPG sign) optimize-pngs.py ================ -A script to optimize png files in the DAPScoin +A script to optimize png files in the PRCYcoin repository (requires pngcrush). fix-copyright-headers.py @@ -93,10 +93,10 @@ If only supported symbols are used the return value will be 0 and the output wil If there are 'unsupported' symbols, the return value will be 1 a list like this will be printed: - .../64/test_dapscoin: symbol memcpy from unsupported version GLIBC_2.14 - .../64/test_dapscoin: symbol __fdelt_chk from unsupported version GLIBC_2.15 - .../64/test_dapscoin: symbol std::out_of_range::~out_of_range() from unsupported version GLIBCXX_3.4.15 - .../64/test_dapscoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15 + .../64/test_prcycoin: symbol memcpy from unsupported version GLIBC_2.14 + .../64/test_prcycoin: symbol __fdelt_chk from unsupported version GLIBC_2.15 + .../64/test_prcycoin: symbol std::out_of_range::~out_of_range() from unsupported version GLIBCXX_3.4.15 + .../64/test_prcycoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15 update-translations.py ====================== diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py index 9f6e7c87ef..317c475925 100644 --- a/contrib/devtools/check-doc.py +++ b/contrib/devtools/check-doc.py @@ -20,7 +20,7 @@ REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions', '-checklevel', '-liquidityprovider', '-anonymizedapscoinamount']) +SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions', '-checklevel', '-liquidityprovider', '-anonymizeprcycoinamount']) def main(): used = check_output(CMD_GREP_ARGS, shell=True) diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py index 36105009ac..7b7e7cd0d4 100644 --- a/contrib/devtools/update-translations.py +++ b/contrib/devtools/update-translations.py @@ -26,7 +26,7 @@ # Name of transifex tool TX = 'tx' # Name of source language file -SOURCE_LANG = 'dapscoin_en.ts' +SOURCE_LANG = 'prcycoin_en.ts' # Directory with locale files LOCALE_DIR = 'src/qt/locale' # Minimum number of messages for translation to be considered at all diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh index e0d208a4f2..08c3206a53 100644 --- a/contrib/gitian-build.sh +++ b/contrib/gitian-build.sh @@ -17,7 +17,7 @@ osx=true SIGNER= VERSION= commit=false -url=https://github.com/dapscoin-project/dapscoin +url=https://github.com/prcycoin-project/prcycoin proc=2 mem=2000 lxc=true @@ -31,7 +31,7 @@ commitFiles=true read -d '' usage <<- EOF Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version -Run this script from the directory containing the dapscoin, gitian-builder, gitian.sigs, and dapscoin-detached-sigs. +Run this script from the directory containing the prcycoin, gitian-builder, gitian.sigs, and prcycoin-detached-sigs. Arguments: signer GPG signer to sign each build assert file @@ -39,7 +39,7 @@ version Version number, commit, or branch to build. If building a commit or bra Options: -c|--commit Indicate that the version argument is for a commit or branch --u|--url Specify the URL of the repository. Default is https://github.com/dapscoin-project/dapscoin +-u|--url Specify the URL of the repository. Default is https://github.com/prcycoin-project/prcycoin -v|--verify Verify the gitian build -b|--build Do a gitian build -s|--sign Make signed binaries for Windows and Mac OSX @@ -237,8 +237,8 @@ echo ${COMMIT} if [[ $setup = true ]] then sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils - git clone https://github.com/dapscoin-project/gitian.sigs.git - git clone https://github.com/dapscoin-project/dapscoin-detached-sigs.git + git clone https://github.com/prcycoin-project/gitian.sigs.git + git clone https://github.com/prcycoin-project/prcycoin-detached-sigs.git git clone https://github.com/devrandom/gitian-builder.git pushd ./gitian-builder if [[ -n "$USE_LXC" ]] @@ -252,7 +252,7 @@ then fi # Set up build -pushd ./dapscoin +pushd ./prcycoin git fetch git checkout ${COMMIT} popd @@ -261,7 +261,7 @@ popd if [[ $build = true ]] then # Make output folder - mkdir -p ./dapscoin-binaries/${VERSION} + mkdir -p ./prcycoin-binaries/${VERSION} # Build Dependencies echo "" @@ -271,7 +271,7 @@ then mkdir -p inputs wget -N -P inputs $osslPatchUrl wget -N -P inputs $osslTarUrl - make -C ../dapscoin/depends download SOURCES_PATH=`pwd`/cache/common + make -C ../prcycoin/depends download SOURCES_PATH=`pwd`/cache/common # Linux if [[ $linux = true ]] @@ -279,9 +279,9 @@ then echo "" echo "Compiling ${VERSION} Linux" echo "" - ./bin/gbuild -j ${proc} -m ${mem} --commit dapscoin=${COMMIT} --url dapscoin=${url} ../dapscoin/contrib/gitian-descriptors/gitian-linux.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-linux.yml - mv build/out/dapscoin-*.tar.gz build/out/src/dapscoin-*.tar.gz ../dapscoin-binaries/${VERSION} + ./bin/gbuild -j ${proc} -m ${mem} --commit prcycoin=${COMMIT} --url prcycoin=${url} ../prcycoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-linux.yml + mv build/out/prcycoin-*.tar.gz build/out/src/prcycoin-*.tar.gz ../prcycoin-binaries/${VERSION} fi # Windows if [[ $windows = true ]] @@ -289,10 +289,10 @@ then echo "" echo "Compiling ${VERSION} Windows" echo "" - ./bin/gbuild -j ${proc} -m ${mem} --commit dapscoin=${COMMIT} --url dapscoin=${url} ../dapscoin/contrib/gitian-descriptors/gitian-win.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-win.yml - mv build/out/dapscoin-*-win-unsigned.tar.gz inputs/dapscoin-win-unsigned.tar.gz - mv build/out/dapscoin-*.zip build/out/dapscoin-*.exe ../dapscoin-binaries/${VERSION} + ./bin/gbuild -j ${proc} -m ${mem} --commit prcycoin=${COMMIT} --url prcycoin=${url} ../prcycoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-win.yml + mv build/out/prcycoin-*-win-unsigned.tar.gz inputs/prcycoin-win-unsigned.tar.gz + mv build/out/prcycoin-*.zip build/out/prcycoin-*.exe ../prcycoin-binaries/${VERSION} fi # Mac OSX if [[ $osx = true ]] @@ -300,10 +300,10 @@ then echo "" echo "Compiling ${VERSION} Mac OSX" echo "" - ./bin/gbuild -j ${proc} -m ${mem} --commit dapscoin=${COMMIT} --url dapscoin=${url} ../dapscoin/contrib/gitian-descriptors/gitian-osx.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-osx.yml - mv build/out/dapscoin-*-osx-unsigned.tar.gz inputs/dapscoin-osx-unsigned.tar.gz - mv build/out/dapscoin-*.tar.gz build/out/dapscoin-*.dmg ../dapscoin-binaries/${VERSION} + ./bin/gbuild -j ${proc} -m ${mem} --commit prcycoin=${COMMIT} --url prcycoin=${url} ../prcycoin/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-osx.yml + mv build/out/prcycoin-*-osx-unsigned.tar.gz inputs/prcycoin-osx-unsigned.tar.gz + mv build/out/prcycoin-*.tar.gz build/out/prcycoin-*.dmg ../prcycoin-binaries/${VERSION} fi # AArch64 if [[ $aarch64 = true ]] @@ -311,9 +311,9 @@ then echo "" echo "Compiling ${VERSION} AArch64" echo "" - ./bin/gbuild -j ${proc} -m ${mem} --commit dapscoin=${COMMIT} --url dapscoin=${url} ../dapscoin/contrib/gitian-descriptors/gitian-aarch64.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-aarch64 --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-aarch64.yml - mv build/out/dapscoin-*.tar.gz build/out/src/dapscoin-*.tar.gz ../dapscoin-binaries/${VERSION} + ./bin/gbuild -j ${proc} -m ${mem} --commit prcycoin=${COMMIT} --url prcycoin=${url} ../prcycoin/contrib/gitian-descriptors/gitian-aarch64.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-aarch64 --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-aarch64.yml + mv build/out/prcycoin-*.tar.gz build/out/src/prcycoin-*.tar.gz ../prcycoin-binaries/${VERSION} popd if [[ $commitFiles = true ]] @@ -340,32 +340,32 @@ then echo "" echo "Verifying v${VERSION} Linux" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../dapscoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../prcycoin/contrib/gitian-descriptors/gitian-linux.yml # Windows echo "" echo "Verifying v${VERSION} Windows" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../dapscoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../prcycoin/contrib/gitian-descriptors/gitian-win.yml # Mac OSX echo "" echo "Verifying v${VERSION} Mac OSX" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../dapscoin/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../prcycoin/contrib/gitian-descriptors/gitian-osx.yml # AArch64 echo "" echo "Verifying v${VERSION} AArch64" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-aarch64 ../dapscoin/contrib/gitian-descriptors/gitian-aarch64.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-aarch64 ../prcycoin/contrib/gitian-descriptors/gitian-aarch64.yml # Signed Windows echo "" echo "Verifying v${VERSION} Signed Windows" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../dapscoin/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../prcycoin/contrib/gitian-descriptors/gitian-osx-signer.yml # Signed Mac OSX echo "" echo "Verifying v${VERSION} Signed Mac OSX" echo "" - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../dapscoin/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../prcycoin/contrib/gitian-descriptors/gitian-osx-signer.yml popd fi @@ -380,10 +380,10 @@ then echo "" echo "Signing ${VERSION} Windows" echo "" - ./bin/gbuild -i --commit signature=${COMMIT} ../dapscoin/contrib/gitian-descriptors/gitian-win-signer.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-win-signer.yml - mv build/out/dapscoin-*win64-setup.exe ../dapscoin-binaries/${VERSION} - mv build/out/dapscoin-*win32-setup.exe ../dapscoin-binaries/${VERSION} + ./bin/gbuild -i --commit signature=${COMMIT} ../prcycoin/contrib/gitian-descriptors/gitian-win-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-win-signer.yml + mv build/out/prcycoin-*win64-setup.exe ../prcycoin-binaries/${VERSION} + mv build/out/prcycoin-*win32-setup.exe ../prcycoin-binaries/${VERSION} fi # Sign Mac OSX if [[ $osx = true ]] @@ -391,9 +391,9 @@ then echo "" echo "Signing ${VERSION} Mac OSX" echo "" - ./bin/gbuild -i --commit signature=${COMMIT} ../dapscoin/contrib/gitian-descriptors/gitian-osx-signer.yml - ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../dapscoin/contrib/gitian-descriptors/gitian-osx-signer.yml - mv build/out/dapscoin-osx-signed.dmg ../dapscoin-binaries/${VERSION}/dapscoin-${VERSION}-osx.dmg + ./bin/gbuild -i --commit signature=${COMMIT} ../prcycoin/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../prcycoin/contrib/gitian-descriptors/gitian-osx-signer.yml + mv build/out/prcycoin-osx-signed.dmg ../prcycoin-binaries/${VERSION}/prcycoin-${VERSION}-osx.dmg fi popd diff --git a/contrib/gitian-descriptors/README.md b/contrib/gitian-descriptors/README.md index fff21f59c1..ef733069c3 100644 --- a/contrib/gitian-descriptors/README.md +++ b/contrib/gitian-descriptors/README.md @@ -20,7 +20,7 @@ Sanity checks: Once you've got the right hardware and software: - git clone git://github.com/dapscoin-project/dapscoin.git + git clone git://github.com/prcycoin-project/prcycoin.git git clone git://github.com/devrandom/gitian-builder.git mkdir gitian-builder/inputs cd gitian-builder/inputs @@ -62,5 +62,5 @@ Here's a description of Gavin's setup on OSX 10.6: 5. Still inside Ubuntu, tell gitian-builder to use LXC, then follow the "Once you've got the right hardware and software" instructions above: export USE_LXC=1 - git clone git://github.com/dapscoin-project/dapscoin.git + git clone git://github.com/prcycoin-project/prcycoin.git ... etc diff --git a/contrib/gitian-descriptors/gitian-aarch64.yml b/contrib/gitian-descriptors/gitian-aarch64.yml index 5a950c806b..092713a624 100644 --- a/contrib/gitian-descriptors/gitian-aarch64.yml +++ b/contrib/gitian-descriptors/gitian-aarch64.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-aarch64-3.0" +name: "prcycoin-aarch64-3.0" enable_cache: true suites: - "xenial" @@ -25,8 +25,8 @@ packages: - "python" reference_datetime: "2015-06-01 00:00:00" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin.git" - "dir": "dapscoin" +- "url": "https://github.com/prcycoin-project/prcycoin.git" + "dir": "prcycoin" files: [] script: | @@ -110,7 +110,7 @@ script: | chmod +x ${WRAP_DIR}/${prog} done - cd dapscoin + cd prcycoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do @@ -132,13 +132,13 @@ script: | ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist - SOURCEDIST=`echo dapscoin-*.tar.gz` + SOURCEDIST=`echo prcycoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST - find dapscoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + find prcycoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 39ff30f9fa..5a1bb6b6f2 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-linux-3.0" +name: "prcycoin-linux-3.0" enable_cache: true suites: - "trusty" @@ -29,8 +29,8 @@ packages: - "python" reference_datetime: "2015-06-01 00:00:00" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin.git" - "dir": "dapscoin" +- "url": "https://github.com/prcycoin-project/prcycoin.git" + "dir": "prcycoin" files: [] script: | @@ -114,7 +114,7 @@ script: | chmod +x ${WRAP_DIR}/${prog} done - cd dapscoin + cd prcycoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do @@ -136,13 +136,13 @@ script: | ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist - SOURCEDIST=`echo dapscoin-*.tar.gz` + SOURCEDIST=`echo prcycoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST - find dapscoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + find prcycoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index a633f5ef48..0c6ba37548 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-dmg-signer" +name: "prcycoin-dmg-signer" suites: - "trusty" architectures: @@ -7,10 +7,10 @@ architectures: packages: - "faketime" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin-detached-sigs.git" +- "url": "https://github.com/prcycoin-project/prcycoin-detached-sigs.git" "dir": "signature" files: -- "dapscoin-osx-unsigned.tar.gz" +- "prcycoin-osx-unsigned.tar.gz" script: | WRAP_DIR=$HOME/wrapped mkdir -p ${WRAP_DIR} @@ -27,11 +27,11 @@ script: | chmod +x ${WRAP_DIR}/${prog} done - UNSIGNED=dapscoin-osx-unsigned.tar.gz - SIGNED=dapscoin-osx-signed.dmg + UNSIGNED=prcycoin-osx-unsigned.tar.gz + SIGNED=prcycoin-osx-signed.dmg tar -xf ${UNSIGNED} OSX_VOLNAME="$(cat osx_volname)" ./detached-sig-apply.sh ${UNSIGNED} signature/osx - ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "Dapscoin-Qt" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app + ${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "Prcycoin-Qt" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app ${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED} diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 50b81b576b..fafe94f393 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-osx-3.0" +name: "prcycoin-osx-3.0" enable_cache: true suites: - "trusty" @@ -28,8 +28,8 @@ packages: - "python-setuptools" - "fonts-tuffy" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin.git" - "dir": "dapscoin" +- "url": "https://github.com/prcycoin-project/prcycoin.git" + "dir": "prcycoin" files: - "MacOSX10.11.sdk.tar.gz" script: | @@ -83,7 +83,7 @@ script: | create_per-host_faketime_wrappers "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} - cd dapscoin + cd prcycoin BASEPREFIX=`pwd`/depends mkdir -p ${BASEPREFIX}/SDKs @@ -104,14 +104,14 @@ script: | ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist - SOURCEDIST=`echo dapscoin-*.tar.gz` + SOURCEDIST=`echo prcycoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST - find dapscoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + find prcycoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST popd ORIGPATH="$PATH" diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 7233654b7b..8dbf5bcdab 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-win-signer" +name: "prcycoin-win-signer" suites: - "trusty" architectures: @@ -8,12 +8,12 @@ packages: - "libssl-dev" - "autoconf" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin-detached-sigs.git" +- "url": "https://github.com/prcycoin-project/prcycoin-detached-sigs.git" "dir": "signature" files: - "osslsigncode-1.7.1.tar.gz" - "osslsigncode-Backports-to-1.7.1.patch" -- "dapscoin-win-unsigned.tar.gz" +- "prcycoin-win-unsigned.tar.gz" script: | BUILD_DIR=`pwd` SIGDIR=${BUILD_DIR}/signature/win @@ -23,7 +23,7 @@ script: | echo "a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 osslsigncode-Backports-to-1.7.1.patch" | sha256sum -c mkdir -p ${UNSIGNED_DIR} - tar -C ${UNSIGNED_DIR} -xf dapscoin-win-unsigned.tar.gz + tar -C ${UNSIGNED_DIR} -xf prcycoin-win-unsigned.tar.gz tar xf osslsigncode-1.7.1.tar.gz cd osslsigncode-1.7.1 diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 3bd9a53154..889ee245ec 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "dapscoin-win-3.0" +name: "prcycoin-win-3.0" enable_cache: true suites: - "trusty" @@ -22,8 +22,8 @@ packages: - "ca-certificates" - "python" remotes: -- "url": "https://github.com/dapscoin-project/dapscoin.git" - "dir": "dapscoin" +- "url": "https://github.com/prcycoin-project/prcycoin.git" + "dir": "prcycoin" files: [] script: | WRAP_DIR=$HOME/wrapped @@ -101,7 +101,7 @@ script: | create_per-host_linker_wrapper "2000-01-01 12:00:00" export PATH=${WRAP_DIR}:${PATH} - cd dapscoin + cd prcycoin BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do @@ -119,14 +119,14 @@ script: | ./autogen.sh CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ make dist - SOURCEDIST=`echo dapscoin-*.tar.gz` + SOURCEDIST=`echo prcycoin-*.tar.gz` DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` # Correct tar file order mkdir -p temp pushd temp tar xf ../$SOURCEDIST - find dapscoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + find prcycoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST mkdir -p $OUTDIR/src cp ../$SOURCEDIST $OUTDIR/src popd @@ -145,7 +145,7 @@ script: | make ${MAKEOPTS} make deploy make install DESTDIR=${INSTALLPATH} - cp -f dapscoin-*setup*.exe $OUTDIR/ + cp -f prcycoin-*setup*.exe $OUTDIR/ cd installed rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; diff --git a/contrib/init/README.md b/contrib/init/README.md index 06db0ff0e8..d97d5bd1dc 100644 --- a/contrib/init/README.md +++ b/contrib/init/README.md @@ -1,10 +1,10 @@ Sample configuration files for: -SystemD: dapscoind.service -Upstart: dapscoind.conf -OpenRC: dapscoind.openrc - dapscoind.openrcconf -CentOS: dapscoind.init +SystemD: prcycoind.service +Upstart: prcycoind.conf +OpenRC: prcycoind.openrc + prcycoind.openrcconf +CentOS: prcycoind.init have been made available to assist packagers in creating node packages here. diff --git a/contrib/init/dapscoind.openrcconf b/contrib/init/dapscoind.openrcconf deleted file mode 100644 index 351e90a6cb..0000000000 --- a/contrib/init/dapscoind.openrcconf +++ /dev/null @@ -1,26 +0,0 @@ -# /etc/conf.d/dapscoind: config file for /etc/init.d/dapscoind - -# Config file location -#BITCOIND_CONFIGFILE="/etc/dapscoin/dapscoin.conf" - -# What directory to write pidfile to? (created and owned by $BITCOIND_USER) -#BITCOIND_PIDDIR="/var/run/dapscoind" - -# What filename to give the pidfile -#BITCOIND_PIDFILE="${BITCOIND_PIDDIR}/dapscoind.pid" - -# Where to write dapscoind data (be mindful that the blockchain is large) -#BITCOIND_DATADIR="/var/lib/dapscoind" - -# User and group to own dapscoind process -#BITCOIND_USER="dapscoin" -#BITCOIND_GROUP="dapscoin" - -# Path to dapscoind executable -#BITCOIND_BIN="/usr/bin/dapscoind" - -# Nice value to run dapscoind under -#BITCOIND_NICE=0 - -# Additional options (avoid -conf and -datadir, use flags above) -BITCOIND_OPTS="" diff --git a/contrib/init/dapscoind.service b/contrib/init/dapscoind.service deleted file mode 100644 index dd3fe0083d..0000000000 --- a/contrib/init/dapscoind.service +++ /dev/null @@ -1,26 +0,0 @@ -[Unit] -Description=DAPScoin's distributed currency daemon -After=network.target - -[Service] -User=dapscoin -Group=dapscoin - -Type=forking -PIDFile=/var/lib/dapscoind/dapscoind.pid - -ExecStart=/usr/bin/dapscoind -daemon -pid=/var/lib/dapscoind/dapscoind.pid \ - -conf=/etc/dapscoin/dapscoin.conf -datadir=/var/lib/dapscoind - -ExecStop=-/usr/bin/dapscoin-cli -conf=/etc/dapscoin/dapscoin.conf \ - -datadir=/var/lib/dapscoind stop - -Restart=always -PrivateTmp=true -TimeoutStopSec=60s -TimeoutStartSec=2s -StartLimitInterval=120s -StartLimitBurst=5 - -[Install] -WantedBy=multi-user.target diff --git a/contrib/init/dapscoind.conf b/contrib/init/prcycoind.conf similarity index 76% rename from contrib/init/dapscoind.conf rename to contrib/init/prcycoind.conf index ef1b216d9e..2038c445f4 100644 --- a/contrib/init/dapscoind.conf +++ b/contrib/init/prcycoind.conf @@ -1,16 +1,16 @@ -description "DAPS Daemon" +description "PRCY Daemon" start on runlevel [2345] stop on starting rc RUNLEVEL=[016] -env BITCOIND_BIN="/usr/bin/dapscoind" -env BITCOIND_USER="dapscoin" -env BITCOIND_GROUP="dapscoin" -env BITCOIND_PIDDIR="/var/run/dapscoind" +env BITCOIND_BIN="/usr/bin/prcycoind" +env BITCOIND_USER="prcycoin" +env BITCOIND_GROUP="prcycoin" +env BITCOIND_PIDDIR="/var/run/prcycoind" # upstart can't handle variables constructed with other variables -env BITCOIND_PIDFILE="/var/run/dapscoind/dapscoind.pid" -env BITCOIND_CONFIGFILE="/etc/dapscoin/dapscoin.conf" -env BITCOIND_DATADIR="/var/lib/dapscoind" +env BITCOIND_PIDFILE="/var/run/prcycoind/prcycoind.pid" +env BITCOIND_CONFIGFILE="/etc/prcycoin/prcycoin.conf" +env BITCOIND_DATADIR="/var/lib/prcycoind" expect fork @@ -20,12 +20,12 @@ kill timeout 60 pre-start script # this will catch non-existent config files - # dapscoind will check and exit with this very warning, but it can do so + # prcycoind will check and exit with this very warning, but it can do so # long after forking, leaving upstart to think everything started fine. # since this is a commonly encountered case on install, just check and # warn here. if ! grep -qs '^rpcpassword=' "$BITCOIND_CONFIGFILE" ; then - echo "ERROR: You must set a secure rpcpassword to run dapscoind." + echo "ERROR: You must set a secure rpcpassword to run prcycoind." echo "The setting must appear in $BITCOIND_CONFIGFILE" echo echo "This password is security critical to securing wallets " @@ -38,7 +38,7 @@ pre-start script echo "It is also recommended that you also set alertnotify so you are " echo "notified of problems:" echo - echo "ie: alertnotify=echo %%s | mail -s \"Dapscoin Alert\"" \ + echo "ie: alertnotify=echo %%s | mail -s \"Prcycoin Alert\"" \ "admin@foo.com" echo exit 1 diff --git a/contrib/init/dapscoind.init b/contrib/init/prcycoind.init similarity index 62% rename from contrib/init/dapscoind.init rename to contrib/init/prcycoind.init index cf4b4f1c74..2567eb37f1 100644 --- a/contrib/init/dapscoind.init +++ b/contrib/init/prcycoind.init @@ -1,31 +1,31 @@ #!/bin/bash # -# dapscoind The DAPS core server. +# prcycoind The PRCY core server. # # # chkconfig: 345 80 20 -# description: dapscoind -# processname: dapscoind +# description: prcycoind +# processname: prcycoind # # Source function library. . /etc/init.d/functions -# you can override defaults in /etc/sysconfig/dapscoind, see below -if [ -f /etc/sysconfig/dapscoind ]; then - . /etc/sysconfig/dapscoind +# you can override defaults in /etc/sysconfig/prcycoind, see below +if [ -f /etc/sysconfig/prcycoind ]; then + . /etc/sysconfig/prcycoind fi RETVAL=0 -prog=dapscoind -# you can override the lockfile via BITCOIND_LOCKFILE in /etc/sysconfig/dapscoind -lockfile=${BITCOIND_LOCKFILE-/var/lock/subsys/dapscoind} +prog=prcycoind +# you can override the lockfile via BITCOIND_LOCKFILE in /etc/sysconfig/prcycoind +lockfile=${BITCOIND_LOCKFILE-/var/lock/subsys/prcycoind} -# dapscoind defaults to /usr/bin/dapscoind, override with BITCOIND_BIN -bitcoind=${BITCOIND_BIN-/usr/bin/dapscoind} +# prcycoind defaults to /usr/bin/prcycoind, override with BITCOIND_BIN +bitcoind=${BITCOIND_BIN-/usr/bin/prcycoind} -# dapscoind opts default to -disablewallet, override with BITCOIND_OPTS +# prcycoind opts default to -disablewallet, override with BITCOIND_OPTS bitcoind_opts=${BITCOIND_OPTS} start() { diff --git a/contrib/init/dapscoind.openrc b/contrib/init/prcycoind.openrc similarity index 71% rename from contrib/init/dapscoind.openrc rename to contrib/init/prcycoind.openrc index ea71bde6a1..d5b609f8c3 100644 --- a/contrib/init/dapscoind.openrc +++ b/contrib/init/prcycoind.openrc @@ -2,24 +2,24 @@ # backward compatibility for existing gentoo layout # -if [ -d "/var/lib/dapscoin/.dapscoin" ]; then - BITCOIND_DEFAULT_DATADIR="/var/lib/dapscoin/.dapscoin" +if [ -d "/var/lib/prcycoin/.prcycoin" ]; then + BITCOIND_DEFAULT_DATADIR="/var/lib/prcycoin/.prcycoin" else - BITCOIND_DEFAULT_DATADIR="/var/lib/dapscoind" + BITCOIND_DEFAULT_DATADIR="/var/lib/prcycoind" fi -BITCOIND_CONFIGFILE=${BITCOIND_CONFIGFILE:-/etc/dapscoin/dapscoin.conf} -BITCOIND_PIDDIR=${BITCOIND_PIDDIR:-/var/run/dapscoind} -BITCOIND_PIDFILE=${BITCOIND_PIDFILE:-${BITCOIND_PIDDIR}/dapscoind.pid} +BITCOIND_CONFIGFILE=${BITCOIND_CONFIGFILE:-/etc/prcycoin/prcycoin.conf} +BITCOIND_PIDDIR=${BITCOIND_PIDDIR:-/var/run/prcycoind} +BITCOIND_PIDFILE=${BITCOIND_PIDFILE:-${BITCOIND_PIDDIR}/prcycoind.pid} BITCOIND_DATADIR=${BITCOIND_DATADIR:-${BITCOIND_DEFAULT_DATADIR}} -BITCOIND_USER=${BITCOIND_USER:-dapscoin} -BITCOIND_GROUP=${BITCOIND_GROUP:-dapscoin} -BITCOIND_BIN=${BITCOIND_BIN:-/usr/bin/dapscoind} +BITCOIND_USER=${BITCOIND_USER:-prcycoin} +BITCOIND_GROUP=${BITCOIND_GROUP:-prcycoin} +BITCOIND_BIN=${BITCOIND_BIN:-/usr/bin/prcycoind} -name="DAPS Daemon" -description="DAPS crypto-currency p2p network daemon" +name="PRCY Daemon" +description="PRCY crypto-currency p2p network daemon" -command="/usr/bin/dapscoind" +command="/usr/bin/prcycoind" command_args="-pid=\"${BITCOIND_PIDFILE}\" \ -conf=\"${BITCOIND_CONFIGFILE}\" \ -datadir=\"${BITCOIND_DATADIR}\" \ @@ -65,7 +65,7 @@ checkconfig() { if ! grep -qs '^rpcpassword=' "${BITCOIND_CONFIGFILE}" ; then eerror "" - eerror "ERROR: You must set a secure rpcpassword to run dapscoind." + eerror "ERROR: You must set a secure rpcpassword to run prcycoind." eerror "The setting must appear in ${BITCOIND_CONFIGFILE}" eerror "" eerror "This password is security critical to securing wallets " @@ -78,7 +78,7 @@ checkconfig() eerror "It is also recommended that you also set alertnotify so you are " eerror "notified of problems:" eerror "" - eerror "ie: alertnotify=echo %%s | mail -s \"Dapscoin Alert\"" \ + eerror "ie: alertnotify=echo %%s | mail -s \"Prcycoin Alert\"" \ "admin@foo.com" eerror "" return 1 diff --git a/contrib/init/prcycoind.openrcconf b/contrib/init/prcycoind.openrcconf new file mode 100644 index 0000000000..50d255d3f5 --- /dev/null +++ b/contrib/init/prcycoind.openrcconf @@ -0,0 +1,26 @@ +# /etc/conf.d/prcycoind: config file for /etc/init.d/prcycoind + +# Config file location +#BITCOIND_CONFIGFILE="/etc/prcycoin/prcycoin.conf" + +# What directory to write pidfile to? (created and owned by $BITCOIND_USER) +#BITCOIND_PIDDIR="/var/run/prcycoind" + +# What filename to give the pidfile +#BITCOIND_PIDFILE="${BITCOIND_PIDDIR}/prcycoind.pid" + +# Where to write prcycoind data (be mindful that the blockchain is large) +#BITCOIND_DATADIR="/var/lib/prcycoind" + +# User and group to own prcycoind process +#BITCOIND_USER="prcycoin" +#BITCOIND_GROUP="prcycoin" + +# Path to prcycoind executable +#BITCOIND_BIN="/usr/bin/prcycoind" + +# Nice value to run prcycoind under +#BITCOIND_NICE=0 + +# Additional options (avoid -conf and -datadir, use flags above) +BITCOIND_OPTS="" diff --git a/contrib/init/prcycoind.service b/contrib/init/prcycoind.service new file mode 100644 index 0000000000..7f10b93e06 --- /dev/null +++ b/contrib/init/prcycoind.service @@ -0,0 +1,26 @@ +[Unit] +Description=PRCYcoin's distributed currency daemon +After=network.target + +[Service] +User=prcycoin +Group=prcycoin + +Type=forking +PIDFile=/var/lib/prcycoind/prcycoind.pid + +ExecStart=/usr/bin/prcycoind -daemon -pid=/var/lib/prcycoind/prcycoind.pid \ + -conf=/etc/prcycoin/prcycoin.conf -datadir=/var/lib/prcycoind + +ExecStop=-/usr/bin/prcycoin-cli -conf=/etc/prcycoin/prcycoin.conf \ + -datadir=/var/lib/prcycoind stop + +Restart=always +PrivateTmp=true +TimeoutStopSec=60s +TimeoutStartSec=2s +StartLimitInterval=120s +StartLimitBurst=5 + +[Install] +WantedBy=multi-user.target diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index 371882f417..ee0db5e068 100644 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -96,7 +96,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000): if 'host' not in settings: settings['host'] = '127.0.0.1' if 'port' not in settings: - settings['port'] = 53573 + settings['port'] = 59683 if 'min_height' not in settings: settings['min_height'] = 0 if 'max_height' not in settings: diff --git a/contrib/macdeploy/README.md b/contrib/macdeploy/README.md index c7b0b4a458..d071b9a945 100644 --- a/contrib/macdeploy/README.md +++ b/contrib/macdeploy/README.md @@ -11,5 +11,5 @@ This script should not be run manually, instead, after building as usual: During the process, the disk image window will pop up briefly where the fancy settings are applied. This is normal, please do not interfere. -When finished, it will produce `Dapscoin-Qt.dmg`. +When finished, it will produce `Prcycoin-Qt.dmg`. diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index ef48415cd1..c36d3521f8 100644 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -54,7 +54,7 @@ ds['.']['vSrn'] = ('long', 1) ds['Applications']['Iloc'] = (370, 156) -ds['DAPScoin-Qt.app']['Iloc'] = (128, 156) +ds['PRCYcoin-Qt.app']['Iloc'] = (128, 156) ds.flush() ds.close() diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 5111abc79b..29d0b2017e 100644 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -5,7 +5,7 @@ UNSIGNED=$1 SIGNATURE=$2 ARCH=x86_64 ROOTDIR=dist -BUNDLE=${ROOTDIR}/Dapscoin-Qt.app +BUNDLE=${ROOTDIR}/Prcycoin-Qt.app TEMPDIR=signed.temp OUTDIR=signed-app diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 71167a179c..f7ce02fe1d 100644 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -2,7 +2,7 @@ set -e ROOTDIR=dist -BUNDLE=${ROOTDIR}/Dapscoin-Qt.app +BUNDLE=${ROOTDIR}/Prcycoin-Qt.app CODESIGN=codesign TEMPDIR=sign.temp TEMPLIST=${TEMPDIR}/signatures.txt diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist index 63c820d627..71ad811bed 100644 --- a/contrib/macdeploy/fancy.plist +++ b/contrib/macdeploy/fancy.plist @@ -22,7 +22,7 @@ 370 156 - Dapscoin-Qt.app + Prcycoin-Qt.app 128 156 diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index 6003f2a591..28aa5c1285 100644 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -155,7 +155,7 @@ class FrameworkInfo(object): class ApplicationBundleInfo(object): def __init__(self, path): self.path = path - appName = "DAPScoin-Qt" + appName = "PRCYcoin-Qt" self.binaryPath = os.path.join(path, "Contents", "MacOS", appName) if not os.path.exists(self.binaryPath): raise RuntimeError("Could not find bundle binary for " + path) @@ -603,7 +603,7 @@ else: # ------------------------------------------------ -target = os.path.join("dist", "DAPScoin-Qt.app") +target = os.path.join("dist", "PRCYcoin-Qt.app") if verbose >= 2: print("+ Copying source bundle +") diff --git a/contrib/prcycoin-qt.desktop b/contrib/prcycoin-qt.desktop new file mode 100644 index 0000000000..29d443bf40 --- /dev/null +++ b/contrib/prcycoin-qt.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=PRCYcoin-qt +Comment=PRCYcoin QT Wallet +Exec=prcycoin-qt +Icon=prcycoin +Categories=Utility; diff --git a/contrib/dapscoin-qt.pro b/contrib/prcycoin-qt.pro similarity index 93% rename from contrib/dapscoin-qt.pro rename to contrib/prcycoin-qt.pro index 9644f02515..845d190ed5 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/prcycoin-qt.pro @@ -149,7 +149,7 @@ HEADERS += src/activemasternode.h \ src/wallet/wallet_ismine.h \ src/wallet/walletdb.h \ src/compat/sanity.h \ - src/config/dapscoin-config.h \ + src/config/prcycoin-config.h \ src/crypto/common.h \ src/crypto/hmac_sha256.h \ src/crypto/hmac_sha512.h \ @@ -354,7 +354,7 @@ HEADERS += src/activemasternode.h \ src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h \ src/crypto/aes_helper.c \ src/qt/bitcoinamountfield.moc \ - src/qt/dapscoin.moc \ + src/qt/prcycoin.moc \ src/qt/intro.moc \ src/qt/overviewpage.moc \ src/qt/rpcconsole.moc \ @@ -411,9 +411,9 @@ SOURCES += src/activemasternode.cpp \ src/core_read.cpp \ src/core_write.cpp \ src/crypter.cpp \ - src/dapscoin-cli.cpp \ - src/dapscoin-tx.cpp \ - src/dapscoind.cpp \ + src/prcycoin-cli.cpp \ + src/prcycoin-tx.cpp \ + src/prcycoind.cpp \ src/db.cpp \ src/eccryptoverify.cpp \ src/ecdhutil.cpp \ @@ -521,8 +521,8 @@ SOURCES += src/activemasternode.cpp \ src/qt/coincontroldialog.cpp \ src/qt/coincontroltreewidget.cpp \ src/qt/csvmodelwriter.cpp \ - src/qt/dapscoin.cpp \ - src/qt/dapscoinstrings.cpp \ + src/qt/prcycoin.cpp \ + src/qt/prcycoinstrings.cpp \ src/qt/editaddressdialog.cpp \ src/qt/encryptdialog.cpp \ src/qt/entermnemonics.cpp \ @@ -611,7 +611,7 @@ SOURCES += src/activemasternode.cpp \ src/test/sighash_tests.cpp \ src/test/sigopcount_tests.cpp \ src/test/skiplist_tests.cpp \ - src/test/test_dapscoin.cpp \ + src/test/test_prcycoin.cpp \ src/test/timedata_tests.cpp \ src/test/transaction_tests.cpp \ src/test/uint256_tests.cpp \ @@ -702,37 +702,37 @@ SOURCES += src/activemasternode.cpp \ src/leveldb/helpers/memenv/memenv.cc \ src/leveldb/helpers/memenv/memenv_test.cc \ src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c -RESOURCES += src/qt/dapscoin.qrc src/qt/dapscoin_locale.qrc +RESOURCES += src/qt/prcycoin.qrc src/qt/prcycoin_locale.qrc -TRANSLATIONS += src/qt/locale/dapscoin_bg.ts \ - src/qt/locale/dapscoin_ca.ts \ - src/qt/locale/dapscoin_cs.ts \ - src/qt/locale/dapscoin_da.ts \ - src/qt/locale/dapscoin_de.ts \ - src/qt/locale/dapscoin_en.ts \ - src/qt/locale/dapscoin_en_US.ts \ - src/qt/locale/dapscoin_eo.ts \ - src/qt/locale/dapscoin_es.ts \ - src/qt/locale/dapscoin_es_ES.ts \ - src/qt/locale/dapscoin_fi.ts \ - src/qt/locale/dapscoin_fr_FR.ts \ - src/qt/locale/dapscoin_hi_IN.ts \ - src/qt/locale/dapscoin_hr.ts \ - src/qt/locale/dapscoin_hr_HR.ts \ - src/qt/locale/dapscoin_it.ts \ - src/qt/locale/dapscoin_ja.ts \ - src/qt/locale/dapscoin_ko_KR.ts \ - src/qt/locale/dapscoin_lt_LT.ts \ - src/qt/locale/dapscoin_nl.ts \ - src/qt/locale/dapscoin_pl.ts \ - src/qt/locale/dapscoin_pt.ts \ - src/qt/locale/dapscoin_pt_BR.ts \ - src/qt/locale/dapscoin_ro_RO.ts \ - src/qt/locale/dapscoin_ru.ts \ - src/qt/locale/dapscoin_sk.ts \ - src/qt/locale/dapscoin_sv.ts \ - src/qt/locale/dapscoin_tr.ts \ - src/qt/locale/dapscoin_uk.ts \ - src/qt/locale/dapscoin_vi.ts \ - src/qt/locale/dapscoin_zh_CN.ts \ - src/qt/locale/dapscoin_zh_TW.ts +TRANSLATIONS += src/qt/locale/prcycoin_bg.ts \ + src/qt/locale/prcycoin_ca.ts \ + src/qt/locale/prcycoin_cs.ts \ + src/qt/locale/prcycoin_da.ts \ + src/qt/locale/prcycoin_de.ts \ + src/qt/locale/prcycoin_en.ts \ + src/qt/locale/prcycoin_en_US.ts \ + src/qt/locale/prcycoin_eo.ts \ + src/qt/locale/prcycoin_es.ts \ + src/qt/locale/prcycoin_es_ES.ts \ + src/qt/locale/prcycoin_fi.ts \ + src/qt/locale/prcycoin_fr_FR.ts \ + src/qt/locale/prcycoin_hi_IN.ts \ + src/qt/locale/prcycoin_hr.ts \ + src/qt/locale/prcycoin_hr_HR.ts \ + src/qt/locale/prcycoin_it.ts \ + src/qt/locale/prcycoin_ja.ts \ + src/qt/locale/prcycoin_ko_KR.ts \ + src/qt/locale/prcycoin_lt_LT.ts \ + src/qt/locale/prcycoin_nl.ts \ + src/qt/locale/prcycoin_pl.ts \ + src/qt/locale/prcycoin_pt.ts \ + src/qt/locale/prcycoin_pt_BR.ts \ + src/qt/locale/prcycoin_ro_RO.ts \ + src/qt/locale/prcycoin_ru.ts \ + src/qt/locale/prcycoin_sk.ts \ + src/qt/locale/prcycoin_sv.ts \ + src/qt/locale/prcycoin_tr.ts \ + src/qt/locale/prcycoin_uk.ts \ + src/qt/locale/prcycoin_vi.ts \ + src/qt/locale/prcycoin_zh_CN.ts \ + src/qt/locale/prcycoin_zh_TW.ts diff --git a/contrib/dapscoind.bash-completion b/contrib/prcycoind.bash-completion similarity index 83% rename from contrib/dapscoind.bash-completion rename to contrib/prcycoind.bash-completion index f47c6bba91..b98b8a95cb 100644 --- a/contrib/dapscoind.bash-completion +++ b/contrib/prcycoind.bash-completion @@ -1,12 +1,12 @@ -# bash programmable completion for dapscoind(1) and dapscoin-cli(1) +# bash programmable completion for prcycoind(1) and prcycoin-cli(1) # Copyright (c) 2012,2014 Christian von Roques # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -have dapscoind && { +have prcycoind && { -# call $dapscoind for RPC -_dapscoin_rpc() { +# call $prcycoind for RPC +_prcycoin_rpc() { # determine already specified args necessary for RPC local rpcargs=() for i in ${COMP_LINE}; do @@ -16,23 +16,23 @@ _dapscoin_rpc() { ;; esac done - $dapscoind "${rpcargs[@]}" "$@" + $prcycoind "${rpcargs[@]}" "$@" } -# Add dapscoin accounts to COMPREPLY -_dapscoin_accounts() { +# Add prcycoin accounts to COMPREPLY +_prcycoin_accounts() { local accounts - accounts=$(_dapscoin_rpc listaccounts | awk '/".*"/ { a=$1; gsub(/"/, "", a); print a}') + accounts=$(_prcycoin_rpc listaccounts | awk '/".*"/ { a=$1; gsub(/"/, "", a); print a}') COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$accounts" -- "$cur" ) ) } -_dapscoind() { +_prcycoind() { local cur prev words=() cword - local dapscoind + local prcycoind - # save and use original argument to invoke dapscoind - # dapscoind might not be in $PATH - dapscoind="$1" + # save and use original argument to invoke prcycoind + # prcycoind might not be in $PATH + prcycoind="$1" COMPREPLY=() _get_comp_words_by_ref -n = cur prev words cword @@ -53,7 +53,7 @@ _dapscoind() { if ((cword > 3)); then case ${words[cword-3]} in addmultisigaddress) - _dapscoin_accounts + _prcycoin_accounts return 0 ;; getbalance|gettxout|importaddress|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock) @@ -74,7 +74,7 @@ _dapscoind() { return 0 ;; move|setaccount) - _dapscoin_accounts + _prcycoin_accounts return 0 ;; esac @@ -90,7 +90,7 @@ _dapscoind() { return 0 ;; getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany) - _dapscoin_accounts + _prcycoin_accounts return 0 ;; esac @@ -114,12 +114,12 @@ _dapscoind() { # only parse --help if senseful if [[ -z "$cur" || "$cur" =~ ^- ]]; then - helpopts=$($dapscoind --help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) + helpopts=$($prcycoind --help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' ) fi # only parse help if senseful if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then - commands=$(_dapscoin_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }') + commands=$(_prcycoin_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }') fi COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) ) @@ -133,7 +133,7 @@ _dapscoind() { esac } -complete -F _dapscoind dapscoind dapscoin-cli +complete -F _prcycoind prcycoind prcycoin-cli } # Local variables: diff --git a/contrib/qos/README.md b/contrib/qos/README.md index 323b139e33..d848c7a7bb 100644 --- a/contrib/qos/README.md +++ b/contrib/qos/README.md @@ -1,5 +1,5 @@ ### Qos ### -This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 53572, but not if the destination IP is within a LAN (defined as 192.168.x.x). +This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 59682, but not if the destination IP is within a LAN (defined as 192.168.x.x). -This means one can have an always-on dapscoind instance running, and another local dapscoind/dapscoin-qt instance which connects to this node and receives blocks from it. +This means one can have an always-on prcycoind instance running, and another local prcycoind/prcycoin-qt instance which connects to this node and receives blocks from it. diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index c4136561ef..16535e49ee 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -32,10 +32,10 @@ tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11 # ret=$? #done -#limit outgoing traffic to and from port 53572. but not when dealing with a host on the local network +#limit outgoing traffic to and from port 59682. but not when dealing with a host on the local network # (defined by $LOCALNET) # --set-mark marks packages matching these criteria with the number "2" # these packages are filtered by the tc filter with "handle 2" # this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT} -iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 53572 ! -d ${LOCALNET} -j MARK --set-mark 0x2 -iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 53572 ! -d ${LOCALNET} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 59682 ! -d ${LOCALNET} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 59682 ! -d ${LOCALNET} -j MARK --set-mark 0x2 diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index 30e0978cf7..2820170563 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -8,7 +8,7 @@ and remove old versions as necessary. The seeds compiled into the release are created from fuzzbawls' DNS seed data, like this: - curl -s http://seeder.fuzzbawls.pw/dapscoin-mainnet.txt > seeds_main.txt + curl -s http://seeder.fuzzbawls.pw/prcycoin-mainnet.txt > seeds_main.txt python3 makeseeds.py < seeds_main.txt > nodes_main.txt python3 generate-seeds.py . > ../../src/chainparamsseeds.h diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 559ccddb77..5e1589dcce 100644 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -127,10 +127,10 @@ def main(): g.write(' * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.\n') g.write(' */\n') with open(os.path.join(indir,'nodes_main.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_main', 53572) + process_nodes(g, f, 'pnSeed6_main', 59682) g.write('\n') with open(os.path.join(indir,'nodes_test.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_test', 53574) + process_nodes(g, f, 'pnSeed6_test', 59684) g.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n') if __name__ == '__main__': diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 6fb51023e2..68d570e3b2 100644 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -26,7 +26,7 @@ PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(/DAPS:1.0.4.6)/)$") +PATTERN_AGENT = re.compile(r"^(/PRCY:1.0.4.6)/)$") def parseline(line): sline = line.split() diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md index bc604b884c..ebb7174d47 100644 --- a/contrib/spendfrom/README.md +++ b/contrib/spendfrom/README.md @@ -7,7 +7,7 @@ address (or addresses). Depends on [jsonrpc](http://json-rpc.org/). spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \ - --fee=fee --datadir=/path/to/.dapscoin --testnet --dry_run + --fee=fee --datadir=/path/to/.prcycoin --testnet --dry_run With no arguments, outputs a list of amounts associated with addresses. @@ -16,7 +16,7 @@ With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOAD ### Notes ### - You may explicitly specify how much fee to pay (a fee more than 1% of the amount -will fail, though, to prevent dapscoin-losing accidents). Spendfrom may fail if +will fail, though, to prevent prcycoin-losing accidents). Spendfrom may fail if it thinks the transaction would never be confirmed (if the amount being sent is too small, or if the transaction is too many bytes for the fee). diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py index 463b58dcb1..bd6bb3a103 100644 --- a/contrib/spendfrom/spendfrom.py +++ b/contrib/spendfrom/spendfrom.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -# Use the raw transactions API to spend DAPSs received on particular addresses, +# Use the raw transactions API to spend PRCYs received on particular addresses, # and send any change back to that same address. # # Example usage: # spendfrom.py # Lists available funds # spendfrom.py --from=ADDRESS --to=ADDRESS --amount=11.00 # -# Assumes it will talk to a dapscoind or dapscoin-Qt running +# Assumes it will talk to a prcycoind or prcycoin-Qt running # on localhost. # # Depends on jsonrpc @@ -33,15 +33,15 @@ def check_json_precision(): raise RuntimeError("JSON encode/decode loses precision") def determine_db_dir(): - """Return the default location of the dapscoin data directory""" + """Return the default location of the prcycoin data directory""" if platform.system() == "Darwin": - return os.path.expanduser("~/Library/Application Support/DAPScoin/") + return os.path.expanduser("~/Library/Application Support/PRCYcoin/") elif platform.system() == "Windows": - return os.path.join(os.environ['APPDATA'], "DAPScoin") - return os.path.expanduser("~/.dapscoin") + return os.path.join(os.environ['APPDATA'], "PRCYcoin") + return os.path.expanduser("~/.prcycoin") def read_bitcoin_config(dbdir): - """Read the dapscoin.conf file from dbdir, returns dictionary of settings""" + """Read the prcycoin.conf file from dbdir, returns dictionary of settings""" from ConfigParser import SafeConfigParser class FakeSecHead(object): @@ -59,20 +59,20 @@ def readline(self): return s config_parser = SafeConfigParser() - config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "dapscoin.conf")))) + config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "prcycoin.conf")))) return dict(config_parser.items("all")) def connect_JSON(config): - """Connect to a dapscoin JSON-RPC server""" + """Connect to a prcycoin JSON-RPC server""" testnet = config.get('testnet', '0') testnet = (int(testnet) > 0) # 0/1 in config file, convert to True/False if not 'rpcport' in config: - config['rpcport'] = 53575 if testnet else 53573 + config['rpcport'] = 59685 if testnet else 59683 connect = "http://%s:%s@127.0.0.1:%s"%(config['rpcuser'], config['rpcpassword'], config['rpcport']) try: result = ServiceProxy(connect) # ServiceProxy is lazy-connect, so send an RPC command mostly to catch connection errors, - # but also make sure the dapscoind we're talking to is/isn't testnet: + # but also make sure the prcycoind we're talking to is/isn't testnet: if result.getmininginfo()['testnet'] != testnet: sys.stderr.write("RPC server at "+connect+" testnet setting mismatch\n") sys.exit(1) @@ -81,36 +81,36 @@ def connect_JSON(config): sys.stderr.write("Error connecting to RPC server at "+connect+"\n") sys.exit(1) -def unlock_wallet(dapscoind): - info = dapscoind.getinfo() +def unlock_wallet(prcycoind): + info = prcycoind.getinfo() if 'unlocked_until' not in info: return True # wallet is not encrypted t = int(info['unlocked_until']) if t <= time.time(): try: passphrase = getpass.getpass("Wallet is locked; enter passphrase: ") - dapscoind.unlockwallet(passphrase, 5) + prcycoind.unlockwallet(passphrase, 5) except: sys.stderr.write("Wrong passphrase\n") - info = dapscoind.getinfo() + info = prcycoind.getinfo() return int(info['unlocked_until']) > time.time() -def list_available(dapscoind): +def list_available(prcycoind): address_summary = dict() address_to_account = dict() - for info in dapscoind.listreceivedbyaddress(0): + for info in prcycoind.listreceivedbyaddress(0): address_to_account[info["address"]] = info["account"] - unspent = dapscoind.listunspent(0) + unspent = prcycoind.listunspent(0) for output in unspent: # listunspent doesn't give addresses, so: - rawtx = dapscoind.getrawtransaction(output['txid'], 1) + rawtx = prcycoind.getrawtransaction(output['txid'], 1) vout = rawtx["vout"][output['vout']] pk = vout["scriptPubKey"] - # This code only deals with ordinary pay-to-dapscoin-address + # This code only deals with ordinary pay-to-prcycoin-address # or pay-to-script-hash outputs right now; anything exotic is ignored. if pk["type"] != "pubkeyhash" and pk["type"] != "scripthash": continue @@ -139,8 +139,8 @@ def select_coins(needed, inputs): n += 1 return (outputs, have-needed) -def create_tx(dapscoind, fromaddresses, toaddress, amount, fee): - all_coins = list_available(dapscoind) +def create_tx(prcycoind, fromaddresses, toaddress, amount, fee): + all_coins = list_available(prcycoind) total_available = Decimal("0.0") needed = amount+fee @@ -159,7 +159,7 @@ def create_tx(dapscoind, fromaddresses, toaddress, amount, fee): # Note: # Python's json/jsonrpc modules have inconsistent support for Decimal numbers. # Instead of wrestling with getting json.dumps() (used by jsonrpc) to encode - # Decimals, I'm casting amounts to float before sending them to dapscoind. + # Decimals, I'm casting amounts to float before sending them to prcycoind. # outputs = { toaddress : float(amount) } (inputs, change_amount) = select_coins(needed, potential_inputs) @@ -170,8 +170,8 @@ def create_tx(dapscoind, fromaddresses, toaddress, amount, fee): else: outputs[change_address] = float(change_amount) - rawtx = dapscoind.createrawtransaction(inputs, outputs) - signed_rawtx = dapscoind.signrawtransaction(rawtx) + rawtx = prcycoind.createrawtransaction(inputs, outputs) + signed_rawtx = prcycoind.signrawtransaction(rawtx) if not signed_rawtx["complete"]: sys.stderr.write("signrawtransaction failed\n") sys.exit(1) @@ -179,10 +179,10 @@ def create_tx(dapscoind, fromaddresses, toaddress, amount, fee): return txdata -def compute_amount_in(dapscoind, txinfo): +def compute_amount_in(prcycoind, txinfo): result = Decimal("0.0") for vin in txinfo['vin']: - in_info = dapscoind.getrawtransaction(vin['txid'], 1) + in_info = prcycoind.getrawtransaction(vin['txid'], 1) vout = in_info['vout'][vin['vout']] result = result + vout['value'] return result @@ -193,12 +193,12 @@ def compute_amount_out(txinfo): result = result + vout['value'] return result -def sanity_test_fee(dapscoind, txdata_hex, max_fee): +def sanity_test_fee(prcycoind, txdata_hex, max_fee): class FeeError(RuntimeError): pass try: - txinfo = dapscoind.decoderawtransaction(txdata_hex) - total_in = compute_amount_in(dapscoind, txinfo) + txinfo = prcycoind.decoderawtransaction(txdata_hex) + total_in = compute_amount_in(prcycoind, txinfo) total_out = compute_amount_out(txinfo) if total_in-total_out > max_fee: raise FeeError("Rejecting transaction, unreasonable fee of "+str(total_in-total_out)) @@ -221,15 +221,15 @@ def main(): parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--from", dest="fromaddresses", default=None, - help="addresses to get DAPSs from") + help="addresses to get PRCYs from") parser.add_option("--to", dest="to", default=None, - help="address to get send DAPSs to") + help="address to get send PRCYs to") parser.add_option("--amount", dest="amount", default=None, help="amount to send") parser.add_option("--fee", dest="fee", default="0.0", help="fee to include") parser.add_option("--datadir", dest="datadir", default=determine_db_dir(), - help="location of dapscoin.conf file with RPC username/password (default: %default)") + help="location of prcycoin.conf file with RPC username/password (default: %default)") parser.add_option("--testnet", dest="testnet", default=False, action="store_true", help="Use the test network") parser.add_option("--dry_run", dest="dry_run", default=False, action="store_true", @@ -240,10 +240,10 @@ def main(): check_json_precision() config = read_bitcoin_config(options.datadir) if options.testnet: config['testnet'] = True - dapscoind = connect_JSON(config) + prcycoind = connect_JSON(config) if options.amount is None: - address_summary = list_available(dapscoind) + address_summary = list_available(prcycoind) for address,info in address_summary.iteritems(): n_transactions = len(info['outputs']) if n_transactions > 1: @@ -253,14 +253,14 @@ def main(): else: fee = Decimal(options.fee) amount = Decimal(options.amount) - while unlock_wallet(dapscoind) == False: + while unlock_wallet(prcycoind) == False: pass # Keep asking for passphrase until they get it right - txdata = create_tx(dapscoind, options.fromaddresses.split(","), options.to, amount, fee) - sanity_test_fee(dapscoind, txdata, amount*Decimal("0.01")) + txdata = create_tx(prcycoind, options.fromaddresses.split(","), options.to, amount, fee) + sanity_test_fee(prcycoind, txdata, amount*Decimal("0.01")) if options.dry_run: print(txdata) else: - txid = dapscoind.sendrawtransaction(txdata) + txid = prcycoind.sendrawtransaction(txdata) print(txid) if __name__ == '__main__': diff --git a/dapscoin.conf b/dapscoin.conf deleted file mode 100644 index 6999b51c69..0000000000 --- a/dapscoin.conf +++ /dev/null @@ -1,15 +0,0 @@ -rpcuser=dapscoinrpc -rpcpassword=6QmU2at85BVn5dLFKUeAZQMDDvdxCDGyo9P62khqty5S -server=1 -daemon=1 -testnet=0 -addnode=104.196.7.250:53572 -addnode=35.229.54.148:53572 -addnode=35.227.81.1:53572 -addnode=35.237.184.1:53572 -addnodeee=35.237.17.148:53572 -staking=0 -masternode=1 -externalip=45.77.28.38 -masternodeprivkey=87XfMpHkaGnHRV7kyJq6YkepgXFvsNuCypwotLJn4qf2gXqZtnE - diff --git a/depends/README.md b/depends/README.md index c34185013c..cb20c4c358 100644 --- a/depends/README.md +++ b/depends/README.md @@ -62,7 +62,7 @@ For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): sudo apt-get install g++-riscv64-linux-gnu binutils-riscv64-linux-gnu -RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_daps` executable (see https://github.com/bitcoin/bitcoin/pull/13543), +RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_prcy` executable (see https://github.com/bitcoin/bitcoin/pull/13543), this is apparently fixed in gcc-8.1.0. ### Dependency Options diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index cd8db0f4b7..c33b25eabd 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "DAPS" +PROJECT_NAME = "PRCY" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -1264,7 +1264,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs" # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_BUNDLE_ID = io.dapscoin.DAPScoin +DOCSET_BUNDLE_ID = io.prcycoin.PRCYcoin # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style @@ -1272,7 +1272,7 @@ DOCSET_BUNDLE_ID = io.dapscoin.DAPScoin # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_ID = io.dapscoin.DAPScoin +DOCSET_PUBLISHER_ID = io.prcycoin.PRCYcoin # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. diff --git a/doc/README.md b/doc/README.md index 766c0505e8..682e35b440 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,39 +1,39 @@ -DAPScoin +PRCYcoin ===================== Setup --------------------- -[DAPScoin](https://officialdapscoin.com/wallet) is the original DAPS client and it builds the backbone of the network. However, it downloads and stores the entire history of DAPS transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. Thankfully you only have to do this once. +[PRCYcoin](https://prcycoin.com/wallet) is the original PRCY client and it builds the backbone of the network. However, it downloads and stores the entire history of PRCY transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. Thankfully you only have to do this once. Running --------------------- -The following are some helpful notes on how to run DAPS on your native platform. +The following are some helpful notes on how to run PRCY on your native platform. ### Unix Unpack the files into a directory and run: -- bin/32/dapscoin-qt (GUI, 32-bit) or bin/32/dapscoind (headless, 32-bit) -- bin/64/dapscoin-qt (GUI, 64-bit) or bin/64/dapscoind (headless, 64-bit) +- bin/32/prcycoin-qt (GUI, 32-bit) or bin/32/prcycoind (headless, 32-bit) +- bin/64/prcycoin-qt (GUI, 64-bit) or bin/64/prcycoind (headless, 64-bit) ### Windows -Unpack the files into a directory, and then run dapscoin-qt.exe. +Unpack the files into a directory, and then run prcycoin-qt.exe. ### OSX -Drag DAPScoin-Qt to your applications folder, and then run DAPScoin-Qt. +Drag PRCYcoin-Qt to your applications folder, and then run PRCYcoin-Qt. ### Need Help? -* See the documentation at the [DAPS Wiki](https://en.bitcoin.it/wiki/Main_Page) ***TODO*** +* See the documentation at the [PRCY Wiki](https://en.bitcoin.it/wiki/Main_Page) ***TODO*** for help and more information. -* Ask for help on [BitcoinTalk](https://bitcointalk.org/index.php?topic=1262920.0) or on the [DAPS Forum](https://forum.officialdapscoin.com/). -* Join one of our Slack groups [DAPS Slack Groups](https://officialdapscoin.com/slack-logins/). +* Ask for help on [BitcoinTalk](https://bitcointalk.org/index.php?topic=1262920.0) or on the [PRCY Forum](https://forum.prcycoin.com/). +* Join one of our Slack groups [PRCY Slack Groups](https://prcycoin.com/slack-logins/). Building --------------------- -The following are developer notes on how to build DAPS on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc. +The following are developer notes on how to build PRCY on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc. - [OSX Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) @@ -41,7 +41,7 @@ The following are developer notes on how to build DAPS on your native platform. Development --------------------- -The Dapscoin repo's [root README](https://github.com/DAPScoin-Project/DAPScoin/blob/master/README.md) contains relevant information on the development process and automated testing. +The Prcycoin repo's [root README](https://github.com/PRCYcoin-Project/PRCYcoin/blob/master/README.md) contains relevant information on the development process and automated testing. - [Developer Notes](developer-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) @@ -55,8 +55,8 @@ The Dapscoin repo's [root README](https://github.com/DAPScoin-Project/DAPScoin/b ### Resources -* Discuss on the [BitcoinTalk](https://bitcointalk.org/index.php?topic=1262920.0) or the [DAPScoin](https://forum.officialdapscoin.com/) forum. -* Join the [DAPScoin-Dev](https://dapscoin-dev.slack.com/) Slack group ([Sign-Up](https://dapscoin-dev.herokuapp.com/)). +* Discuss on the [BitcoinTalk](https://bitcointalk.org/index.php?topic=1262920.0) or the [PRCYcoin](https://forum.prcycoin.com/) forum. +* Join the [PRCYcoin-Dev](https://prcycoin-dev.slack.com/) Slack group ([Sign-Up](https://prcycoin-dev.herokuapp.com/)). ### Miscellaneous - [Assets Attribution](assets-attribution.md) diff --git a/doc/README_osx.md b/doc/README_osx.md index b95aa92ed9..8f9b206ad5 100644 --- a/doc/README_osx.md +++ b/doc/README_osx.md @@ -92,6 +92,6 @@ build process to remain somewhat deterministic. Here's how it works: that have been previously (deterministically) built in order to create a final dmg. - **TODO** The Apple keyholder uses this unsigned app to create a detached signature, - using the script that is also included there. Detached signatures are available from this [repository](https://github.com/DAPScoin-Project/dapscoin-detached-sigs). + using the script that is also included there. Detached signatures are available from this [repository](https://github.com/PRCYcoin-Project/prcycoin-detached-sigs). - Builders feed the unsigned app + detached signature back into Gitian. It uses the pre-built tools to recombine the pieces into a deterministic dmg. diff --git a/doc/README_windows.txt b/doc/README_windows.txt index 91ff97a21e..024e23cce9 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -1,9 +1,9 @@ -DAPScoin +PRCYcoin ===================== Intro ----- -DAPS is a free open source peer-to-peer electronic cash system that is +PRCY is a free open source peer-to-peer electronic cash system that is completely decentralized, without the need for a central server or trusted parties. Users hold the crypto keys to their own money and transact directly with each other, with the help of a P2P network to check for double-spending. @@ -11,9 +11,9 @@ with each other, with the help of a P2P network to check for double-spending. Setup ----- -Unpack the files into a directory and run dapscoin-qt.exe. +Unpack the files into a directory and run prcycoin-qt.exe. -DAPS is the original DAPS client and it builds the backbone of the network. -However, it downloads and stores the entire history of DAPS transactions; +PRCY is the original PRCY client and it builds the backbone of the network. +However, it downloads and stores the entire history of PRCY transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 5f72de9c22..d92922e073 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -51,7 +51,7 @@ https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki Example: ``` -$ curl localhost:53572/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff7627ff72e5e8b0f71210f92ea7a4000c5d75-0.json 2>/dev/null | json_pp +$ curl localhost:59682/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff7627ff72e5e8b0f71210f92ea7a4000c5d75-0.json 2>/dev/null | json_pp { "chaintipHash" : "00000000fb01a7f3745a717f8caebee056c484e6e0bfe4a9591c235bb70506fb", "chainHeight" : 325347, @@ -90,4 +90,4 @@ Only supports JSON as output format. Risks ------------- -Running a web browser on the same node with a REST enabled dapscoind can be a risk. Accessing prepared XSS websites could read out tx/block data of your node by placing links like `
  • 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%0A<(l55NDr?n(k?dMqn_#hI>U8v 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

    kLZ`hKv#@wUTf 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 diff --git a/src/qt/res/icons/browse.png b/src/qt/res/icons/browse.png index 48b48a1a52717abab6427a6f85490636892cb8c6..764cd20608e6a567255784aece0d747c30b843e1 100644 GIT binary patch delta 1275 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 delta 2803 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 diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png index af38f2992bc1a6deab09a434b9eb5e34c019137b..3bc0b31db39ddae2dbb81194542fb998b536bc9e 100644 GIT binary patch delta 162 zcmV;T0A2st36ckpBe7rE0)K%?L_t&-(_>@+0!AqK0b(;Sa56F)fVgKF8GnBV3UIPP z_&{)q@%wj11};uhm=?yvjIS9PMQs=nU>75!q$?vbSkJ=5ha$j44FN_D*0_49KUrmD=FW+YxqFAT)j=ud zklehudv^Qk{xLQxEpqsqLnN;|Zv(xjW=E}^Mk~1UgZwB#P zvfNquleN|LsOr+xr=nAhcs7MzHQieJmABXTtnS*}w?#akWaq}-wcT6$S6Iz&mQCs^ zrshXmUK*#Jn`N8+ZqH9{F}K`31Xx}Hbuf6k`njxg HN@xNAD&WBo diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png index 2478b7f056ae31449b57b09739376be5aadfd314..3615fd90b7893033d8c350e30696f871407e3018 100644 GIT binary patch delta 162 zcmV;T0A2st36ckpBe7rE0)K%?L_t&-(_>@+0!AqK0b(;Sa56F)fVgKF8GnBV3UIPP z_&{)q@%wj11};uhm=?yvjIS9PMQs=nU>75!q$?vbSkJ=5ha$j44FN_D*0_49KUrmD=FW+YxqFAT)j=ud zklehudv^Qk{xLQxEpqsqLnN;|Zv(xjW=E}^Mk~1UgZwB#P zvfNquleN|LsOr+xr=nAhcs7MzHQieJmABXTtnS*}w?#akWaq}-wcT6$S6Iz&mQCs^ zrshXmUK*#Jn`N8+ZqH9{F}K`31Xx}Hbuf6k`njxg HN@xNAD&WBo diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png index 9a8d5fd232b20f888afc3a18257a9c03fda38974..807ad0454a62e92bcb261a5dde578cd2987d9725 100644 GIT binary patch delta 175 zcmV;g08szd37iLzBe7rB0)LK4L_t&-(_>@+0!AqK0b(;Sa56F)fVgKF8GnBV3UIPP z_&{)q@%wj11};uhm=?yvjIS9PMQs=nU>75!q$?vbSkJ=5ha$j)EbxUFEWisF;6qoz zh*f}*L$(KrpT)??puso=&QD>y2XwkJ<18pYfsye7$a5NubHV)hA0(_7K)z*QkdT3> dIRBl20RRj$7bq*Gs`UT>002ovPDHLkV1oOMM*aW* delta 490 zcmbQkevNa2vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqv8#wdd4JgcNc~ZR#^|AI`$GzUsv|W9OBHZhW(*yfu=BW zdAc};NL)@%U|@1nOA`w-E8}D1c<|)Wwrv}?Zhrpo>0_49KUrmD=FW+YxqFAT)j=ud zklehudv^Qk{xLQxEpqsqLnN;|Zv(xjW=E}^Mk~1UgZwB#P zvfNquleN|LsOr+xr=nAhcs7MzHQieJmABXT>{H#fxkWsm-pbC6y=%L-_OGy--z*!~ zM#sWeTV5KcottHw{%+4tZZW-}q=2|RDK9rY)ec)1wKwhUuCLM|5*8umdAIhYzTWoM zy6oMpz3#qq8y%gC-|zd&&L?M8^W=r0Zf^a8V9U~y{`nS_ufELO{QS!o-UIUtO|0r4 zK3aM@yk{%#f`3yD3{8!4)T`PR{@ zv0ioJx>cB`olV;&X)^q~us=Jtd{8n^jrYDJ%stoMX(5Eni>lkQTO1(3cv>x<5x%DS V7GnIX_{{(S002ovPDHLkV1kA#O@IIZ delta 490 zcmbQiev5O0vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqv9Q=dd4JgcNc~ZR#^|AI`$GzUsv|W9OBHZhW(*yfu=BW zdAc};NL)@%U|@1nOA`w-E8}D1c<|)WwvAgimp^#;^fAllpR6)-=fuX`y<^ML>Yx;J zXkOesyM1;47#kgx7CHP)I;glX@uA?vz>9_(3m*ybObYtQ+39&wb7kgB$(fP$H!txR zS?;X-$=d3ARCQ_UQ_-oLc#1-=nrLER(Eag+fO`PvU6ka+U~9WE3D=>%O-V| zQuC!PFOAdA&9Y5@x92Cfm|oPHGYdAQyxjCuJ8WIl-n6&7zDk>|GAdY+duvbX>uqnX z%ii7Eo4$S*8*}rrYy1AP^T}D&JbAJ4@hz)*hvh}DUd^?reD!7K=I7^LOG`A_Ca2Uq ze6;j*__|pyB%J@+0!AqK0b(;Sa56F)fw-p`8GnBV3UIPP z_&{)i@%wj11};u>m=?x^jIS9PMeP_7URW0ONWV=0IdVBNGb~ADr`r7c9UF z7vRI8qQ4F%08-1$@e=0000VU)?{(M#qCniyZzYDK1QWC^#|jqT$BEkB@|SCIxYJdY;r=nfX$3X5`I!%S${) zJ1c*(wz?iwU7Gq-bZY1(o}#O!TT8$4_WGXH6Rh+z(dOCbf%+{*2w@P1Mm9V&Co^xkQ<>_m= zx69w$*&6LUxzW+P`ux4x-~2K*B|lCC%Es0&2)6wCrC-**@Y9u-#_7B~y$9wQnpu|r zJ9N~0x^HRkf`3yDjJI#tvS}M*B`?ENzDVQz#U_%#pi(VyjVMV;EJ?LWE=mPb3`Pcq zmbwNOx<va+R}DKuwXiliZK-3F~liuVTPewRIuV)TCDZ*mXQY z7nZOM&)R~O)GXt9N=yW)wd!#mH5ei-|FwcaRKP%Kk)fr?q*X&&Kgh{{{U*OQRFIk+ z0cs7g+er-K5PxNPmK%F;aPRSxXDyMMW&2`7Y}jdy=ecXp!615R*)fk%?sd0 zt2(^YBqibJC0NL0!AHwZ89jKz-NU+cU|;=y!9&evq~(T-*7s}9r_8N2A1x>5(2X+O z;I^Qjg7$nBx`uXV?R0iHs7XzU%jvY!K`g4-w2vLq>VLG?Su-H_ote#a)T5Vz{;1Sk z3~evU)=f=`+Dap>V~;*YwwBa*>})2F^$*tSkzi5!WUliWL%Z&?TwkEA8Cp@}k<00% z)lXUn>21XT%8#TsOJgGym26T=ex=cEuUj{1(WrRbWG-p-l9uDp5ZYW-Y}rSH#7CIO zXaDT-Gk=pgbfRoJTli3<$Q!8)&>(5;`Dm#Y%65G=DEoEtF?yY~Hls*t-od7lnX<@~ z53cF_+pu<6ChbCpBEP}L?V}Y`n?BOw_r(rHrx|Rt9Ewi+)F-7K>R=Oko}455%_O}_q$;F?0?Azn^R2)fhH4ef3DRd3jnS~k_bvs z(PbsDsD&DlSQ`{&-C8sb5zS7UR(smsYEsPzcszS U)&FwZE&u=k07*qoM6N<$f<*w~qW}N^ delta 1688 zcmV;J250%l2d52?BYyw{XF*Lt006O%3;baP0000WV@Og>004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt00(qQO+^Re2p0ndF^^TP zO#lD|uSrBfR9M5!mP>3~RT_Z5bA8{}v12z)+9W0=Eqw))Xn#slhN8h$)d@&cKv!%l z@z5-0(b0$ntGl5KgfyBB5@>dVP^FGQGoXedb>wy$nx+aF=wmc0q;4qW)s#5S!?AsR zSU7~xwBg#xiUmlSWH_+Rt-k5NeeVwfbNzz3eW7Q`LVSiLC+iRUl-G8v7)@#wNNuHyN zb__}s$Wufju!!SO-;&w$bxsacd3jU^CS2wD-CGWdB;Cul7D;oRadJ3lK!_-sYH!F@ zYpohE;X1$Hxb1QA%!;i=Cisj?jFKaUfr?2CQ;D`@9+@h6pBC;1m~h22+gp3p{q(RA z1IUwRh<}ru;VK!zSVRZ`8Zp$6**v>xx^iokf{9ndM-m;6sZZ0z7EC1bOmK1G>_~sZ zl@sGKR~OQBqG)KC)M2XjrfhpwFZNextuip-iWl13dbI;|(}a$oM4Dkvj-}q2_-+1# ztjld5i|2`85knxbsK?Z_t^{8;{n zucc_7-*ux7Vpzl}-)i;Pws?5FKI4BI_yrTLb7)7$UhM##G-DyiFvfZB^u?j~Mvnc& zM1QIf$vUOYIiV6oV4`7QYI-yuD~5eXkxwvJd8x6jSAB|Z63e!3@&$c!e}8w}UGsuc zGMw3W&CrSC5Tksn)f0|+J)`!VKWl!##8K;T$Id6zBwaKu+q%hlP7MzKb=1A9fdS9R znY3ona0p?dqG743Eo&1+%eH14yx+-x$bTEslO_La`i>P}l0|u4{;l|8ChjW1joleG zf?3j>r*ClhFWGr$woGoH(rwitij9K#LlpgL)PIzz zdp_R1z=W$D?r7^3NgiDlHWxX0<-%Lz$12);DI#8McJnM2=Bg-CRoh-CitY|3T<4|6 zoll5Ebn@Uz*bFV49ZMbm^2b}=H(H^2Dv`Ae&7^)+6h&IsiK4rK30EB2(blUb>84?I z*o^eQGx2)GSY>NwA#tm50cRzObbn%K_l}~qVCAsct3I_hY>r1ztA+@P(c*k z3AS$7RF74*R!J276wF811er>rXf>G6un98$qv%Jl3c@B3n$IX&0jn%*0-^beqB2+& zVH0G0M^W{ww)*+GJO~8|n;`RZQKY(|mu>d&ERXO2Ad%eWvUhg=!@e1}^nXiX0rHiC z`|plXM_0n=I0zy{&g1XumO=>0*z~2zOJma^uQZU~Ft_s?GJM0Sk@MAtO)zU_A#tlQgX9XI{B!WnqnDS| zp~6tH?LV#GdeIeIy5;gFf=+aFf&cORsaA1C3HntbYx+4WjbwdWNBu305UK!IV~_aEiyAy iFf%$ZH99moEig1XFcC095CrM~0000GQ`1E8u<#o%ygf`ke3zlYK`WXh)>BIr$Gx zJKqb(eA#BUW+_R%HaUVf$D`N3H^;m*-;uE}1ubav}g-7vi_Vcq8i@@3s;07aj9WohO#w2>qYuPS)HkfdJ^TbxNj&?Kw? O0000ex#>eO-aZO7a;C6?!(zVqjp5 z^>lFzk+__kz`*Dx7iU*jXBQ{uW-z_6b7t$rslE;Y9uY1cAq~A#C$`S)Y>f4Z>1lR$ z3i66_3kzy$W4irYB#xbnW8R%jO0qM)hWfrY0Az zU%qPpQo>{r=OR1e}8vx;)xSyPMte>_O!l+ zj?Ss`+IlC?ojQ}Cp{u=q#hO*?R<2!LzdC|KT1itoO>fBE+H>$iZGCEUh-`*RNz=PCqllE>}xj-Qvl?hU#Z)ZWcc~GtYFg z^cmK2hD|f`GIugh+XxJP)e_f;l9a@fRIB8oR3OD*WMF8iYhbBsWEx^VX4vL1{{FKbJO57SYm@rQOYGCkm^>bP0l+XkKfuH6s diff --git a/src/qt/res/icons/connect0_16.png b/src/qt/res/icons/connect0_16.png index 87761c7141f446bc028bf6a552cbfc5cd9e1efb1..9279f89e48a27a45ff3906e21fc5540c0e55c076 100644 GIT binary patch delta 268 zcmV+n0rURc2AKtrBe7q10e|XAL_t(2Q;p8oRst~?1mLlN%7WOC;;M)h5m1*VsMrv( zi#qTBDBf(cNyzST?q zzYK&v4*lf`05EzUcpSdG3Vsvs)nUuK{O`k}BdPqf@K?ZP3y;4=ets<+kw5cNTZ9oL SA2$F1002ovPDHLkU;%={#(w4i delta 463 zcmbQqdWUU-vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhcjvJ!6u$yGwX2*G+k#I`$GzUsv|W9OBHZhW(*yfu=CL z_jGX#(KtW#!ppEj1_G=P90evebx3!M-i&czUD{y1;>`jjjqiWuS)Z6>1_kk*S%2p5 zIZq?!EkQfY?i4)`ob7u+`=?lq({|q3zqdAA$eduaLwHi$t=1P0_tySYW*7KV|3M?^ zce=>5-^o#T%&u=ddBI=E!dLIi+@yJIM%~#bo378y$`w4fEBfH`mrv^ocb+Mp(!M!9 z_I|*@qV;D>Me>`={o;%oidt9k)%~9@!T;sQl26a4SAL3G{7d>f)AMrUpEKr4`)5%wF@3h8q4<>&U-@SfClzHvv?`>T5ZzCW7(Wpo%^gH-CKCE6iYW1?uLD4Pi z_BmApJ+E5g8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd42-P|Os!0SToWq;17qJkVJI4M c^HVa@DsgLY5@2}+)WFH$>FVdQ&MBb@0N+%&Z~y=R diff --git a/src/qt/res/icons/connect1_16.png b/src/qt/res/icons/connect1_16.png index 018df43cac408d57f43ff1cf2506f4c1f30c4666..43dc9b885878e3e4ce1c0844c823b6548a31d0de 100644 GIT binary patch delta 109 zcmV-z0FwXP1DOJlB#~f}V@^p#K~yLe?ZG(`KtKQlz;U1JzM21jlZ}*M1Og?{joYxgstFZJ;vt5>H=O_QxFJ%&dm}p=*JLFa&wJ zIEHAPPfn0vZI&|-nvlL|clV5sCpK=_w2*6q@hZG_O17j{FJ#tvBTJYOD$SbOC%>gEcviU4ZjG4?uK+{#TN?apKQW8s2 zt&)pUffR$0fuW_YfrYM-afpGjm4T_136N`IWnf_JyC)2!1Fj)AKP5A*61N5?0hU)l O4Gf;HelF{r5}E)hEL;@; diff --git a/src/qt/res/icons/connect2_16.png b/src/qt/res/icons/connect2_16.png index 370cc36623ad92d0733f3457945541eefa098808..d1d771d2aca69e52434043c79d4e059078be7629 100644 GIT binary patch delta 163 zcmV;U09^l&1;qo9B(Y!$0e^x?L_t(2745-C5`s_wM8QGKqGC>%vzW8K``=4gf7rOQ z%5MGrA}e7hQ)$J?5Xk28idJw46-$a%b}Ln&R#%)x6KE+?yVI3=;Pqv)1~43HJb|f9 zGXmaR3s}muBDB^9e3^VgTkU|740{5HqvUWp%W%1ZcawCtABymNxfpMK;{z}m5{$h! RB|QKD002ovPDHLkV1jLGM+yJ{ delta 365 zcmX@gJb`tBiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@6A}?b-W0JSKi_P+^#PdLP>?NMQuI!IF#F<$Q`$N|PO=0Nw zba4#PIREy%xzM2i9+nHNlMNG!j83NboZIkyzxc1bi}^2Rd=!&9yT?ge;henM#FC(w zJySPNdGd*sTRir$&Q#sFkE={SRvoTda8oG%^|hDZ8th*3Z+YZgWO7VJVL4a*c_01y zKGvNf6{26`lAYVQ+6D7BPG0$En|YN5lb-+c{CzP`zxYnu{rSSbs(pLR>rS#8NDB2# zeqyl#=r+|7*NBpo#FA92@$bflG&z0Lv?&4hBzGKbLh*2~7Z=MuEBj diff --git a/src/qt/res/icons/connect3_16.png b/src/qt/res/icons/connect3_16.png index 4f303cea1cb3bb3bfe5aaa09612583e00111da1a..bfd5028971b9ad31d45efcfb81ecc887cda26167 100644 GIT binary patch delta 266 zcmV+l0rmc&2h0VKBe7qr0e|U9L_t(273IO@TEYMThSATMfq{X94AFssU|=gMPO$^K zvEKW?2RDC>$sRAjbM&t@HMg`H3e*O)cXWo-SQkIKd(=>GxUV1Az@P#|hN3_$t{{nF zAZf}kHIg13GbAgMg>g$h6F4TPLQ)QxmQN&)t6)kqFgquo`QpMNuz$3yl~u^-x3zU( zLn^_hrFvW2WoZZOUF}t1UtXyLI6Ttv352CnD9P&#hkdRKNJ>?>l-Cums;;3T-9SNJ z6*f~kH^qXY7M{BC{@mWmB?@NFC23vYM`=dTG QQUCw|07*qoM6N<$f*r(qUH||9 delta 480 zcmX@Zx{!T>vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqvBe|dd4JgcbAkyw{~y>)v=d&`ns||<`8FQHS7;v3p9n1 z!PCVtMC1I^3D<*|90gqUxzdiZG&Q|w;%Z_vRuGC&*638)srF@95Vx9hG)SB2LsU-z7-%G4+Kb&INxpDW*7{reCa*Pl1F!6$%u~e>@csA?D)kXE4ViVGKH|zae_VB`Pm*q=d9<^h*pT1%F z`LAE+@>+|1Y~KG`Ji5y2xBlgrJYWE+mbgZgq$HN4S|t~y0x1R~14Bz)0}EXv;}8R5 wD+5z26Cl^b%D}+bcTX6KhTQy=%(O~$4N?dlP68~ifI1jFUHx3vIVCg!02z9|R{#J2 diff --git a/src/qt/res/icons/connect4_16.png b/src/qt/res/icons/connect4_16.png index 53783588b8bf857b07bef605629b1c14915f7a70..93a55d59dd928230aa154b829a5c3dd5cd18a816 100644 GIT binary patch delta 398 zcmV;90dfAd3E>BjBe7pT0)GK&Nkl5>2`Cp3x0D$plHndhmn(56MQBk={Nvos~ zQjX+~oRf&TkI3=-*|uKxsaYSt_o!wl%hqkxQF6BLQ0sTH)GoDQ_nt;bH3ixnXMc&kE~wuJv?R1O z!eZrZ`wy6R@DLmhw4GudM>^H6I2=_g`AhdPwI@w)mG-45=s!MiVlWD^p+HZ@ICWZw zDL7-!*>jCBqL#sVt%>nR$EbN@X}F*lFLAj+$0@inarK&d{RTI0=@8u3Nfx_vS8akR zy%%Fp`zW~oAOa6H`G1JV8GXWZU@%Rnze1nRkb0(V@LZ>$S!W5oFemwv7VUwozJk~K zhR|E{vb@s_4C@%Y*AIj;=6xilrun2@FsYvj)tVE`!KjHZeAPN=*DRrUt0qT)`GIc` s{oXkbGeL5e-+IRfA{&5CCe4VX00000NkvXXt^-0~f_{L%oB#j- delta 610 zcmaFJzLj%=vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqoM;-Jp*Hsx4TQHOrqKuphET%PhVH|#~k9!tcLxeYk|fv zHh8)?hG?8$J1I1r*^#GJzvSYhsE9oQbHvKKcJJOTUS7V_es;<2c}|)ioaEAqKc!BZ zeTM0Og5ADd@hcv=|6*rh``ggGa;BZi6>EO(auoxmOVv&xB|dBB9zQBwH)%rsgcV*+ zL7UQTR84iGCeNFvcxT4T#?2}jr_P;Z<*5u(xS!m@)UKDj@P}*Fr8l2T4ZI6Grv*f@ zO*#FyD}R^P>Q$}RJ?=*RtcrAq-FrlOO-7HxY`fm;cP`z!rgv&8-^$x77p$KBrtooG z_3eFif_4gi3I-m>wBBuVp0zGf+rX)>FR}iPi{Fm*{(ipaIp)tj{D`!vhH?~c*z7e|e-L97Q3Dv(1WG09`m=MGI>7=r{-8H#S zEUreT1zz(QpFe38j?dcVU+8+PK~9o!hg$xe8_OO>YZOHls?TPfcA{F{Z%go3Mu|oL z1pPlb*E5KIE8^oe@_x-&I4?S$;coU<;|=SN?Od|3Flp7f&$ajNecWElpd{VkXWu8( z1B@Zn64!{5l*E!$tK_0oAjM#0U}&jpV4-Vd9AaQ>WngM$0_2)l85kJ*?g>NDkei>9 bnO2FaK?YfelK{&rpbiF4S3j3^P6f-1g-yz8o`E4z%o!oASXyZL+=MB8?M;e_so^YrOc7p2*^sKr~w5e4yU5 zwsp-XPWkn7nageF#4xYv`tLq{$AdO~mykb9F&`XSj^6*h|7P8q-3|^-*?Sn`1PYGX zyTq;F%*t7C!K_*T!37SF?M@DD43gyVCU;=5VEjf3ThC{abs7uQok<2 z%Du_8|DJ;Tt3tbl4rV*KzH=(p;^V2M|K+OJ#JLX^z^Fm*W?d&dbxDK~|5=qfD; zKAYwntRmc`@<8UX70YCStSb^hir;z{~=HA;HmwfSzg3a+cx37yrX%NgmOg9 z$tlYBGMT2{RC=Lx!KESKyo~fzxBqz!4NvnAS|3`qD^pNmtGU;={sr9K=QYGqIt5RC z5Im?`&-6s4=*o)ak1wcl9DOEm<$l@Dv=>uk85eTPi!FBVNLkKh$Ry#|ZeYZ8!H`Lr zfq~7MruGSRTBw^(_e{(b!OLOP7DRUIQ{xn@B`0IhUzH5C2OYHv(la#mEWiN2k*uv{1 zq|9Sitzp_!cRkA0tKizb{UtJu_pENspMQM9{icKKEaf?8n`tF%+S&Ty@s^X^qS?HY z7Acu>IwqBDaEY=x_^Bo8wy%((&TR*;-T=v~kKPrDGM&8i_Q@5FOB>{v?e01}*z_lc z)vzhB;17S{;dWcrdcPgFWDOU)Pv|y};JTS=WK8Nw%g`%-1L8XWeUSN;WXwJ*S##InHt~RBoti^ zUkKGqPb9eL#OBPL8?^1R*;&CV6)0(E;JDFBmwHj5Q+>!O4H-CB{dz7+N Q3R literal 1377 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 Hu0mjfM9S+- literal 5432 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 S{fx!{0000004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x1fWSoK~z}7#g1tN(dA`it!;wup!aWAe+L|L#faew2|mAWx5d?Y522qv0n zKsFE;1`Q~b7%(cS5GrV(LM0TceOPAhy>rg*;!dGLA47rgCnvL*|MC5=bB}Z#?o(zc zza9Vm(xFs6R8A+~)pEB|8-3?<6GQOA$R6CP_BUV0)27=O5-6#y`j8*J`Q8SV>_xgZfp z0b1q@Ha*9y_dHnK`sMfgZ+HtX85sEdTMMZWwhMs>EqCN&ylnJW4)vTS^@Z}LZ3h}! z?`r}OV8_ux&h|uvB_WI<44~L9jEtUU!<;rc+S@44D|6w(1%Uge^V#qWjM2XPRgIX4 zU;$tun13UL7M_mJ6VC6%J4H+*i#-E?{ihR#PXsg-At(vXL#YG)O)l`<+zL?`pkAr@ zn*{LQ*A-f{fXuIFKM$H?p}lgJ&hjd}_o!8jZ@jY&19bP-IDS-VZUHk-s5zzeb|G;U zUT8}R0*m*8!p#BrwCf^m8sf{K2I3Z>wNgNYM?kq#ifg}21G2* zDT+q~D%F%~r2@>F1I!*5^or8RtVsb<&9B`(N0eo=41yWDoK)(Impti?kNio)qQi6i8ywl>cl#dVoz{`sk;=Id?C^@aF#~491-<-*V`YI$97|Z~j5Pv|& z{oZ!57wBMM^dcYa+shj(mJu`;aZUk6MDhxV~LW0~h&VBpj*?A+eX z-{r-;`N%`4g8IvtT36O_X&Yk*!T?By;cWkvL8qO8@iLmF{MEdG*Y00aAF{mcO1}4F zw8lUb#zb*MA#5UUY65C$eWWJs%70Y=W16Z^t2rKCvzm3wS5r;0%R2sY_Dyj_7)2C< zAg_)p`u~Uir*M!!0000b zbVXQnWMOn=I%9HWVRU5xGB7bYEigDOGBZ>#GdeIeIy5;gFf=+aFf&cORsaA1C3Hnt zbYx+4WjbwdWNBu305UK!IV~_aEiyAyFf%$ZH99moEig1XFfc+81nK|)002ovPDHLk FV1mshbHM-r diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png index 24f89919abdcc04f8f40df650728e21d3e7fefb0..1dd4bf8f30e659f6578d495d8f13da6511295e73 100644 GIT binary patch delta 363 zcmV-x0hIo}2I&NlB#~g|e*sBJL_t(IPleBWTY@kghGDH_ZF3vSfUFc151^EEw6oRs z|4?l**cf*C{;Bu%8&9isbdE95wkN@PH3v3C2@viQNF8`$3k{gt6QF-;iRuXtb3z?N z{j<8LfOx~DV86~`;IV+h@M19dAGicwUJb6naAYKFfH0@gxbO7Ae`IPTo8LfVe>NY_ z!D4A7D}X%ANRqC6f3_09NGg4P~+dtO9ER?w2}Q z0r7wNga8kZI=KLdVe{gE{5=6r&pNrR5c4o*TpZ$H`=XO20QR=8I$45tM{hWpyuE*X z>f}8zHky9zzJGpovJD!^2S7c!39RG;7wXA2Xe8UfOfJ?sx<9(tFSI4UybS;V002ov JPDHLkV1jA%qZ9xD delta 575 zcmaFKvX5&sl#w2fd7lsa2Sr4E(&H|6fVg?3oVGw3ym^DWND9B#o z>Fdh=m_wYI)v!NwEzoF2Z%-G;5R22Tmv0s|8Hh9_=4vnZ^l1`Wuq`ws#vxbu*& z*RN0$@^z6ouUb<)X}+XX@8ZW1%x6Do6zr2`ca%M_#8*O{K= zGKo(6wfN%g-^Z7G-ebsSd%XVr{QLHkW7ybFiYD0q6qqte+w6_{^n;E?k~dBst(N)! z^FQOR>-t+{cwUDA16#GkHKHUXu_Vr)|M0stANn+kuBDdz)O^27l~O3T-Rm*ns=El7^s& zV-BAyrt6h)Q}{r^)>$+?ie0`X_LB|M%gfM|*d|%iaa*UMIEGy7wJtnQUBMpv4SH~z znu5&-TXf)7e8W{BVFm}|>sKlGXVZb(ssk1FPe^ zpuURe@bcgBHGhFOnc+-|?-rQBYczP4=p2~Bw+I9;A^Hf+;C@CK;l`s+<@oBsOH`O( zkm~^57GFL15Wy33B*?q;Gy|R3DDWKu!5gcfBb&W7f8CmI?B zzVH?m_8GGWKO%VNl9lLW6nK_<_85+fc7{7nt0ru(dKqvJmg@&#HUc`CQ~JRG0000< KMNUMnLSTYr`^ohH delta 601 zcmdnV{E=mXay{XE)7O>#F^4!at6_iWT3-eR#tEJ-jv*e$-(I)%W;SFv_VNGLBEBx!C9A^( z*yGvR9j_epl(D)ITM+QVTtMcEr+q_-u(FnbQx8)_i_0JIVs3kN$u#L z{cM4iENf2i7ar{dcgE;BzuGvtZan)i@d#I(gi-5u(VSMv%S&%OiB7VQFuS|Q#I$qm zL_^y=?-0?`6Y6vKTx(svLgR+*@@Ba?i`FC*ztgiSP~LZMmUx0O563eC=i@)t&FSn=pLH$I}M^9dTk+A*0 z(eZ&cOH;U5Lv3kI=>wMeUyoU5Cd7)y%UV3P+%A1EKyupkyrn-&&Ko{I_;9~E13$+- zi^O{YpG?(vq;=PQ_TREcykGRWcl|rLmA|d8wOX_PX9zA|`|a-4z{kKCQ!R0gC`m~y zNwrEYN(E93Mh1qKx&{`yK}N2bVvPScrHO@Mx zUR0lwG?l1!>PbP(Xuc&&)?i4f)qcK-CiLJP>gI~NGEYI8sw;D`5D!Sf8#I5qbvM(H zB0SN~UvYQgD^{?ILBD0SKzVAS+NJlk;-jo#%>8UxPt>}v;ts5EV;6obVE_%YrJWfH zN>g=a%$DLI$$y%M4*~q9Pxqb|2%-@$@eM)j)7--b9D!E1j;JX{%dHEv!a*ws5F!mh zjN{dd+k$uvwRleu|3DhsSR}=bQxzR)3Q$vtsS{;HtB+RQme==S4Igm7yGRf<$V4NC zu`d6xPpVxQ3AK51_)``SiZGWnQDK(-sQAUB&O9;ZWr21)x=|`EU{m(iF6}X>X@f}cG!3dgYCt6n0Iy2ll z3YsAb`7kX%(Q?GhbJhz+#aDjJ_ zBo?AEjSYjeN+hX|F*ZyK(aFkS3}eHzbf2Vg#4rMK$g{;b=P3i?|AfC1`dIjGfB=<4W0u(FLxqSwE53rHQ)x# z=zoLu&=a=6)9=?6yQY!DTPg-ihvB_}0lcO;5S1EB^hCq2OI$MXxb_}26SYV|@X^tZ z(OifsCVion$#TUnwK~$g7o$pOhz`_GbC36b(nL&AWbpkLpMWWf4DRhp002ovPDHLkV1fgJ&&B`% delta 1714 zcmV;j22J_U2f+=HBYyw{XF*Lt006O%3;baP0000WV@Og>004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt00(qQO+^Re2p0ndF^^TP zO#lD|$w@>(R9M5snO$sDRRVy&bAM*;&;0cV>~x@kvZYi@LVtJG)-}4)v?@enLb4&g z7_(V}*<@cZ1bw_O8nW4BAAH$;+82${RFd7mY}f=dYZo1*U_gFSMWKaepirPQWjcR% zjt?!^N`dLjEu7am_vAa@otg9HUIDOG%ld+$f?B+BY!=C*86s}_8vJfH6D%gnpaEjD z_4_8Jn;@yf7k?Zc37T-kKnqWit(+Q~N@kH-TyOWku<3W*Y{rI&KX>UbGY=h2>BgJMhs@`%$)yg?x9%|d#oMn+kVZn^ncKbN@LT7rZbJFHFqt)Wdjiu zU>!cxPV=1`fm!DvfjQ#Ok-#$y@EfA&2sGO1Q!?sSW2+=W7!3mz4O7!CVavdD%3XO| zj~wb}!qA(}n=x zCTIDQLx1iqH7SK_xv^<9415>}6ilJ{eFnYP4y+uSaJ22+?awLw^spKOL6(c8NTiM@ zCicwTEk~JdEWaU#N{s zdvcPB+nQ;~Vqg$J2UNmndZ1}GHtC@?;V9d>)(tBC^v>JLGtMy%o=km|c8a&BsXt%w zMSrPfsy(agxJ@WQK$Ix z-@3Z+q9nfZhNd{`K|u{zhB59VvMCiVtiTi4mEKhGB0<`17qzAk)zGJiER zdNgKDi&bSG^3h~Y;77db^@GVxK`DK1qq>e35+QMP8x zN_1Ay2%%u0{{NL3Dx9R2v*(pdKdgQQ$D z9Y5#Si4dR>&D8gSr9fEuJBdiec8@Jfz3scC0k|{jo^F~`7l{U z8|xQ@&6kzKM~{8@LoHZ!jDOu`rb)go_sj34lv28~AagP&3(}QRO8J94Ape+Y-fh;p zeoe*zQm#M0Ac{;>baYhD!ls__i(~rs@Z`Bi&BoxaDDs1MVWZWhOgd%0-E`5`RSQ2h zaD%gz;amSYbls`cwQ_yNU_lgV6iIWO#K=f>VY8CP=B(v8wc%R8Z+}cd{>;pO6PN#1 zr!7y6%~_L`XeN4rv)_LA_bcyt^7ut~u?T<^2tbNQ^~&eIoAhj(@Dr#@FaX)a@`?Ze z03~!qSaf7zbY(hYa%Ew3WdJfTF*z+TI4v?WR4_9-Ff}?fIV~_WIxsLZO}thB001R) zMObuXVRU6WZEs|0W-ECBGB7bYEigDOGBZ>#GdeIeIy5;gFf=+aFhURn>Hq)$07*qo IM6N<$g8d95{{R30 diff --git a/src/qt/res/icons/explorer.png b/src/qt/res/icons/explorer.png index da4151ca6bde8c73bc96f5228b53a6e9b8a4c792..0417ca092dea0a752a36df5176a8eea99282360f 100644 GIT binary patch delta 2047 zcmV(ABYy|eNklEKQ8F|q%HuJ`w`TNF$@T1YO>$Yv}Vb8T2E;wVU2{X$hEY!Xn|M~TWiG5EF z9GQCWgMCl5GDqygPfmX%15My3U%GFEExYcGF7Ng(u{P1?K$^5r0*FRLz%URI0zaVF zuamW602+-t00u(FH0bIvG5Q^E$Hje{`no@}=?BY0cYnmk#wXKvU;QfOg%{RnKm&;0 zO0L`UbrmmaV@s8gDn+V5X-HEcO$8Al)g~BL`ykWCv>Z&^#k5>nsX?{YqS4f(wuj|A zFuY}$T+eMlaSa0@faMekvSek7Y{n%;lV}iaAV|kQK{RM-@0q!IjvYTvd2tTI5NszP z2(zr;uz!(aAxoNodp zrsqpks!N#C#IYkvwG7opiml6#{(~b&USiw!om@RKg71UhJPY<_@G}`8Si?XSz_fa? zUGDt(B<}Sc`a9Z_j&axV7@wNrwS&)c+2te5sDI7O;gTuXYXAs<;}x+i8o6#<3sOuHrOtV8m=;TwDn}1K&-Tl%QONc{R=7@O(ko?p)Jt@}L)v%yC)@aPx6>EilDL}+EZ z@PADqQIKc>(I^eBZ}Y~HLu_2Xk(0?5B!V!2`3h7maI95luDC29wXUJ|);O~#4>I0J z!3!YB1|0?rKvpZEN+Y~5hoOnHUAU&ErG!KYEd`i1i%Vr{rL%e<$t4&=FJa_Fe1$6@HDMV4%gB&6HO`x1}3KI zu)JKRyI3Ig3iRfn7PpPJ)C&C_1~kM9lmX%3I;{6yp1S^%pi;P;Npqg+zmqtYk|2c;AJdg2A-qK)u;UmVfE; zal9^)*aFg30Jc-akGgGD#mV?M7BmtQtrQ}HLZL8d)a&$EDS5{wa3FA@(Q12~bo6Q& zZAP*Il$D@cHOzDd3=Lt{!V9`cVjGC<^EA+p7n)X5!HYb!QnXS*v_=rL(l}v`GxLiK z*XD7$hVX3gEoixI<4SkRtI-Ze6o0_%#4^oFiJ?>doH77EW8wyRSaL25fob*Q`q-+D z8TOE*?f458Am~(x^4%nEj+xWPS@)?SJO?bm5fGhCX+>l&teXb6%r1R3yx2yiY0U^_iH9%1V&wqs(LCW3)im7oKD6l|K>oZs7B`-a%6*SZWD^EI3}U!oc|= z?8kPw=b^vhJ-ml(WPoL1qJJ?uacz^J*s*gv-NlF_PyLSkiPz{|zlk7QM2oOkTHy3M zZ;;DIT)%fOhb9&{(U>6dTpXi}3J1Xp!W9Nq0XW_ej>lAS1NB-S@3k`3dJENRki6o+WDv2kv@@8-9B`s~x`s>Kd z`0|==$caOb$D>ClV$ z7U%BlzJFd>8Mub0A9#Sl`}Z~(d;2Ibb8f=<(Cx_Xv`eoOC+k1FKeY2^=#t&Wo%?6y zr`;m&-XP^yZg>%M*WTX%JtFdv2dC$G*aFnb%=&MxwpY`q56b8xkGO}A!P{q;eEvOT zX(qEWm>MhI8|Te^|MitAWVv+DgO)e^IX!(~TE>q50eDPAX8$(;RtN8`o%|mIW<^Ad d|NGnVzW@(rkd5~SDw6;J002ovPDHLkV1g`600000 literal 6472 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 diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png index 2e1ae8b95a85e8147f67a415388b47ce719ef701..19ea7d9c3711e41d601366a311b066fe38fd0999 100644 GIT binary patch delta 2036 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 diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png index ba7922f00afa9dd8691902e51afb59d0c075a107..1a84f1804f328b356389092d67c507763d6b98df 100644 GIT binary patch delta 136 zcmV;30C)ec1-Ao`B(Y!?0exsmL_t&-8C}6K3c^4XMbUdnWoIFXk`$8tFKMtya0`Mk zJSQptIZ{X=h2rEuh930dVPVVR>s5WK*z-x^O=mp)*c0!*K*b(-$A_+{B%vkF>Z+2Y qC2?9jk<;cRs{v@P|*aN$LX6X`?R< zN&-wrJ~nBbe7#ktlj*!-K#1@8PiM<^pEiyS7B%o$t?{k>@yi-buG1z5KR<2`S{P9SBeC+-5_1EV2xHmK#bS>Zfv&O70dI(QCQop9AlKIFPp*dPhjm?3sRV{IiC`m~yNwrEYN(E93Mh1qKx&{`yM#doq x##RQVRwh8MiIstYvG1NRpav_1j@SB(Y#o0e^T&L_t&-8C}6K3c^4DMZxzHw6e1hMA1fKA%Wcg7Qw<` z=@qO3^4+A|8L3D`DvDbRQp`bjF7CXt__|kbD*p0L;z2uH%}j|$AE4qd@Qf$zQAxs> zcu{+mBx4fWt1D7$oNOC93tXUW!^+`I@v&`KHG>q9id6nI*DyO~2@Z(*00000NkvXX Hu0mjfo4!N7 delta 403 zcmZo-`O7*%#gZl6(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF?ITh8GMBr3MTP zuM!v-tY$DUh!@P+6=<_jF@&+6G0EHAg`tC0)&r=Hy~NYkmHjb?I5VqZf9P7EDGXaZ zT^vIsE+;1_$Ql?K6&4f~e*REUTv%jaXk=vY>C;DU4z9>ZPEM{5pFbKIaddZdMc%$~ z>*med5#60#9L62q9#$3>R+hVW?6S1*@ai!3@Z7z7cXdToWo0#kF}Icv&L#y z)h{--Hn(GH%a)}nFd8Hn^D{CQ?_k*7s>%@|@J*WGQm8aXuUr5h&#llarf+Ai_x(v4Rxt{pSO5 zs5oig!AU4;99mRd%=i&P&``^pSh1LEP6ZRW5M0Q5TAEZ9k7 zLpqoxG#W>>w@E-VKrGx%tcC&Eaof@ogK7W))mae3_%N>|>GFn``G$~j adAl59eatVuPggw4sm8y!~W2ZE>SR!q%IzcjM+iX4|{&aNg#o%TJ&Ee3)S~^IXNf`nN?* z?IJ9R`y%whKR=%!w_uN5U`+nD+h?OhYU8;6G$v$hx0mT}|Enp(`NL7F_o(p65UaUf zY3FXv;aO5txi3Ix>glOjZ=EiG72gwVvTnVUe1MTob#ml0?is5p^H*(<57>T7*Yq31 zs`CopEVkY+0eVQa#5JNMC9x#cD!C{%F}5U?!N|bSQrEyj*T^`;z}U*b)XD_NHL)@< iF!tROhN2@kKP5A*61N5?0hU)l4Gf;HelF{r5}E+$Nt^`$ diff --git a/src/qt/res/icons/facebook.png b/src/qt/res/icons/facebook.png index d7c79c4527b6627c86b2cb50c22a295d298ed659..81fcf086506a70014dd1c2c9a8176620b45a0522 100644 GIT binary patch delta 289 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 delta 1066 zcmV+_1l9Yy2EGW8BYyw{XF*Lt006O%3;baP00002VoOIv0RM-N%)bBt010qNS#tmY z3ljhU3ljkVnw%H_000McNliru;|Lc61u>6RtxW&`16@f(K~y-)m6Tm*9Ay-SpYLa; zn_Z12C26}Ub{n%4+a{r2D2QNF6?#=_y$~ZQ{^dplr4q3IwtvuySG`aXC6FuivOzDJ zV3v(wsgz=9nr;gQYa43T)NXdOF*`fEJ2PG+ogI_Sk7sVqne)EyIp6mkj`*Bfrda6w z?!@c^$^}O@&UK#%kGnOI`ZH>qcc^k$Es16MdQ6Ph#_9P$ATg_fkb(adQB9Nx_M$tg z3<^x4{1$?Bq<Cx)nTj4`Xrha{XX+lz&7L6PGfe$u)l3fAdJ)8dqi! zJNs_$gR>4E29gpgPKG)fsNfK>I)1#qEAxn6g{K5dk6fuxA zE(+Wti$Y?O;S$%V&}r=(8QYg@)qeFYiQ_$6GsAqt2zkOt1a443E=__#mNBl-UU)h& z)|qeBfX$Y~2S@FhGmJ1#$e*Z10jZDzUHuGg=znRWpHljx?xv)LMN{&_?sB@Hv|(sN z2eC>hL|;epy}QjSuw*1>i`KoujpM|!Cj|))|m@-E;-8pbt|8)G$ z3&yesD>~AwynkWxrQ2PHAy)X7TwD3{!t+uEaf%s6U1h$dcdU4GS&EmN_e`kSRC%s^ zAAgznm6P@nX)MPn{>iDv9(L9ke&z1I^{mMsnS6u&V&Y8cDQSR*i$JjGNkHBZtx39S z53YlQng%DTmR7At9R(yFf)E8HjIObf6ecRFqUI94L@(cSfFcfWbC$=k`Clu|V=ryQ zDI@75PK*km>R*=+ZB*hn#yN+B$8~;X1b-LzPrY?&8e>Cr%_J#8C?LgU>Trlo>4T?+ znAxV>jYt@NDH9V%Zc86L^)I`eF-+V=*M0y103~!qSaf7zbY(hYa%Ew3WdJfTF*z+T zI4v?WR4_9-Ff}?fIV~_WIxsLZO}thB001R)MObuXVRU6WZEs|0W_bWIFflnTFe5lE kGBZ>#GdeIeIy5;gFf=+aFhURn>Hq)$07*qoM6N<$f=jQ~z5oCK diff --git a/src/qt/res/icons/instagram.png b/src/qt/res/icons/instagram.png index ddd7571e961b55e31ab78a93d7e03f4870d5870a..46a75fdb0246f7ce4644295ddbd4a1ae448b9182 100644 GIT binary patch delta 2500 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 O0000lIBs?)JxR0a<0C0i>99)<# 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 O12QwV#?~5n$NUT4TINmw diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png index 40986f67eed8eedb9a930da8e42ce15245ae514d..5d8e3a0cc106d8d8702c3933f11e95a8b37f136d 100644 GIT binary patch delta 143 zcmV;A0C4}#1C9caB#~fde{V@dK~y-)?b5jpfG`XL&_GWLcx@fvJiQtKfIt;khZ3rw;y3^bE^^{&oN$*5o&gP?Ugf!sDW1kz!<7&D x_)U@GOFM#fA-I@u=#9N$@7UF~fL{Hv?1M}Z;tJk&^8f$<07*qo1w^hwV1gAZKKuXx delta 334 zcmeBUI>$Ug#gZl6(btiIVPik{pF~y$1_p&>k04(LhAK4%hK3dfhF?ITh8GMBr3MTP zuM!v-tY$DUh!@P+6=*Y2F|(dA$=lsUm}hs)G@vr}5>H=O_QxFJ%&dm}p=*JLFcf;a zIEGl9emlvNuR%e8MKEQeYstU=5zQRzivH76>6c%gI4`l*`{Hus;^Wm-udYvcclgZ3nawqS)YxC{)UQ7{i7{3q z`mN~Q#Kjk1gfY0+_wY9R2tJy!!<_?YyK0GRL`h0wNvc(HQ7VvPFfuT-)HSfsH8Kt{ wFt#!PsvQH#I3r>mdKI;Vst0G|eL@c;k- diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png index d0571e59e4ab7135fe9160ee9f627195275a81d9..06ea8ec813018f1d3868e775f535605801ccaac2 100644 GIT binary patch delta 354 zcmV-o0iFKi1pES!BYy!yNkl3E_-iI2FQ|e&I$4H~hkDngBFe`#)|`jqC_v4>#}C1kc^!zyt^G zaFMAqJEdrO^9lsJpU|P45m4~6PtJLQPw*eY?{ugCN>p1o@&Et;07*qoM6N<$f;IN1 A5dZ)H delta 587 zcmeyv^q6IWay{XE)7O>#F^4!at6_iWT3-eR#wJe}#}JR>Z>QO3IXMcn?-ySr#-_w&*}%ai zcjT1ul8qi4HcT>!JHTAQ!M)bm!^7%rj!k2#5=T~j%a8W>u8!9H>u<7nR4gvrq&=&B zGkfm+cicw`-@Ng-Bm6`Bz=;RZ)0X?qmvlPwB3S+Xfgfx#%MWUWY*^&@N1&i<-A0EF zy_K~G1+88muytL>uw%)I%T~7(cggQ)6Y$P+mM%Ulq?q-)LAXb7QO=#uMovB+KbpNc zJ|@X7PjAuq*<62{BXC0#H^;?q?EC`3Nnr&&nn@4%|2cdq%Uaz&_b03&1 zB%O^4o3oKC`L?m$S`XtAHh$0D&9l!%D9&1zkg)4>6Q}r&+q-$Lrfqo6yIMi!ceQzk zc7X6^M8_}q0ou6y>bX8FAb_@})$?uqW3_}S22>A7C!iAz!cIp2OV z)ZLWU_I_sFgJ*LOsDB82BfML>*lvM2?@?eJsg}4#l%yn}eU zBjXSQV=DtwD-$5s#Kp?Mz}RbVE{FKbJN*p?X8k_`JUI8^Qc)I$ztaD0e0syiy B>VyCQ diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png index 3a6368ab6911d5ad0930e417b4f3c3a80731ca13..0b147350f789027ef377a9e87bd3aa0ccf7be46e 100644 GIT binary patch delta 348 zcmV-i0i*uh1oi@uBYy!sNklk}nccz=P1amNiitOF3RoA%yO zaDz_}V#xmFq*G^z5JxWX3O$6VGcAV*5xKy72yxH!%yEsla)B=qVw5o`ZdrwF24N2;@68JCo5P_M9Gb&5B4ak9 uW^?CN3CDjz-?bhgRX^*Lzd>^NFTx-G!1Hp{$^LKv0000{XE)7O>#F^4!at6_iWT3-eR#%fO&#}JR>Z>MeaVs;d0+ix7`sQZNJR=Y#f zFS#(YeGR@+o`SP89&<-Tb)27|WG2?7aYHjAD?Pnlv$5G&(5I-!cZbsU)tjXkE6mL7 zyLq#JZ+&{1xqw=-vG60mgZmlWcO zH$#DgU!>;X<~zL1({na5Ih-hy+N=1S-OfdT?M<55vSSR6H@-9K3oCP&KA!hpkz*qN zjxL2eQC*r3>X{ziVXtXZ$ccJwa$KrX{sXsDd*%JO4dwT=KAdT1%Q3R9;H&t0G->Lh zl-!;`{hb*xOV+Y&*L-!**ECFE*0O|zU7wrGr^#G-)1`Qur)*E6YQf4b!?))T+P)Iu zSa~`4T);Fh+qnf3WUo$-HWOL)Ab|av*TfxN%UQ!Oub(^r>JI;U<_5OfxgvVJLJY?y z{=cYD*&ef8_{g3|H!=%lZGYV2tV#W8@4Pd# zvuC~sgFm>u5&l^hl5u<1hcsa1sFt`!l%yn}eUBjXSQV=Dtw rD-$5s#LB?H*mqBuEsBoZ{FKbJO58e}1Xx}HH86O(`njxgN@xNA7IETx diff --git a/src/qt/res/icons/medium.png b/src/qt/res/icons/medium.png index a02a1d69a1d03f22a8d8b96e676cb38a6b9782d6..aafee7f14e798e5326acbbf3e0cfa2d0a9b84f3c 100644 GIT binary patch delta 500 zcmV~!$?RGi!`Fw1RPN#!vwSW3!&2&12cswo-pjNBF zou%aE3)y2>~=flE0qexn$0F`HXE|<_d8fD7G(gU(I{=&>2#o2EV2^E zVlm3^c02MjnSTr{mrDjzQ@Pds$*kYF5nQv!yXMI2p_{|no24q`90dGHl#(#fHZ8P`|UD#Ho}OZwrfdG@=7vV20f179QmMr8@v&>o{{B9Ew*ioh)B2F6{VB_lFQ{pM8q^ru`EkO zL>7yM=(@gED}VOXWHJGu-|y4w^#IT`jd(l`z{SM{0ES^O7z_Xq5nf+kJ$h*NifR4Rq0X~beNrqe0SW|M=1gH2p+ z1`rO1F${zGd=9|b*%?}^JOIlYA08fJ+cvdY4Zq*NQSh|^EX#7)^?Kc9KR!Ov>-ARB z|9RiH0V0uz%Wk*Zyu7?PcCA(e+_&E6^AU|k*Kz-KBf7u8cbbogNT<^gK+5H^GpA{q zWHK2U4q%7!QM1`h^7;IijmYy7&gXNw-7c18p_Fo7z}?*)M@L7D$77zJo=7H>OePbC z!yzI9EdPSff5^re`026r?|28W1K0s5;MX<*{sKnfT^_grsCxha002ovPDHLkV1lJh B7kmH! diff --git a/src/qt/res/icons/notsynced.png b/src/qt/res/icons/notsynced.png index 7de4ba0541d90f0ed2744398779e85c3df8ac558..c4ca456b4428915014902ccea8c6847baac57354 100644 GIT binary patch delta 226 zcmV<803H8;3hM`uBe7rd0)N3tL_t&-83n;XD}wZo)}B*_XDD zl)ICQ-L#|@Cl|HsLhZ+hA(De1u%Ez13I|FK^E}1?C#U$HcvpZH(B{RABWUB;8OmDd zfM)KTWd~gF^)auhOT|9AJS`N#Ql1F(A_Mu-9DoRKhNCu3zaKljELS2Jnc8CTd-J)n zxPeQ#*tL1(`L$G0r(rbqWUj&bpGQg5%To7L;Z729NcuC5TSy`%8wqP3fFvSfyD%#T cLptf|Kd&__!QOLZaR2}S07*qoM6N<$f-cu+XaE2J delta 504 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 literal 494 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZA!2%@LAG@9cq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W> zdx@v7EBj*(ab{M-{?N5RLm0k!x;TbtoKG$hdv`Lmp~;%viGK}$*o9OD4lgz1ij{xc zn?LjN@LZqvSDmS1D?qtY>rH{_)YWdHSvY|HHo-8{~Ag z-0;vzNK8mbm|(nP(|ms!r42jXE=q3y#H?#sJ<;S7SBCY0B~!MV$QESpG3P#(bR}(a zctc^`zPrD#g-x0+KL37So!UL?E37J3qHJ<@3v?K3{(X4CG=Ik$HD+e!!*{d)^9gMG zc)I+Q5X1Z*%RB{r$L%md<;Y z2M!bzzdava;q;lShn0bsb?c8+FN|z~A)s2~8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd v42-P|Os!0SToWq;17qJkVJI4M^HVa@DsgLY5@2}+)WG2B>gTe~DWM4fVB@XL diff --git a/src/qt/res/icons/privacy.png b/src/qt/res/icons/privacy.png index 1ccec1032f0ba15f1eafed3f4280d1eb355ce0d2..0318bb97442b2159b59ec5209e8b4937a65c1e59 100644 GIT binary patch literal 4140 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 MrKYD^qhcTRA3MclApigX diff --git a/src/qt/res/icons/qr-code.png b/src/qt/res/icons/qr-code.png index 84f74b1bb6b3dbf7a78d8d25f9185ef91e937493..da08396bcdf90aefec8a8c860705f043aa373e50 100644 GIT binary patch delta 3179 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 literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^4j{}3Bp8~6e2Re-OS+@4BLl<6e(pbstU$g(vPY0F z14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yuk)iNb{ySp$j-t7`z0_1TP zctiqCj~z?)FK#IZ0z|d0Hz(Uu^IK;r%%D~jh1jse9GB7aq g-4lkQAvZrIGp!Q01}6cQS3nI6p00i_>zopr0Cc=?mjD0& diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png index 6e11a072d3b8b9502bb4f14ea9542d6eab8badf9..1631a164f5211f1e509cf17eb370312220d044ff 100644 GIT binary patch delta 1819 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 diff --git a/src/qt/res/icons/receive_dark.png b/src/qt/res/icons/receive_dark.png index f6f17d0bc6c9e5ef22d1100f803790f68bd892e5..8021371b24ac27e864e50b4f1fc0c3bb34094fee 100644 GIT binary patch delta 1907 zcmV-(2aNc)7poPJBe7pD1AhlZNkl0{JH6u>iYHn3$m3kBp@Kx@%j3WW;Q zg507YEr(Poh~R;Ops08NQY#b`mBUs*M4_Uhc!0NfU-`q_&9#}y+)4UAWs{k_-@bX7 zl*M5R(ial|M<`hXI0}*p0H|uOKz~4r0Jfg?0Krbt z0*-;CXaUDiQUHJi>Q#I}29V>bA2c{$H3Ykb@Q|wf;6Z!@oWufprqyo<8Gv@fTADQk z0PNP6v?fF1HYc01!4^uAD&p10r5W}JphI+u^fOhoTR)Qfb14% zPmEUvk$xipOY|+oD%1LHNDd$(U{n_Npk@FBf~*NNzZy9}%oT}GfvRd-l8(a=fNa?4 zr$9LXX)8$20_3M9_^u`T1pq^b4IfdKk)tdmBjCSK*lCFYs((lO6~|bdg$1*9`T7;- z524hI^=pn(nc7PM^jDb`0F`x}3;<;TKzs_pm%synEGz&>I>F$LSt&Jv9VcJ{AOiy^ z0g!G0aRA#zKt`eu5VHVa^$?9Q08K#Hp4E*i$4=A$fCJ#)${rwUg7E#g^7*+Fl1u@B zazlCyw)iuUlz%KxK*VrE4*`NXTS@>#Utq@poXmY7LQpbC9DuSx`T$Wk1Qq~EpbRkn z2EY0QjaVz`0~U*b31Cm0M9bvjlwd+KwItOwI01meZ2~~kZoH}X=DO*(+)7FPZ4G|q z8I6rIXU?25%K*RB&cFZwB5e@pU*PBh;JeCFkPyTzfJp*h|H4JOQR>A@ zrY~K(bXnbUT>wPdzz4WH^6C}$%$t2LEhAU1@*m%~dR$vu+k~oi_gC{8Z2(3`VXa*k z-dcbE27mT2JBR9uJKSFnY%l?!oy2-DywSc!HW;mr18nTv)X~w=zF8RnM+-n?-RC^C zMR_!g06gqH*~%~h#{v|=w&2GjkE##Ho)0|sc`&SK{6#$;uv*+28JbyR-`Mo8nu}v)ikuop%SFJB90QmA! ztQR^bb+ShCr+F^B_9nz zuy%V#08s4p3w542na}5s_t6Cgmmj_>1+Yo|9>8h;#u)*?+8KVKvz!7hK)nnASRs^f zEa;uc2Y4^2c8*ivoC*N2r{$ggt#yLY@P9y1Z#bvG`>ZCQrsWV{9=Zk22RA?91AG{i zxlp+``C|Wq{{Eu(~t_ukL(O~i?!QE!=jHs$RD6%->nC_i^@5iTomoN8C zl`Kp+;q=cw5AN4r;Q&ksO6=b-F-$S&b0^cs)mKK`<@pztS#cFhJzf$PIJD@}mwzFE z8#Cxq2H*!Mni|4qr@uN%zi!&7O++8mMK-}fQMi^BBXZ&~BG?gm+_LQJmGiG|b>-@X zk+o;8QT0QcfAei?YisXD_j*#-cST8rgt^1*FU`JRrMf0;ZfMAdEwjAXS1fuH$+?d6 zgBk!kPWYpm`tFNAojS!_yzFjS@qaTTV6GmhJg)?>o!d_gy?*@)9W5@+3#8k1l?cgU z1^u;p`Jko7F26Y!4Oa6r98k}Cnf_lC5(sng_ya`4^`iZPg}*k4)Hn91{C%4dEeGWd zi&?*o3opB{THdFNPATm%$z4&L-_1!zOo;&GuTo1)H}pj? zP3>mY#M-W4W0n8Gu>dc-KSAqr>?lY`O?s40wCGm>u#+Lg>$2NWe8`1)TBRU5)CjnM z*!8pzxo`+vGuXg<9e|AxrxFj^?4Xmn<&z$C0{%fWMdh+yL}mfVC1^YAR#u+_a|@uP z$L)};6IDI%nALGZjYF^59Jo{lux(w0^1-)MEuduv^&ZpU;B%_Sjt!4~r*`hz3?S%- tS*l@R4!?tq3$cTbxdOH!xdjGV{s+mrvo0lHgH!+j002ovPDHLkV1k%kbtnJ; delta 2176 zcmZ|QX*|>m7YFe3H!}@GS(-t}t~5zwR5Y>-V;z$vq3n$%SC&F4YW~rpQbZ#m+-Itr zv>+l&23aObN|q8sN!D<0sW7hR)${6kaX!D#IiJt>oR_DFRH2ZjMFVUIoka&INtIj- zzyW|d+s>5*a6$(FO#=9}ypm%8u@r!De*jt*fI?)tUz1IV1_i?bLwo8L?pXO9=Vk0j1;;$*JE&Wmsz;wrmIUn{{T(4v~E(aX8GX#Od#)cMG|gzDe;ZcvH>le zC!BGKreJ3#Yg)v8&&d|YMrISN&~4K%Wy-+$Y<$L(0!*v@$N90GM-!u~93twf5(dqV zU@Nl4d(U>8$RIt7uy1`ZkFR4N8aTNqjK!BdQl zcJ?s7u*)FE)}N+fgNntmTV|=xj5SJC%{V36R<@OULAdA6+`2UT9$%whzc=lPth|~L zYV^*w`K_{2aC??PKrjJPPy}t>_c$lP@M)hOUJ7NdMa3y05s&{oHdr^(O$0>*mlkPo zG+!RQ$vxaLaa?}72!weg5=wU$y~O|vNa(MlA|_0S2W>hi{#?9LkN%lc&#`0zr*pWF znW?vr7Ib3^1h8e0{@r_P7q2{hJpDOn<|4Oqq}u)R{@N4Yv#Pp<_s1f_Ag~~+`#$Sp z_s7So4@xN}uF2SAPqZaT6wn{9}IC@B%atzyCI)CO0<4+97`HkB2n&6x^YjIVy!?+o>9W4>#o_kf-Z5QsHHd}wR_7jH zsY^dR5x0iV#_>GfrspdDex8eOL|3k0J}i#hyd6_>2o6xbsk2i<5`B1A=S;|g zvb35R_5CXNnkT2Wx)|T9npfLEoR8@!XFtBl9W={o1Yri9#uo2sro|>0X=Z+ zR@bRT2FEPlyt{GpKU@3~n3BR0krlefr9KqL&mOz_X59r#ps?`JE9Wq$_f>T>KF(x^ z$z~VhFfsU9R%1%uUlgY_eQ9cy197093N2aXn%i)|`Hga3LRa*dYX?IIewFh=p^s{WdP+DL!vN3Qui_p3g`$!~}= znUTf$9?N7h=g$e_yjzT{4dACHskUZqZT89PH%8a){QjMgej}(U?|?zB-K*K9Z|%@~ zuqm=-Fz4yFnwdsH#@DvCS6@cVFRm;0yt^v|Tg+{}wfwFqK>9y^r=nd}j&~6R8kpsb z3m0As^m}r73PmF(Dt0}zo6Gr9J7m6ao`1&|T%Q<`RS&H1_)eZ*?X#i6X)CFvXvE_3 zSu$7#i>R){OTtHWtG8b?pBHG4f1w)+2T~}gtJm+79cm9eM7M%^{iZ@hqLy|Oy4t)> z;+*O>z@Yb@+}iGF%-#b%5YcelP+E64j-ybfnkdiqayY-NqxBlhnCdmy+}SVNx+tj?FqMt? z7}y6<=fGP`G4@+Yn0sSj>(TW37svObaVpK;NmK1QK3IOVWJ7A|)5M8Br`+6S zFA+{q^;my_wE4%%tJaCJ_KXP(hzX*xj|8m*P$>pGw@{3?Pz~KEhBV4{+P0N;8;wFS jWYxH@0NVdVcw}H`@bUjIEM>6cD+27TcQYPZ`X~MiQZ&C% diff --git a/src/qt/res/icons/received.png b/src/qt/res/icons/received.png index 7e8065db551a05e2c2d9ab715062a92082c274ea..f72451a545272d86cbdb066d8dca23f78be1f875 100644 GIT binary patch delta 162 zcmV;T0A2s#1DyhpB#~fZe}YLwK~yLeb-@7=f-nq4!B>s7w6W#i|FQ}Lqd?qcmu`2H z-ER+$vT0{ezRILuQ(;q0M^;%C)0q_(O;-~iS&gaCAwmrq1eC`GxQIxm@^a` zbj3PJu>`Kj3}i(zA5B+{MRA>ZVO3p6UfGnUU#;+!UAsARl=^V_80d-38}XMP+JBrz QApigX07*qoM6N<$g6jT6{r~^~ delta 357 zcmbQs^pJUiiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@5Vro5OlDE5yQ1zZ1pehFT5>H=O_QxFJ%&dm}p=*JLFm!mj zIEHAPubmVrbXbAM+4qrOlO#!AyIngzzxcS0 zv(fO-LaVfe9@DiS_5Bw+&J`^ZsrBB7{hEYV*CY*Xudq{7j&Vw@a+iDcqJHno&l;`g zj_=himtFt+&S%fPSu<2Q_uESdyIuc(?ta;=m+O5_F`YcQGHR{CyD}n%Ai`} z8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd42-P|Os!0SToWq;17qJkVJI4M^HVa@D&ZOw WF?2Wyu)G55VDNPHb6Mw<&;$ToL3@7y diff --git a/src/qt/res/icons/reddit.png b/src/qt/res/icons/reddit.png index 84b8c2947d326809976354ae6c3db8bf848c0d09..c3612383628e34031d8a16533fb479801dcbbb53 100644 GIT binary patch delta 1956 zcmV;V2V3~A6R{7FBYy{YNklm80AoFRU3(=$C8Fwhq;Pm3`0d!Jp0E( zOpRTqz2>>D=db&|zu)`#``tgCqPVyyN^r2E*lfBN{1io&6@MipL{Vho8B)Ou< zvhM#$F4pRNac^Y9)Uyg>|3V0yv1PYcmzQC=^>1}L(czxu?W`~fro`BmEK(&MFD7Ype4z7hO7O30{DHmFt z-O#90^tCIN27eDP!Q^qThulfLhe%xks*3pbJYth8?6QXo9pJ$@P*tRjlNR=9GEh-M zLOPrq-WBe(g}f<9Qkz$Q@3N4+OJBL+V7U%d6{fGRBNOohEe2JM+?PMEXMaePJv3~DdDZ|;KdTVQ?bNH0 zI~mM~v{Vf+reAIO$bN0ccNz1qB#S{+;d=+T*b1s$q3lCMT;&Usb5++6i&G@B_lMAS zA*McK5#Jn#2V)VFVlfBiVD`?z)2Xjwl3OTBNJ!sJVSQk8G!$nd-IxctXK{}!q=7!M z4j~Qd?SBHV-FP$|F(cf1Hg9mq21Su&+?~S_VNOU%UYOG-BVAkrr5m7n3#dP88K^!2 zr8nS`y{|*2K6b>alCGY;ObBOhoa^~wvi%;9hy|F#8zVRQ032g#)iP)`(#Cu^ztx&j z+&%J}{Ca_6$^u01QSj9PDDABgJ^U7K=@Dn6kbe%j!~UI!{gWVDfwRt*ySK_i*Qk0e z?WK8;auHLED~xXgd1ko&HBwOw(w2BUgY7kPbNfi7{7g_)tL^5{xBRbkvc%tC1l5D! zUMo;jk&04b{cRXJ5CVtd=6Q#PE|nM^6L57LhH$x(@ODc%X=&WmH~r%!SXT^%_dwkS z_kU%mo(A_4;lfSC4^>()XUY*BM(YrJZh)%#E=Vt%u`$lA)9U^eh@v!2sbmSvs)y{C zN+So$bN5Sq`!b~Fr!mbuj3_Z^=R{EpMD$XO0T&@Xu2%ZfWLC2L)*3>e);-5Op7k93O z8SajGYkO=J=Hz~wV$P??%`<9xMAr9)7SoVgZ=$}V^vuYOj;q06hsp08_WI}=d$;CE zh@5s>CX!b|*J8`Q@{Ep0E6(YyUft^)T&CxPB6GwJGiiM=KxW~Yh+0u(Mig4mAgJ`A_&q2B0DWa80P%kq=a@K76s}$q_lO^Hw4v+a$cn7 zz~_fVp`Al*fWrx){q|LP{?98^lsd%Xtfw}4?o_!DdC6t1MDqvM^ZPmSfgL;J#uorhhk1LOsVi_6?oqB6p0!wAv48Sp`i@>z_XaM4mC*Z(9 zq+5R4q?|fD>NoyZYREk;aYz~3?jZi+gk;G6`5LyT2qSyAkh)oYQxpe53}A2Q)?OVes82X8)4-fSatyM=_$;yg%~X} zGJ-uG9Hvzo_et9tD`K`!Ksyqt}gkK3<#c q^*u6Q*w$uy^c_0><;WF9mj46weUIfS=Y>ZA0000E8b)9?qEL7V?U>ZXdlfTi|&h_`_|95>z6LZZcJ(?`=Vd@+sVJ>;0xRHNom7c_vp z^INJpA!PG(Qh&;x;TODjE&F)sD}!v${$}7Sf`{}zK;xF9q-P!}1?d|@Rv4*fY$Qvp zq&JP+ai;I7O+7{@Rg_r6{RQN6b6Vpy|4rH1Nu3Ji%{<7-!yzkXLT=UrJNE#!c8K^K zpnCztXM0~7@x=3+8`kw`TC?CmPop;(m=sK-anLmrxPM~L1I8`|#sN5f5hB^{A8jEIHK)D;Q`ywXx2a*_|-E}n)!dQbU7&g;(wf*5MS39n&C&FNhCzIj0~Vo(zmx4TNk5WIj;cAF@0i8rNaS z+JE;UaS$T-KA_7;LrM6#Zkr8i*(@}9^feA(p9=r`gP`eY15!!>%SMQcn}E!4XqUh3 zt~}}&G~Ij~O0b`7SWjo-V1t?DdK0i?M45T3h!lVUG z)ImNn7gWDKPfFS6uiw_Z`cX>f(HkZ;P(8b=MO@`;$RzRR(pwA}>?C)jw&YLy0#xf~Sih}Zx8RSD^_reHa0|KbvleIeT7Mcx zHBu2;5J=ay?lSX`#YgAJ#VIA>pa%dF=9jeqp4BP;Aw9@ym*GSAlLHx^k_vZHVR*;49aE1|Kdx;@YF{tOO#y3HRUW`C0F`df8U z#?F_rmoaY#jWK_2aWZBId1ePGL3OggB}Q{-6^;AvYfWq`J+WuQ-aB+1dro7wBV_LJ zb^`lTXfWJ$={K?cA6yi>%b#o;T(F;pXaKFdKslucD&GN`#zIyOx-`h`s#YNu_JTkBNXNb4zJE{_1LfH`i0|G8(jI|)vBvH3e08Z_Mn4lcsVu$en7g=Q zB08O3)_xTSHT{6PY6UXD2Vwjkz}U;=9JzPtN>lzv5wmU8W_j}16<;!zudO({`yzZY z%I#^~*zsE5|GD=`&*8uqAUpt?)?5}#)AHL|O1JiaS|pT?qn7zp?0>}crm$-KimBB~ zGJ~}2I4RjLnu};&Q{2*`6;oRM?d!NXtr4h=1d{8;z?+6%nxJs`z>|;qA9dYtdUXa3 zLw+O!0y_e;d(bkPM~)Geck&Rlrj$1r-oJFAjZd|$fq&vdKy5vgvS zaS+qSLV4qL8Xj7iv46K_DPXgGpHmrGUJ^YD%8*ZhyAJ?a_fmBXLUW}H8f^iDWdRyu zmO;c6Lt{7vNa~yf`Nj&!ZW8jtAow%CYlXdB@%mma1a6LjxUs;L z^urhT9$H^H;p3h5n`2$KGc@{jXy#mm7?%r}9{`Yic@6x9kbfm_L8OO{eCbo~;?8vk zn_SL^la^WSz>3*Gd=_vx9Ze}y+_m{NzeoT87&L5~@xu*~VF!l~Esrl7QZ+U86qJu5 z(C||LIw{rgMKwX(91Bg<6iAi;zG%quFet}Wc#nSYrM>ROkZfDf+E8!!cHQ_x5RX3# zL~MjSG#bq_?|*jJIObhdL=K19yz2O$R!3!gdX}u;O3Ek5GgHa8&XRZcW*6I2RD%aI zSV>}_ILMxmw2H4t{rHrk=;5>C=6d^Oy{n}$|4ULvllA*(*z`12+mc_x6CJ@@MU#+F zTL_Hz12d-saSMUqen9g|h;v%Vk_O1i`9R&H5Yh{ww|^U7={~R9WXrkYNnGv8Q&s`> z3UFXHH1F($C*A4xHQ=fQuJrh%DL4y=alxP19~fB%^ce@3`T(6O0F(lNL4m#dBJYK= zu=5{OP0!DR%!-3%*LvXaO!tMlQCF+DxElCn^Id}^VbKS}-&H{A))zi=4xnGyXM4zr zn4_Up|9^VuMB-8VsY0M)EIjqI+&-+wub9JOvx)!JPv&orwb=l(S@U~>15W3E0G=M; z9!JU>#Q*>RC3HntbYx+4WjbSWWnpw>05UK!H!UzYEipG#Fg7|fI65;nEigAaFfia> zUuggU03~!qSaf7zbY(hiZ)9m^c>ppnF*hwRIDaiMH&ie-Ix{#rGd3+SH##sdkpkz{ z0001QbVXQnb9QGsVqtS-Ep>8f0A^`yWjZe}FKBOVWiN1SVPR={ZhC2BZ*MPfbz*F3 zV_#@=ZEP=OVsBw`WG{7dWpZ$GZ)9I#Y;SI5FEA}MIXO8mH#0IXaBN{|ZfRq0ZZ2bQ jZ5}N*GcqkVGc{y6E^~Hgl7U0B00000NkvXXu0mjfkm8pP diff --git a/src/qt/res/icons/remove.png b/src/qt/res/icons/remove.png index 29523c94cb8c79194a548c7d8eb05402f33581d7..e528691f3c5f691767161a70f4c93875cac3b608 100644 GIT binary patch delta 238 zcmV3HJt&Be7p{0)Nd(L_t(I%VT6902oIV5UBtRAk^dAE=Bcrf3 zBR;T`QB+%o@u>{D_!A(OdI2Q%Fp6sdDIIhL??5Vat}!z1Wt7Oe0}@e0mVOUWVe|1C z<3UC#S3$;)f{ctvwtVJ$1Xpp0QQD0GqFoFk`xUH$<2F!5@Oqn%Gh-NKy3R5hL%qeo z@C98(FQZ&PP~a~-T)-+MUO`m2d|rQ&QN9l~07*qoM6N<$g2#hn6951J delta 519 zcmey)*3UUX*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL%)no-xVW-DRsWUz9gc9eatVuPggw4sm8y!~W2Kr`lobqV}fg3M8zkpO88sdUxL6wygyWVH*WkC0)KG5Xts)>k5V? zNybjCOwEfX8Cl&}v}Vz&W$PBMT)KAg>f;9%I>FtNEAv~8T&sVOppx5P`rje+6r z$|?2HuLX>N;iy{T8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd42-P|Os!0SToWq;14m=u gJz*$1a`RI%(<*W6a1vm71=PUc>FVdQ&MBb@00kbup#T5? diff --git a/src/qt/res/icons/reward.png b/src/qt/res/icons/reward.png index 76df4add9f8fc2c1f7223e88f78ebf22d626442b..d1a28897d5950ee24d8235d0dedaa641ed66beef 100644 GIT binary patch delta 162 zcmV;T0A2s#1DyhpB#~fZe}YLwK~yLeb-@7=f-nq4!B>s7w6W#i|FQ}Lqd?qcmu`2H z-ER+$vT0{ezRILuQ(;q0M^;%C)0q_(O;-~iS&gaCAwmrq1eC`GxQIxm@^a` zbj3PJu>`Kj3}i(zA5B+{MRA>ZVO3p6UfGnUU#;+!UAsARl=^V_80d-38}XMP+JBrz QApigX07*qoM6N<$g6jT6{r~^~ delta 357 zcmbQs^pJUiiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@5Vro5OlDE5yQ1zZ1pehFT5>H=O_QxFJ%&dm}p=*JLFm!mj zIEHAPubmVrbXbAM+4qrOlO#!AyIngzzxcS0 zv(fO-LaVfe9@DiS_5Bw+&J`^ZsrBB7{hEYV*CY*Xudq{7j&Vw@a+iDcqJHno&l;`g zj_=himtFt+&S%fPSu<2Q_uESdyIuc(?ta;=m+O5_F`YcQGHR{CyD}n%Ai`} z8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd42-P|Os!0SToWq;17qJkVJI4M^HVa@D&ZOw WF?2Wyu)G55VDNPHb6Mw<&;$ToL3@7y diff --git a/src/qt/res/icons/send.png b/src/qt/res/icons/send.png index 0c34886c35f3db96f695d2d5662475ef4a409a47..d4cc30ca9d49ea2bf64bab758cd1f767e7b77398 100644 GIT binary patch delta 247 zcmV2QH47fumH;goT~rC&vi!}Y9aF=xr1TdBTfOkK3Q$#4(@8yBCDyHa>+PzMbY z2ah%9lJJz+L&svqf*>WnSux7naO5RSJ>k%eALoCjm;=+qRi)1Hz(Z5L<1bD@3@~Y_ xeR5G;shAg6C>F(K#7H_$Aj-vM#GQ0piZ4w&X7}yXZhim&002ovPDHLkV1lH^Ztnm9 literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^GC(ZB!2%?mr-pI@DVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWJ06c;GMlHd zshqS9e{-wB|CD8shdHlDav^JmnqO?mBcD@Klfy1I#DDagAuO}t>#`Y1x=s8V zcjr3u-djIQLnA?+`^*tlmVdU3G-NM3J>CA{0GqJ;;%8o}>dfqtg2m14Rw0Y)5Atw7 z+&}yC-Ka)8b)StQ=Cj}LC_K0At^GX9q?=_7d~b~9ua|tCu=zp0ra|RiEBhjN@7W>RdP`(kYX@0FtpS)u+TL!4lyvcGBC9= o0dh^O3=E8Y_k^Kn$jwj5OsmAL!AXGS6;K0%r>mdKI;Vst050gL>Hq)$ diff --git a/src/qt/res/icons/send_dark.png b/src/qt/res/icons/send_dark.png index f976a756a8b6a18381b4520f71d56ac158856396..6f0c7195a2ed36878c5f916450db9ddb9c1fa137 100644 GIT binary patch delta 1811 zcmV+u2kiKz7Mm21Be7rp0)GbNNklq8Yq6u{@s?7adhLdHX)2#mN!MPeGD zs69Y4O)8bLqDT_8LZvb-O)Jt~1Z8GwFHIAAlRfs&>pph&&dknx=U&by?l8OOx97~x zoH=_2084=od0sLvp64N`d0m1LP-<}o;ImRf0ADOc1%L|W6a{n*0DnDA?I8nlZ2{j* zTwB057gqq#PCaITF#%xGUVR?Hiv<8x>VdigjOPLa2WxdT1Q6a4Ap{{TEDR7K;RV!4 z&<79|HJx(M0;*iQG{g#wwoz*@cZYE6LX=#RZ-1#Zv-i0BU%1A~<- zDIm}SK+MH{_L#9 z+%Ex@E|4uHc7u_;quK@T+^1@qC0QgLnW{)xjk<>h&kaS;PWXOModr!3ohZ zU^NAr0stKV;M4;7(3IGmCAhC4vh#o%AhdZ%;N{eMVt{N6<7t0Ra4wNCQNJ(SN({PV1+}?@<5%L0B$X2|MmJ z$;~SP06#1j>tE67I|bm30}6ok!19&8TL2CLxm#cX?ptN}d8E2(_5EF4T^-#$A^;o{ z7Q8@i7Fd8a^zAFxveMQ|_gJ^Stg^SaH{HHL0>BVR0P2ZbKk(o~9S_&_F;dsx7W{wX zrbjZ;zkm7B+^^0p5&%RKQ1K`=2;tW7AB~S~<4=$S%v1~?&;5EL3-ILj4H@BBfFwvt z0CwPM*55g(yBH-2fTz}_Gw$H0TL>G70iF(h-w$j6cFFQR8UXMa+`LAAIZi#B`_kKRqcb5S*8(Vw2g-uBCH4SE zIDgAAU;_eSM07N0>wL={0Hq%)V!}88Z}S0Q^!ZtUo+!Xd3xKVaSxGYhP#6<(UxTAI zgRmjrd~APK298qzlzyn*8NGu;?GqA!?zKU$-kt3k89K>!c$X|IDm*^Y*qXf;G`(Lh z0jLjCwJkd`vVDT>@Bxt<(b$@i0H<)BqS36A8elxKoo7 zfaiZ{hNKGbh$ctG0Au*N&jcN&qWJ-&nWCAlz-^xk^?z{&_xZBWI5Kti?9^0W{>N95 z6b;nQ5uL+rt+h%IOcFus*SVHW!Q5k-q#_7bgl*>qA5dCC1GHAvUBImub1mPPWq--I zKKM3l{O%%8|B>&>d;g#TAWl?rbHxh_jYE4b)lgPYGnoHgcAkYcC1IcmW*eD z>D?NsvC~GWMGXKdUHMnFLjO<$C@KJ$yDrs#xDU7j5PmzJ`@2G*{o46K<5~(K0QF^= z$yiQw_5XAI%D+<0!+;D2ViQMflu%xC?8tWRkwD6{~IT0D%PDHLkV1kaT BMAQHP delta 2076 zcmZwIc{J1w7YFeBo0-gHWX96i!q`eQnnL19gX}|tY=w-SkS%4OUmm?lwn99%N4;qw zsSFijRMtXdNhC{Jl%*(5!sGe#J?H)7p6|K$oX-6zNIJkY8$d4)KqBO#d$Z|f1uO>;Po|kMvWB6JuG5X7 z=7%Eyh+_X10{MlK>qGnr3u_bnBtZhZVONGj#rkTzjD@kGebnpb0=}2Hws>n*`~f^eXC(++71FHkv8muTj*b^=>wyltz>Fa#Wi?E?XpF; zj}uWW^Lx_it20P!WH3Dr*)rvUI|X01v7|zCVDIOh@(MTygq>C2qkn}|cwmgoE-y<5 zc1998H7izq)q?N}eTIt#DnF%^Gvr#5??-QcPv|2ogERk4S6EJTy8>?X+v|Z#5dNdC zU7b8Ze}$O;`s&FJN#QFg-oa3fyq4zT6oaP*S(n zx5#V}CGW*)KjbLCH{41@ZirDQ1L=t4AR!co?zIk%xrfY*djpl3kbp(WB(SLmEO?m3+67E3JIA;W`GefxX`@*FWweV>G( zCi?EM7|MhZ;Id2;q{awj5lI+Xltr{yreZi?NcBsjQbbF5D;|o6;?%hBGf19^IWTU;+JLYpGO0jD@F;JP{?d=j?JDG`ynZe-JaI|q&B*9z0<%>}5(V2a*~~*_r@9&< zyMo=)F86#pq$LN0DCjrRTKW;~`>CxqUkl8O&h10%r5;Uo)mOwxcIm*4Zzw*~@$qck zmnj;E<6MO;e-SCQ9}5uiXdaR*l2_Me@%AxxH?qv7Vn!alvStJwKN8O3uvn~9b9MxD zcB8s2Tb^Q!`ot}zJu~^NHm~h?>sH7PaY24`xfWnf3zX!1`Zc;dJC{)6Q_ZHuyM3Jt z9N6#7ZHOf0R8npa0=XC+&Iq?i)=_3~_3K5pSGeb;d{vq%H)BFZ@DT^CGkE93TLNs& zBHt%87ZLV^XSNT>aojKL{LcX-bNmWm_g#3}K;lD?m!c}hdk4&CaigT}3AE`uG^m}R ztR+Yb@HVbr5rJO&AxebWEsTXPV`F0x!)LjWw*Xp#j=jAfswj|kQiw#F8>uef&uk!| z{oCjUW~w8F6zZNmF1}bu>NLc3C)N1}oW=6af9-7KaQ(VRMKj>4WvDA})3@SYS(Xnz)_ z=sP0vNG_Kar=$-D(^+Wwl0p7Qj^T6~$P2@mEnt4eA=nuBp3u6VxvXiQ=OgyP$ z4sbY0*s;aC(x_}@NVAEXnKnFnHhJU>Z6RgPe2w#X(N%YiRb?-MC>@QMN(bzV{Q9z) z5m&CYlINMFfX0rWfk=AKJuhi=lG}?nI73ojDf{k$X7~@aN~0|Q(vwQ4+Ujc^Wo!O} zk59=$ch1%VAWN|og~V`^=fM zLJbyzjr!Mn8H=*ROG^}(KW{lzH_@K+__XYY>k-GPFT3a7`8LIoR&L&od$SG8F*XzF zgO2-CUJ`i&!3@`Wt;mod#!UL)ZAJ!sWWNik(N8 zF5^l{W~QcB4z^6a!x)vw5gLa+=`3bc$~(;#WvnJN$)aIRLyVxs5AG(J7t+q=?*2N6 zQFWu&yt(x^Bi;2m290&&`&DraIqXYW4Vq9JV_nV(tuAPorHUQkrSZ!-+Ay8l9Tb^8 z2%&3-DWlHmi;FAqGZTzkGcFM^!vmZ*TnikEkgWRnh?^{RQ!irf8nnUYrKa+{uHu+D zOBy6!i!0>uW`wTy7!g5;Pj!fQBP3OMYxfSOWkWw0#1^xjaq9x zhZG17@y;PPUn{UlDQH~_^;AM%j$0+9G2@~fN-X14>^t{4-)&q9acRA_O=zD3qHSOt|dUS0)t@Tz*k51RLu6O(& d5gg(j;2Zs~`2WC&jGJBuU}195__h%{@gIJkft&yU diff --git a/src/qt/res/icons/sent.png b/src/qt/res/icons/sent.png index fbe4c5c89039d2a79a9aefa89bcd416a33f41127..c55dbaab2e17eaef1fc95e524d5eeabe5b366cea 100644 GIT binary patch delta 162 zcmV;T0A2s#1DyhpB#~fZe}YLwK~yLeb-@7=f-nq4!B>s7w6W#i|FQ}Lqd?qcmu`2H z-ER+$vT0{ezRILuQ(;q0M^;%C)0q_(O;-~iS&gaCAwmrq1eC`GxQIxm@^a` zbj3PJu>`Kj3}i(zA5B+{MRA>ZVO3p6UfGnUU#;+!UAsARl=^V_80d-38}XMP+JBrz QApigX07*qoM6N<$g6jT6{r~^~ delta 357 zcmbQs^pJUiiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@5Vro5OlDE5yQ1zZ1pehFT5>H=O_QxFJ%&dm}p=*JLFm!mj zIEHAPubmVrbXbAM+4qrOlO#!AyIngzzxcS0 zv(fO-LaVfe9@DiS_5Bw+&J`^ZsrBB7{hEYV*CY*Xudq{7j&Vw@a+iDcqJHno&l;`g zj_=himtFt+&S%fPSu<2Q_uESdyIuc(?ta;=m+O5_F`YcQGHR{CyD}n%Ai`} z8c~vxSdwa$T$Bo=7>o=IEp-hnbd8Kd42-P|Os!0SToWq;17qJkVJI4M^HVa@D&ZOw WF?2Wyu)G55VDNPHb6Mw<&;$ToL3@7y diff --git a/src/qt/res/icons/staking_inactive.png b/src/qt/res/icons/staking_inactive.png index 1409cb84178cac00575b7891d1d44973635e5d56..3e7115429b875f053ddb2e677c837318fab90f18 100644 GIT binary patch delta 157 zcmV;O0Al~y1Gxc^B!7TOL_t(2&y~}`4S*mFh2gS-XSO5k@n6}3WgLK67@!^uYSic> zy^!!Fl=3j_s7RvH=yV#DL_BxLB9K|}Tdicm6)uzq8dX>Z3?FQ#VTbvXIZnom_|n_6 z*Jz|)<~Yfy60Am(U^BV|`vjDamMS_7;T9`w+cN+QMiEGs00000 LNkvXXu0mjfjY&l- literal 473 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc0wmQNuC@UwmUKs7M+SzC{oH>NS%G|oWRD)rBU^Zn$1Cx5$I z+aE2Oc|>aOxxlw3Hg5L~KCRjCal6~o!|FQQJ|v{)KdsmHpB6P;yXVcGU7=bs&RzP2PkZX&Gf@|PqpIZ7jvYOC^Kr(+Uh}2g`?=E}Y1c5arWl!+O5HvW z^p|RhYeY#(Vo9o1a#1RfVlXl=wA3}Q)HN~O@uObEOcn*>nu_Jaiy@Zrb`K2&^bVbO=aEtbsM|7EH0y7;v z!NO?UnFem$jVrFvP(0%f`UA%uRT7?1#W8nPmdW(b6wj!V!wagE@KcN`$9N{tP#Ed` zWOc5gmCZfItj~0?PEk_-a%mqUv=)-t^yFaQ7m07*qoM6N<$f(1-ws{jB1 delta 428 zcmbQl`habMvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqvCwVdd4JgcbCLX8+_V;>ex#>eO=ifbBXf^@%icq>;?** z^>lFzk+__k00d7SJ$v}{@pEwj5h1a}BnIZRK*K^#PtD9sP02{hO4hUq65Wd?6~)+y zsAyyuM*4SQeQv>W`F1Ud^n?=$DKhP$@^|ejG}y4Kxrsi{}Z?oq)&FSAR&aL5KS^M`-FY_8E=Cw^t&Q7(KijLRIB8oR3OD*WMF8iYiOWrWE^5>W@Tt$WoV*n pU}9xpaOllv6_^gNhTQy=%(P0}8a8kA1_m<&gQu&X%Q~loCIA})k9`0D diff --git a/src/qt/res/icons/steemit.png b/src/qt/res/icons/steemit.png index d2e92a03352de9833df9c09d1d6b0105c4ccb09e..aac1c93c1094d115225c0244ad8a4d774d2dc4c2 100644 GIT binary patch delta 1101 zcmV-T1hV_l3*iWmBYy-aNklna-KJKkwXk zpEdAt@0^)CbLN~g=X}>VB zUjP_Tn^ZBaK3L;!Zt4aEm^t|XYZEIIyoYg(5}c9G+c=e<-QV5gKyTc{_YF3Cj*p%K zshp146=)+rcz;hmiAj6H95?zN_Da$-{g~R+oPqgQ>?gD#Si*UX&D8M=>mX^A;7?n%=^R`?i?>Ywww#2MjO&s7eDZ7rWiMyk^0orlZ4M|gHIF~g{ z|DIl*jZyh>aFNjs;*|UliV9?MIzB^0o+_6& z!*?8uI9Vpk@U-jV@6owvcBvf(OK^-l;+7jyEka?*R%b0)%b@67YJS}4Y3mm{<`gJ=`!Pagj;J*CPXL@2p`5Za*rufW@}dtLJE?3j1Q}XJYK2u!;d;gt(0IYQ zEzW+On=tJ<_E7~m!_>=@CdXI05eDR{*xOWo^M6shtibO-6J+V`TU1_B*CEG;{Y0sU zJRvC1qf^f{!4iGCf-Z>d+Jm=reC7T^dRnQa7rml$*B>g9=c2_Jd_j7)TSO*fcxN%7 z99@HS;eH4}DJPWHEAfGWiGhgn>eg;5LpRNjyiN@GL^&#uZl=B`X4cAX2-qep8k$ff zD}R7(58Tl$=i&2ZZOXN9-h@!J3ouX3vD8CBwi!T)PFVX>I0I)9@@VBQTS5i=11gr)YDeAVF1Vs%Y0>+LYcYz(iXTgB~%KtLJ z>#NKH)&Z-4jL^QOVs!)_0G|RIf&qU=$_6-Ie-D&~Jd-f#lfQ%f0=yCo_^wsS=XfMpoDPSH}ERGmzk>(I*H^X9slH>D^Jp923B zRb3TQYB}B)0jokDn$O5u!|%iL`Vm+^kEaIpjl-wH4}Yxn`YH>|2&~39YBqySDk6Ni zxQxD8y#Pp0bFt<9nH1!@X=#0ED761Co>jsKZ?WZUZ1xx| zC)}Z+iy_;%FG?+-(5_L46pBrFr>%qizh4Gm`h+2jE6$~}OZn!&xv+#eWy2}dHARc5y9oM zczC^*%#R77z2oO@@M~=YB0|NaLW&AJG&Z;K-J!^p z?t5V*`8jT`+_+2C(Tj)(6Q9XrQpsRq<;T{91vCkfGa8)=yIeN!tU*Jd7z@MlpBEs@HV}GJLqd7r1&}3mxGK9`(qy!^>Kb^cvZT)Rj zmAO-jumtKG?y~3DB~%qvWkLDVq*)fV^|v{6@+zvzjEO_(o0)+rKe`;Lw}2Xr2~zBP zH_G$X0Jv27A^UlVDbZfFXK^g?AEoXY& z5mFU8D6wmoCA|9a9$N1|ioy>XkbgyYxANYmpSjm={7oqyv&cq+1 avG5;5eP8N5l%dW50000_a-sJ-vEo@Hx#_%@Zi==oEbIyf5{NJ=wFI4|TVy%LGbC@hAQ-Wnot6%X>2 l`K}=n{V-x~(-4U`@e3p7C=3DPVvqm;002ovPDHLkV1g~zRxbbm delta 428 zcmdnXwuxhcvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhcXbJ!6u$y9+}HtE>l59eatVuPggw4sm8y!~W2!Bms>?5LOr)3h+vrPs`Owv`Dm)>XG} z`o!hV$flky?zo^~_3Y}@(5>wg44Tt>r<nORHA~TK-SX}0>kl3A{K#pvspu0IPgkes>W(iQIhI*u-S3LxW?qb@917m612C3>ahY&bjlm@@G{6V{L77(;+2i z^wdk*ELw diff --git a/src/qt/res/icons/telegram.png b/src/qt/res/icons/telegram.png index 4b65b515c506e3a4cb54a9646180191bb177aa93..86a2e82bfbb3e9774f07789a5f17433a7339e08e 100644 GIT binary patch delta 342 zcmV-c0jd6h1^xuEG68=#Nkl9)O;325se!F4!0>SpPy)S030w!X*v6x3bBltIIY7Q(^7vrepyV#%G;~t#s~u% zI(}K)Pefv_Y4qXJ_`aVAYo=&a;V=;|MP|xW7Y;Y%d?KtbO{)W!M)dP|CpKn^mV*H; zrGMvQZ7P}Sp~j5*dk`xN&D1sOXUwSCM2Nd(OsjbUbeR)<2=SnqssI=fOI>b(zx6h1}l(hU?B>K#gOt~=HELDM3udqa`j*Pp<0>6qawF_=J9HA%- onlu`f5M@rno)ZL4FFZ!(A0pUwct3WiwEzGB07*qoM6N<$f*B~90{{R3 delta 345 zcmV-f0jB=`1c3#xG68=&NklKZP#3Z z7|;|=d@qs;A(yCwFJIwjqqJqjOLq`l${llkk+ps$QW^u)P>A1@+K2;O0BEN+?3LQZ zJa<4Vr#{B^^}tbg93=mH4_O!@=hg!pHBb^gn((iJxm+NDo0pdZU}iTPTOOqN*XexF rhAhV}QCf5z$TN28hHV>lX9VmQBG`3!0K^Gj00000NkvXXu0mjf%*dQU diff --git a/src/qt/res/icons/trade.png b/src/qt/res/icons/trade.png index 83a5dc401e7280ffdacb2f152ab02bf873fd9e3b..f2b7aaaafc54056a55d7b351eecad56186456a2c 100644 GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2{2-Fxq*#IEGZ*dV9x{@2~?0i^Ko_ zm(TG(QZ-;)c0{&(x=3+R-{%|EX6yNZI*`GXYLDuM6|TCBkHXEEP6XvnH2v)!ZS%gX zJnP|+)p_9;&uE`FZ>U-seyv|6gImD$!nV5Lh8rHK3`U3gm{x2nH*`3Awvl0{;%3fC zjORZ64rX?XwP9f3Vt#V{d@abi3`=xRtluy3z@pm6Yq{Rj`AR%%>*ptA{QS+a_%-tm zM}s~8Oc@(qeqGPOz#tJXe;~YRI>Udq?i1V~t=k!`_Wfc6u^Nnl@=%~4w%|65jX~dL zn3EsP#IV7#;rug(oc~WV%9|FH6~F%dzd`-%v#IqLv%-FAmcLsLHWW#-*&KfM+{2rU SdXv9^L_J;oT-G@yGywpawtTVx literal 786 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2_SGmUKs7M+SzC{oH>NS%G|}ByV>Y zhX3vTXZ8bmoCO|{#S9E8FF}|wK;`)lpdfpRr>`sfV-9gS_#wZ1@2hMq2tAr-gY z&UP$nG2mfgp8CIjrcBX|RUsQvl~+!*t@Rb_zja7rn(eyvdo5owmY*A~tX_60p{0*rxS$|5_` zd2N?7saV9bE;{{P{$Qv>&Ch>}Ex1l--mhNr*4!zN>C?0OPbcV z9}X6YZa-zC*Kga{&ETCia*B^V1zmfv$98dck1Q$n>Y|)5PyA z&d1jkUAHg#Yj{0m>5o9pW5Eleek%8eis}4w-p{{FHehEBcXvG7@5|+Owg+y%4Bb${ z{w0%Zh5i4(T33KRpVii2>es-|bZw#O)XDdG{%${f>W#$ykK11`a86+0+;MaVN0gj? zO3id@qkXx7clI&EL+o+rgZEvl)_yPo1sm8wu#i3b#5wTS#GQ4|6fF>}RhMEwNs(jj3JUKRhhKGcSrcOKZbYxr)mT zb()9v|L9z$n-aa2BvG7za^rR^nmF}wZt`|BqgyV)hf9t z6-Y4{85mmX8d&HW8HX4cTN#*InE<&aRt5&fzI(z@H00)|WTsW(*5D+-@(QSd!PC{x JWt~$(699d7CcOXv diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png index a00b715453597364d047aaa2ca1e7646614ff45e..5e880446bca3e3b83e6646ca1454a41180b5bfa4 100644 GIT binary patch delta 267 zcmV+m0rdXg1EvCyB!BHmL_t(2&tqUf25bxh45ADo3|tJ13>bisLChvE>tfxDvPZ#- z8Dtrl&=m;gUODvt(ErW?$qd+>s+j$F%YXm0yA0yk^^3+_-tfQR z6`KY&k1{Z@nr5y1U-^|y7t@mv!0Wqh#ea{j3_J`t0AI-ACI4OL0Yef8VA1!nnWAaI zz=BHwhkaZ4HS;X&9s~z>$fX(o-8SKN1CQtClJEAD7&vh$U}WH9kVK7a03ClqO7cOY R%>V!Z07*qoLlDyqr z82-2SpV<%Ov6p!Iy0Sm!5NBpJ>!-(JD4IwnR2Ywlp?3wv|1{tN$H;llUMt0SFqk ze;ofHwkp6Q?u+^1y}3O0k{cM@*p9wA9{q3m-Bf|}16(f2dig)%KXmyrpZw|3aMdLH z>Hkyfb9QkYH(sdmV8Vx==L`NFSpR#1!GVwiC(iwDfB4?J#e|vJxT|UZ8h!o!^_Kt7 zCda64;E3?F{wS%~y-4eU$k)OvPrfH49A5h1`}Ownx<54sK8RZ;1T=R}Z=C&5S!t7` z1jD+<08tZDmo2~$Q!R0gC`m~yNwrEYN(E93Mh1qKx&{`yM#doq##RQVRwh8MiIstY hvG1NR6b-rgDVb@NxHUKluz+HW!PC{xWt~$(69D~&yPyC7 diff --git a/src/qt/res/icons/transaction0_dark.png b/src/qt/res/icons/transaction0_dark.png index 65f3bb8d7112d7bbd85295a9fb5f6ad1f0b699ed..09172c80c5e4ed9d4e63d561120d4c3ba45964d8 100644 GIT binary patch delta 109 zcmV-z0FwWp1K|OXB#~fRV@^p#K~xyijm$v~fFKYAK}Hr>5$yl})|;>wV;?J%N$F2I zvSFpZPz`{*7P&-g(6vBA82mk5 z977~7_nvVSYEa;D4s_xUVJZH9dy#aed0+icwaHWdwdi>1er;VgTe~DWM4fda_vN diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png index 3f008499d9bdd1667a4b81bc5d3aeeb549298b47..885e272a3a48fb9e683a42ab19ecc3d18c593efa 100644 GIT binary patch delta 137 zcmV;40CxYV1nB~hB#~goe`-lYK~xyiZOp+ILQoVyQCA_Ukf@$SAv*v6fsJ_gt<@Rs z!STF5$&xP)Y_>tDA=*K#V4uL@XyKGXmaE4Zii=n%E4a!6x4Wq!H7h)58hFYIEkMy( rc)fvMEXXjzM}x#LIWQ+*qrmA0*~$ocKod;d00000NkvXXu0mjfE7m;z delta 328 zcmaFKw1Q=ViX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@5;>mi(ByV>Yh7ML)51=yk5>H=O_QxFJ%&dm}p=*JLFl2kW zIEF}E&OPHP)Z`$*;CM?mKv3XHU`W}T|MmiU2DXCN4Edi{)=%0w)ndcFoN}pe>>or~ z6lMIy&I!gOef3b-+tsSmKKo2T{S0-Nv_^4P#{9?!heLjC4G0sylH@q6Ud)R3k@Ncl z0{?oLmJ8lI#Zjped+im_UeyxUh?11Vl2ohYqEsNoU}RuuscT@NYh)Z^U~FYzYGnfC mnphba82j!CL(!0%pOTqYiCcq{01L05AWu1MC5iB!9C>L_t(2kz-&$25bxh45ADo3|tJ14A_7TLl#3FLm5LbR#}Ez z1_loMw(x7_SqyBoAOUn!${A7_e7CLm@3D0`!vO|QpmHpxgdAS--*sLF!ybkh1_oX% z3Lqx5Gi+zD0y!C%30oM_usaiGLIGCING9NvX5fXGz`%n`0ZAXk1Yk(w04(}GHd8b$ z7+7#AfQKY51%e@$X8d>Cgxd`~o|{X)+fQQP#HE0dfsa8FHL?Lxgf-zc&}fqY0000< KMNUMnLSTa0G)|oW literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCik>lDyqr z82-2SpV<%Ov6p!Iy0Sm!5NBpJ>EaloaXvZ4fh~t8hGz}Wf60A@HR(V2 z1(RH+ZBM+AERgu)V8Qf6U1qTfrw<%Ryf0RF)~360t=PJmoC_Pe6~D62cU-V+!S_$` z=XmDv@Vv?3vXV?Q-thTf;*Z~-6b{R?C9<)FnXvKzfxZ1^1B33<#(&aw96#_uxSOei za~IER$v#7aKZi08$+fW-2(D4{Y0fyds6jmGkiHz743~tWn!z7u4#UM7KTiMp^y&BX z&-ZQIG#pJET@QHO>O9X8DH6)Kd`16awf*eO(t51>_uK9H{P;O@+kTI8PNgc$`po8s z-Ca_Q4Hy`fJaW!GbbU!V(95bNt`Q|Ei6yC4$wjF^iowXh&{EgHLf6PR#K73fz|_hF n$ThJtFfjJr6NaK8H$NpatrE8eCjk~vEHHSw`njxgN@xNAK5v#> diff --git a/src/qt/res/icons/twitter.png b/src/qt/res/icons/twitter.png index 51f20d9c73151cb1c49043d007e4c2564924b521..433bdfb708eb8128f1b2968b2e42a89fbabd1d21 100644 GIT binary patch delta 626 zcmV-&0*(EI2#N)eBYy%>Nkl`ikPZlb@h!t<*%}aaeq5c8= z4@&Xi$(wj6wAW&cu~ccXYDr5$Q1FB3p%k&D9#lwM6cyBNHoI#+joD;6vyw*5Zr)^# zx&s5tzW3%gZ@!-pT@W5 z;79~iU@`5bGj!H9J)gOSLI%XJl3)X0WI9VSNLIzS4k+JT1D7z$Vq3$v_W*smS3U3o zqs-Tbt&E#r1^5{y94$e9s;b$`xWhIkC|Ir>ybzp-Rhnv-h;}#Gan2Q#v)2V)w1Tf# z;TT1xZanI|{(nY=-XAIW9m~OPG6%0V(@^_93J(|J(EM3>2>q|zw?Cn3L3c*BHd zyZ#aZ?PzvC3oTy^XW4{p)o+OcZPSJ&P)X&G<+?q+O(P0W&RS?ZM( zB1S2`_iIUqzO@ug?PMUCwU2={-GugO11g#u{|~Q>W^^A54%PVigDf1NkByT&{6tXy zpJV8nJF;TLT{H4TJHGLO#1kXgjSr=s7|T8JF!99G%oC5(YkHpl137TrrFJ$mSpWb4 M07*qoM6N<$g3yL4z5oCK delta 1007 zcmV~6l_#bQi&F%H-aDtYJbDt_;(Ws!BWJVSSV@n zx(Hg3La-s=#kx`?HWi6!B8AX3v}AXUEq1b#X0tozcrn@7W_EYRkkmex^PM^GJKuNa zobw6%GI%z`gU@#(L@$U=BngyG03gLYih0m8Xgxw9lV=1rv7 z?#rywCW5c16n{UZuRXsp1F6w4UCDmXA0TAZm+*SDvOo-RdEz)HdrJNd3}@p6qvt^G z-;l5iHBQ+&Tq_%H1E;P%juANzqHS};tLW>L>>g6_srm+nvvGp4iOmd6gp6Xu1^@(uXG6rh7rZu^ZBfCZrE3Qze7LWf_x6Md2jJ_u6$XD<;=n^8 zu9_8Q|FYfhC~cBYw+c=dUM3J2Yb3sVSAfx%w)5=yTijSwuK4E%qI~jb#PxhESK*_J z7Sn%LYJX2`+pkDxZ*NRADA==2^84#89O?+)9Sp+9d&4!~d#purv*b3sh7i35h)yp9 zlM5BBil#Lp`R;`n7oTY227tV&=>5LPx7TW4_iU{> zoPR0uQ=Pb5Uym3RGHK%7W}~gRV`qRP9bul_5#ZHCkY>YOhRMHe-o8-e*PO@7ucEX` zA(M7y`f}kELcHH-{3E*pyt6mLz8wZ#Es`cfkhK&)->C4-)e`BsGWc7c4qBh)-PWV` z$#LA*o(C~>Ps9NbL)B~9zZ=oziQ}Ngw`g8mjXPSaR_==Zua{DAN>N!p1p4}xh?nf1 z^}T`nEI9h`ZB(Y#b0e=CmNklbp0&zoeI>FQiiAjPuum!ST8iX^cu7z-vxsB!JhPvZw&O-gK4< zz;ETK1b`V^0(gztIVu3JKEFT(;FTAbr~v$GjtampF53biP+VE1d4C{KTeD~$2$a_I zG!FzT1sVrJg$)`9Lg!5y2SVp9TL}Q$7KH$?lc9MaaN6CYc_8q-e?ap<;Q6q~AwYy1 z$Y=nmqyG6!elPOpA6tx*hyZYsrvmWipJu55{2$X9g#d7VK`n4;D*@mt{(MGSz%_+H zZ~hInK#@uSxTO*R?tkW#KyLwAYJmc^z`d;n9xQ4Bd5|8QuV%Dfq^o0+{PHVGeI(7J z7lk&;lK3fflqt8(P4H7N|O6paw0_g%)T-3rD!n0s|Io6sXpq1-j4z zC1`;%v_Qqt0>c(;4Cq1&G@u2V&;qWb1%6tv5uk%4z&QUgpKL3*-F7EkWB>pF07*qo IM6N<$g3_1DN&o-= delta 735 zcmZ3(wv%ImiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@6qB~l5A!mU{WHAE+w=f7ZGR&GI0Tg5} z@$_|Nf6O7y%xc&lx)x|Q;|ot0$B>MBZ?Bj8A2twR{a~|Tiqp;N_j}E^__8m(@c4JV zf>KLRxJb>`zby`X_fOjVr7q}P;S`Nmq3i!eEi7KT`fu%qsoWFv_)_XM9ClgE5M`UN zj`wK`YorUFeq_sN$lk6T#eadjcJAxs!0l;wUH5%G-LFygd9AcjLG^Lgck(&LA6V+; z);fPXt$(9@Vt8HPM&H^`-iG2D;U@aC*aJfMo_zPy^lsq8Iscc~bjN&tZ7BXj#(;mt zs{ZWlf71VcKcKmP;r|CmCT^{h+VIZ(PEb7ipG$Z9E3O~NF8_ZrmihbxCf0L-X;MiEi8nb{?FMvT@qrQoIN|N4(yA92Zz6Fg^I}Ql%aIk&G zWY25C@qtTzLHPfT_ZV}uciiPDShpOQ6jV!GBT7;dOH!?pi&B9UgOP!urLKX6u90zw xfw7f=sg((kYhq44$rjF6*2Ung9jIBMSfk diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png index 77712772ae0435da648a470ceb357953fc17ca00..d300ef8ac07c5f4af2083fc0492817230c4776c3 100644 GIT binary patch delta 384 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 diff --git a/src/qt/res/icons/tx_output.png b/src/qt/res/icons/tx_output.png index bc0b2d9d8823a2c43efcb91da28d431733596dc5..a77e2fac59147d459290e65c64acfa622cd57a66 100644 GIT binary patch delta 207 zcmdnSa*Sz$%EW}Y`t_bJjv*QM-d^?OIuyXba`D$p^~K-q*J?Wo_~? z0$zj1Oy)5O`@a;_$^S^1&wRhIkxhKZLndpz4G)=WCpI#QyGj%`%8K78U`&2czCga9 zQBZtFL8F*B(CiH6{SAWR5e1E+;y1duS1>c1ESYlYsx9ODO0QLy#CE4K0D-5gpUXO@ GgeCySk5Uc* delta 446 zcmX@cw2ftgiX}_Bqpu?a!^VE@KZ&di3=9g%9znhg3{`3j3=J&|48MRv4KElNN(~qo zUL`OvSj}Ky5HFasE6`@5Vq!gGlDE5y;G?a!yMW5rOFVsD*&lO=GqW1@hpq)0!tl`3 z#W5t~-rH%8d`%7lEYn>@M34U8e{Dv>p)}!TbLV;5l-MqK9ndm2s71huLlI2;o3`+h z4EL+U$Q^G1$tMt#5JNMC9x#cD!C{XNHG{0 z7+UHYSm+uVhZq=J8JJp`0J$bs1_s8yd%{pO)78&qol`;+ E0N??iC;$Ke diff --git a/src/qt/res/icons/unit_dapscoin.png b/src/qt/res/icons/unit_dapscoin.png index 230c2702ce2ed491b673cfd4a1ad9d444a15e3dd..81de6509119eeedf520bf7d0ff680e65f18ff750 100644 GIT binary patch delta 294 zcmV+>0one{1i%82BYy!0Nkl}^L(cYj=m%wxd|(Z1joL}5Wx zufAZUC$4xslY6U(*A17wmh3vj>Sy>9XI|xu*d9@c6@Y}%Mm%3|v*TLW+HGD@nCD7R zv?Jyxt{W>M?dl(h?#|@f?Nm41=0#t|;N^2q+%}>}R7AO7W6{WD2k>zTp13?N@o7_C s=h^2WxP)y5BOfydB?Q;e=1>0u-Y5Kl;wA~9z5oCK07*qoM6N<$f;S_FqyPW_ delta 564 zcmX@WbcSVuayCx45bDP z46hOx7_4S6Fo@?*ia+WGRLhj)?e4Lv%<)^y(bosVAjdvl( zpXUE>n4NNArqbriALK4vS`=cz1WMcl*}2Dd$O+h?FyrmfOj+#h=cv5RvZ=^hdX`VIIcl8!67={vg#5Dw=VMG94*xXmt zqYcOyieS`dTm>Lv8~_{`Ms}QlgEoXVGd2uPFa2|6;6PoXqJJo5!6nCa(GejGTt}WX z>VoULfN^km9RsHrf#k&qTNiuMfI=g9>33Yh*x51m#fl-ipVU#^IWG#f;0kqmXWq$S zMZR=y2ebG00000NkvXXu0mjf D`9zAY literal 583 zcmeAS@N?(olHy`uVBq!ia0vp^>Od^O!2%@hudZ7Sq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3R2di=ni&{={s+=885l|p7#Ln9FfdrnU|pA>)84XBnW$=lt9;eUJonf*W> zXMsm#F#`j)FbFd;%$g$s6l5>)^mS!_%puOqYS>Zfz!k}{EP*SIgRe!WMWTsWvC*I{!LdN$hQOBgEwMANr1@Fqyk4O9^7ZfU@Ac|M z-uIl}zUiZX>0Y7Lch99Ir(C}L)-|wa)%B9iart2(3&OV57#(}tvpDIB_Ok0G!Yf47 z3xY(BFL=$lXz#r}ir?n{;Ck8b|88Px>59`uE25J-Z8Hl?x2;(#QD71wcW0Ndn#$CJ z0#~xPL_GPh>uRLPzB4;!ES<1VY-!tb zFaKrr*gJKu$jx`tfdQ*p;u=wsl30>zm0Xkxq!^403@vpHEOd>GLkx_q3{0&|fLs$R k0|R5FVdQ&MBb@02oQ$k^lez diff --git a/src/qt/res/icons/unit_tdapscoin.png b/src/qt/res/icons/unit_tdapscoin.png index 030f61ed68d82db1a560956c1f9b13f298b45462..33eeb04737d76548816524bcf3f9826175608667 100644 GIT binary patch delta 289 zcmV++0p9+!1iJ!|BYyz`NklxOcUA4@E=}F8r^p!$7AbA2j;pfcnh-*E z4@^=!;U*z0(uhq8p-Dqx=-I0I2s>BQtUdIV_~{SBZ)OdCc)S*;i}JDUIIt{DC{~YE$wkIuwuISo9?x`V#DK nM&+W}Ug0x_{~G_#{ucKK%ej}`cvKI-00000NkvXXu0mjfODvI2 literal 564 zcmeAS@N?(olHy`uVBq!ia0vp^>Od^O!2%@hudZ7Sq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3R2di=ni&{={s+=885l|p7#Ln9FfdrnU|pA>)84XBnW$=lt9;eUJonf*W> zXMsm#F#`j)FbFd;%$g$s6l5>)^mS!_%puOqYSVS7#`XrM2~G_H#}vQFNia@3ZGLy#&Jy46fBru&7ten< z_2cWM8SC4cqpl^0Jl&nS{gtPL*S$R1M3!Dpj?L3<%nI9~<2gw~-GJjKgSp2fPm5%+ zNh;jF3p8`q7Va(!nR55k)wvb6{4{ahkTpn!4 zPkt+}tIqG;z3Wx?HqWPB=Z>H1_?%cNw=vWngM$0_2)l85kJ*?g>NDkei>9nO2EggOdQu QE1(7jPgg&ebxsLQ0Kl!)5C8xG diff --git a/src/qt/res/icons/unit_tmdapscoin.png b/src/qt/res/icons/unit_tmdapscoin.png index c82281df1fc7a9a2a7ee4f1c23f0d0dd5a3bd51f..e8ebbe0fa659b29643b5d66273425d428bbdd918 100644 GIT binary patch delta 296 zcmV+@0oVS%1i}K4BYy!2NklM(?^2?d7=>O`6$Y?E7&gw3JNyXTWT41W)Y(1fQhUbtOYFcd?1 z;j)l4p;~3z>#&D*e#7?0ZNe%EyQaTo*O81X<99A2Y+rKuCYC$9IvI?E(>&B zRfT*Hd#>xLx_WWrTW uL7w>}BxN=y#Ub*N+L`XG`vw2(Pwqcr4W_+V+`2*l0000Od^O!2%@hudZ7Sq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3R2di=ni&{={s+=885l|p7#Ln9FfdrnU|pA>)84XBnW$=lt9;eUJonf*W> zXMsm#F#`j)FbFd;%$g$s6l5>)^mS!_%puOqYSN{F*sXr)|gN6HaYaQ@AcO-#h*e)*Dn@u z&My*8YyQyc$^VNSkSgt>fI&efxHA z358lppVzNheClST(Wb*IcKhcFUwjzyMCSBQv&(|37k_0ezj)`nc3s_hSSf~Xo)B+Z;PzzYV zLiRx5J!ap`UiPr%5}Nd%qy!W5{xO;OM8u3%&E1?eCEYDQarJ>4h1n=dlwe;ydtN=@quH#Ysbiunh8}? vEg8M+)Z5aiDI!|-dabj1@c;kWzr}q6#1NfNwrXIX00000NkvXXu0mjf!tj;& literal 576 zcmeAS@N?(olHy`uVBq!ia0vp^>Od^O!2%@hudZ7Sq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3R2di=ni&{={s+=885l|p7#Ln9FfdrnU|pA>)84XBnW$=lt9;eUJonf*W> zXMsm#F#`j)FbFd;%$g$s6l5>)^mS!_%puOqYSL-DnF(2bZ`}Rj<>Lrp;{X z%+}?T5B`;oUA{(UZQkL#Dw`K(}F3>$@VvYRm0xtzP@S9i8WE!?pIUxcp$o1xv} z^SYb1dEc2c^>6K(-jj0bp=Qc6L^4>-N_QRKY1QgEn>XrluIl#5 diff --git a/src/qt/res/icons/unit_udapscoin.png b/src/qt/res/icons/unit_udapscoin.png index 77a9f372ac2bbdef023045ed8f55b3497e48d0a3..0b3c93df2d660f1b92a2ff5439175e61e1756832 100644 GIT binary patch delta 300 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 F{|D!i7F+-T diff --git a/src/qt/res/movies/spinner-000.png b/src/qt/res/movies/spinner-000.png index ebb0116f06219724be777f99583f63c9213f2062..1749c85928bdfdaeadcc53da8681db15800b78e9 100644 GIT binary patch delta 256 zcmV+b0ssD<3Bm`EBe7qr0)O90L_t&-83n;DOcVeB2GH-h9SG@k1Fw<@aBP-Sq5%sk zM_?2kG&U#{55gUV!*H2Iabr+ScT6b+DnE(sFtd@IZeWrfWAdIP>F@ndlBah`BpLWO z2>upt6Unoi=hpGX?_s3>{zXlT&$O-+r9N;q0xIr^u*g@HvvpTaGI{#?(;iTK z2}f_KYR|S0WxCp_b{x!fs^0y;985X-HoyOo-HL@bj)9#lY0p}wa?bWcVFgI~R?FRT zmob-H^`^%6_l&|%8=H+tO1}ylV69b4Bq@E^NkK35W|Bu3LOC&&gF|ls00000dmX$ delta 477 zcmX@aK96&PvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqvBeodd4Jgcb7Hcsh_%m>ex#>eO=ifbBHsu8uo{-1)9R} z*VDx@MB;LC0s~W-o50Bf2N_uB@WkA)*;Dg}he=?cLi2=za{v7K9U9FucCZB4PEPsH zqM13fbF$j$rYEXTo`{M}oiZ~tJ$)Be7p}0)Ng)L_t&-83n<=E5rc+2hh)Bp)M1Xg;*$MLIxQqKXZ&y z46H}uUof5FSS^%nbP^d1CNW7?VzJq7VDa^yBvB+un*NeVqDV9RCW%DRVjEQy4N)C6rCR)J~#_y4{EIXZ(tc*TzoUGyQ!#V~%!@%od5lwkk>002ovPDHLkV1nG1Y1se( delta 460 zcmeyxc8z0#vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhc9TJ!6u$yUY9+TPM#2s$(zl^mS!_%puOqYSW@TxWlA7Hj z>C&LIDCv>Vq#&M4Mw^Pxe&XTcvEk|Rawt8;qqRym>y^|jo~T<^yQ+A6ezCRHyB%Ab ztG0}XC+)55+-E#u)52n}-8Hk_##6TU8(&|opUpYFb$|1O??_76sQJx$V|n!S?e>F5 zub;P9n4qX(p;D3+QQ?xJ!t5Mk(#(IMX-4M8!jBGCiiVnzjg5+`rnRc{69` zPM%7K&YHHSLy?=GpP3sTawdT38~25+OY2jgicSqpsNCS8(86|_nL**2@$Aih#K10tc6!6YSRIm1OL zMJzIzTrpuegT*F;gp@>zltGDPQ0$gtao&?8{3S`lUpK z8lx1e#p+GQVf;oWz}4jC)ChMZGdP>$WS*l~WblE5B+K?!_F19V6L34WD@%uKI^f05 sdL@!VEgP_%^-3a1p}dtOo4=JL|B#tGL!*E;EdT%j07*qoM6N<$g0$Cg`v3p{ delta 463 zcmZo*zr!&>*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL&P#o-xVW-DTeVO^dmK>ex#>eO=ifbBHsu8uo{-1)9R} z-qXb~MB;LC0t1tqn!w2eXHGCMI?QUF+B=u|3=@+do8G%)%btnJ#o2A(P~YFMV8Vuu z6%pC9ceJPkOciO~(xVgL{!d1JLZR=w^#ol$Lc_o{HJcCcXk-h1i z@CcyiRZCnWN>UO_QmvAUQh^kMk%6J5u7QQFk#UHDv6X?Tl?jk*Vr5`p?7JrnMMG|W bN@iLmZVgTXEU$nXI2k-${an^LB{Ts5+_gPzH-hiAgcA_?@Jb zfue3x?kIl)y7B4;gF)8wv&cYM49dd7W-yr;E$6%^Nurq~EgFd=Nm}7Ig+?Upu+0HK z9p4In&2)kd6}}{0d?x9pSpDeH%bFVA`r*~UvQu~-WYIapz(Ypo>s;n8?qq!S(#+Lu zCZ?~!lu0+#GY@0;vH)jG81aaelhvUoYDw0qMiB#Ez;QM!QaUWthj;8ovbU3cC?`oI h*=s8$$*?YcB5^r6fq~J@;N+1r4D32E+4YJGU;+u8xt-ae+d>&IubjR?MjI zU*EDs#G`jhkB-N}IeVPuD>Vx>Z|chW&th82>&vE_D;sOe#`d>!G7nF0k8iz%&)GBT z{u?)>Y}mAI8{zodHC7b&d-dyXSc78=O5$dGAm%F~13C*rH%2SiUcE1JLWL zC9V-ADTyViR>?)FK#IZ0z|d0Hz(Uu^IK;r%%D~jh1jse9GB7aq-4lkQAvZrIGp!Q0 V1}6cQS3nI6p6srEF6*2UngBDcosa+k diff --git a/src/qt/res/movies/spinner-004.png b/src/qt/res/movies/spinner-004.png index 4f33efef375f59d3bdf21d7ad040a64942ec5c02..ec616718b2f582d3a7cf23befb7e4eca134ce348 100644 GIT binary patch delta 233 zcmV@yjq*7z7VvF;qaWeTsRfyWZ6n)gz!UR5>kGG2$})~$-AYusdU zUVEY4lI3}AT&@7Jii@m)Sx+_^wV7v5ldWkl*ukVXpnDoAcJ>+L-CRKB&^00000NkvXXu0mjf)p~4n delta 462 zcmZo-f5tIE*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL%-oo-xVW-K8TtO)Ltij=jXw*OmP-hd48Ffh6qoIG-dfl+4-4^Pe;nK?W>34(eG&z@!GWj=lSI9-5YwSb6_n4qX| ze)jYUQzoTNm^gLv`v3+mZ7t36RR$}JR+N^m&d$ind~IOx;?+xO0|N;u$=UTYX3aE? zh=_{({^b_K)LY+fe)Zpwo={LwQZ(^D0L zn;}bkOIxeEi;;ng>+vH-21kyntEj1-pE2{$gi{mDv~87zSD0jfoAYK)OxvD6O^0@V z?&|XPI(?)FK#IZ0z|d0Hz(Uu^IK;r%%D~jh1jse9GB7aq-4lkQAvZrI ZGp!Q01}6cQS3nI69G6DRD zWM(t?lflGH24PeuA?jjLoRmQ^DT5DSGf;QllO&>&q^43$q?X^L9zRiyBx%5k9lljH z0$8%gmu3st|4dpf9(=S(JHTrfUZmU1DNlXn^cNH#WT0?XP`qzyVPWdroeY||q*NIh zyEb}rCF3J*E>ib5$#6+griX5w&UottCuWc5`pXWJ`CdG-fF92PN3y)TLWg&3Cy^}g mW))jW)@({*eIrSvn&cnr@i?tu@9I4O000045bDP z46hOx7_4S6Fo+k-*%fHBQL&z>o-xVW-K8TtO)Ltij=jXw*OmP-hd48Ffh5fsRqV3tsli$Y6uf zkDu&5+&oNNEdKnQsT|zbJ3D&1`Z`k+I+8o)Pn^Ip#bcIb_P04tMB1)w`O>rVv(e^F z#YLY#adWjwNOVbbd3!zA*U(qxj6)2Jtqe@9On_VyD+2>#-#uX{8glbf aGSez?Yj6@^dBwmD)Z*#t=d#Wzp$Pz^A)j9W diff --git a/src/qt/res/movies/spinner-006.png b/src/qt/res/movies/spinner-006.png index 66d99a8b97f2dde0352230e56cf93b3b0925fb7d..941fd7891b8174cb54dbfbd611eba8a9e5b50060 100644 GIT binary patch delta 228 zcmVGXa!Hx4#70-jaLITnlaU{wKDT%t2^b_pgP}5!BuR$(O^Px`0PvHd zl+h+yXgcNF*w;At%!J*Gk0}+lFTwi^dQz>o>#n^fb2e{YWF9;%16hxZO+5**{2bKQL?3?p6z}cRnK}8>v=pRc_9s%G`Qj|%HW|Ab56n|@- eWV&{6Vn6>auQJjZW%2?5000045bDP z46hOx7_4S6Fo+k-*%fHBQE@I)J!6u$yUVie8>FWK)v=d&`ns||<`8FQHS7;v3p9n{ zgQtsQh{WaOgoK2Yq_o6TAf23&?!dt3r>DRv^zhlkr;o)2M1;fyMVmW1zJL4bKVia@ zN%Jf`-NO3jI?i)+4D^h2o!aQ=Tf2#^S*>~6wsRt}wzbU8%52HP!Nv>3>OZd(ySywq ziZSw0zl(~DG7f&{B?p{56cl&bjfCJUb`q$5|XK+pkDDcRT2vDdAb5WVl)iuvn zJuOdXf~ffX2`45@nKNnDG&_Ce;6BH0#q7E=K4#~_#@0F~2N!#1M_V&rsdty18|z`0n$E*8sqL=MU0WU=hM2kLoGq_)UIKlu zTH+c}l9E`GYL#4+3Zxi}3=A!G4J>qxj6)2Jtqe@9On_VyD+2>#-#uX{8glbfGSez? XYj6@^dBwoM#lYa{>gTe~DWM4fun(Go diff --git a/src/qt/res/movies/spinner-007.png b/src/qt/res/movies/spinner-007.png index 01335d3f1fdb21d23831fec4fdf9f2982c11c913..94bca7d10ded4766ccc8114310c02771c57abb8d 100644 GIT binary patch delta 269 zcmV+o0rLKw3CahMBe7qn0)OjCL_t&-83n;RC47%9N28&0Rl)?8200w^R0{#F(llo2b z7qonW!H?E;H&pfAwl_nnE@gDVtkw+HI#hk3%h~;E*!DKlIj8fFk$*~$dMEvphfWkM zNALSg9bH==bL?0zhf2g9Jvo;V^_1{)LK9~eB{_Vd7L&$H4qg>(99It_m8sZ`(Xu*| zOAp+-$DFFW3x-nK?URP9s(GQ|Z%tJ@eO=uWLa7XFuLL&LWdzuH=v~Y@55PbEEI!bM T!Hehs00003Gng zaYE(7#D{`wCI)_9oGf<4$Y8^?)FK#IZ0z|d0Hz(Uu^IK;r%%D~jh r1jse9GB7aq-4lkQAvZrIGp!OsgCtyslK{&rpbiF4S3j3^P6{RQkxZ`ZM#;@;O!r#hVOD)eJ#5be&{R=gf*yRbRddPU2h zjc+o(HUS_0VzK;H(sT438u-VoB=a*#7GP>_R+6kJEtitj$t3S_8a}j6`Jg)h0000< KMNUMnLSTYclz;dD delta 471 zcmdnQ-oiOS*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQE?_yJ!6u$yUS9&onHDtb?haczOL+#ImDS+4f{ja0!?A~ z?&;zfB5^r6fq^N^jg8H$jL(nF;6ciRN6#KUWj6eIkcp|u>5%PSrA0}Pgm{`17(LlE zGbL}@Syr;Ts;Z?)8^i_bN`mGFOcl>JEylUkLMi^&l$OSaSn|6^6~a;3*!Da99Zx`V1dJno(%{-*!F@?-F)Hm){tgiFRyVq3H#>Cd<)VAo+ zq)VGxpNdWm<;hW4zRNh|`ju-}^`rJIsb9E}^Udrufs2=JUAuRXK``OPn=F>fz0yb6 z7&sr9y-j$*TnY>X)e_f;l9a@fRIB8oR3OD*WMF8iYha;kWE^5(Y-M0-Wdh`ySQ!`? j`|b%t(U6;;l9^VCQ-h#^lK{&rpbiF4S3j3^P6f3B(7GBe7qc0)OyHL_t&-83n-uLjwT-fYI;jF5R-bmTeo$wd|H{Uan=^ zuH}Ab?*RxFmR4YGBLe^$TRZ!62S>mO0Gx4gb-Qr)@bp3fWW~%|>*MQp=^qdnWF8D5 zgkFVRhet$45q%Sbf)E=Qf18kamqc<(YFfGo8TSvFS=l+{>hkg*3x9yZqT&*rczD7t zFN?l?Y?$N;qCm%e0@b)pc$cNAT2_KU}|0XaE2J delta 463 zcmbQpev@N@vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhc9TJ!6u$yG#4;o7|^?>ex#>eO=ifbBHsu8uo{-1)9R} z-qXb~MB=h(|K&24KoM5$H+)v#j%-`onOmLYlVdG>`_J_|(r>26?v^_j#qM(EjIPew z4bSwuxXgZUE4z`sUs^_H?i~J@7)Pn2XYW4#aH8Z*<)f!>m3#T_2k$rj-|+cB{elM* z0uCwIC>d#4JySC4`_Xb_Ns7l#A75o#<;gmm))yU_cxO+|7gi>&t&1KBU0j;_bd_I; zt7_==t4vvWS+7H0NlRsB--O9Iq@n)BC>GwPKU!3MItWPM&_)(bhCG$;X%uEL5 z$-$TPjo0VDm)~6c*=Y65%G9szOC#%(YaeG9b2oqbzv0-ob9&W9^~_~^jhi+! z>^%(hylRPSL`h0wNvc(HQ7VvPFfuT-)HSfsH8Kt{Ft#! bPsvQH#I3`4NL8h8@mks3P=6<0A@^uA;Ma4kL zeQ8;F1yD)VLp4xSTSq+&jZHMSJhpFw(u7 zGB!RjIrZ`RH9a${0y4+^_rlNO((($c0H|y08^4=d3Z{d~_RcPQ`vUv{bcr=B2Weg4 P00000NkvXXu0mjfCK!8V delta 471 zcmZ3+{+VNfvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhbeBJ!6u$yUU^tcklNA)v=d&`ns||<`8FQHS7;v3p9n{ zyQhm|h{WaO1RzLBN=rygO-@K}U~pq&jDPlpTI$#os@$810eRv-}4`X1slU8$;WH z1qp2vF04%C;d#g-II)K(@Z#m9q{qvSt25l4IAhA3Nmk0bw#m=d+??r9xgh$>rcK2~ zpP!wXJ3T%igR>}G(D~z^Nvum#pNjHKO{l*g5f*w~XU*En$qk`Q^o(pwCd#|-lZ5Z&2Vd2ni9{tem|Nnb5>csT zhUMAi_n&W}s@60s@ER3$FZEMaF=-9Y(x|Y(m`%9a>6`ZE$7UW_ uYA8!mSf6Wp!eScAk)*d5^U1@`H-^`!@0000pJ!6u$yGvga>*jo*I`$GzUsv|W9OBHZhW(*yfu=Bg z^>lFzk+__k00b#aLT7Z=@Z|6$95`{{z`27bubw%3_%z4E&mXzBY}v-SjoXl;`A3e@ zBH6jINsojk1tna)#A9^Vc2m(OuD!KgUZ=Di1VgvhmGYkD6yCa}wB)PA7s+}F9yLiR zLy6flW*HjHh>l?5-MDF6;s(~4dFk&BZVGx>`xcfJvU2V)+)-U&WKdE0`-hRikDu%; zMl7uDEk*_{hAr+cZm#}w#e}8JYu#)-GM$nxoryfDxiWL}^CjsiOstzEHWe3r{`CCZ z?D&9)B}^h3+w>y?b`@NFwCNKUo9Kr6_ePRh(?de9Uomp{$@8uBD{rsEF3uzD3|H2e z#WhTC0tOg^YKdz^NlIc#s#S7PDv)9@GBC8%HL%b%G7d2?wlXlaG68Z;tPBi{efNZ+ eXvob^$xN%nt-*<3faMiX2ZN`ppUXO@geCw5{HI(1 diff --git a/src/qt/res/movies/spinner-013.png b/src/qt/res/movies/spinner-013.png index 3226febc99b377a0e042da23637852988233a978..810712dde0fab66446b77db4d1670f1c7ec17eb8 100644 GIT binary patch delta 259 zcmV+e0sQ{+2%iU#Be7qF0)OI3L_t&-83n;HNE84710zrq6=#ZS0 za1bOMa!}+PT&^J(L6D|OZgIH~9CC^pjwIbcOkEp^Ye+zATsA2=S(s$XvY!fWi{|sEn6N_7#rFaFlI4{c3{I*}i z(0B%U{`%X=i@UQVDbMU4$rz1Rl5z0U#KENfSK#~f%fmgz$Gs>!{+e0r$eS;7qo=^g z+2@KZ{g{HMIEU!GH3+}?P_0QS^_5Z+-lupSiL6>rlC_&!@*nLgJU)Iwo$&ww002ov JPDHLkV1oDqeE0wW delta 472 zcmbQw{+VNfvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhdQ#J!6u$yUXI^x86$u)v=d&`ns||<`8FQHS7;v3p9n{ zho_5Uh{R>t{?u^hKpvO(kK*o#X}$~F<55^%-u@`y&fU9r>otFy$rq`qPoBxskkY16 z%&ilu&^UE#@7lY4wtPutM?4?z*}c8K;Kd^?jY+e2AHVqV ztmYyL+m6DU1D>Ij*r@T^ptv6d{?yKq5`2kgN zb&apWB0^$gan1g21kecA9hwg@oU+$Y1fV~H_Lec;!V(syI*X+fBVYM!^gY7 zC!r;~pAqK`)2BuafK(2|E nfq}8_o-h;*x%nxXX_dG%2pJeS39!5Z>R|A6^>bP0l+XkKP|Unq diff --git a/src/qt/res/movies/spinner-014.png b/src/qt/res/movies/spinner-014.png index 75c838811286d14a0f59a59947c3e13f5f76b9c3..0adba834055bc8fe3747f22ae0dd1e628c94d353 100644 GIT binary patch delta 226 zcmV<803HAE2!#ibBe7qM0)N3tL_t&-83n;TD8vB(2hiWkc$>*b*%(AlnJhlaf{|n} z5}Uia*f<-m$V66y$cRN@GF>sqVpC!kll;9W34ckFB#A_k7Qj#GTa-{mqt^KSBCS-> zsM+PCUB`Q8#U8+Gw;q;`U(&k>htGY|51(y-2N?$UNs>{wGR{qsOjls~^4jFp6u`yI z*xfm^XLBRCJ8(=HIJ4lRw#QMM3Vzq-LI6N4DiU#HW60fUz_;M1&07*qoM6N<$g2F^-F8}}l delta 462 zcmZo=|G+Up*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL&Gyo-xVW-DRoXPA`3+I`$GzUsv|W9OBHZhW(*yfu=CL z^K@|xk+__k00b#X4valKJZE&)y!H!>FzCJm)xZ7d1g1$$XN5qn~dlv_9 zSsm>Y)8shGvCDDS@^H5>zc|N0&&XECsgAy}i~T1zI=~HdWn*+UwC7J?3@x(!gFHo#=?)Bot`H(S7vU$Bx%&ZG&Az%=I2k&%r&of%!{+T zu#}ajmAku3TsJN#D2mNwV&lR&3+opdEnBr~*|xsMg>qMK^D5Xe^c^$PTM~VV4d{2( z64!{5l*E!$tK_0oAjM#0U}&jpV4-Vd9AaQ>WngM$0_2)l85kJ*?g>NDkei>9nO2Eg VgOdQuE1(7j4o_D+QI2>`(u5P&IF|Cs(oLe++P zqW&ne-*d6&#?4sIzA!VIkDIEheqwgGP)j}_w`)>M26+p;qMapGD{bDqm4p>vVYMBp z`XpgV^#Onl@6C)hU4K;Hm+!XLo^LI;wxf3Bi`VR^SC(5>Dged|9V*q9*Df|OY`Z|9*HLmXf0000ex#>eO=ifbBHsu8uo{-1)9R} z+|$J|MB;LC0t1s9n?XWS19O^Km{}Pg8=Id%d-v@2>FXD5S~V-)A%J5^#06XLesPY0o{_8?3r;P#wuWzsX;hTy?JW{pBugYpzDm@8;pOS= z@x5j3BYCEw=$V+qp-Bf%-8y#doLowG^Ww>yxsOzZn@?EyPHyhJxO;Y!_VLuk{^Q|c zlbMp>qxj6)2Jtqe@9On_VyD+2>#-#uX{8glbfGSez?Yj6@^ Sc?HzK;OXk;vd$@iu?Ya=jij#t diff --git a/src/qt/res/movies/spinner-016.png b/src/qt/res/movies/spinner-016.png index 584126c877c030a9b8b02913acbed061acc598d2..d2fdb2deb522600950280fcc53f2c2656b518ff9 100644 GIT binary patch delta 243 zcmV13cGV;OboygPRn@lVZy_b!y68hqy)qIa@uokox@fN6A}ra1#?!Lu zRnW1O;xX9LodsLxS-Fvsb(*fq@&jJdhV>b9v6u5Y~p<` tWLfdG2fM27ll%iD>;XU{0Y-guEGj0&4G#bS002ovPDHLkV1i#XZ!Z7< delta 465 zcmeBRf66gI*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL%xko-xVW-DRQXl|D0|I`$GzUsv|W9OBHZhW(*yfu=Bg z^mK6yk+__kz`*3jW{{AS&}I-J5pnZ|rNvH(9f~z_Y;pU3wH;HdV`OtwREVG9xMZhm z$eOKd_d3ToO=@)Pa*T2d^NVu~^o(4(*?VfEW3S`hXyz3G!QRpC;r{a*57svvywGv* z#*r&$_AKAN{ytO6ilw3xHl%IXxOH=RLIKOHmrve2dd0S-yYb-N!;>2ip1z%a=!oa! z+P{C8C77C<8V@NhOnfLfG0-8b#7E~uZej2;zixjIA1^=8x%1de8WnAojkDdpotbkd za`Wd;+znjZ-4b2i&(6#>uXoIhWIR&-w4O(FYUowdtvmtujf}52)@1TNVrJ0vF?NmY ztBD4BU$w+Fq9i4;B-JXpC>2OC7#SE^>Ka(+8X1Qe7+V>bTA2X3CRPRp#=d*PP&DM` br(~v8;@03K!19WL8>q$8)z4*}Q$iB}-+rjT diff --git a/src/qt/res/movies/spinner-017.png b/src/qt/res/movies/spinner-017.png index 85aac66e660008829875166c9f445b77f5204d70..055fc2828c798deb553f53da4e023fbf55eebf6b 100644 GIT binary patch delta 238 zcmVbS5@_fbL{dMh42_s|+M% zQItvO@=>CEbV)1*Ww4M-D083{m)=Ipl2h6$D``+y(eayH5{nY_H4`V(J8Rz!VFk|jK zjNFd`nZ%%{n`zgD314RQtAdMp&KE2KPCKUbydJN}>d{(>H%i_QHufc(dt16tbFy5i oOR}@Q3)YiFk`!x6lBVAz|A&@0D=~cF1ONa407*qoM6N<$f~Q7oX#fBK delta 466 zcmbQo-pDyY*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQE@g?J!6u$yUX$e+qId2>ex#>eO=ifbBHsu8uo{-1)9R} z$Fvd$|Ao0|kd%l-ZK?gzJOZ*o=$2 zJtym~U6Y$5`9|W6tjt`AIg&9k%YEiPJ9gl~yN8ywZPU%0`J30zuXjigV0JF>$hdJP z@*$7lM4p(yi|=?0H*S7@R|A6^>bP0l+XkK&9b?+Be7q30)NX%L_t&-83n;DECc`m2GH+0NzrUaQJC9qW|IU-Idg#> z)f9pW=4T@riGU9^vmc9RA2ION<2@N_lmOZzyo{oDQ{zg;)NVYFzYb5kg<%QRds7d7o+ee) z?^P>2nylYV-_CG7YYyPzFZ0g(Bn#j)OK{2Z$x8XH{DxBFsMwUk>fwe#G#nJ0kz{Ls m8|>}uCX!_RFiBEuCiw>|i#bxz$6{gt0000@|}oVGUm=laG4O$#@z+O=$3-$J=p(QQc_tkc*TbXOZ? z1l~CK0O)_!64!{5l*E!$tK_0oAjM#0U}&jpV4-Vd9AaQ>WngM$0_2)l85kJ*?g>ND dkei>9nO2EggOdQuD;}T@22WQ%mvv4FO#pnBrDp&D diff --git a/src/qt/res/movies/spinner-019.png b/src/qt/res/movies/spinner-019.png index 3a6b5573b804f3df56306f2d090e2bf9344aa68a..f5b7806b9ff23b51b5c9b8a3d6c12dddebabfd37 100644 GIT binary patch delta 253 zcmVEJyK?FI-OK11`iz{9 zoO3x)EEP+|lEFf`P#(U3p?U*U%kL%6cTKSp{p2Pl+U!zb8pn)|31PV4Xc-@agny00000NkvXXu0mjf De~Ete delta 460 zcmeBYzsoT}*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL&b(o-xVW-DN6ALRB+R9eatVuPggw4sm8y!~W2o^z99)OP!o6o3ElW!9s&k6#~uATJ;xA|oUv zc1}RhvNTHM#Do_!UT)+m{K(1E>3NbzlV@e-OJgIW%?&~~EqC%{I#~59)<0X*bZF6| zNjI0KPEwfutZ-`hnVHu4b*ZAxrf2d^>$jGEhE>KU-Y@USr~rMg zTH+c}l9E`GYL#4+3Zxi}3=A!G4J>qxj6)2Jtqe@9On_VyD+2>#-#uX{8glbfGSez? WYj6@^c?HzK;OWZd=d#Wzp$Pyf^Q1KZ diff --git a/src/qt/res/movies/spinner-020.png b/src/qt/res/movies/spinner-020.png index a5aa5fe383bb03b33f83898c5b528dfb833152f5..a84853d59cebe0cad1bfe5fdc7756b318a833da4 100644 GIT binary patch delta 244 zcmVs7?9OA0v;ywifllKGV~3PW7(KeuGih?n@X1B`hEBl% z^q-$)5c)1;RPQAmjCbF3yEcJRd4IB8qU+Y4>D`%*JGPU|u{E!lqRj)?_+DO<%AXaQ u@yNz|B*jNoVJXE&B1!T2mn7>Jll%iJk~!UkN9_Rs0000J*V)v=d&`ns||<`8FQHS7;v3p9n{ zqo<2wh{WaO1O`SogOf+jFtF@FhyED_B`q~Q z#hbU)Rdo*^RXBY>L7hKn#ex-A)}L8$=)i(i%hoMixpeK}1*@0mCuAH+$T2!tzvcXy zJ52{Kow}8_NSC?!u1Yog@soZ$Jm-RAV(#9tm9W{nr?zJKFGGVL>?~}o{@jTP9K5sT zK9?ajnnyMD29i|giPl0Ocmds;(@Q5|>Gd z3`gB)Bl$DvN-PG;DT^@cl2R<{>IRF!pbWmi88KY)Jdz~*CF#>kBuSD1{ATbcQh+Uv z`0DQ|b(0~m>6ES%C445s)SDlp$~HL1TgLEeV(pUEtC!LU%WgU{31pr#g~i(^nO1F8 zTMwCC(5klXWzPH^ZWm$ZQI_C(1(kNCP3>ZRvO_be!pJ!6u$yUXI^x86$u)v=d&`ns||<`8FQHS7;v3p9n{ zgQtsQh{WaO1O`SoHGz|74mB{W$$2Bg!!t)gP28McU%o!Ny1ik60CPaEL4c1-h);~u zrp?}7QEV&PyujA2 zc;m{Mnnx*w+Z z1SCXcgsilC8WnAnjI?Gcs+sB4l^vRMM5QgIZOYD-nJ*odO3sYDY3Y#uEWep diff --git a/src/qt/res/movies/spinner-022.png b/src/qt/res/movies/spinner-022.png index f16800382cc6b0376e28120da93f9ca2352f8f9c..ae8c3ddc9448ede8d2df3a99e03381fd11fc7429 100644 GIT binary patch delta 246 zcmVL_t&-83n;FEQDbIz~SHTyLWe=_x&XOf*{`nT@!>$ zXEO@7otbJ1#!R8wY`0O&m|%jx>7roFO_GeFNj^d0c>ur+pdugy{iUYTZhCy9+ zSHDsz45_M1?&+s>UC{kEhPBgG>#=>Hs{MvD$4}WuIxUK#cu9TY>}z=>5Vh$A_v3oq zx+E|#d39%mIN@!`Q$`+|wVP^2wb#olc_}URgz2*>Rdw!ge(XWJbR5-3bx|8WtE%ou wDpzzwU)=_h;2*218=LP(YwG}R0gwRr2MtazwpQ`L?EnA(07*qoM6N<$g2#e&(f|Me delta 469 zcmbQt{*hyXvK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqhbeBJ!6u$yUU^tcklNA)v=d&`ns||<`8FQHS7;v3p9n{ ztEY=&h{WaO1O`SoHGz|7IG!17*s#gaU_)_1k)c6B^A8(`GpCQ=zoez0!6GOqCMYUA zeZrKi?CH}crY2699RA|Po1m10fS|CKVWGk46E45Fc;(Wyi&rnF8yLJXWqM^$Z)Rv} zyggw6AtTg1n?z#vd9ag8WRNi0dVN-jzTQVd20hL*Yp7P>~pAqK`)2BuafK(2|Efq}8_ ho-h;*x%nxXX_dG&IPnXxyaMWA@O1TaS?83{1OT^fu{Hnz diff --git a/src/qt/res/movies/spinner-023.png b/src/qt/res/movies/spinner-023.png index b30240f2343fca4c845ed33462d80a3505831472..4db34070032a3e34d18f1d64c273a8e66b9a0dc0 100644 GIT binary patch delta 235 zcmVu3;Be7q60)NU$L_t&-83n<;Duw|72GHjWVs`^dAsLhsW$;^~h$1qe zK4P_6Fj$S06pM%=ijex#>eO=ifbBHsu8uo{-1)9R} z!PCVtMB;LCLPA1HQd(jPkWOWu$iwp{VNzo=vxkF=gyqg1l@&jKu(GrsP&%ZvDCv>V zq@YV@b&WO^ed6KaTASPT*2_UMbt+#dn<-l<8?Uc!u57GrEgSP;Kjj52^&35>ubjD4 zU_xqQW-9NJoL#wZtKLXT$jHo{QytsDv@Wmqo!q=Qo_l}o_6h%KVEQMl&T3%5V#MM* zPsqlUMMFSJOzxn7 zjJFHC`M2oNq{`3Ur%!2XtyZW@OsHS6Zspq5=?%=sSPZUSxN+pr0S1PJo=IEp-hnbd8Kd42-P|Os!0SToWq;17qJkVJI4M^HVa@ ZDsgLY5@317z`(`8;OXk;vd$@?2>_7eowNV| diff --git a/src/qt/res/movies/spinner-024.png b/src/qt/res/movies/spinner-024.png index 8cf01a75dc5785bd636738f35c095bf276df7c7f..d29feb4c561d5f9387764068328161b53f33e4d9 100644 GIT binary patch delta 248 zcmVnX|mjCMDqacx^9Z{JJ5 y9jo;slDE&=H5Mn*EQE+iR?J6iEq_GKSNs4I#XMzc!lfes0000g^G!eP1DRq#UjTL z6KiLmoI8hHKXwZ@L#ud;UvKF3aEp@)78&qol`;+0Q`)viU0rr diff --git a/src/qt/res/movies/spinner-025.png b/src/qt/res/movies/spinner-025.png index 57bfd208c2c852b0e3f04c1d50209136e3be45b7..b399a262104c5b9c8fd5b565c15916c0f34e73ff 100644 GIT binary patch delta 257 zcmV+c0sj8^2&)H>Be7qT0)OC1L_t&-(>1|8D1-q3fZ_Kwpcs!uD1$nZK|TY^MJWRV zk_-kEnQl0V{9THRViJYHAPED5iEg>YCxe8NMNAkeXEES;@7faGTL)K7qd50JvI z{ArV_zDM4WqSs0hqw5jSJ*V)v=d&`ns||<`8FQHS7;v3p9n{ zgQtsQh{WaOga!sTwKTCXj>)}^bDJk~pLxPI*=Eh2yS6odn3|jp@hB-U2C^9zcHXn| zTv?YX$rh=`X318`>Z+P58p>w+l~amm7EjbIE8)_wUwCe{?g^3RZCk9?L z+-RJ3jFI(`u+U_QNs>WnOV9buo_vmBi+XZinwWE$UtZk5Jxpy*Y-*8*7yUe{x|I9W zDQzvuRWlB(Tfc7Q+STzpG76cUm1o4Cs6TMw%9#t7Ze7c}!T7NtU7T5lfgw%UG|^=S zOEA#)swJ)wB`Jv|saDBFsX&Us$iUE2*T6#8$T-Bn*vi1v$^^(Yu`)0)_T3YPq9Hdw bB{QuOw+1HxmRAf6Tnr4Ju6{1-oD!M=j4CrJ206MSDO^e> zC3S>iFmVc}oD^A1>XcJbCI%f!SL)&}gF#A)1uKh_y5X{UPXH|wP)mSNSq`W_K(Gix z)pzx>Ce^QC5vlpCRh{2fKkDACe`}a?M}2KnpPLQoq^71*KD4O!(tR2;ZS3H#%|iRw z;jMJ2>TiK=^-6m668bLs%|xS_GZ`E>S5Jo3o~*|*V%PQ2s77*;TqKuve1D?z#=WU< zKAaEdcV}eibk={5Sz%!-u7-Saor;pcN)i&<^s=^^K!Bt!v7w8basB{*3PP#IUEibt O000045bDP z46hOx7_4S6Fo+k-*%fHBQE?ViJ!6u$yUVie8>FWK)v=d&`ns||<`8FQHS7;v3p9n{ zo2QFoh{R>x{#1YGKoJ)9TS`ao-o3kU$F_hyJDj_BgTR0Pyw5jM{LLoM;b&G-Tc$8s z`^L`hEH%969e*2-?<=JJ9m9m41I*5$ohE;ldk-j4?Ty7cG&80#AyS=w9L z1pQo6t{iP_a*te@29^UA=JIx_u8o(%b7LTUKk($bLi2f@8|13ae36OUX=Y>djITAYwPd7of~`Ow*3Qv ze+=1~W<`nC}Q!>*kacdB85@2}+)WP8C>gTe~DWM4f%t^y+ diff --git a/src/qt/res/movies/spinner-027.png b/src/qt/res/movies/spinner-027.png index a463b836924c437125cde40b990efadf7a0a1970..74205bc22ecb7897af846915e0a1b8f29fa48c2c 100644 GIT binary patch delta 269 zcmV+o0rLL$2(Sl`Be7qN0)OjCL_t&-88yKLJ40arfYH~7T{Yd^UDNIA?wU5+bery+ z?rwgm;c*ToX2RUU5{1M+E36M}Y{5?OONqUMxqEnedHW#17rzt# z)3bo{K!Sop5D*#`ei0FQ85K>;Rcu^5BwXJls*;jZQqxGk%>Xj9vVU{P&4YZops)xi zE-9sqaw;mRx~m3i?rZC)r=hW_xuvxY)a@M)or12%r|zEK=RVNTuhpR+7#w;TejOQA zfQGU0iOH$yxA%{kS+xO>nVVnuTwGdSS!InMGOTZGer>TW@kcW3u)DW!Gy>n*xi$0Y T?LIpI0000HfYh{R>n^H+nI14Udeo@L;C2L$sD-qqc)+qvNSgLi!Kr(}aH{g+>N4mWM+Ovy^? z^XmPmv%zNDCN}Al6LL3hF1N5OEnzx2VQ%cXn7emuZT9XF{dn;Eo%fF}{nx5*IItkW z)ye7by2HwON{c)8^>+3)|JePz<;apJQ?8g?k~ea3PYWyK+gZ6_;%9CyRuR$Z0bY_% zMMLbuI9JrITDi3ESKF~=&!&Z4*tXTa+@oaQp0d*Kd%il!|7C9G;qC9)*I(P?zd~f@ zoLTc`&i(!8*Sz=(uUtCMJi7Gh{Ha&BezDch{-2z3+>M6A92{J{s0_2U2K zZ|*ex{4?l)2`~gyOI#yLQW8s2t&)pUffR$0fuW_YfrYM-afpGjm4T_136N`IWnf_J iyC)1qLvDUbW?Cg~4Nd}lEU$n%7(8A5T-G@yGywoe^}_c6 diff --git a/src/qt/res/movies/spinner-028.png b/src/qt/res/movies/spinner-028.png index 7597e0ec2baf02a6c5bc0ecac4ae6ed30c995c1b..912279c8f623d773a6475e2659c1ef21a18610e5 100644 GIT binary patch delta 271 zcmV+q0r38i3C9PJBe7qi0)OpEL_t&-(>2FaLqlNzfZ?}gZJFofE!)PjZ7k!#o&?BlvittQ;gN@@m$wgU(BOOQ zcXH|KkZmYHk5tYg>Bl^$XWDT2J+wANDKZZ&= Vxkho?YybcN07*qoLp${y z@Nk7GadYx=_jlOzc3tc1?EU?&+uqwl#dEF?*UIOai&SitC$GtoEh>6i`IFU2L`-!0 zlv5=Odp>n@DQfAj{<3Q2%C(F4E!@aya#nY3?w0bH(z4R{`(GNa+`evaU{PXiQ&j%n zz-pOb+sDq6$5$?YKK=Sj$y(1T9rfw=pFOL;FD^EHLftWs(`#yK)~)+^JgL9yYp?IN zZAbsIws~3Yylelg5*P}qC9V-ADTyViR>?)FK#IZ0z|d0Hz(Uu^IK;r%%D~jh1jse9 nGB7aq-4lkQAvZrIGp!Pr1|b6jCjpjMKphO8u6{1-oD!M<@pHR? diff --git a/src/qt/res/movies/spinner-029.png b/src/qt/res/movies/spinner-029.png index 01b4d22796317462c435f316afa1a2262f7673e0..27f1d5218c5dff696d82e949ea89bd6b7a3fe056 100644 GIT binary patch delta 273 zcmV+s0q*{a3BL!BBe7qY0)OvGL_t&-83nV9I+^O4TC=+PhDK`u7}5N5XPR~zW%4@fx)4d z*Wr;-V2ts%iTBBm&#$RzSpl@>GqZE^-#-hBODF&=v-115y0&hC0s!bOH#SwUr2zl` X;W45bDP z46hOx7_4S6Fo+k-*%fHBQE?ViJ!6u$yUU6I4zo!>b?haczOL+#ImDS+4f{ja0!?A~ zR)}WM(!8K0+j4JjdwXSD?(V;{|4uq-_x9$@y~W}!Ps9>3 zTTR(C4;;IecUz9#R!h{v%5wLPcRO}guP9mb?aQsZx9u&y*nM(TW{UsQ=kNEoo|)P!?4(Tf?E!JDVD7mB8neXFu&Q2B8|x|LbC zx4IrxJv7DZ)G6%)J3g)R(p|i3*|jC>_AL~gm65k_>)OBj7H@w2aAWkJz$=$;U;qEb z#=zpsCo3BxtzF4I`+fKL*VWYd`kvmR6fpB#{h4!T>;LQM=q!C8<`)MX5lF!N|bSQrEyj*T^`;z}U*b t)XD_NHL)@44$rjF6*2UngE-s!a4u| diff --git a/src/qt/res/movies/spinner-030.png b/src/qt/res/movies/spinner-030.png index 932f4f78280d9403c7ade16b1a48882186c8ea40..cc8af110305dff12ed0f33dde367060e8680d2c6 100644 GIT binary patch delta 250 zcmV_L_t&-(*?n?E2aSe2jJgBl;JbItIePkC6TTugG>xE z84N<*)q4w*+r-53DkUtGNd{ltVz^=;DM=}V|KL;Vvz_oflJJ?N)koX^MB*#$u(C}v zqSoxB+$mMBMI#jaf(qW=6^*W+c467xORXv0miDpW5RZM*KY!$Y0B>%GAwRepy-boZ z)93$We5%exGU2O*zb4wKX9~_{Mz2m4jae9ReKI$4<5+4PlZM=4(A~kJ)S646j|a~^ zlA`gOUOd_^E6K{%YVQ+lrmP~#+QuL2Nm5qHH;B?aOp5!dZ~y=R07*qoM6N<$f}3V~ A#Q*>R delta 464 zcmeBUf6OsK*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL&z>o-xVW-DRQXl|D0|I`$GzUss^9;>@gu{h@1trZ9Z) zba4!kxUAZnT+R|G;PU>+jo!^0bET#Ia&B+Sz5UGpZ1v=S7p`viyROM_)J4bVtbw~U ztB%gvHM!ezORIX{id3^7mtB6>Ha$jVx73|){Cxd=cWrI*wq36+XPN z;h4$Ex08dHyMM=?uAZ(wMX^Wg9t(T;c=>s%>e?y`Z`xFR;_9oOO7oviTzTBxU9GEB zvoa%hUg$cdwPM}MwX2suTo<^_#B}?XZFlXrT>g0DrfS^Rws-TEKfkx{U*q)aj%_Um zKb&}RR{Cr|PDS(U^bJCU^9xs&IAGVf^Y(xa(GXY_)C&>{U(tVI_U;{7dlet`RcVn zy=M2b*p@!lQLokc=x-Tl4OTS(??Z1&tQ~k6Ud2AoQeHjO90lBu%Vfmj>C=e2B$?ty zDqJVY^iPkuiz}tq8G!SJ%FUU=JSMq4$r6rb`DkVQ9vFMvn-*PbP)5_`tQ6bpW#B=* pwky@fCcsX$5lOOTJ4sS)B>z!DH~3YHfB^si002ovPDHLkV1h$4ZrlI> delta 467 zcmZo45bDP z46hOx7_4S6Fo+k-*%fHBQL&b(o-xVW-DRQXl|D0|I`$GzUsv|W9OBHZhW(*yfu=Bg z_H=O!k+__kz`*3jW{}Vnz;lL&M`umW8<{yVcNEN+jrp1N<9%~w>uZ}CniT>ZJR+8C zT)ESAOQ=swQ{<#Z$4QQ>*2YG;h55xf26j5mY;<%DUF#g%?6`UJ>fP?%(e>;rT(^h& z&p&wJ!igJ4uAG^3u&MFjrt@9LZ?WafUpv=!LPIa<_em0eNz(J1B$6b(@YBb4q#yPn0I{?-9funXpHUpYsQsDyh($07*qoM6N<$f+2=$v;Y7A delta 464 zcmZo>|G+Up*@}TB-O<;Pfnj4m_n$;o1_lO&WRD45bDP z46hOx7_4S6Fo+k-*%fHBQL%@qo-xVW-DOGSzN(!-b?haczOL+#ImDS+4f{ja0!?A~ z;OXKRB5^r6fq}_Q;NXEH4Gd>=*5th5k(m>tz-P{{FJB*A+}*GsV6{Or2XnJVb3}Bt zdwO`efBt-nW)=ajZ~hY|O`AA%a(F;UQb1ZjVCd`>=MF4bXqoxxiDr}oBU^p0Y%H5C zXDzd{aIzRbwN4h()zeMZV6UGU8yFcH8yp>e{{X{7nC}Q!>*k YacgiAV0p#Bz{SAe>FVdQ&MBb@0INQii~s-t diff --git a/src/qt/res/movies/spinner-033.png b/src/qt/res/movies/spinner-033.png index 8f11c16739bbb399e58a450e662cd62ea9739c55..7550af7b7a02e571079abcc32296eee691b5992a 100644 GIT binary patch delta 233 zcmVl}<#o&79wyd=v23_MgyveAe7VBLVa<2TuYUZR0*Ns=9~-CTT+ jq<`LKnhL+!Ex#xKcnLN+nzu%Z00000NkvXXu0mjf0bgd3 delta 479 zcmZ3(zL0Z*vK0eMx}&cn1H;CC?mvmF3=9kk$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo z7+xhXFj&oCU=S~uvn$YMqvATIdd4JgcbBAt21}w%c zXXcvQo9NgmO;XgF)i|-yR?SS$F3~Ybh~2r!OUqe`*}2LsEv(EhFRsq<;UT5AB(}Cm zuHDmhbYsK9_SLw$F6FqeWYw!#w{}fkT_3hSF8Kb18!TV_i@md>tJ$TO8_ZaK|K`yH z2aX&&aDn#`GsFDn)*1eHeXW3jp<3b^QIe8al4_M)lnSI6j0_Adbqy?Zjf_JKjI9hz ttxSMi6DtD)W8XbtC>nC}Q!>*kF*HcRbvOyIyaMWA@O1TaS?83{1OUI0uY&*p diff --git a/src/qt/res/movies/spinner-034.png b/src/qt/res/movies/spinner-034.png index c2d6971789f937d0e53f7136db62e011054a529d..afcd2c2826a958d90c3e2133b0e7fdfb56155027 100644 GIT binary patch delta 250 zcmV_L_t&-83n<=D4w?1X(CgQq@6oW(-zy1It!)1EZQ}_8ul9u-*N%1X-B(3!}@LDYT zCuyyJQAX8E66tvEEZb6M6Lddy1DI2LRC?&+_LDx~T1O9;LmGuCdvB(GpX>UH(~O*b zGie`VjQ`O#-tF!pqNIOJ;ofa^#hdnt zi>7SpStHYIv$$!|q)lC`X6+gt6fz*K4*ThwYeQrTjn5}_DrmvXIfa= zwcus9Zuo6ZPMEN{yr3j0p&+fWaIW3qvv->hUOrvDtbe_Hv%RxJLV!Uq2eb2wH5+ag zA5wmzv{+(MGK;OGMAG9&!a|cL1qVr9x@0V2BpI>!*}2o_PM%FZtFJL9{)obf17R^i zyAmEQ+VrXGsJE8nssnkctJg*D%K6zfb!&ZTXqrP_t+TRoaItrGv^BHwncclSJUTi& zJhBRA3{E$#vLlaOJPr&9)e_f;l9a@fRIB8oR3OD*WMF8iYha;kWE^5(Y-M0-Wdh`y oSQ!`?`|b%t(U6;;l9^VCRf8y4hm!!yE1(VrPgg&ebxsLQ07l%Zs{jB1 From 8c54526088bcba325fca5821a09797263351bdd3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 20:40:00 -0500 Subject: [PATCH 0051/1888] [Bug] Segfault with -enableswifttx=0 / -enableswifttx=false --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 888f2ff2cd..08064c4ac0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -837,7 +837,7 @@ bool AppInit2(bool isDaemon) } if (!GetBoolArg("-enableswifttx", fEnableSwiftTX)) { - if (SoftSetArg("-swifttxdepth", 0)) + if (SoftSetArg("-swifttxdepth", "0")) LogPrintf("AppInit2 : parameter interaction: -enableswifttx=false -> setting -nSwiftTXDepth=0\n"); } From f559654a53316b12a54c9740f4cb6075877ae60a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 22:13:35 -0500 Subject: [PATCH 0052/1888] Add locked, immature to getbalances --- src/wallet/rpcwallet.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6be769d5be..90a15ad90d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -725,9 +725,11 @@ UniValue getbalances(const UniValue& params, bool fHelp) "getbalances" "\nArguments:\n" "\nResult:\n" - "total (numeric) The total amount in DAPS received for this wallet.\n" - "spendable (numeric) The total amount in DAPS spendable for this wallet.\n" - "pending (numeric) The total amount in DAPS pending for this wallet." + "total (numeric) The total amount of DAPS received for this wallet.\n" + "spendable (numeric) The total amount of DAPS spendable for this wallet.\n" + "pending (numeric) The total amount of DAPS pending for this wallet.\n" + "immature (numeric) The total amount of DAPS that are immature for this wallet.\n" + "locked (numeric) The total amount of DAPS that are locked for this wallet." "\nExamples:\n" "\nThe total amount in the server across all accounts\n" + HelpExampleCli("getbalances", "")); @@ -736,6 +738,8 @@ UniValue getbalances(const UniValue& params, bool fHelp) obj.push_back(Pair("total", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("spendable", ValueFromAmount(pwalletMain->GetSpendableBalance()))); obj.push_back(Pair("pending", ValueFromAmount(pwalletMain->GetUnconfirmedBalance()))); + obj.push_back(Pair("immature", ValueFromAmount(pwalletMain->GetImmatureBalance()))); + obj.push_back(Pair("locked", ValueFromAmount(pwalletMain->GetLockedCoins()))); return obj; } From 9bce161f97b6a644ce3a0461fb66430777d47b35 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 22:16:26 -0500 Subject: [PATCH 0053/1888] Fix Spendable showing Locked coins --- src/qt/overviewpage.cpp | 7 +++---- src/wallet/wallet.cpp | 3 +++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index eb28a13fca..e992b85e52 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -171,10 +171,9 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed currentWatchOnlyBalance = watchOnlyBalance; currentWatchUnconfBalance = watchUnconfBalance; currentWatchImmatureBalance = watchImmatureBalance; - CAmount nSpendableBalance = balance - immatureBalance; - if (nSpendableBalance < 0) { - nSpendableBalance = pwalletMain->GetSpendableBalance(); - } + CAmount nSpendableBalance = 0; + nSpendableBalance = pwalletMain->GetSpendableBalance(); + CAmount nSpendableDisplayed = nSpendableBalance; //if it is not staking if (nLastCoinStakeSearchInterval) { //if staking enabled diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8633d4a26e..214672e923 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1699,6 +1699,7 @@ CAmount CWallet::GetBalance() CAmount CWallet::GetSpendableBalance() { + CAmount nLockedBalance = 0; CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); @@ -1712,6 +1713,8 @@ CAmount CWallet::GetSpendableBalance() } } + nLockedBalance = pwalletMain->GetLockedCoins(); + nTotal = nTotal - nLockedBalance; return nTotal; } From b71886352f542cb8b7f352219a6386b68edb5bc6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 22:32:57 -0500 Subject: [PATCH 0054/1888] Bump version to v1.0.5.5 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6c7544399f..756f847daa 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 4) +define(_CLIENT_VERSION_BUILD, 5) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) From 152199313022f3b26b6d7ea4c045464faff965ba Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 28 Dec 2019 23:29:49 -0500 Subject: [PATCH 0055/1888] Add F2 Shortcut to open DAPSCoin folder --- src/qt/bitcoingui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 46be2570e3..c07912d2cb 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -414,6 +414,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openMNConfEditorAction->setStatusTip(tr("Open Masternode configuration file")); showDataDirAction = new QAction(QIcon(":/icons/browse"), tr("Show &DAPScoin Folder"), this); showDataDirAction->setStatusTip(tr("Show the DAPScoin folder")); + showDataDirAction->setShortcut(Qt::Key_F2); showBackupsAction = new QAction(QIcon(":/icons/browse"), tr("Show Automatic &Backups"), this); showBackupsAction->setStatusTip(tr("Show automatically created wallet backups")); From 19f11db282fb792b65ff9b139a63082d6cc1e51e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 17:07:30 -0500 Subject: [PATCH 0056/1888] Remove HistoryPage::txalert --- src/qt/historypage.cpp | 48 ------------------------------------------ src/qt/historypage.h | 2 -- src/qt/walletview.cpp | 1 - 3 files changed, 51 deletions(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index d25e973658..5851dad6f6 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -340,51 +340,3 @@ void HistoryPage::setModel(WalletModel* model) connect(model, SIGNAL(WalletUnlocked()), this, SLOT(updateTableData())); } - -void HistoryPage::txalert(QString a, int b, CAmount c, QString d, QString e, QString f){ - // ui->tableView->setSortingEnabled(false); - // int row = ui->tableView->rowCount(); - // ui->tableView->insertRow(row); - // int col = 0; - // QStringList splits = d.split(" "); - // QString type = splits[0]; - // if (type == QString("Payment")) { - // type = d; - // } - // QString addr = e.trimmed().mid(1, e.trimmed().length() - 2); - // if (!e.trimmed().startsWith(QString("("))) { - // addr = e.trimmed(); - // } - // for (QString dataName : {"date", "type", "address", "amount", "confirmations"}) { - // QTableWidgetItem* cell = new QTableWidgetItem(); - // switch (col) { - - // case 0: /*date*/ - // cell->setData(0, a); - // break; - // case 1: /*type*/ - // cell->setData(0, type); - // break; - // case 2: /*address*/ - // cell->setData(0, addr); - // break; - // case 3: /*amount*/ - // cell->setData(0, BitcoinUnits::format(0, c)); - // break; - // case 4: /*confirmations*/ - // cell->setData(0, f); - // break; - // /*default: - // cell->setData(0, data); - // break;*/ - // } - // ui->tableView->setItem(row, col, cell); - // col++; - // ui->tableView->update(); - // } - // ui->tableView->setSortingEnabled(true); - // ui->tableView->setVisible(ui->tableView->rowCount()); - // ui->tableView->update(); - // ui->tableView->viewport()->update(); - //updateTableData(pwalletMain); -} diff --git a/src/qt/historypage.h b/src/qt/historypage.h index 60c97ff071..1bb38319a0 100644 --- a/src/qt/historypage.h +++ b/src/qt/historypage.h @@ -46,8 +46,6 @@ class HistoryPage : public QDialog public slots: void updateFilter(); void syncTime(QDateTimeEdit* calendar, QTimeEdit* clock); - void txalert(QString, int, CAmount, QString, QString, QString); - protected: virtual void keyPressEvent(QKeyEvent* event); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 7a7dbd937d..b6538f073d 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -115,7 +115,6 @@ void WalletView::setBitcoinGUI(BitcoinGUI* gui) // Pass through transaction notifications connect(this, SIGNAL(incomingTransaction(QString, int, CAmount, QString, QString, QString)), gui, SLOT(incomingTransaction(QString, int, CAmount, QString, QString, QString))); - connect(this, SIGNAL(incomingTransaction(QString, int, CAmount, QString, QString, QString)), historyPage, SLOT(txalert(QString, int, CAmount, QString, QString, QString))); connect(this, SIGNAL(stakingStatusChanged(bool)), gui, SLOT(setStakingInProgress(bool))); } } From 6b03adaff91616913f71aa9b79e06366eb96acad Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 17:08:05 -0500 Subject: [PATCH 0057/1888] Remove extra returns --- src/qt/historypage.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 5851dad6f6..11293dc47c 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -207,8 +207,6 @@ void HistoryPage::updateTableData() void HistoryPage::updateTableData(CWallet* wallet) { - if (!wallet) return; - if (!wallet || wallet->IsLocked()) return; TRY_LOCK(cs_main, lockMain); if (!lockMain) return; From 8e7edaa1b3090fca012d68e24c1b39bb2ae5eed9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 18:39:35 -0500 Subject: [PATCH 0058/1888] [RPC] Show script verification errors in signrawtransaction result --- src/rpc/rawtransaction.cpp | 43 ++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 88ca93e78b..1060cbdfd4 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -15,6 +15,7 @@ #include "primitives/transaction.h" #include "rpc/server.h" #include "script/script.h" +#include "script/script_error.h" #include "script/sign.h" #include "script/standard.h" #include "uint256.h" @@ -608,6 +609,18 @@ UniValue decodescript(const UniValue& params, bool fHelp) return r; } +/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */ +static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage) +{ + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", txin.prevout.hash.ToString())); + entry.push_back(Pair("vout", (uint64_t)txin.prevout.n)); + entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + entry.push_back(Pair("sequence", (uint64_t)txin.nSequence)); + entry.push_back(Pair("error", strMessage)); + vErrorsRet.push_back(entry); +} + UniValue signrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) @@ -649,8 +662,18 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" - " \"hex\": \"value\", (string) The raw transaction with signature(s) (hex-encoded string)\n" - " \"complete\": n (numeric) if transaction has a complete set of signature (0 if not)\n" + " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" + " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" + " {\n" + " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" + " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" + " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" + " \"sequence\" : n, (numeric) Script sequence number\n" + " \"error\" : \"text\" (string) Verification or signing error related to the input\n" + " }\n" + " ,...\n" + " ]\n" "}\n" "\nExamples:\n" + @@ -683,7 +706,6 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) // mergedTx will end up with all the signatures; it // starts as a clone of the rawtx: CMutableTransaction mergedTx(txVariants[0]); - bool fComplete = true; // Fetch previous transactions (inputs): CCoinsView viewDummy; @@ -793,12 +815,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Script verification errors + UniValue vErrors(UniValue::VARR); + // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; const CCoins* coins = view.AccessCoins(txin.prevout.hash); if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) { - fComplete = false; + TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); continue; } const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; @@ -812,13 +837,19 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) for (const CMutableTransaction& txv : txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i))) - fComplete = false; + ScriptError serror = SCRIPT_ERR_OK; + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { + TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); + } } + bool fComplete = vErrors.empty(); UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(mergedTx))); result.push_back(Pair("complete", fComplete)); + if (!vErrors.empty()) { + result.push_back(Pair("errors", vErrors)); + } return result; } From 5fe689d9a38cac63b45b4fbe0407043fe2235df9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 18:39:58 -0500 Subject: [PATCH 0059/1888] [Wallet] Write new transactions to wtxOrdered properly --- src/wallet/wallet.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b3a22fb8ac..47e7a07ba5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1069,8 +1069,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) wtx.BindWallet(this); bool fInsertedNew = ret.second; if (fInsertedNew) { - wtx.nTimeReceived = GetAdjustedTime(); + if (!wtx.nTimeReceived) + wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = ComputeTimeSmart(wtx); AddToSpends(hash); } From 6c8ca22b4a1de561aa189e66336d878af21b43f1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 19:13:26 -0500 Subject: [PATCH 0060/1888] [Output] Properly log reason(s) for increasing a peer's DoS score. --- src/masternode-budget.cpp | 12 ++++++++---- src/masternode-payments.cpp | 7 +++++-- src/masternodeman.cpp | 22 ++++++++++++---------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 34b98f93fc..6a6f117b2e 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -1070,8 +1070,10 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { - LogPrint("masternode","mvote - signature invalid\n"); - if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); + if (masternodeSync.IsSynced()) { + LogPrintf("CBudgetManager::ProcessMessage() : mvote - signature invalid\n"); + Misbehaving(pfrom->GetId(), 20); + } // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, vote.vin); return; @@ -1142,8 +1144,10 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { - LogPrint("masternode","fbvote - signature invalid\n"); - if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); + if (masternodeSync.IsSynced()) { + LogPrintf("CBudgetManager::ProcessMessage() : fbvote - signature invalid\n"); + Misbehaving(pfrom->GetId(), 20); + } // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, vote.vin); return; diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 7eac1c1fab..088a7000fa 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -376,7 +376,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st if (Params().NetworkID() == CBaseChainParams::MAIN) { if (pfrom->HasFulfilledRequest("mnget")) { - LogPrint("masternode","mnget - peer already asked me for the list\n"); + LogPrintf("CMasternodePayments::ProcessMessageMasternodePayments() : mnget - peer already asked me for the list\n"); Misbehaving(pfrom->GetId(), 20); return; } @@ -421,7 +421,10 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st } if (!winner.SignatureValid()) { - if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); + if (masternodeSync.IsSynced()) { + LogPrintf("CMasternodePayments::ProcessMessageMasternodePayments() : mnw - invalid signature\n"); + Misbehaving(pfrom->GetId(), 20); + } // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, winner.vinMasternode); return; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 9e2ffeb088..fe0b7bb294 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -738,7 +738,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // make sure the vout that was signed is related to the transaction that spawned the Masternode // - this is expensive, so it's only done once per Masternode if (!obfuScationSigner.IsVinAssociatedWithPubkey(mnb.vin, mnb.pubKeyCollateralAddress)) { - LogPrint("masternode","mnb - Got mismatched pubkey and vin\n"); + LogPrintf("CMasternodeMan::ProcessMessage() : mnb - Got mismatched pubkey and vin\n"); Misbehaving(pfrom->GetId(), 33); return; } @@ -796,6 +796,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (i != mAskedUsForMasternodeList.end()) { int64_t t = (*i).second; if (GetTime() < t) { + LogPrintf("CMasternodeMan::ProcessMessage() : dseg - peer already asked me for the list\n"); Misbehaving(pfrom->GetId(), 34); return; } @@ -858,7 +859,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >> lastUpdated >> protocolVersion >> donationAddress >> donationPercentage; // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrint("masternode","dsee - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); Misbehaving(pfrom->GetId(), 1); return; } @@ -908,7 +909,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData strMessage = HexStr(ser.begin(), ser.end()); if (protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) { - LogPrint("masternode","dsee - ignoring outdated Masternode %s protocol version %d < %d\n", vin.prevout.hash.ToString(), protocolVersion, masternodePayments.GetMinMasternodePaymentsProto()); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - ignoring outdated Masternode %s protocol version %d < %d\n", vin.prevout.hash.ToString(), protocolVersion, masternodePayments.GetMinMasternodePaymentsProto()); Misbehaving(pfrom->GetId(), 1); return; } @@ -917,7 +918,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pubkeyScript = GetScriptForDestination(pubkey); if ((pubkey.IsCompressed() && pubkeyScript.size() != 35) || (!pubkey.IsCompressed() && pubkeyScript.size() != 67)) { - LogPrint("masternode","dsee - pubkey the wrong size\n"); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - pubkey the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } @@ -925,13 +926,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CScript pubkeyScript2; pubkeyScript2 = GetScriptForDestination(pubkey2); if ((pubkey2.IsCompressed() && pubkeyScript2.size() != 35) || (!pubkey2.IsCompressed() && pubkeyScript2.size() != 67)) { - LogPrint("masternode","dsee - pubkey2 the wrong size\n"); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - pubkey2 the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } if (!vin.scriptSig.empty()) { - LogPrint("masternode","dsee - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); Misbehaving(pfrom->GetId(), 100); return; } @@ -939,7 +940,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData std::string errorMessage = ""; CScript sc = GetScriptForDestination(pubkey); if (!obfuScationSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)) { - LogPrint("masternode","dsee - Got bad Masternode address signature\n"); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - Got bad Masternode address signature\n");; Misbehaving(pfrom->GetId(), 100); return; } @@ -995,7 +996,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // make sure the vout that was signed is related to the transaction that spawned the Masternode // - this is expensive, so it's only done once per Masternode if (!obfuScationSigner.IsVinAssociatedWithPubkey(vin, pubkey)) { - LogPrint("masternode","dsee - Got mismatched pubkey and vin\n"); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - Got mismatched pubkey and vin\n"); Misbehaving(pfrom->GetId(), 100); return; } @@ -1012,7 +1013,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (fAcceptable) { if (GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS) { - LogPrint("masternode","dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); + LogPrintf("CMasternodeMan::ProcessMessage() : dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); Misbehaving(pfrom->GetId(), 20); return; } @@ -1069,12 +1070,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } if (sigTime > GetAdjustedTime() + 60 * 60) { + LogPrintf("CMasternodeMan::ProcessMessage() : dseep - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); Misbehaving(pfrom->GetId(), 1); return; } if (sigTime <= GetAdjustedTime() - 60 * 60) { - LogPrint("masternode", "\ndseep - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); + LogPrintf("CMasternodeMan::ProcessMessage() : dseep - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); Misbehaving(pfrom->GetId(), 1); return; } From 89bfdfff2f5731d535f3345502f38adf7a9b6d34 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 19:48:41 -0500 Subject: [PATCH 0061/1888] [Refactor] Use references instead of copies in for loops --- src/main.cpp | 8 ++++---- src/miner.cpp | 2 +- src/primitives/transaction.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a4ae2f9191..c58d5fdca0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1945,7 +1945,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). - for (const CTxIn txin : tx.vin) { + for (const CTxIn& txin : tx.vin) { if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; @@ -2862,7 +2862,7 @@ bool RecalculateDAPSSupply(int nHeightStart) CAmount nValueIn = 0; CAmount nValueOut = 0; CAmount nFees = 0; - for (const CTransaction tx : block.vtx) { + for (const CTransaction& tx : block.vtx) { nFees += tx.nTxFee; if (tx.IsCoinStake()) { for (unsigned int i = 0; i < tx.vin.size(); i++) { @@ -4843,7 +4843,7 @@ bool static LoadBlockIndexDB(string& strError) // Calculate nChainWork vector > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); - for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { + for (const std::pair& item : mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } @@ -4898,7 +4898,7 @@ bool static LoadBlockIndexDB(string& strError) // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); set setBlkDataFiles; - for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { + for (const std::pair& item : mapBlockIndex) { CBlockIndex* pindex = item.second; if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); diff --git a/src/miner.cpp b/src/miner.cpp index 8375722982..0ad32ae2b9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -368,7 +368,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP ++nBlockTx; nFees += nTxFees; - for (const CBigNum bnSerial : vTxSerials) + for (const CBigNum& bnSerial : vTxSerials) vBlockSerials.emplace_back(bnSerial); if (fPrintPriority) { diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index d390c294c3..08677b114c 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -159,7 +159,7 @@ CAmount CTransaction::GetValueOut() const bool CTransaction::UsesUTXO(const COutPoint out) { - for (const CTxIn in : vin) { + for (const CTxIn& in : vin) { if (in.prevout == out) return true; } From 2bf9b79ae96c12a316110f99ad2288d094db8988 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 20:20:45 -0500 Subject: [PATCH 0062/1888] [UI] Add address to the payment request history --- src/qt/receivecoinsdialog.cpp | 2 ++ src/qt/recentrequeststablemodel.cpp | 6 +++++- src/qt/recentrequeststablemodel.h | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index a6fbab727a..b91205a15a 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -36,6 +36,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent, Qt::Wi QAction* copyLabelAction = new QAction(tr("Copy label"), this); QAction* copyMessageAction = new QAction(tr("Copy message"), this); QAction* copyAmountAction = new QAction(tr("Copy amount"), this); + QAction* copyAddressAction = new QAction(tr("Copy address"), this); // context menu contextMenu = new QMenu(this); @@ -43,6 +44,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : QDialog(parent, Qt::Wi contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyMessageAction); contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyAddressAction); // Show privacy account address ui->lineEditAddress->setStyleSheet("border:none; background: transparent; text-align:center;"); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index eb7ec80cea..a3f1337da9 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -22,7 +22,7 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* addNewRequest(request); /* These columns must match the indices in the ColumnIndex enumeration */ - columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle(); + columns << tr("Date") << tr("Label") << tr("Address") << tr("Message") << getAmountTitle(); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); } @@ -63,6 +63,8 @@ QVariant RecentRequestsTableModel::data(const QModelIndex& index, int role) cons } else { return rec->recipient.label; } + case Address: + return rec->recipient.address; case Message: if (rec->recipient.message.isEmpty() && role == Qt::DisplayRole) { return tr("(no message)"); @@ -215,6 +217,8 @@ bool RecentRequestEntryLessThan::operator()(RecentRequestEntry& left, RecentRequ return pLeft->date.toTime_t() < pRight->date.toTime_t(); case RecentRequestsTableModel::Label: return pLeft->recipient.label < pRight->recipient.label; + case RecentRequestsTableModel::Address: + return pLeft->recipient.address < pRight->recipient.address; case RecentRequestsTableModel::Message: return pLeft->recipient.message < pRight->recipient.message; case RecentRequestsTableModel::Amount: diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index d0b84bcc2a..210a782c67 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -67,8 +67,9 @@ class RecentRequestsTableModel : public QAbstractTableModel enum ColumnIndex { Date = 0, Label = 1, - Message = 2, - Amount = 3, + Address = 2, + Message = 3, + Amount = 4, NUMBER_OF_COLUMNS }; From 27651fd50b9f130c6b0478907d9dfba527cdc00d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 20:39:18 -0500 Subject: [PATCH 0063/1888] [RPC] Add more verbosity to validateaddress --- src/rpc/misc.cpp | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index b9e05244e0..86fb5e9fed 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -233,22 +233,20 @@ class DescribeAddressVisitor : public boost::static_visitor { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("isscript", true)); - if (mine != ISMINE_NO) { - CScript subscript; - pwalletMain->GetCScript(scriptID, subscript); - std::vector addresses; - txnouttype whichType; - int nRequired; - ExtractDestinations(subscript, whichType, addresses, nRequired); - obj.push_back(Pair("script", GetTxnOutputType(whichType))); - obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); - UniValue a(UniValue::VARR); - for (const CTxDestination& addr : addresses) - a.push_back(CBitcoinAddress(addr).ToString()); - obj.push_back(Pair("addresses", a)); - if (whichType == TX_MULTISIG) - obj.push_back(Pair("sigsrequired", nRequired)); - } + CScript subscript; + pwalletMain->GetCScript(scriptID, subscript); + std::vector addresses; + txnouttype whichType; + int nRequired; + ExtractDestinations(subscript, whichType, addresses, nRequired); + obj.push_back(Pair("script", GetTxnOutputType(whichType))); + obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); + UniValue a(UniValue::VARR); + for (const CTxDestination& addr : addresses) + a.push_back(CBitcoinAddress(addr).ToString()); + obj.push_back(Pair("addresses", a)); + if (whichType == TX_MULTISIG) + obj.push_back(Pair("sigsrequired", nRequired)); return obj; } }; @@ -266,8 +264,11 @@ UniValue validateaddress(const UniValue& params, bool fHelp) "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" " \"address\" : \"dapscoinaddress\", (string) The dapscoin address validated\n" + " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" + " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" " \"isscript\" : true|false, (boolean) If the key is a script\n" + " \"hex\" : \"hex\", (string, optional) The redeemscript for the P2SH address\n" " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" " \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n" @@ -291,14 +292,15 @@ UniValue validateaddress(const UniValue& params, bool fHelp) CTxDestination dest = address.Get(); string currentAddress = address.ToString(); ret.push_back(Pair("address", currentAddress)); + CScript scriptPubKey = GetScriptForDestination(dest); + ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + #ifdef ENABLE_WALLET isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; - ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); - if (mine != ISMINE_NO) { - ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true : false)); - UniValue detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); - ret.pushKVs(detail); - } + ret.push_back(Pair("ismine", bool(mine & ISMINE_SPENDABLE))); + ret.push_back(Pair("iswatchonly", bool(mine & ISMINE_WATCH_ONLY))); + UniValue detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); + ret.pushKVs(detail); if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); #endif From 06f04d4b06143a26230f6092a9b1e1bf27b013c3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 29 Dec 2019 20:48:05 -0500 Subject: [PATCH 0064/1888] [RPC] Show the configured/set txfee in getwalletinfo --- src/wallet/rpcwallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6be769d5be..e1bfe714b6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2015,6 +2015,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in DAPS/kB\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); @@ -2029,6 +2030,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); return obj; } From 16a1104cf86a5a88c5ba8f6a0f17c61085a81fd8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 1 Jan 2020 16:16:06 -0500 Subject: [PATCH 0065/1888] Lower min refresh time between History tab clicks to 30 seconds (might be removed altogether) --- src/qt/walletview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index b6538f073d..526093b24a 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -197,7 +197,7 @@ void WalletView::gotoHistoryPage() { int lastTime = GetAdjustedTime(); setCurrentWidget(historyPage); - if (GetAdjustedTime() - lastTime < 90) { + if (GetAdjustedTime() - lastTime < 30) { historyPage->updateTableData(); } } From e3c098f24913d46e176c6cfb06900837c579cc8b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 1 Jan 2020 16:20:49 -0500 Subject: [PATCH 0066/1888] Minor QT.pro / Makefile adjustments --- .gitignore | 2 + contrib/dapscoin-qt.pro | 150 +++++++++---- src/Makefile.qt.include | 2 +- src/db.cpp | 455 ---------------------------------------- src/db.h | 328 ----------------------------- 5 files changed, 111 insertions(+), 826 deletions(-) delete mode 100644 src/db.cpp delete mode 100644 src/db.h diff --git a/.gitignore b/.gitignore index 54d167c232..5d30879824 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,5 @@ CMakeLists.txt cmake-build-debug .vscode/* BackupWallet* +dapscoin-qt.pro +!contrib/dapscoin-qt.pro diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index 2aafcd8531..af4c922058 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -60,7 +60,13 @@ HEADERS += src/activemasternode.h \ src/alert.h \ src/allocators.h \ src/amount.h \ + src/arith_uint256.h \ src/base58.h \ + src/bignum.h \ + src/bip38.h \ + src/bip39.h \ + src/bip39_english.h \ + src/blocksignature.h \ src/bloom.h \ src/chain.h \ src/chainparams.h \ @@ -75,15 +81,18 @@ HEADERS += src/activemasternode.h \ src/compressor.h \ src/core_io.h \ src/crypter.h \ - src/obfuscation-relay.h \ - src/obfuscation.h \ - src/config/dapscoin-config.h \ - src/wallet/db.h \ src/eccryptoverify.h \ + src/ecdhutil.h \ src/ecwrapper.h \ + src/enum.h \ + src/guiinterface.h \ src/hash.h \ + src/hdchain.h \ + src/httprpc.h \ + src/httpserver.h \ src/init.h \ - src/swifttx.h \ + src/invalid.h \ + src/kernel.h \ src/key.h \ src/keystore.h \ src/leveldbwrapper.h \ @@ -97,33 +106,45 @@ HEADERS += src/activemasternode.h \ src/masternodeman.h \ src/merkleblock.h \ src/miner.h \ + src/mintpool.h \ src/mruset.h \ src/net.h \ src/netbase.h \ src/noui.h \ + src/obfuscation-relay.h \ + src/obfuscation.h \ + src/poa.h \ src/pow.h \ src/protocol.h \ src/pubkey.h \ src/random.h \ - src/rpc/client.h \ - src/rpc/protocol.h \ - src/rpc/server.h \ + src/reverselock.h \ + src/reverse_iterate.h \ + src/scheduler.h \ src/serialize.h \ + src/stakeinput.h \ src/streams.h \ + src/swifttx.h \ src/sync.h \ src/threadsafety.h \ src/timedata.h \ src/tinyformat.h \ + src/torcontrol.h \ src/txdb.h \ src/txmempool.h \ - src/guiinterface.h \ src/uint256.h \ + src/uint512.h \ src/undo.h \ src/util.h \ src/utilmoneystr.h \ src/utilstrencodings.h \ src/utiltime.h \ + src/validationinterface.h \ src/version.h \ + src/rpc/client.h \ + src/rpc/protocol.h \ + src/rpc/server.h \ + src/wallet/db.h \ src/wallet/wallet.h \ src/wallet/wallet_ismine.h \ src/wallet/walletdb.h \ @@ -152,40 +173,55 @@ HEADERS += src/activemasternode.h \ src/obj/build.h \ src/primitives/block.h \ src/primitives/transaction.h \ + src/qt/2faconfirmdialog.h \ + src/qt/2fadialog.h \ + src/qt/2faqrdialog.h \ src/qt/addressbookpage.h \ src/qt/addresstablemodel.h \ src/qt/askpassphrasedialog.h \ + src/qt/bantablemodel.h \ + src/qt/bip38tooldialog.h \ src/qt/bitcoinaddressvalidator.h \ src/qt/bitcoinamountfield.h \ src/qt/bitcoingui.h \ src/qt/bitcoinunits.h \ + src/qt/blockexplorer.h \ src/qt/clientmodel.h \ src/qt/coincontroldialog.h \ src/qt/coincontroltreewidget.h \ src/qt/csvmodelwriter.h \ src/qt/editaddressdialog.h \ + src/qt/encryptdialog.h \ + src/qt/entermnemonics.h \ src/qt/guiconstants.h \ src/qt/guiutil.h \ src/qt/historypage.h \ + src/qt/importorcreate.h \ src/qt/intro.h \ + src/qt/lockdialog.h \ src/qt/macdockiconhandler.h \ src/qt/macnotificationhandler.h \ + src/qt/masternodelist.h \ + src/qt/multisenddialog.h \ + src/qt/multisigdialog.h \ src/qt/networkstyle.h \ src/qt/notificator.h \ src/qt/openuridialog.h \ src/qt/optionsdialog.h \ - src/qt/optionspage.h \ src/qt/optionsmodel.h \ + src/qt/optionspage.h \ src/qt/overviewpage.h \ - src/qt/paymentrequest.pb.h \ src/qt/paymentrequestplus.h \ src/qt/paymentserver.h \ src/qt/peertablemodel.h \ + src/qt/platformstyle.h \ + src/qt/qgoogleauth.h \ src/qt/qvalidatedlineedit.h \ src/qt/qvaluecombobox.h \ src/qt/receivecoinsdialog.h \ src/qt/receiverequestdialog.h \ src/qt/recentrequeststablemodel.h \ + src/qt/revealtxdialog.h \ src/qt/rpcconsole.h \ src/qt/sendcoinsdialog.h \ src/qt/sendcoinsentry.h \ @@ -200,6 +236,7 @@ HEADERS += src/activemasternode.h \ src/qt/transactiontablemodel.h \ src/qt/transactionview.h \ src/qt/txentry.h \ + src/qt/unlockdialog.h \ src/qt/utilitydialog.h \ src/qt/walletframe.h \ src/qt/walletmodel.h \ @@ -213,8 +250,6 @@ HEADERS += src/activemasternode.h \ src/script/sigcache.h \ src/script/sign.h \ src/script/standard.h \ - src/univalue/univalue.h \ - src/univalue/univalue_escapes.h \ src/leveldb/db/builder.h \ src/leveldb/db/db_impl.h \ src/leveldb/db/db_iter.h \ @@ -292,17 +327,17 @@ HEADERS += src/activemasternode.h \ src/secp256k1/src/testrand.h \ src/secp256k1/src/testrand_impl.h \ src/secp256k1/src/util.h \ - src/test/data/alertTests.raw.h \ - src/test/data/base58_encode_decode.json.h \ - src/test/data/base58_keys_invalid.json.h \ - src/test/data/base58_keys_valid.json.h \ - src/test/data/script_invalid.json.h \ - src/test/data/script_valid.json.h \ - src/test/data/sig_canonical.json.h \ - src/test/data/sig_noncanonical.json.h \ - src/test/data/sighash.json.h \ - src/test/data/tx_invalid.json.h \ - src/test/data/tx_valid.json.h \ + src/test/data/alertTests.raw \ + src/test/data/base58_encode_decode.json \ + src/test/data/base58_keys_invalid.json \ + src/test/data/base58_keys_valid.json \ + src/test/data/script_invalid.json \ + src/test/data/script_valid.json \ + src/test/data/sig_canonical.json \ + src/test/data/sig_noncanonical.json \ + src/test/data/sighash.json \ + src/test/data/tx_invalid.json \ + src/test/data/tx_valid.json \ src/leveldb/helpers/memenv/memenv.h \ src/leveldb/include/leveldb/c.h \ src/leveldb/include/leveldb/cache.h \ @@ -352,7 +387,11 @@ SOURCES += src/activemasternode.cpp \ src/alert.cpp \ src/allocators.cpp \ src/amount.cpp \ + src/arith_uint256.cpp \ src/base58.cpp \ + src/bip38.cpp \ + src/bip39.cpp \ + src/blocksignature.cpp \ src/bloom.cpp \ src/chain.cpp \ src/chainparams.cpp \ @@ -364,18 +403,19 @@ SOURCES += src/activemasternode.cpp \ src/core_read.cpp \ src/core_write.cpp \ src/crypter.cpp \ - src/obfuscation-relay.cpp \ - src/obfuscation.cpp \ src/dapscoin-cli.cpp \ src/dapscoin-tx.cpp \ - src/dapscoin.cpp \ - src/wallet/db.cpp \ + src/dapscoind.cpp \ + src/db.cpp \ src/eccryptoverify.cpp \ + src/ecdhutil.cpp \ src/ecwrapper.cpp \ - src/editaddressdialog.cpp \ src/hash.cpp \ + src/hdchain.cpp \ + src/httprpc.cpp \ + src/httpserver.cpp \ src/init.cpp \ - src/swifttx.cpp \ + src/kernel.cpp \ src/key.cpp \ src/keystore.cpp \ src/leveldbwrapper.cpp \ @@ -388,17 +428,34 @@ SOURCES += src/activemasternode.cpp \ src/masternodeman.cpp \ src/merkleblock.cpp \ src/miner.cpp \ + src/mintpool.cpp \ src/net.cpp \ src/netbase.cpp \ src/noui.cpp \ + src/obfuscation-relay.cpp \ + src/obfuscation.cpp \ + src/poa.cpp \ src/pow.cpp \ src/protocol.cpp \ src/pubkey.cpp \ src/random.cpp \ src/rest.cpp \ + src/scheduler.cpp \ + src/stakeinput.cpp \ + src/swifttx.cpp \ + src/sync.cpp \ + src/timedata.cpp \ + src/torcontrol.cpp \ + src/txdb.cpp \ + src/txmempool.cpp \ + src/uint256.cpp \ + src/util.cpp \ + src/utilmoneystr.cpp \ + src/utilstrencodings.cpp \ + src/utiltime.cpp \ + src/validationinterface.cpp \ src/rpc/blockchain.cpp \ src/rpc/client.cpp \ - src/wallet/rpcdump.cpp \ src/rpc/budget.cpp \ src/rpc/masternode.cpp \ src/rpc/mining.cpp \ @@ -407,16 +464,9 @@ SOURCES += src/activemasternode.cpp \ src/rpc/protocol.cpp \ src/rpc/rawtransaction.cpp \ src/rpc/server.cpp \ + src/wallet/db.cpp \ + src/wallet/rpcdump.cpp \ src/wallet/rpcwallet.cpp \ - src/sync.cpp \ - src/timedata.cpp \ - src/txdb.cpp \ - src/txmempool.cpp \ - src/uint256.cpp \ - src/util.cpp \ - src/utilmoneystr.cpp \ - src/utilstrencodings.cpp \ - src/utiltime.cpp \ src/wallet/wallet.cpp \ src/wallet/wallet_ismine.cpp \ src/wallet/walletdb.cpp \ @@ -449,13 +499,19 @@ SOURCES += src/activemasternode.cpp \ src/json/json_spirit_writer.cpp \ src/primitives/block.cpp \ src/primitives/transaction.cpp \ + src/qt/2faconfirmdialog.cpp \ + src/qt/2fadialog.cpp \ + src/qt/2faqrdialog.cpp \ src/qt/addressbookpage.cpp \ src/qt/addresstablemodel.cpp \ src/qt/askpassphrasedialog.cpp \ + src/qt/bantablemodel.cpp \ + src/qt/bip38tooldialog.cpp \ src/qt/bitcoinaddressvalidator.cpp \ src/qt/bitcoinamountfield.cpp \ src/qt/bitcoingui.cpp \ src/qt/bitcoinunits.cpp \ + src/qt/blockexplorer.cpp \ src/qt/clientmodel.cpp \ src/qt/coincontroldialog.cpp \ src/qt/coincontroltreewidget.cpp \ @@ -463,25 +519,34 @@ SOURCES += src/activemasternode.cpp \ src/qt/dapscoin.cpp \ src/qt/dapscoinstrings.cpp \ src/qt/editaddressdialog.cpp \ + src/qt/encryptdialog.cpp \ + src/qt/entermnemonics.cpp \ src/qt/guiutil.cpp \ src/qt/historypage.cpp \ + src/qt/importorcreate.cpp \ src/qt/intro.cpp \ + src/qt/lockdialog.cpp \ + src/qt/masternodelist.cpp \ + src/qt/multisenddialog.cpp \ + src/qt/multisigdialog.cpp \ src/qt/networkstyle.cpp \ src/qt/notificator.cpp \ src/qt/openuridialog.cpp \ src/qt/optionsdialog.cpp \ - src/qt/optionspage.cpp \ src/qt/optionsmodel.cpp \ + src/qt/optionspage.cpp \ src/qt/overviewpage.cpp \ - src/qt/paymentrequest.pb.cc \ src/qt/paymentrequestplus.cpp \ src/qt/paymentserver.cpp \ src/qt/peertablemodel.cpp \ + src/qt/platformstyle.cpp \ + src/qt/qgoogleauth.cpp \ src/qt/qvalidatedlineedit.cpp \ src/qt/qvaluecombobox.cpp \ src/qt/receivecoinsdialog.cpp \ src/qt/receiverequestdialog.cpp \ src/qt/recentrequeststablemodel.cpp \ + src/qt/revealtxdialog.cpp \ src/qt/rpcconsole.cpp \ src/qt/sendcoinsdialog.cpp \ src/qt/sendcoinsentry.cpp \ @@ -496,6 +561,7 @@ SOURCES += src/activemasternode.cpp \ src/qt/transactiontablemodel.cpp \ src/qt/transactionview.cpp \ src/qt/txentry.cpp \ + src/qt/unlockdialog.cpp \ src/qt/utilitydialog.cpp \ src/qt/walletframe.cpp \ src/qt/walletmodel.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6e7e47825f..3e3bed670a 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -18,7 +18,7 @@ QT_TS = \ qt/locale/dapscoin_fr_FR.ts \ qt/locale/dapscoin_hi_IN.ts \ qt/locale/dapscoin_hr.ts \ - qt/locale/dapscoin_hr_HR.ts \ + qt/locale/dapscoin_hr_HR.ts \ qt/locale/dapscoin_it.ts \ qt/locale/dapscoin_ja.ts \ qt/locale/dapscoin_ko_KR.ts \ diff --git a/src/db.cpp b/src/db.cpp deleted file mode 100644 index f4080895c3..0000000000 --- a/src/db.cpp +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "db.h" - -#include "addrman.h" -#include "hash.h" -#include "protocol.h" -#include "util.h" -#include "utilstrencodings.h" - -#include - -#ifndef WIN32 -#include -#endif - -#include -#include -#include - -#include - -using namespace std; -using namespace boost; - - -unsigned int nWalletDBUpdated; - - -// -// CDB -// - -CDBEnv bitdb; - -void CDBEnv::EnvShutdown() -{ - if (!fDbEnvInit) - return; - - fDbEnvInit = false; - int ret = dbenv.close(0); - if (ret != 0) - LogPrintf("CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); - if (!fMockDb) - DbEnv(0).remove(strPath.c_str(), 0); -} - -CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) -{ - fDbEnvInit = false; - fMockDb = false; -} - -CDBEnv::~CDBEnv() -{ - EnvShutdown(); -} - -void CDBEnv::Close() -{ - EnvShutdown(); -} - -bool CDBEnv::Open(const boost::filesystem::path& pathIn) -{ - if (fDbEnvInit) - return true; - - boost::this_thread::interruption_point(); - - strPath = pathIn.string(); - boost::filesystem::path pathLogDir = pathIn / "database"; - TryCreateDirectory(pathLogDir); - boost::filesystem::path pathErrorFile = pathIn / "db.log"; - LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string()); - - unsigned int nEnvFlags = 0; - if (GetBoolArg("-privdb", true)) - nEnvFlags |= DB_PRIVATE; - - dbenv.set_lg_dir(pathLogDir.string().c_str()); - dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet - dbenv.set_lg_bsize(0x10000); - dbenv.set_lg_max(1048576); - dbenv.set_lk_max_locks(40000); - dbenv.set_lk_max_objects(40000); - dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); - dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(strPath.c_str(), - DB_CREATE | - DB_INIT_LOCK | - DB_INIT_LOG | - DB_INIT_MPOOL | - DB_INIT_TXN | - DB_THREAD | - DB_RECOVER | - nEnvFlags, - S_IRUSR | S_IWUSR); - if (ret != 0) - return error("CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret)); - - fDbEnvInit = true; - fMockDb = false; - return true; -} - -void CDBEnv::MakeMock() -{ - if (fDbEnvInit) - throw runtime_error("CDBEnv::MakeMock : Already initialized"); - - boost::this_thread::interruption_point(); - - LogPrint("db", "CDBEnv::MakeMock\n"); - - dbenv.set_cachesize(1, 0, 1); - dbenv.set_lg_bsize(10485760 * 4); - dbenv.set_lg_max(10485760); - dbenv.set_lk_max_locks(10000); - dbenv.set_lk_max_objects(10000); - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); - int ret = dbenv.open(NULL, - DB_CREATE | - DB_INIT_LOCK | - DB_INIT_LOG | - DB_INIT_MPOOL | - DB_INIT_TXN | - DB_THREAD | - DB_PRIVATE, - S_IRUSR | S_IWUSR); - if (ret > 0) - throw runtime_error(strprintf("CDBEnv::MakeMock : Error %d opening database environment.", ret)); - - fDbEnvInit = true; - fMockDb = true; -} - -CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) -{ - LOCK(cs_db); - assert(mapFileUseCount.count(strFile) == 0); - - Db db(&dbenv, 0); - int result = db.verify(strFile.c_str(), NULL, NULL, 0); - if (result == 0) - return VERIFY_OK; - else if (recoverFunc == NULL) - return RECOVER_FAIL; - - // Try to recover: - bool fRecovered = (*recoverFunc)(*this, strFile); - return (fRecovered ? RECOVER_OK : RECOVER_FAIL); -} - -bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector& vResult) -{ - LOCK(cs_db); - assert(mapFileUseCount.count(strFile) == 0); - - u_int32_t flags = DB_SALVAGE; - if (fAggressive) - flags |= DB_AGGRESSIVE; - - stringstream strDump; - - Db db(&dbenv, 0); - int result = db.verify(strFile.c_str(), NULL, &strDump, flags); - if (result == DB_VERIFY_BAD) { - LogPrintf("CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n"); - if (!fAggressive) { - LogPrintf("CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n"); - return false; - } - } - if (result != 0 && result != DB_VERIFY_BAD) { - LogPrintf("CDBEnv::Salvage : Database salvage failed with result %d.\n", result); - return false; - } - - // Format of bdb dump is ascii lines: - // header lines... - // HEADER=END - // hexadecimal key - // hexadecimal value - // ... repeated - // DATA=END - - string strLine; - while (!strDump.eof() && strLine != "HEADER=END") - getline(strDump, strLine); // Skip past header - - std::string keyHex, valueHex; - while (!strDump.eof() && keyHex != "DATA=END") { - getline(strDump, keyHex); - if (keyHex != "DATA=END") { - getline(strDump, valueHex); - vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex))); - } - } - - return (result == 0); -} - - -void CDBEnv::CheckpointLSN(const std::string& strFile) -{ - dbenv.txn_checkpoint(0, 0, 0); - if (fMockDb) - return; - dbenv.lsn_reset(strFile.c_str(), 0); -} - - -CDB::CDB(const std::string& strFilename, const char* pszMode) : pdb(NULL), activeTxn(NULL) -{ - int ret; - fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); - if (strFilename.empty()) - return; - - bool fCreate = strchr(pszMode, 'c') != NULL; - unsigned int nFlags = DB_THREAD; - if (fCreate) - nFlags |= DB_CREATE; - - { - LOCK(bitdb.cs_db); - if (!bitdb.Open(GetDataDir())) - throw runtime_error("CDB : Failed to open database environment."); - - strFile = strFilename; - ++bitdb.mapFileUseCount[strFile]; - pdb = bitdb.mapDb[strFile]; - if (pdb == NULL) { - pdb = new Db(&bitdb.dbenv, 0); - - bool fMockDb = bitdb.IsMock(); - if (fMockDb) { - DbMpoolFile* mpf = pdb->get_mpf(); - ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); - if (ret != 0) - throw runtime_error(strprintf("CDB : Failed to configure for no temp file backing for database %s", strFile)); - } - - ret = pdb->open(NULL, // Txn pointer - fMockDb ? NULL : strFile.c_str(), // Filename - fMockDb ? strFile.c_str() : "main", // Logical db name - DB_BTREE, // Database type - nFlags, // Flags - 0); - - if (ret != 0) { - delete pdb; - pdb = NULL; - --bitdb.mapFileUseCount[strFile]; - std::string tempCopy(strFile); - strFile = ""; - throw std::runtime_error(strprintf("CDB : Error %d, can't open database %s", ret, tempCopy)); - } - - if (fCreate && !Exists(string("version"))) { - bool fTmp = fReadOnly; - fReadOnly = false; - WriteVersion(CLIENT_VERSION); - fReadOnly = fTmp; - } - - bitdb.mapDb[strFile] = pdb; - } - } -} - -void CDB::Flush() -{ - if (activeTxn) - return; - - // Flush database activity from memory pool to disk log - unsigned int nMinutes = 0; - if (fReadOnly) - nMinutes = 1; - - bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); -} - -void CDB::Close() -{ - if (!pdb) - return; - if (activeTxn) - activeTxn->abort(); - activeTxn = NULL; - pdb = NULL; - - Flush(); - - { - LOCK(bitdb.cs_db); - --bitdb.mapFileUseCount[strFile]; - } -} - -void CDBEnv::CloseDb(const string& strFile) -{ - { - LOCK(cs_db); - if (mapDb[strFile] != NULL) { - // Close the database handle - Db* pdb = mapDb[strFile]; - pdb->close(0); - delete pdb; - mapDb[strFile] = NULL; - } - } -} - -bool CDBEnv::RemoveDb(const string& strFile) -{ - this->CloseDb(strFile); - - LOCK(cs_db); - int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); - return (rc == 0); -} - -bool CDB::Rewrite(const string& strFile, const char* pszSkip) -{ - while (true) { - { - LOCK(bitdb.cs_db); - if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { - // Flush log data to the dat file - bitdb.CloseDb(strFile); - bitdb.CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(strFile); - - bool fSuccess = true; - LogPrintf("CDB::Rewrite : Rewriting %s...\n", strFile); - string strFileRes = strFile + ".rewrite"; - { // surround usage of db with extra {} - CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(&bitdb.dbenv, 0); - - int ret = pdbCopy->open(NULL, // Txn pointer - strFileRes.c_str(), // Filename - "main", // Logical db name - DB_BTREE, // Database type - DB_CREATE, // Flags - 0); - if (ret > 0) { - LogPrintf("CDB::Rewrite : Can't create database file %s\n", strFileRes); - fSuccess = false; - } - - Dbc* pcursor = db.GetCursor(); - if (pcursor) - while (fSuccess) { - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); - if (ret == DB_NOTFOUND) { - pcursor->close(); - break; - } else if (ret != 0) { - pcursor->close(); - fSuccess = false; - break; - } - if (pszSkip && - strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) - continue; - if (strncmp(&ssKey[0], "\x07version", 8) == 0) { - // Update version: - ssValue.clear(); - ssValue << CLIENT_VERSION; - } - Dbt datKey(&ssKey[0], ssKey.size()); - Dbt datValue(&ssValue[0], ssValue.size()); - int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); - if (ret2 > 0) - fSuccess = false; - } - if (fSuccess) { - db.Close(); - bitdb.CloseDb(strFile); - if (pdbCopy->close(0)) - fSuccess = false; - delete pdbCopy; - } - } - if (fSuccess) { - Db dbA(&bitdb.dbenv, 0); - if (dbA.remove(strFile.c_str(), NULL, 0)) - fSuccess = false; - Db dbB(&bitdb.dbenv, 0); - if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) - fSuccess = false; - } - if (!fSuccess) - LogPrintf("CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes); - return fSuccess; - } - } - MilliSleep(100); - } - return false; -} - - -void CDBEnv::Flush(bool fShutdown) -{ - int64_t nStart = GetTimeMillis(); - // Flush log data to the actual data file on all files that are not in use - LogPrint("db", "CDBEnv::Flush : Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); - if (!fDbEnvInit) - return; - { - LOCK(cs_db); - map::iterator mi = mapFileUseCount.begin(); - while (mi != mapFileUseCount.end()) { - string strFile = (*mi).first; - int nRefCount = (*mi).second; - LogPrint("db", "CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount); - if (nRefCount == 0) { - // Move log data to the dat file - CloseDb(strFile); - LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile); - dbenv.txn_checkpoint(0, 0, 0); - LogPrint("db", "CDBEnv::Flush : %s detach\n", strFile); - if (!fMockDb) - dbenv.lsn_reset(strFile.c_str(), 0); - LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile); - mapFileUseCount.erase(mi++); - } else - mi++; - } - LogPrint("db", "CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); - if (fShutdown) { - char** listp; - if (mapFileUseCount.empty()) { - dbenv.log_archive(&listp, DB_ARCH_REMOVE); - Close(); - if (!fMockDb) - boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); - } - } - } -} diff --git a/src/db.h b/src/db.h deleted file mode 100644 index d380c2a307..0000000000 --- a/src/db.h +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_DB_H -#define BITCOIN_DB_H - -#include "clientversion.h" -#include "serialize.h" -#include "streams.h" -#include "sync.h" -#include "version.h" - -#include -#include -#include - -#include - -#include - -class CDiskBlockIndex; -class COutPoint; - -struct CBlockLocator; - -extern unsigned int nWalletDBUpdated; - -void ThreadFlushWalletDB(const std::string& strWalletFile); - - -class CDBEnv -{ -private: - bool fDbEnvInit; - bool fMockDb; - // Don't change into boost::filesystem::path, as that can result in - // shutdown problems/crashes caused by a static initialized internal pointer. - std::string strPath; - - void EnvShutdown(); - -public: - mutable CCriticalSection cs_db; - DbEnv dbenv; - std::map mapFileUseCount; - std::map mapDb; - - CDBEnv(); - ~CDBEnv(); - void MakeMock(); - bool IsMock() { return fMockDb; } - - /** - * Verify that database file strFile is OK. If it is not, - * call the callback to try to recover. - * This must be called BEFORE strFile is opened. - * Returns true if strFile is OK. - */ - enum VerifyResult { VERIFY_OK, - RECOVER_OK, - RECOVER_FAIL }; - VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)); - /** - * Salvage data from a file that Verify says is bad. - * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation). - * Appends binary key/value pairs to vResult, returns true if successful. - * NOTE: reads the entire database into memory, so cannot be used - * for huge databases. - */ - typedef std::pair, std::vector > KeyValPair; - bool Salvage(std::string strFile, bool fAggressive, std::vector& vResult); - - bool Open(const boost::filesystem::path& path); - void Close(); - void Flush(bool fShutdown); - void CheckpointLSN(const std::string& strFile); - - void CloseDb(const std::string& strFile); - bool RemoveDb(const std::string& strFile); - - DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) - { - DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(NULL, &ptxn, flags); - if (!ptxn || ret != 0) - return NULL; - return ptxn; - } -}; - -extern CDBEnv bitdb; - - -/** RAII class that provides access to a Berkeley database */ -class CDB -{ -protected: - Db* pdb; - std::string strFile; - DbTxn* activeTxn; - bool fReadOnly; - - explicit CDB(const std::string& strFilename, const char* pszMode = "r+"); - ~CDB() { Close(); } - -public: - void Flush(); - void Close(); - -private: - CDB(const CDB&); - void operator=(const CDB&); - -protected: - template - bool Read(const K& key, T& value) - { - if (!pdb) - return false; - - // Key - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(1000); - ssKey << key; - Dbt datKey(&ssKey[0], ssKey.size()); - - // Read - Dbt datValue; - datValue.set_flags(DB_DBT_MALLOC); - int ret = pdb->get(activeTxn, &datKey, &datValue, 0); - memset(datKey.get_data(), 0, datKey.get_size()); - if (datValue.get_data() == NULL) - return false; - - // Unserialize value - try { - CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); - ssValue >> value; - } catch (const std::exception&) { - return false; - } - - // Clear and free memory - memset(datValue.get_data(), 0, datValue.get_size()); - free(datValue.get_data()); - return (ret == 0); - } - - template - bool Write(const K& key, const T& value, bool fOverwrite = true) - { - if (!pdb) - return false; - if (fReadOnly) - assert(!"Write called on database in read-only mode"); - - // Key - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(1000); - ssKey << key; - Dbt datKey(&ssKey[0], ssKey.size()); - - // Value - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(10000); - ssValue << value; - Dbt datValue(&ssValue[0], ssValue.size()); - - // Write - int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); - - // Clear memory in case it was a private key - memset(datKey.get_data(), 0, datKey.get_size()); - memset(datValue.get_data(), 0, datValue.get_size()); - return (ret == 0); - } - - template - bool Erase(const K& key) - { - if (!pdb) - return false; - if (fReadOnly) - assert(!"Erase called on database in read-only mode"); - - // Key - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(1000); - ssKey << key; - Dbt datKey(&ssKey[0], ssKey.size()); - - // Erase - int ret = pdb->del(activeTxn, &datKey, 0); - - // Clear memory - memset(datKey.get_data(), 0, datKey.get_size()); - return (ret == 0 || ret == DB_NOTFOUND); - } - - template - bool Exists(const K& key) - { - if (!pdb) - return false; - - // Key - CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(1000); - ssKey << key; - Dbt datKey(&ssKey[0], ssKey.size()); - - // Exists - int ret = pdb->exists(activeTxn, &datKey, 0); - - // Clear memory - memset(datKey.get_data(), 0, datKey.get_size()); - return (ret == 0); - } - - Dbc* GetCursor() - { - if (!pdb) - return NULL; - Dbc* pcursor = NULL; - int ret = pdb->cursor(NULL, &pcursor, 0); - if (ret != 0) - return NULL; - return pcursor; - } - - int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT) - { - // Read at cursor - Dbt datKey; - datKey.set_data(NULL); - if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { - datKey.set_data(&ssKey[0]); - datKey.set_size(ssKey.size()); - } - Dbt datValue; - datValue.set_data(NULL); - if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { - datValue.set_data(&ssValue[0]); - datValue.set_size(ssValue.size()); - } - datKey.set_flags(DB_DBT_MALLOC); - datValue.set_flags(DB_DBT_MALLOC); - int ret = pcursor->get(&datKey, &datValue, fFlags); - if (ret != 0) { - if (datKey.get_data() != NULL) - free(datKey.get_data()); - if (datValue.get_data() != NULL) - free(datValue.get_data()); - - return ret; - } - else if (datKey.get_data() == NULL || datValue.get_data() == NULL) { - if (datKey.get_data() != NULL) - free(datKey.get_data()); - if (datValue.get_data() != NULL) - free(datValue.get_data()); - - return 99999; - } - - // Convert to streams - ssKey.SetType(SER_DISK); - ssKey.clear(); - ssKey.write((char*)datKey.get_data(), datKey.get_size()); - ssValue.SetType(SER_DISK); - ssValue.clear(); - ssValue.write((char*)datValue.get_data(), datValue.get_size()); - - // Clear and free memory - memset(datKey.get_data(), 0, datKey.get_size()); - memset(datValue.get_data(), 0, datValue.get_size()); - free(datKey.get_data()); - free(datValue.get_data()); - return 0; - } - -public: - bool TxnBegin() - { - if (!pdb || activeTxn) - return false; - DbTxn* ptxn = bitdb.TxnBegin(); - if (!ptxn) - return false; - activeTxn = ptxn; - return true; - } - - bool TxnCommit() - { - if (!pdb || !activeTxn) - return false; - int ret = activeTxn->commit(0); - activeTxn = NULL; - return (ret == 0); - } - - bool TxnAbort() - { - if (!pdb || !activeTxn) - return false; - int ret = activeTxn->abort(); - activeTxn = NULL; - return (ret == 0); - } - - bool ReadVersion(int& nVersion) - { - nVersion = 0; - return Read(std::string("version"), nVersion); - } - - bool WriteVersion(int nVersion) - { - return Write(std::string("version"), nVersion); - } - - bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); -}; - -#endif // BITCOIN_DB_H From 385829df38768f049cb8788a806c31f58bd3a6e2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 1 Jan 2020 16:25:08 -0500 Subject: [PATCH 0067/1888] Update depends from upstream --- depends/.gitignore | 2 + depends/Makefile | 18 +- depends/README.md | 42 +- depends/config.guess | 584 +++--- depends/config.site.in | 3 +- depends/config.sub | 1656 ++++++++--------- depends/description.md | 2 +- depends/hosts/darwin.mk | 2 +- depends/hosts/default.mk | 4 + depends/packages/boost.mk | 6 +- depends/packages/expat.mk | 3 +- depends/packages/libX11.mk | 4 + depends/packages/libXau.mk | 4 + depends/packages/libXext.mk | 4 + depends/packages/libxcb.mk | 1 + depends/packages/miniupnpc.mk | 6 +- depends/packages/native_biplist.mk | 17 +- depends/packages/native_ds_store.mk | 6 +- depends/packages/native_mac_alias.mk | 15 +- depends/packages/openssl.mk | 8 + depends/packages/packages.mk | 6 +- depends/packages/protobuf.mk | 5 + depends/packages/qrencode.mk | 4 + depends/packages/qt.mk | 19 +- depends/packages/xextproto.mk | 3 +- depends/packages/xproto.mk | 4 + depends/packages/xtrans.mk | 4 + depends/packages/zeromq.mk | 5 +- ...0x_powerpc_mips_mipsel_architectures.patch | 17 + .../0001-fix-build-with-older-mingw64.patch | 16 +- 30 files changed, 1268 insertions(+), 1202 deletions(-) create mode 100644 depends/patches/qt/fix_s390x_powerpc_mips_mipsel_architectures.patch diff --git a/depends/.gitignore b/depends/.gitignore index 3cb4b9ac15..72734102c5 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -8,3 +8,5 @@ i686* mips* arm* aarch64* +riscv32* +riscv64* diff --git a/depends/Makefile b/depends/Makefile index 78ba36692e..ee046e3e45 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -1,6 +1,7 @@ .NOTPARALLEL : SOURCES_PATH ?= $(BASEDIR)/sources +WORK_PATH = $(BASEDIR)/work BASE_CACHE ?= $(BASEDIR)/built SDK_PATH ?= $(BASEDIR)/SDKs NO_QT ?= @@ -22,7 +23,6 @@ BUILD_ID_SALT ?= salt host:=$(BUILD) ifneq ($(HOST),) host:=$(HOST) -host_toolchain:=$(HOST)- endif ifneq ($(DEBUG),) @@ -31,9 +31,9 @@ else release_type=release endif -base_build_dir=$(BASEDIR)/work/build -base_staging_dir=$(BASEDIR)/work/staging -base_download_dir=$(BASEDIR)/work/download +base_build_dir=$(WORK_PATH)/build +base_staging_dir=$(WORK_PATH)/staging +base_download_dir=$(WORK_PATH)/download canonical_host:=$(shell ./config.sub $(HOST)) build:=$(shell ./config.sub $(BUILD)) @@ -173,13 +173,19 @@ $(host_prefix)/share/config.site: check-packages check-packages: check-sources +clean-all: clean + @rm -rf $(SOURCES_PATH) x86_64* i686* mips* arm* aarch64* riscv32* riscv64* + +clean: + @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD) + install: check-packages $(host_prefix)/share/config.site download-one: check-sources $(all_sources) download-osx: - @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one + @$(MAKE) -s HOST=x86_64-apple-darwin14 download-one download-linux: @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one download-win: @@ -188,4 +194,4 @@ download: download-osx download-linux download-win $(foreach package,$(all_packages),$(eval $(call ext_add_stages,$(package)))) -.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources +.PHONY: install cached clean clean-all download-one download-osx download-linux download-win download check-packages check-sources diff --git a/depends/README.md b/depends/README.md index acade2b371..d983dfef34 100644 --- a/depends/README.md +++ b/depends/README.md @@ -22,34 +22,51 @@ Common `host-platform-triplets` for cross compilation are: - `i686-w64-mingw32` for Win32 - `x86_64-w64-mingw32` for Win64 -- `x86_64-apple-darwin11` for MacOSX +- `x86_64-apple-darwin14` for macOS - `arm-linux-gnueabihf` for Linux ARM 32 bit - `aarch64-linux-gnu` for Linux ARM 64 bit +- `riscv32-linux-gnu` for Linux RISC-V 32 bit +- `riscv64-linux-gnu` for Linux RISC-V 64 bit No other options are needed, the paths are automatically configured. -Install the required dependencies: Ubuntu & Debian --------------------------------------------------- +### Install the required dependencies: Ubuntu & Debian -For macOS cross compilation: +#### For macOS cross compilation - sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools + sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools -For Win32/Win64 cross compilation: +#### For Win32/Win64 cross compilation - see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux) -For linux (including i386, ARM) cross compilation: +#### For linux (including i386, ARM) cross compilation - sudo apt-get install curl g++-aarch64-linux-gnu g++-4.8-aarch64-linux-gnu gcc-4.8-aarch64-linux-gnu binutils-aarch64-linux-gnu g++-arm-linux-gnueabihf g++-4.8-arm-linux-gnueabihf gcc-4.8-arm-linux-gnueabihf binutils-arm-linux-gnueabihf g++-4.8-multilib gcc-4.8-multilib binutils-gold bsdmainutils +Common linux dependencies: + sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch -Dependency Options: +For linux ARM cross compilation: + + sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf + +For linux AARCH64 cross compilation: + + sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + +For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): + + sudo apt-get install g++-riscv64-linux-gnu binutils-riscv64-linux-gnu + +RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_daps` executable (see https://github.com/bitcoin/bitcoin/pull/13543), +this is apparently fixed in gcc-8.1.0. + +### Dependency Options The following can be set when running make: make FOO=bar SOURCES_PATH: downloaded sources will be placed here BASE_CACHE: built packages will be placed here - SDK_PATH: Path where sdk's can be found (used by OSX) + SDK_PATH: Path where sdk's can be found (used by macOS) FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up NO_QT: Don't download/build/cache qt and its dependencies NO_ZMQ: Don't download/build/cache packages needed for enabling zeromq @@ -62,10 +79,10 @@ The following can be set when running make: make FOO=bar If some packages are not built, for example `make NO_WALLET=1`, the appropriate options will be passed to bitcoin's configure. In this case, `--disable-wallet`. -Additional targets: +### Additional targets download: run 'make download' to fetch all sources without building them - download-osx: run 'make download-osx' to fetch all sources needed for osx builds + download-osx: run 'make download-osx' to fetch all sources needed for macOS builds download-win: run 'make download-win' to fetch all sources needed for win builds download-linux: run 'make download-linux' to fetch all sources needed for linux builds @@ -73,4 +90,3 @@ Additional targets: - [description.md](description.md): General description of the depends system - [packages.md](packages.md): Steps for adding packages - diff --git a/depends/config.guess b/depends/config.guess index 69ed3e573b..2b79f6d837 100755 --- a/depends/config.guess +++ b/depends/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2017-03-05' +timestamp='2018-07-06' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-03-05' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -27,7 +27,7 @@ timestamp='2017-03-05' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . @@ -39,7 +39,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -101,15 +101,15 @@ trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && e trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; +case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" ; for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; @@ -132,14 +132,14 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu - eval $set_cc_for_build - cat <<-EOF > $dummy.c + eval "$set_cc_for_build" + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc @@ -149,13 +149,20 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -169,30 +176,30 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + eval "$set_cc_for_build" if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -208,10 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -219,46 +226,55 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" + echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -310,28 +326,19 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos + echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos + echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition @@ -343,7 +350,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} + echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos @@ -370,19 +377,19 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} + echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build + eval "$set_cc_for_build" SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. @@ -395,13 +402,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in @@ -410,25 +417,25 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} + echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not @@ -439,44 +446,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} + echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} + echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} + echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} + echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} + echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} + echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} + echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} + echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -485,23 +492,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} + echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax @@ -527,17 +534,17 @@ EOF AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] then - echo m88k-dg-dgux${UNAME_RELEASE} + echo m88k-dg-dgux"$UNAME_RELEASE" else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else - echo i586-dg-dgux${UNAME_RELEASE} + echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) @@ -554,7 +561,7 @@ EOF echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id @@ -566,14 +573,14 @@ EOF if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -584,7 +591,7 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else @@ -598,7 +605,7 @@ EOF exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc @@ -607,18 +614,18 @@ EOF IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx @@ -633,28 +640,28 @@ EOF echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in + case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in + case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if [ "$HP_ARCH" = "" ]; then + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -687,13 +694,13 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = hppa2.0w ] + if [ "$HP_ARCH" = hppa2.0w ] then - eval $set_cc_for_build + eval "$set_cc_for_build" # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -712,15 +719,15 @@ EOF HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -745,11 +752,11 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) @@ -758,7 +765,7 @@ EOF *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) @@ -766,9 +773,9 @@ EOF exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + echo "$UNAME_MACHINE"-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) @@ -793,128 +800,109 @@ EOF echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} + echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin + echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 + echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 + echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 + echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case "$UNAME_MACHINE" in x86) - echo i586-pc-interix${UNAME_RELEASE} + echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} + echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} + echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin + echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in @@ -928,63 +916,63 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) - eval $set_cc_for_build + eval "$set_cc_for_build" if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + eval "$set_cc_for_build" + sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el @@ -998,70 +986,70 @@ EOF #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" + test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } ;; mips64el:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} + echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} + echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} + echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1075,34 +1063,34 @@ EOF # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx + echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop + echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable + echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} + echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp + echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) @@ -1112,12 +1100,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1127,9 +1115,9 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv32 + echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) @@ -1149,9 +1137,9 @@ EOF exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) @@ -1171,9 +1159,9 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; @@ -1182,28 +1170,28 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} + echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} + echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} + echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} + echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} + echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 @@ -1214,7 +1202,7 @@ EOF *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi @@ -1234,23 +1222,23 @@ EOF exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos + echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} + echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv"$UNAME_RELEASE" else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. @@ -1269,49 +1257,56 @@ EOF echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} + echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} + echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} + echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} + echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} + echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} + echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux${UNAME_RELEASE} + echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} + echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build + eval "$set_cc_for_build" if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub @@ -1322,7 +1317,7 @@ EOF # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` @@ -1330,22 +1325,25 @@ EOF UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} + echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; - NSX-?:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk${UNAME_RELEASE} + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux @@ -1354,7 +1352,7 @@ EOF echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 @@ -1365,7 +1363,7 @@ EOF else UNAME_MACHINE="$cputype" fi - echo ${UNAME_MACHINE}-unknown-plan9 + echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 @@ -1386,14 +1384,14 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in + case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; @@ -1402,32 +1400,44 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos + echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros + echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx + echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 </dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/depends/config.site.in b/depends/config.site.in index 723dc878ae..e633752066 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -71,8 +71,7 @@ fi if test -n "@CXX@" -a -z "${CXX}"; then CXX="@CXX@" fi -CCACHE=$depends_prefix/native/bin/ccache -PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH +PYTHONPATH=$depends_prefix/native/lib/python3/dist-packages:$PYTHONPATH if test -n "@AR@"; then AR=@AR@ diff --git a/depends/config.sub b/depends/config.sub index 40ea5dfe11..c95acc681d 100755 --- a/depends/config.sub +++ b/depends/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2018 Free Software Foundation, Inc. -timestamp='2017-04-02' +timestamp='2018-07-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-04-02' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -33,7 +33,7 @@ timestamp='2017-04-02' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -57,7 +57,7 @@ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -67,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -94,7 +94,7 @@ while test $# -gt 0 ; do *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -110,134 +110,455 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +IFS="-" read -r field1 field2 field3 field4 <&2 + exit 1 ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + *-*-*-*) + basic_machine=$field1-$field2 + os=$field3-$field4 ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ + | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + os=linux-android + ;; + *) + basic_machine=$field1-$field2 + os=$field3 + ;; + esac ;; - -psos*) - os=-psos + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc532* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* | hitachi* \ + | c[123]* | convex* | sun | crds | omron* | dg | ultra | tti* \ + | harris | dolphin | highlevel | gould | cbm | ns | masscomp \ + | apple | axis | knuth | cray | microblaze* \ + | sim | cisco | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + os= + ;; + *) + basic_machine=$field1 + os=$field2 + ;; + esac ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + os=bsd + ;; + a29khif) + basic_machine=a29k-amd + os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=scout + ;; + am29k) + basic_machine=a29k-none + os=bsd + ;; + amdahl) + basic_machine=580-amdahl + os=sysv + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=bsd + ;; + aros) + basic_machine=i386-pc + os=aros + ;; + aux) + basic_machine=m68k-apple + os=aux + ;; + balance) + basic_machine=ns32k-sequent + os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=linux + ;; + cegcc) + basic_machine=arm-unknown + os=cegcc + ;; + cray) + basic_machine=j90-cray + os=unicos + ;; + craynv) + basic_machine=craynv-cray + os=unicosmp + ;; + delta88) + basic_machine=m88k-motorola + os=sysv3 + ;; + dicos) + basic_machine=i686-pc + os=dicos + ;; + djgpp) + basic_machine=i586-pc + os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=ose + ;; + gmicro) + basic_machine=tron-gmicro + os=sysv + ;; + go32) + basic_machine=i386-pc + os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=hms + ;; + harris) + basic_machine=m88k-harris + os=sysv3 + ;; + hp300bsd) + basic_machine=m68k-hp + os=bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=hpux + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=proelf + ;; + i386mach) + basic_machine=i386-mach + os=mach + ;; + vsta) + basic_machine=i386-unknown + os=vsta + ;; + isi68 | isi) + basic_machine=m68k-isi + os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=sysv + ;; + merlin) + basic_machine=ns32k-utek + os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + os=coff + ;; + morphos) + basic_machine=powerpc-unknown + os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=moxiebox + ;; + msdos) + basic_machine=i386-pc + os=msdos + ;; + msys) + basic_machine=i686-pc + os=msys + ;; + mvs) + basic_machine=i370-ibm + os=mvs + ;; + nacl) + basic_machine=le32-unknown + os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=newsos + ;; + news1000) + basic_machine=m68030-sony + os=newsos + ;; + necv70) + basic_machine=v70-nec + os=sysv + ;; + nh3000) + basic_machine=m68k-harris + os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=cxux + ;; + nindy960) + basic_machine=i960-intel + os=nindy + ;; + mon960) + basic_machine=i960-intel + os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=ose + ;; + os68k) + basic_machine=m68k-none + os=os68k + ;; + paragon) + basic_machine=i860-intel + os=osf + ;; + parisc) + basic_machine=hppa-unknown + os=linux + ;; + pw32) + basic_machine=i586-unknown + os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=rdos + ;; + rdos32) + basic_machine=i386-pc + os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=coff + ;; + sa29200) + basic_machine=a29k-amd + os=udi + ;; + sei) + basic_machine=mips-sei + os=seiux + ;; + sps7) + basic_machine=m68k-bull + os=sysv2 + ;; + stratus) + basic_machine=i860-stratus + os=sysv4 + ;; + sun2os3) + basic_machine=m68000-sun + os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=solaris2 + ;; + sv1) + basic_machine=sv1-cray + os=unicos + ;; + symmetry) + basic_machine=i386-sequent + os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=unicos + ;; + t90) + basic_machine=t90-cray + os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + os=tpf + ;; + udi29k) + basic_machine=a29k-amd + os=udi + ;; + ultra3) + basic_machine=a29k-nyu + os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=none + ;; + vaxv) + basic_machine=vax-dec + os=sysv + ;; + vms) + basic_machine=vax-dec + os=vms + ;; + vxworks960) + basic_machine=i960-wrs + os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=vxworks + ;; + xbox) + basic_machine=i686-pc + os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + os=unicos + ;; + *) + basic_machine=$1 + os= + ;; + esac ;; esac @@ -252,12 +573,12 @@ case $basic_machine in | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv6m | armv[78][arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ - | c4x | c8051 | clipper \ + | c4x | c8051 | clipper | csky \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ @@ -296,14 +617,15 @@ case $basic_machine in | mt \ | msp430 \ | nds32 | nds32le | nds32be \ + | nfp \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ + | pdp10 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ - | riscv32 | riscv64 \ + | riscv | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ @@ -316,7 +638,6 @@ case $basic_machine in | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | wasm32 \ - | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown @@ -335,20 +656,23 @@ case $basic_machine in ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) + ;; + m9s12z | m68hcs12z | hcs12z | s12z) + basic_machine=s12z-unknown + os=${os:-none} ;; ms1) basic_machine=mt-unknown ;; - strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown - os=-none + os=${os:-none} ;; xscaleeb) basic_machine=armeb-unknown @@ -364,11 +688,6 @@ case $basic_machine in i*86 | x86_64) basic_machine=$basic_machine-pc ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ @@ -382,7 +701,7 @@ case $basic_machine in | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ + | c8051-* | clipper-* | craynv-* | csky-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ @@ -423,6 +742,7 @@ case $basic_machine in | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ + | nfp-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ @@ -432,7 +752,7 @@ case $basic_machine in | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ - | riscv32-* | riscv64-* \ + | riscv-* | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ @@ -460,141 +780,77 @@ case $basic_machine in ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; abacus) basic_machine=abacus-unknown ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; amd64) basic_machine=x86_64-pc ;; amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv + basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; amiga | amiga-*) basic_machine=m68k-unknown ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; asmjs) basic_machine=asmjs-unknown ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; bluegene*) basic_machine=powerpc-ibm - os=-cnk + os=cnk ;; c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc + os=${os:-unicos} ;; convex-c1) basic_machine=c1-convex - os=-bsd + os=bsd ;; convex-c2) basic_machine=c2-convex - os=-bsd + os=bsd ;; convex-c32) basic_machine=c32-convex - os=-bsd + os=bsd ;; convex-c34) basic_machine=c34-convex - os=-bsd + os=bsd ;; convex-c38) basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp + os=bsd ;; cr16 | cr16-*) basic_machine=cr16-unknown - os=-elf + os=${os:-elf} ;; crds | unos) basic_machine=m68k-crds @@ -607,7 +863,7 @@ case $basic_machine in ;; crx) basic_machine=crx-unknown - os=-elf + os=${os:-elf} ;; da30 | da30-*) basic_machine=m68k-da30 @@ -617,58 +873,38 @@ case $basic_machine in ;; decsystem10* | dec10*) basic_machine=pdp10-dec - os=-tops10 + os=tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec - os=-tops20 + os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; dpx20 | dpx20-*) basic_machine=rs6000-bull - os=-bosx + os=${os:-bosx} ;; - dpx2* | dpx2*-bull) + dpx2*) basic_machine=m68k-bull - os=-sysv3 + os=sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=$os"spe" ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; encore | umax | mmax) basic_machine=ns32k-encore ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose + elxsi) + basic_machine=elxsi-elxsi + os=${os:-bsd} ;; fx2800) basic_machine=i860-alliant @@ -676,45 +912,13 @@ case $basic_machine in genix) basic_machine=ns32k-ns ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 + os=hiuxwe2 ;; hp300-*) basic_machine=m68k-hp ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; @@ -744,200 +948,82 @@ case $basic_machine in hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv32 ;; i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv4 ;; i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=sysv ;; i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach + basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` + os=solaris2 ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta + j90 | j90-cray) + basic_machine=j90-cray + os=${os:-unicos} ;; iris | iris4d) basic_machine=mips-sgi case $os in - -irix*) + irix*) ;; *) - os=-irix4 + os=irix4 ;; esac ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux + basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` ;; m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv + basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; microblaze*) basic_machine=microblaze-xilinx ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; miniframe) basic_machine=m68000-convergent ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari - os=-mint + os=mint ;; mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` ;; mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos + basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown ;; ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos + basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` ;; news-3600 | risc-news) basic_machine=mips-sony - os=-newsos + os=newsos ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) + next | m*-next) basic_machine=m68k-next case $os in - -nextstep* ) + nextstep* ) ;; - -ns2*) - os=-nextstep2 + ns2*) + os=nextstep2 ;; *) - os=-nextstep3 + os=nextstep3 ;; esac ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; np1) basic_machine=np1-gould ;; @@ -950,43 +1036,26 @@ case $basic_machine in nsr-tandem) basic_machine=nsr-tandem ;; + nsv-tandem) + basic_machine=nsv-tandem + ;; nsx-tandem) basic_machine=nsx-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki - os=-proelf + os=proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; pa-hitachi) basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux + os=hiuxwe2 ;; parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` + os=linux ;; pbd) basic_machine=sparc-tti @@ -1001,7 +1070,7 @@ case $basic_machine in basic_machine=i386-pc ;; pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc @@ -1016,16 +1085,16 @@ case $basic_machine in basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould @@ -1035,43 +1104,27 @@ case $basic_machine in ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; rm[46]00) basic_machine=mips-siemens ;; @@ -1084,10 +1137,6 @@ case $basic_machine in s390x | s390x-*) basic_machine=s390x-ibm ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; sb1) basic_machine=mipsisa64sb1-unknown ;; @@ -1096,32 +1145,17 @@ case $basic_machine in ;; sde) basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux + os=${os:-elf} ;; sequent) basic_machine=i386-sequent ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; sh5el) basic_machine=sh5le-unknown ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) + simso-wrs) basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 + os=vxworks ;; spur) basic_machine=spur-unknown @@ -1129,44 +1163,12 @@ case $basic_machine in st2000) basic_machine=m68k-tandem ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; sun3 | sun3-*) basic_machine=m68k-sun ;; @@ -1176,25 +1178,9 @@ case $basic_machine in sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; tile*) basic_machine=$basic_machine-unknown - os=-linux-gnu + os=linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1202,88 +1188,32 @@ case $basic_machine in tx39el) basic_machine=mipstx39el-unknown ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; tower | tower-32) basic_machine=m68k-ncr ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - wasm32) - basic_machine=wasm32-unknown - ;; w65*) basic_machine=w65-wdc - os=-none + os=none ;; w89k-*) basic_machine=hppa1.1-winbond - os=-proelf + os=proelf ;; - xbox) - basic_machine=i686-pc - os=-mingw32 + x64) + basic_machine=x86_64-pc ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim + basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` ;; none) basic_machine=none-none - os=-none + os=${os:-none} ;; # Here we handle the default manufacturer of certain CPU types. It is in @@ -1309,10 +1239,6 @@ case $basic_machine in vax) basic_machine=vax-dec ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; pdp11) basic_machine=pdp11-dec ;; @@ -1322,9 +1248,6 @@ case $basic_machine in sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; cydra) basic_machine=cydra-cydrome ;; @@ -1344,7 +1267,7 @@ case $basic_machine in # Make sure to match an already-canonicalized machine name. ;; *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; esac @@ -1352,10 +1275,10 @@ esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` ;; *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` ;; *) ;; @@ -1363,200 +1286,246 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if [ x$os != x ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + # First match some system type aliases that might get confused + # with valid system types. + # solaris* is a basic system type, with this one exception. + auroraux) + os=auroraux ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` + bluegene*) + os=cnk ;; - -solaris) - os=-solaris2 + solaris1 | solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; - -svr4*) - os=-sysv4 + solaris) + os=solaris2 ;; - -unixware*) - os=-sysv4.2uw + unixware*) + os=sysv4.2uw ;; - -gnu/linux*) + gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; - # First accept the basic system types. + # es1800 is here to avoid being matched by es* (a different OS) + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos + ;; + # Now accept the basic system types. # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) + # Each alternative MUST end in a * to match a version number. + # sysv* is not here because it comes later, after sysvr4. + gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | kopensolaris* | plan9* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | rtu* | xenix* \ + | knetbsd* | mirbsd* | netbsd* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* \ + | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ + | linux-newlib* | linux-musl* | linux-uclibc* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* \ + | morphos* | superux* | rtmk* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; - -qnx*) + qnx*) case $basic_machine in x86-* | i*86-*) ;; *) - os=-nto$os + os=nto-$os ;; esac ;; - -nto-qnx*) + hiux*) + os=hiuxwe2 ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` + nto-qnx*) ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` + sim | xray | os68k* | v88r* \ + | windows* | osx | abug | netware* | os9* \ + | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; - -linux-dietlibc) - os=-linux-dietlibc + linux-dietlibc) + os=linux-dietlibc ;; - -linux*) + linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` + lynx*178) + os=lynxos178 + ;; + lynx*5) + os=lynxos5 + ;; + lynx*) + os=lynxos ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` + mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` ;; - -opened*) - os=-openedition + opened*) + os=openedition ;; - -os400*) - os=-os400 + os400*) + os=os400 ;; - -wince*) - os=-wince + sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; - -osfrose*) - os=-osfrose + sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; - -osf*) - os=-osf + wince*) + os=wince ;; - -utek*) - os=-bsd + utek*) + os=bsd ;; - -dynix*) - os=-bsd + dynix*) + os=bsd ;; - -acis*) - os=-aos + acis*) + os=aos ;; - -atheos*) - os=-atheos + atheos*) + os=atheos ;; - -syllable*) - os=-syllable + syllable*) + os=syllable ;; - -386bsd) - os=-bsd + 386bsd) + os=bsd ;; - -ctix* | -uts*) - os=-sysv + ctix* | uts*) + os=sysv ;; - -nova*) - os=-rtmk-nova + nova*) + os=rtmk-nova ;; - -ns2 ) - os=-nextstep2 + ns2) + os=nextstep2 ;; - -nsk*) - os=-nsk + nsk*) + os=nsk ;; # Preserve the version number of sinix5. - -sinix5.*) + sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf + sinix*) + os=sysv4 ;; - -triton*) - os=-sysv3 + tpf*) + os=tpf ;; - -oss*) - os=-sysv3 + triton*) + os=sysv3 ;; - -svr4) - os=-sysv4 + oss*) + os=sysv3 ;; - -svr3) - os=-sysv3 + svr4*) + os=sysv4 ;; - -sysvr4) - os=-sysv4 + svr3) + os=sysv3 ;; - # This must come after -sysvr4. - -sysv*) + sysvr4) + os=sysv4 ;; - -ose*) - os=-ose + # This must come after sysvr4. + sysv*) ;; - -es1800*) - os=-ose + ose*) + os=ose ;; - -xenix) - os=-xenix + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint + zvmoe) + os=zvmoe ;; - -aros*) - os=-aros + dicos*) + os=dicos ;; - -zvmoe) - os=-zvmoe + pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=eabi + ;; + *) + os=elf + ;; + esac ;; - -dicos*) - os=-dicos + nacl*) ;; - -nacl*) + ios) ;; - -ios) + none) ;; - -none) + *-eabi) ;; *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac @@ -1574,179 +1543,179 @@ else case $basic_machine in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + os=linux ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 ;; pru-*) - os=-elf + os=elf ;; *-be) - os=-beos - ;; - *-haiku) - os=-haiku + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna + os=luna ;; - *-next ) - os=-nextstep + *-next) + os=nextstep ;; *-sequent) - os=-ptx + os=ptx ;; *-crds) - os=-unos + os=unos ;; *-ns) - os=-genix + os=genix ;; i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac fi @@ -1757,79 +1726,82 @@ vendor=unknown case $basic_machine in *-unknown) case $os in - -riscix*) + riscix*) vendor=acorn ;; - -sunos*) + sunos*) vendor=sun ;; - -cnk*|-aix*) + cnk*|-aix*) vendor=ibm ;; - -beos*) + beos*) vendor=be ;; - -hpux*) + hpux*) vendor=hp ;; - -mpeix*) + mpeix*) vendor=hp ;; - -hiux*) + hiux*) vendor=hitachi ;; - -unos*) + unos*) vendor=crds ;; - -dgux*) + dgux*) vendor=dg ;; - -luna*) + luna*) vendor=omron ;; - -genix*) + genix*) vendor=ns ;; - -mvs* | -opened*) + clix*) + vendor=intergraph + ;; + mvs* | opened*) vendor=ibm ;; - -os400*) + os400*) vendor=ibm ;; - -ptx*) + ptx*) vendor=sequent ;; - -tpf*) + tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + vxsim* | vxworks* | windiss*) vendor=wrs ;; - -aux*) + aux*) vendor=apple ;; - -hms*) + hms*) vendor=hitachi ;; - -mpw* | -macos*) + mpw* | macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; - -vos*) + vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$basic_machine-$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/depends/description.md b/depends/description.md index 74f9ef3f20..9fc7093be4 100644 --- a/depends/description.md +++ b/depends/description.md @@ -7,7 +7,7 @@ In theory, binaries for any target OS/architecture can be created, from a builder running any OS/architecture. In practice, build-side tools must be specified when the defaults don't fit, and packages must be amended to work on new hosts. For now, a build architecture of x86_64 is assumed, either on -Linux or OSX. +Linux or macOS. ### No reliance on timestamps diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 4e58bec74e..a1c943d60b 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -1,4 +1,4 @@ -OSX_MIN_VERSION=10.8 +OSX_MIN_VERSION=10.10 OSX_SDK_VERSION=10.11 OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk LD64_VERSION=253.9 diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index 6f60d6b3fd..144e5f88b7 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -1,3 +1,7 @@ +ifneq ($(host),$(build)) +host_toolchain:=$(host)- +endif + default_host_CC = $(host_toolchain)gcc default_host_CXX = $(host_toolchain)g++ default_host_AR = $(host_toolchain)ar diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index d383ebc633..a7226ad7e0 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -15,11 +15,15 @@ $(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win3 $(package)_config_opts_x86_64_mingw32=address-model=64 $(package)_config_opts_i686_mingw32=address-model=32 $(package)_config_opts_i686_linux=address-model=32 architecture=x86 +$(package)_config_opts_s390x_linux=address-model=64 +$(package)_config_opts_sparc64_linux=address-model=64 +$(package)_config_opts_alpha_linux=address-model=64 +$(package)_config_opts_m68k_linux=address-model=32 $(package)_toolset_$(host_os)=gcc $(package)_archiver_$(host_os)=$($(package)_ar) $(package)_toolset_darwin=darwin $(package)_archiver_darwin=$($(package)_libtool) -$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,regex +$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test $(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC endef diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index 531965b28d..a0c1e2d766 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -5,8 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2 define $(package)_set_vars - $(package)_config_opts=--disable-shared --without-docbook - $(package)_config_opts_linux=--with-pic + $(package)_config_opts=--disable-static --without-docbook endef define $(package)_config_cmds diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk index 7c86e62bcd..a013da5192 100644 --- a/depends/packages/libX11.mk +++ b/depends/packages/libX11.mk @@ -10,6 +10,10 @@ $(package)_config_opts=--disable-xkb --disable-static $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk index 69b937aa2e..ce42140689 100644 --- a/depends/packages/libXau.mk +++ b/depends/packages/libXau.mk @@ -10,6 +10,10 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk index 3bcaedbdcc..d94f49f3be 100644 --- a/depends/packages/libXext.mk +++ b/depends/packages/libXext.mk @@ -9,6 +9,10 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index 2d6be4dbbd..3ddd5a7dd9 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -10,6 +10,7 @@ $(package)_config_opts=--disable-static endef define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux &&\ sed "s/pthread-stubs//" -i configure endef diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index db384f1a63..fdbe22cda6 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,12 +1,12 @@ package=miniupnpc -$(package)_version=2.0.20170509 +$(package)_version=2.0.20180203 $(package)_download_path=https://miniupnp.tuxfamily.org/files/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=d3c368627f5cdfb66d3ebd64ca39ba54d6ff14a61966dbecb8dd296b7039f16a +$(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7 define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" -$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)" +$(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)" $(package)_build_opts_mingw32=-f Makefile.mingw $(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)" endef diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk index 3c6e8900f6..c3054cbd1a 100644 --- a/depends/packages/native_biplist.mk +++ b/depends/packages/native_biplist.mk @@ -1,20 +1,15 @@ package=native_biplist -$(package)_version=0.9 -$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_version=1.0.3 +$(package)_download_path=https://bitbucket.org/wooster/biplist/downloads $(package)_file_name=biplist-$($(package)_version).tar.gz -$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=sorted_list.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/sorted_list.patch -endef +$(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6 +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk index 116fa25d38..f99b689ecd 100644 --- a/depends/packages/native_ds_store.mk +++ b/depends/packages/native_ds_store.mk @@ -3,14 +3,14 @@ $(package)_version=1.1.2 $(package)_download_path=https://github.com/al45tair/ds_store/archive/ $(package)_file_name=v$($(package)_version).tar.gz $(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages $(package)_dependencies=native_biplist define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index 488ec8b59c..e60b99dccc 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -1,20 +1,15 @@ package=native_mac_alias -$(package)_version=2.0.6 +$(package)_version=2.0.7 $(package)_download_path=https://github.com/al45tair/mac_alias/archive/ $(package)_file_name=v$($(package)_version).tar.gz -$(package)_sha256_hash=78a3332d9a597eebf09ae652d38ad1e263b28db5c2e6dd725fad357b03b77371 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages -$(package)_patches=python3.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/python3.patch -endef +$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5ee9f17a63..fdfd372806 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -47,10 +47,18 @@ $(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 $(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_armv7l_linux=linux-generic32 $(package)_config_opts_aarch64_linux=linux-generic64 $(package)_config_opts_mipsel_linux=linux-generic32 $(package)_config_opts_mips_linux=linux-generic32 $(package)_config_opts_powerpc_linux=linux-generic32 +$(package)_config_opts_riscv32_linux=linux-generic32 +$(package)_config_opts_riscv64_linux=linux-generic64 +$(package)_config_opts_powerpc64le_linux=linux-generic64 +$(package)_config_opts_sparc64_linux=linux-generic64 +$(package)_config_opts_s390x_linux=linux-generic64 +$(package)_config_opts_alpha_linux=linux-generic64 +$(package)_config_opts_m68k_linux=linux-generic32 $(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc $(package)_config_opts_x86_64_mingw32=mingw64 $(package)_config_opts_i686_mingw32=mingw diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index c115ba7161..ffa0ae3e0c 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,13 +1,9 @@ packages:=boost openssl libevent -native_packages := native_ccache qt_native_packages = native_protobuf qt_packages = qrencode protobuf zlib -qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans -qt_i686_linux_packages:=$(qt_x86_64_linux_packages) -qt_arm_linux_packages:=$(qt_x86_64_linux_packages) -qt_aarch64_linux_packages:=$(qt_x86_64_linux_packages) +qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans qt_darwin_packages=qt qt_mingw32_packages=qt diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk index 54d3fd9245..d201d1183f 100644 --- a/depends/packages/protobuf.mk +++ b/depends/packages/protobuf.mk @@ -11,6 +11,11 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . &&\ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub gtest/build-aux +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index 44fdf1c295..313e4adf2a 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -9,6 +9,10 @@ $(package)_config_opts=--disable-shared -without-tools --disable-sdltest $(package)_config_opts_linux=--with-pic endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub use +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index e3fea4a916..e61589628a 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -7,8 +7,8 @@ $(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352 $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase -$(package)_qt_libs=corelib network widgets gui plugins testlib -$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch +$(package)_qt_libs=corelib network widgets gui plugins testlib concurrent +$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) $(package)_qttranslations_sha256_hash=fb5a47799754af73d3bf501fe513342cfe2fc37f64e80df5533f6110e804220c @@ -76,7 +76,7 @@ $(package)_config_opts += -no-feature-lcdnumber $(package)_config_opts += -no-feature-pdf $(package)_config_opts += -no-feature-printer $(package)_config_opts += -no-feature-printdialog -$(package)_config_opts += -no-feature-concurrent +$(package)_config_opts += -feature-concurrent $(package)_config_opts += -no-feature-sql $(package)_config_opts += -no-feature-statemachine $(package)_config_opts += -no-feature-syntaxhighlighter @@ -107,6 +107,12 @@ $(package)_config_opts_i686_linux = -xplatform linux-g++-32 $(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 $(package)_config_opts_aarch64_linux = -xplatform linux-aarch64-gnu-g++ $(package)_config_opts_riscv64_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ +$(package)_config_opts_s390x_linux += -platform linux-g++ -xplatform linux-g++-64 +$(package)_config_opts_powerpc_linux += -platform linux-g++ -xplatform linux-g++-32 +$(package)_config_opts_powerpc64le_linux += -platform linux-g++ -xplatform linux-g++-64 +$(package)_config_opts_sparc64_linux += -platform linux-g++ -xplatform linux-g++-64 +$(package)_config_opts_alpha_linux += -platform linux-g++ -xplatform linux-g++-64 +$(package)_config_opts_m68k_linux += -platform linux-g++ -xplatform linux-g++-32 $(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-" $(package)_build_env = QT_RCC_TEST=1 $(package)_build_env += QT_RCC_SOURCE_DATE_OVERRIDE=1 @@ -145,6 +151,11 @@ define $(package)_preprocess_cmds cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + echo "!host_build: QMAKE_INCDIR += $(host_prefix)/native/include/c++/v1" >> qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_AR = \$$$$\$$$${CROSS_COMPILE}|QMAKE_AR = $(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_RANLIB=\$$$$\$$$${CROSS_COMPILE}|QMAKE_RANLIB=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_LIBTOOL=\$$$$\$$$${CROSS_COMPILE}|QMAKE_LIBTOOL=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_INSTALL_NAME_TOOL=\$$$$\$$$${CROSS_COMPILE}|QMAKE_INSTALL_NAME_TOOL=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \ sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\ @@ -156,6 +167,7 @@ define $(package)_preprocess_cmds echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch &&\ + patch -p1 -i $($(package)_patch_dir)/fix_s390x_powerpc_mips_mipsel_architectures.patch &&\ echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ @@ -178,6 +190,7 @@ define $(package)_config_cmds endef define $(package)_build_cmds + export PATH=$(build_prefix)/bin:$(PATH) && \ $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ $(MAKE) -C ../qttools/src/linguist/lrelease && \ $(MAKE) -C ../qttools/src/linguist/lupdate && \ diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk index 4adc030929..157b76edf6 100644 --- a/depends/packages/xextproto.mk +++ b/depends/packages/xextproto.mk @@ -3,10 +3,9 @@ $(package)_version=7.3.0 $(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0 -$(package)_patches=fix_aarch64_build.patch define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/fix_aarch64_build.patch + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . endef define $(package)_set_vars diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk index 52fe253c77..23ad5ffa10 100644 --- a/depends/packages/xproto.mk +++ b/depends/packages/xproto.mk @@ -8,6 +8,10 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk index 4c176e1262..1993ff8344 100644 --- a/depends/packages/xtrans.mk +++ b/depends/packages/xtrans.mk @@ -9,6 +9,10 @@ define $(package)_set_vars $(package)_config_opts_linux=--with-pic --disable-shared endef +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index 991a4ae53e..dfbc50580c 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -6,14 +6,15 @@ $(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d83 $(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars - $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf + $(package)_config_opts=--without-docs --disable-shared --without-libsodium --disable-curve --disable-curve-keygen --disable-perf --disable-Werror $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/0001-fix-build-with-older-mingw64.patch && \ - ./autogen.sh + patch -p1 < $($(package)_patch_dir)/0002-disable-pthread_set_name_np.patch && \ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config endef define $(package)_config_cmds diff --git a/depends/patches/qt/fix_s390x_powerpc_mips_mipsel_architectures.patch b/depends/patches/qt/fix_s390x_powerpc_mips_mipsel_architectures.patch new file mode 100644 index 0000000000..57328cfe85 --- /dev/null +++ b/depends/patches/qt/fix_s390x_powerpc_mips_mipsel_architectures.patch @@ -0,0 +1,17 @@ +diff --git a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +index 93729fae..398988c8 100644 +--- a/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h ++++ b/qtbase/src/3rdparty/double-conversion/include/double-conversion/utils.h +@@ -60,9 +60,9 @@ + #if defined(_M_X64) || defined(__x86_64__) || \ + defined(__ARMEL__) || defined(__avr32__) || _M_ARM_FP || \ + defined(__hppa__) || defined(__ia64__) || \ +- defined(__mips__) || \ +- defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ +- defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ ++ defined(__mips__) || defined(__mipsel__) || defined(__i386__) || \ ++ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || defined(__powerpc64el__) || defined(__ppc64el__) || \ ++ defined(__sparc__) || defined(__sparc) || defined(__s390__) || defined(__s390x__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ + defined(__AARCH64EL__) || defined(__aarch64__) || \ diff --git a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch index a6c508fb8a..b911ac5672 100644 --- a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch +++ b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch @@ -1,6 +1,6 @@ -From 1a159c128c69a42d90819375c06a39994f3fbfc1 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Tue, 28 Nov 2017 20:33:25 -0500 +From f6866b0f166ad168618aae64c7fbee8775d3eb23 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:44:58 -0400 Subject: [PATCH] fix build with older mingw64 --- @@ -8,10 +8,10 @@ Subject: [PATCH] fix build with older mingw64 1 file changed, 7 insertions(+) diff --git a/src/windows.hpp b/src/windows.hpp -index 99e889d..e69038e 100644 +index 6c3839fd..2c32ec79 100644 --- a/src/windows.hpp +++ b/src/windows.hpp -@@ -55,6 +55,13 @@ +@@ -58,6 +58,13 @@ #include #include #include @@ -23,8 +23,8 @@ index 99e889d..e69038e 100644 +#include +#endif #include - + #if !defined __MINGW32__ --- -2.7.4 +-- +2.17.1 From 88354b037877d7324fb32924594bc44ec25a6975 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 1 Jan 2020 21:56:19 -0500 Subject: [PATCH 0068/1888] [RPC] Error when calling getreceivedbyaddress with non-wallet address --- src/wallet/rpcwallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e1bfe714b6..d14ae79743 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -524,7 +524,7 @@ UniValue signmessage(const UniValue& params, bool fHelp) UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getreceivedbyaddress \"dapscoinaddress\" ( minconf )\n" "\nReturns the total amount received by the given dapscoinaddress in transactions with at least minconf confirmations.\n" "\nArguments:\n" @@ -547,7 +547,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid DAPS address"); CScript scriptPubKey = GetScriptForDestination(address.Get()); if (!IsMine(*pwalletMain, scriptPubKey)) - return (double)0.0; + throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet"); // Minimum confirmations int nMinDepth = 1; @@ -556,7 +556,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) // Tally CAmount nAmount = 0; - for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; From 2eb7dcb71bc0635d2f9a78f8d2da1f3d7747c57c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 17:35:20 -0500 Subject: [PATCH 0069/1888] Remove unused files --- src/qt/forms/tradingdialog.ui | 3414 ------------------------ src/qt/res/icons/automint_active.png | Bin 884 -> 0 bytes src/qt/res/icons/automint_inactive.png | Bin 421 -> 0 bytes src/qt/res/icons/bittrex.png | Bin 18057 -> 0 bytes src/qt/res/icons/trade.png | Bin 375 -> 0 bytes 5 files changed, 3414 deletions(-) delete mode 100644 src/qt/forms/tradingdialog.ui delete mode 100644 src/qt/res/icons/automint_active.png delete mode 100644 src/qt/res/icons/automint_inactive.png delete mode 100644 src/qt/res/icons/bittrex.png delete mode 100644 src/qt/res/icons/trade.png diff --git a/src/qt/forms/tradingdialog.ui b/src/qt/forms/tradingdialog.ui deleted file mode 100644 index 37d85856fa..0000000000 --- a/src/qt/forms/tradingdialog.ui +++ /dev/null @@ -1,3414 +0,0 @@ - - - tradingDialog - - - - 0 - 0 - 780 - 476 - - - - Bittrex API - - - - true - - - - 10 - 40 - 761 - 431 - - - - - 50 - false - - - - QTabWidget::North - - - 0 - - - - Order Book - - - - - 12 - 60 - 350 - 321 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - - 9 - 50 - false - - - - Qt::ScrollBarAsNeeded - - - - - - 396 - 60 - 350 - 321 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - - 9 - 50 - false - - - - Qt::ScrollBarAsNeeded - - - - - - 10 - 10 - 91 - 16 - - - - Bids - - - - - - 380 - 10 - 91 - 16 - - - - Asks - - - - - - 540 - 10 - 180 - 15 - - - - label - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 160 - 10 - 190 - 15 - - - - label - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 200 - 30 - 150 - 15 - - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 570 - 30 - 150 - 15 - - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 370 - 60 - 20 - 321 - - - - Qt::Vertical - - - - - - Market History - - - - - 10 - 10 - 740 - 371 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - - - - Open Orders - - - - - 10 - 40 - 740 - 341 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - - - - 10 - 10 - 150 - 17 - - - - Advanced View - - - - - - Trade history - - - - - 0 - 10 - 751 - 361 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - - - - Buy - - - - - 30 - 330 - 131 - 23 - - - - Buy DAPS - - - - :/icons/bitcoin:/icons/bitcoin - - - - - - 10 - 110 - 46 - 23 - - - - - 75 - true - - - - Units - - - - - - 310 - 110 - 441 - 23 - - - - - 9 - 75 - true - - - - - - - 310 - 140 - 441 - 23 - - - - - 9 - 75 - true - - - - - - - 780 - 110 - 31 - 23 - - - - DAPS - - - - - - 780 - 140 - 31 - 23 - - - - BTC - - - - - - 10 - 140 - 46 - 23 - - - - - 75 - true - - - - Bid - - - - - - 10 - 170 - 91 - 16 - - - - - 75 - true - - - - Order Type - - - - - - 110 - 110 - 191 - 23 - - - - - 10 - - - - Max - - - - - - 110 - 140 - 191 - 23 - - - - - 10 - - - - - - - 110 - 170 - 191 - 23 - - - - - 10 - - - - - - - 21 - 11 - 227 - 19 - - - - - - - - 75 - true - - - - BTC Available: - - - - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 75 - true - - - - 0.00000000 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - BTC - - - - - - - - - 11 - 301 - 259 - 19 - - - - - - - - 75 - true - - - - Total w/ 0.25% Fee - - - - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 75 - true - - - - false - - - 0.00000000 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 50 - false - - - - BTC - - - - - - - - - 460 - 300 - 281 - 81 - - - - - - - :/images/bittrex - - - - - - Sell - - - - - 780 - 140 - 31 - 23 - - - - BTC - - - - - - 110 - 140 - 191 - 23 - - - - - 10 - - - - - - - 10 - 110 - 46 - 23 - - - - - 75 - true - - - - Units - - - - - - 110 - 110 - 191 - 23 - - - - - 10 - - - - Max - - - - - - 10 - 170 - 91 - 16 - - - - - 75 - true - - - - Order Type - - - - - - 110 - 170 - 191 - 23 - - - - - 10 - - - - - - - 10 - 140 - 46 - 23 - - - - - 75 - true - - - - Bid - - - - - - 780 - 110 - 31 - 23 - - - - DAPS - - - - - - 310 - 110 - 441 - 23 - - - - - 9 - 75 - true - - - - - - - 310 - 140 - 441 - 23 - - - - - 9 - 75 - true - - - - - - - 30 - 330 - 131 - 23 - - - - Sell DAPS - - - - :/icons/bitcoin:/icons/bitcoin - - - - - - 22 - 12 - 258 - 19 - - - - - - - - 75 - true - - - - DAPS Available: - - - - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 75 - true - - - - 0.00000000 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - DAPS - - - - - - - - - 10 - 300 - 268 - 19 - - - - - - - - 75 - true - - - - Total w/ 0.25% Fee - - - - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 75 - true - - - - false - - - 0.00000000 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 50 - false - - - - BTC - - - - - - - - - 460 - 300 - 281 - 81 - - - - - - - :/images/bittrex - - - - - - Balance - - - - - 470 - 30 - 150 - 16 - - - - TextLabel - - - - - - 150 - 30 - 150 - 16 - - - - TextLabel - - - - - - 30 - 30 - 101 - 16 - - - - - 75 - true - - - - DAPS Balance: - - - - - - 320 - 30 - 101 - 16 - - - - - 75 - true - - - - BTC Balance: - - - - - - 150 - 70 - 150 - 16 - - - - TextLabel - - - - - - 30 - 70 - 111 - 16 - - - - - 75 - true - - - - DAPS Available: - - - - - - 30 - 110 - 101 - 16 - - - - - 75 - true - - - - DAPS Pending: - - - - - - 150 - 110 - 150 - 16 - - - - TextLabel - - - - - - 320 - 70 - 111 - 16 - - - - - 75 - true - - - - BTC Available: - - - - - - 470 - 70 - 150 - 16 - - - - TextLabel - - - - - - 320 - 110 - 111 - 16 - - - - - 75 - true - - - - BTC Pending: - - - - - - 470 - 110 - 150 - 16 - - - - TextLabel - - - - - - 30 - 200 - 221 - 16 - - - - - 75 - true - - - - Bittrex DAPS Deposit Address: - - - - - - 30 - 160 - 411 - 23 - - - - Generate Dapscoin Deposit Address - - - - :/icons/bitcoin:/icons/bitcoin - - - - - - 200 - 200 - 261 - 16 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 255 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 75 - true - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - 460 - 300 - 281 - 81 - - - - - - - :/images/bittrex - - - - - - 0 - 250 - 751 - 43 - - - - - 0 - 43 - - - - - - - - - 575 - 0 - 111 - 41 - - - - - 0 - 0 - - - - - calibri - -1 - 75 - true - true - - - - margin:0px;text-align:center;padding:2px;border-radius:3px;font-style:italic;width:100px;font-size:14px;font-family:calibri;font-weight:600; - - - Update - - - - 150 - 35 - - - - true - - - true - - - - - - 30 - 10 - 131 - 20 - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Convert VCoin:</span></p></body></html> - - - - - - 160 - 10 - 100 - 23 - - - - - 100 - 23 - - - - - 100 - 16777215 - - - - border: 1px solid #61696c;margin-left:4px; - - - - - - 260 - 10 - 51 - 23 - - - - - 0 - 23 - - - - border:1px solid #61696c;background:white;font-weight:600; - - - = - - - - - - 330 - 0 - 201 - 41 - - - - - - - $0.0000 / B0.00000000 - - - - - - 670 - 10 - 24 - 24 - - - - - - - :/icons/transaction_1 - - - true - - - Qt::AlignCenter - - - - - - - Settings - - - - - 460 - 300 - 281 - 81 - - - - opacity:0.4 - - - - - - :/images/bittrex - - - - - - 460 - 140 - 201 - 23 - - - - Update API Keys - - - - :/icons/bitcoin:/icons/bitcoin - - - - - - 50 - 60 - 81 - 20 - - - - - 75 - true - - - - API Key - - - - - - 160 - 100 - 501 - 23 - - - - - - - 160 - 60 - 501 - 23 - - - - - - - - - - 50 - 100 - 91 - 20 - - - - - 75 - true - - - - Secret Key - - - - - - - - 10 - 0 - 761 - 34 - - - - - - 0 - 0 - 240 - 16 - - - - - 140 - 0 - - - - 0.00000000 - - - - - - 0 - 20 - 240 - 16 - - - - - 160 - 0 - - - - 0.00000000 - - - - - - 380 - 20 - 240 - 16 - - - - - 201 - 0 - - - - 0.000000000 - - - - - - 380 - 0 - 240 - 16 - - - - - 160 - 0 - - - - 0.00000000 - - - - - - - - - diff --git a/src/qt/res/icons/automint_active.png b/src/qt/res/icons/automint_active.png deleted file mode 100644 index 3cb7a5469bd4f3b35f6a7789db338097732069b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 884 zcmV-)1B?8LP)_DS4VfKpSgj2iCas1%*xPp zX^nk%hAt*M^z`*;VRA1gJ*Al`1>t9cPQ9yH6Ms`?9d0R_+E+soR zFGMjYL3(bH?dtKDjjXDoyQrYKhkTz|NqI6VKr<^qOGH=N+1!A1m{mk}h<%`qf}@g# zr_ajSoRY9uM|dzOKE%Pt>FDaStiHj!&$_e8j)SC4JaBSkj?&HCTugj1DL+^e zWL|A#U2kz_hihDjPd#yfbD7V{*;-0^EF(ELFhw#dKQSmiEhIZeKT?i}m!g}pt)#xz z(cp@GqgqOQFDE@VE<`UTJauq@$HdBNWOHz9cT-DZMmb(hKWQi+Ha9RtH!nqYaDbtm zrz09NGAlkbEJ1g2fvBXeEF(HUH%v=JSpWb3h;v}w0000+bW%=J000000000000000 z0|W+Is?pT9au+Vig_>J*)~I7*G60+yu*QNQ!` z#aksrMkwt44wwJ{0JTX(K~xwS1;M>aLU8~G(BHZKuYKHGqeD=jfm6{3L z57Zpl5Lj!AEfTZ^NhPG`BuSFATS<~cl57J$lStBY1fG2?BiV5RFrNLF>^jHqI?~yj zO8)}Dyt#ibsTz12qWP)@WoQ$QL0gnU13*!V-n0*(D6gl@0RWwslBzY%2vF%{HoF`Q z7EQN1pX}dG7FAN+E$h^E{d9O!{vyfR8CR}({7EE9Hb!{xon!?V8zhlxM}c$z0000< KMNUMnLSTa1znTRA diff --git a/src/qt/res/icons/automint_inactive.png b/src/qt/res/icons/automint_inactive.png deleted file mode 100644 index 532c3749789f07e6dc9e01e050aee8892f1efbc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 421 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 QxBvhE07*qoM6N<$f^&v31ONa4 diff --git a/src/qt/res/icons/trade.png b/src/qt/res/icons/trade.png deleted file mode 100644 index f2b7aaaafc54056a55d7b351eecad56186456a2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H0wgodS2{2-Fxq*#IEGZ*dV9x{@2~?0i^Ko_ zm(TG(QZ-;)c0{&(x=3+R-{%|EX6yNZI*`GXYLDuM6|TCBkHXEEP6XvnH2v)!ZS%gX zJnP|+)p_9;&uE`FZ>U-seyv|6gImD$!nV5Lh8rHK3`U3gm{x2nH*`3Awvl0{;%3fC zjORZ64rX?XwP9f3Vt#V{d@abi3`=xRtluy3z@pm6Yq{Rj`AR%%>*ptA{QS+a_%-tm zM}s~8Oc@(qeqGPOz#tJXe;~YRI>Udq?i1V~t=k!`_Wfc6u^Nnl@=%~4w%|65jX~dL zn3EsP#IV7#;rug(oc~WV%9|FH6~F%dzd`-%v#IqLv%-FAmcLsLHWW#-*&KfM+{2rU SdXv9^L_J;oT-G@yGywpawtTVx From b3a03b98523b56c28ecc17177f9dd9f13732f89d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 17:45:10 -0500 Subject: [PATCH 0070/1888] Remove empty addTableData function --- src/qt/historypage.cpp | 4 ---- src/qt/historypage.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 11293dc47c..bb3400015a 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -194,10 +194,6 @@ void HistoryPage::keyPressEvent(QKeyEvent* event) this->QDialog::keyPressEvent(event); } -void HistoryPage::addTableData(std::map) -{ -} - void HistoryPage::updateTableData() { if (pwalletMain) { diff --git a/src/qt/historypage.h b/src/qt/historypage.h index 1bb38319a0..ef6e63ee42 100644 --- a/src/qt/historypage.h +++ b/src/qt/historypage.h @@ -64,7 +64,6 @@ public slots: void initWidgets(); void connectWidgets(); virtual void resizeEvent(QResizeEvent* event); - void addTableData(std::map); void updateTableData(CWallet *wallet); void updateAddressBookData(CWallet *wallet); From 4fe18e56193264c959d63234f3b39d50cecf81df Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 17:46:51 -0500 Subject: [PATCH 0071/1888] Default to Align Center for QTableWidgetItems on History tab --- src/qt/historypage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index bb3400015a..4a41c5f3fb 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -265,6 +265,7 @@ void HistoryPage::updateTableData(CWallet* wallet) break; } ui->tableView->setItem(row, col, cell); + cell->setTextAlignment(Qt::AlignHCenter); col++; } } From 2e0d23d43179be48658aa8b8086181f6828ea170 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 17:48:16 -0500 Subject: [PATCH 0072/1888] Remove DAPSTableWidgetItem --- src/qt/custom/dapstablewidgetitem.h | 48 ----------------------------- src/qt/historypage.cpp | 3 +- 2 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 src/qt/custom/dapstablewidgetitem.h diff --git a/src/qt/custom/dapstablewidgetitem.h b/src/qt/custom/dapstablewidgetitem.h deleted file mode 100644 index f33c05aed2..0000000000 --- a/src/qt/custom/dapstablewidgetitem.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef DAPSTABLEWIDGETITEM_H -#define DAPSTABLEWIDGETITEM_H -#include -#include -#include -#include - -class DAPSTableWidgetItem : public QTableWidgetItem { - public: - bool operator <(const QTableWidgetItem &other) const - { - QVariant l(text()), r(other.text()); - QString format = "MM/dd/yy HH:mm:ss"; - QDateTime dtl; - QDateTime dtr; - switch (l.type()) - { - case QVariant::Invalid: - return (r.type() == QVariant::Invalid); - case QVariant::Int: - return l.toInt() < r.toInt(); - case QVariant::UInt: - return l.toUInt() < r.toUInt(); - case QVariant::LongLong: - return l.toLongLong() < r.toLongLong(); - case QVariant::ULongLong: - return l.toULongLong() < r.toULongLong(); - case QVariant::Double: - return l.toDouble() < r.toDouble(); - case QVariant::Char: - return l.toChar() < r.toChar(); - case QVariant::Date: - return l.toDate() < r.toDate(); - case QVariant::Time: - return l.toTime() < r.toTime(); - case QVariant::DateTime: - dtl = QDateTime::fromString (l.toString(), format); - dtr = QDateTime::fromString (r.toString(), format); - return dtl < dtr; - case QVariant::String: - default: - return l.toString().compare(r.toString(), Qt::CaseSensitive) < 0; - } - return false; - } -}; - -#endif diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 4a41c5f3fb..7855fe2497 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -15,7 +15,6 @@ #include "transactionrecord.h" #include "walletmodel.h" #include "revealtxdialog.h" -#include "custom/dapstablewidgetitem.h" #include @@ -245,7 +244,7 @@ void HistoryPage::updateTableData(CWallet* wallet) for (QString dataName : {"date", "type", "address", "amount", "confirmations"}) { QString data = txs[row].at(dataName); QString date = data; - DAPSTableWidgetItem* cell = new DAPSTableWidgetItem(); + QTableWidgetItem* cell = new QTableWidgetItem(); switch (col) { case 0: /*date*/ cell->setData(0, date); From 57bc493b2d5d0b3e6d7eaead698031dac6edbbd4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 17:49:37 -0500 Subject: [PATCH 0073/1888] Sort by Confirmations by Default --- src/qt/historypage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 7855fe2497..493ec140c7 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -269,7 +269,7 @@ void HistoryPage::updateTableData(CWallet* wallet) } } ui->tableView->setVisible(ui->tableView->rowCount()); - ui->tableView->sortByColumn(0); + ui->tableView->sortByColumn(4, Qt::AscendingOrder); ui->tableView->setSortingEnabled(true); } } From 936d7d8eb9782d09358f4aba91799f13588e368f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 18:16:34 -0500 Subject: [PATCH 0074/1888] Comment out nConsolidationTime causing "Selecting 0 transactions from mempool" in debug.log (Currently non-functional anyway) --- src/main.h | 2 +- src/miner.cpp | 2 +- src/qt/bitcoingui.cpp | 4 ++-- src/qt/optionspage.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.h b/src/main.h index 37ee0e7331..1cff3851f2 100644 --- a/src/main.h +++ b/src/main.h @@ -160,7 +160,7 @@ extern bool fLargeWorkInvalidChainFound; extern unsigned int nStakeMinAge; extern int64_t nLastCoinStakeSearchInterval; -extern int64_t nConsolidationTime; +//extern int64_t nConsolidationTime; extern int64_t nLastCoinStakeSearchTime; extern int64_t nReserveBalance; extern const int MIN_RING_SIZE; diff --git a/src/miner.cpp b/src/miner.cpp index 8375722982..80f6c50003 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -61,7 +61,7 @@ class COrphan uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; int64_t nLastCoinStakeSearchInterval = 0; -int64_t nConsolidationTime = 0; +//int64_t nConsolidationTime = 0; // We want to sort transactions by priority and fee rate, so: typedef boost::tuple TxPriority; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c07912d2cb..6b92dcc5ef 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1250,11 +1250,11 @@ void BitcoinGUI::setStakingStatus() stakingState->setText(tr("Staking Enabled")); stakingState->setToolTip("Staking Enabled"); stakingAction->setIcon(QIcon(":/icons/staking_active")); - } else if (nConsolidationTime > 0) { + /*} else if (nConsolidationTime > 0) { nConsolidationTime --; stakingState->setText(tr("Consolidating Transactions…")); stakingState->setToolTip("Consolidating Transactions… Please wait few minutes for it to be consolidated."); - stakingAction->setIcon(QIcon(":/icons/staking_active")); + stakingAction->setIcon(QIcon(":/icons/staking_active"));*/ } else { stakingState->setText(tr("Enabling Staking...")); stakingState->setToolTip("Enabling Staking... Please wait up to 1.5 hours for it to be properly enabled after consolidation."); diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 1da4dc3401..3a32b42caf 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -486,7 +486,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) CWallet::MINIMUM_STAKE_AMOUNT, CWallet::MINIMUM_STAKE_AMOUNT, nTime); if (success) { - nConsolidationTime = 1800; + //nConsolidationTime = 1800; QString msg = "Consolidation transaction created!"; QMessageBox msgBox; msgBox.setWindowTitle("Information"); From 9f4449384fb225878b194da42bb8cb1a69c3ffc8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 18:18:11 -0500 Subject: [PATCH 0075/1888] Restore timerStakingIcon timer to 10 seconds --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 6b92dcc5ef..5fb87d4e98 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -248,7 +248,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai QTimer* timerStakingIcon = new QTimer(labelStakingIcon); connect(timerStakingIcon, SIGNAL(timeout()), this, SLOT(setStakingStatus())); - timerStakingIcon->start(1000); + timerStakingIcon->start(10000); setStakingStatus(); } From 1f5a738ef28d0e5f2fdf5deef1bf57accccf4ec7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 18:30:51 -0500 Subject: [PATCH 0076/1888] Bump version to v1.0.5.6 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 756f847daa..9caa50fe3c 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 5) +define(_CLIENT_VERSION_BUILD, 6) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2019) From 342f67ff1bef3770314b94e578e87c41b8ad897e Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Fri, 3 Jan 2020 12:34:15 +1000 Subject: [PATCH 0077/1888] Set theme jekyll-theme-cayman --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..c4192631f2 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file From 8a168e865b429a9565d60e3f95bae57d67909d4f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 22:15:26 -0500 Subject: [PATCH 0078/1888] [GUI] Hide orphans --- src/qt/forms/optionsdialog.ui | 50 +++++++++++++++++++++++++++++++---- src/qt/optionsdialog.cpp | 9 +++++++ src/qt/optionsdialog.h | 2 ++ src/qt/overviewpage.cpp | 3 ++- src/qt/transactionview.cpp | 24 ++++++++++++++++- src/qt/transactionview.h | 3 +++ 6 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 3bf53bf56a..e1120a959a 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -20,7 +20,7 @@ - 4 + 0 @@ -421,7 +421,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + @@ -530,7 +530,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + @@ -554,7 +554,7 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + @@ -568,7 +568,47 @@ https://www.transifex.com/dapscoin-project/dapscoin-project-translations - + + + + + Hide empty balances + + + Qt::LeftToRight + + + Hide empty balances + + + + + + + Hide orphan stakes in transaction lists + + + Hide orphan stakes + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index dd20cb8126..bd4e8a46b5 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -144,6 +144,9 @@ void OptionsDialog::setModel(OptionsModel* model) mapper->setModel(model); setMapper(); mapper->toFirst(); + + /* keep consistency for action triggered elsewhere */ + connect(model, SIGNAL(hideOrphansChanged(bool)), this, SLOT(updateHideOrphans(bool))); } /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */ @@ -267,6 +270,12 @@ void OptionsDialog::clearStatusLabel() ui->statusLabel->clear(); } +void OptionsDialog::updateHideOrphans(bool fHide) +{ + if (ui->checkBoxHideOrphans->isChecked() != fHide) + ui->checkBoxHideOrphans->setChecked(fHide); +} + void OptionsDialog::doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort) { const std::string strAddrProxy = pUiProxyIp->text().toStdString(); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index de043c857d..85c5234620 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -46,6 +46,8 @@ private slots: void on_okButton_clicked(); void on_cancelButton_clicked(); + void updateHideOrphans(bool fHide); + void showRestartWarning(bool fPersistent = false); void clearStatusLabel(); void doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index eb28a13fca..cd9fed02c9 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -305,7 +305,8 @@ void OverviewPage::updateDisplayUnit() void OverviewPage::hideOrphans(bool fHide) { - filter->setHideOrphans(fHide); + if (filter) + filter->setHideOrphans(fHide); } void OverviewPage::updateAlerts(const QString& warnings) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 534567de8b..8f5ccc9c3d 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -150,6 +150,10 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t QAction* copyTxIDAction = new QAction(tr("Copy transaction ID"), this); QAction* editLabelAction = new QAction(tr("Edit label"), this); QAction* showDetailsAction = new QAction(tr("Show transaction details"), this); + hideOrphansAction = new QAction(tr("Hide orphan stakes"), this); + + hideOrphansAction->setCheckable(true); + hideOrphansAction->setChecked(settings.value("fHideOrphans", false).toBool()); contextMenu = new QMenu(); contextMenu->addAction(copyAddressAction); @@ -158,6 +162,7 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t contextMenu->addAction(copyTxIDAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); + contextMenu->addAction(hideOrphansAction); mapperThirdPartyTxUrls = new QSignalMapper(this); @@ -180,6 +185,7 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); + connect(hideOrphansAction, SIGNAL(toggled(bool)), this, SLOT(updateHideOrphans(bool))); } TransactionView::~TransactionView() { @@ -234,7 +240,8 @@ void TransactionView::setModel(WalletModel* model) mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed()); } } - connect(model->getOptionsModel(), SIGNAL(hideOrphansChanged(bool)), this, SLOT(hideOrphans(bool))); + + connect(model->getOptionsModel(), SIGNAL(hideOrphansChanged(bool)), this, SLOT(updateHideOrphans(bool))); } // show/hide column Watch-only @@ -322,6 +329,21 @@ void TransactionView::hideOrphans(bool fHide) transactionProxyModel->setHideOrphans(fHide); } +void TransactionView::updateHideOrphans(bool fHide) +{ + QSettings settings; + if (settings.value("fHideOrphans", false).toBool() != fHide) { + settings.setValue("fHideOrphans", fHide); + if (model && model->getOptionsModel()) + emit model->getOptionsModel()->hideOrphansChanged(fHide); + } + hideOrphans(fHide); + // retain consistency with other checkboxes + if (hideOrphansAction->isChecked() != fHide) + hideOrphansAction->setChecked(fHide); + +} + void TransactionView::chooseWatchonly(int idx) { if (!transactionProxyModel) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index dbeda37969..01d8b4e1a2 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -9,6 +9,7 @@ #include #include +#include class TransactionFilterProxy; class WalletModel; @@ -67,6 +68,7 @@ class TransactionView : public QWidget QComboBox* watchOnlyWidget; QLineEdit* addressWidget; QLineEdit* amountWidget; + QAction* hideOrphansAction; QMenu* contextMenu; QSignalMapper* mapperThirdPartyTxUrls; @@ -108,6 +110,7 @@ public slots: void chooseDate(int idx); void chooseType(int idx); void hideOrphans(bool fHide); + void updateHideOrphans(bool fHide); void chooseWatchonly(int idx); void changedPrefix(const QString& prefix); void changedAmount(const QString& amount); From 63fb1c177d50c734916103b3cacd74506fb14983 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 23:29:23 -0500 Subject: [PATCH 0079/1888] Qt::AlignHCenter -> Qt::AlignCenter --- src/qt/historypage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 493ec140c7..61be691895 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -264,7 +264,7 @@ void HistoryPage::updateTableData(CWallet* wallet) break; } ui->tableView->setItem(row, col, cell); - cell->setTextAlignment(Qt::AlignHCenter); + cell->setTextAlignment(Qt::AlignCenter); col++; } } From a5683eb89fa81e8e044939a72d0a171eb77eb227 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 2 Jan 2020 23:37:06 -0500 Subject: [PATCH 0080/1888] Add Frequently Asked Questions to Help menu --- src/qt/bitcoingui.cpp | 10 ++++++++++ src/qt/bitcoingui.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 5fb87d4e98..2fb88502b6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -459,6 +459,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) showHelpMessageAction->setStatusTip(tr("Show the DAPS help message to get a list with possible DAPS command-line options")); // Help Links + openFAQAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Frequently Asked Questions"), this); + openFAQAction->setStatusTip(tr("Frequently Asked Questions")); openBlockExplorerAPIAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Blockhain Explorer API"), this); openBlockExplorerAPIAction->setStatusTip(tr("Blockhain Explorer API")); openBootStrapAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&BootStrap"), this); @@ -476,6 +478,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(optionsAction, SIGNAL(triggered()), this, SLOT(gotoOptionsPage())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); + connect(openFAQAction, SIGNAL(triggered()), this, SLOT(openFAQClicked())); connect(openBlockExplorerAPIAction, SIGNAL(triggered()), this, SLOT(openBlockExplorerAPIClicked())); connect(openBootStrapAction, SIGNAL(triggered()), this, SLOT(openBootStrapClicked())); connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); @@ -574,6 +577,8 @@ void BitcoinGUI::createMenuBar() QMenu* help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); + help->addAction(openFAQAction); + help->addSeparator(); help->addAction(openBlockExplorerAPIAction); help->addAction(openBootStrapAction); help->addSeparator(); @@ -877,6 +882,11 @@ void BitcoinGUI::showHelpMessageClicked() help->show(); } +void BitcoinGUI::openFAQClicked() +{ + QDesktopServices::openUrl(QUrl("https://officialdapscoin.com/faq")); +} + void BitcoinGUI::openBlockExplorerAPIClicked() { QDesktopServices::openUrl(QUrl("https://explorer.dapscoin.com/api/getblockcount")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 40c1d2619d..793bd2899a 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -132,6 +132,7 @@ class BitcoinGUI : public QMainWindow QAction* instagramAction; QAction* redditAction; QAction* showHelpMessageAction; + QAction* openFAQAction; QAction* openBlockExplorerAPIAction; QAction* openBootStrapAction; QAction* openTGTechSupportAction; @@ -259,6 +260,7 @@ private slots: void aboutClicked(); /** Show help message dialog */ void showHelpMessageClicked(); + void openFAQClicked(); void openBlockExplorerAPIClicked(); void openBootStrapClicked(); void openTGTechSupportClicked(); From 392b8a4e4182e8d8d855133e59f373f8b0242926 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Fri, 3 Jan 2020 15:23:41 +1000 Subject: [PATCH 0081/1888] Create FUNDING.yml DAPS fundraising options for supporting development of the project. --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..8453c41218 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["http://bit.ly/DAPScryptoDonations", dapscoin.com, "http://bit.ly/DAPSfiatDonations"] From b736c83f28f0dd1c0ecc6b33979bc41c1bab91c8 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Fri, 3 Jan 2020 17:09:09 +1000 Subject: [PATCH 0082/1888] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..dd84ea7824 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..bbcbbe7d61 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 9b68d165683c8912279e27f5713c8d7a1bcb6d9b Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Fri, 3 Jan 2020 19:53:01 +1000 Subject: [PATCH 0083/1888] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..21f7258add --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at support@dapscoin.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq From a8d65a514698b3e68d123147ead2215e07ea4653 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Fri, 3 Jan 2020 23:07:13 +1000 Subject: [PATCH 0084/1888] Update README.md --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 54dd54d273..6e10d38a97 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,55 @@ -DAPS integration/staging repository +Welcome to DAPS ===================================== + +## Introduction + DAPScoin is a cutting edge cryptocurrency, with many features not available in most other cryptocurrencies. - Anonymized transactions using Stealth addresses, RingCT and Bulletproofs. - Masternode is secured with a collateral of 1,000,000 DAPS. +DAPS is a cryptocurrency designed for corporate entities, traders, and individuals to have the autonomy to transactions business freely around the world safely and securely without the exposure to malicious actors that threaten financial transactions through traceability. + +DAPS is a privacy coin that aims to be the most private and secure privacy coin on the market in a hybrid chain of PoW, PoSv3 and PoA. We aim to set our protocol to become the new standard of privacy coins. + +What makes DAPS special is that DAPS is the first to solve the "trust problem" for fully private chains with our PoA (Proof of Audit) algorithm which audits the chain for any abnormalities without compromising the chain's anonymity features. + +DAPS is the world's first coin to implement Bulletproofs and RingCT & Ring Signatures in a staking chain. With DAPS it is possible to stake, run masternodes and mine PoA blocks. In 2019 DAPS completed two successful testnets, sponsored Consensus 2019 NYC and Futurist Conference in Canada, achieved and kept top 200 coin status, passed security audit by Red4Sec, launched mainnet and achieved over 3000 hosted masternodes in the first month, staying in the top 10. + +## About this Project + +DAPS is a non-ICO community driven project. The project has funded itself to deliver ground-breaking technology in the privacy coin industry and the main team consists of: + +Adel de Meyer – Leading DAPS +Andrew Huntley – CTO +Justin Da Silva - Development Lead +Charley van Laar - Senior Management +Stuart Gee -DAPS Council +Matt Howard - DAPS Community Manager +Dave van Muster - DAPS Community - International + + +DAPS Team +The team consists of a total of 20 members located worldwide. + + +## Social + +Facebook - (https://www.facebook.com/officialDAPScoin/) + +Twitter - (https://twitter.com/DAPScoin) + +LinkedIn - (https://www.linkedin.com/company/daps-coin/) + +Reddit - (https://www.reddit.com/r/DAPSCoin/) + +Forum - (https://forum.officialdapscoin.com/) + +Telegram - (https://t.me/dapscoin) + +Discord - (https://discord.gg/hxfmWpR) + +Bitcointalk - (https://bitcointalk.org/index.php?topic=5146718.0) + More information at [officialdapscoin.com](https://officialdapscoin.com) Visit our ANN thread at [BitcoinTalk](https://bitcointalk.org/index.php?topic=5146718) @@ -12,6 +58,6 @@ More information at [officialdapscoin.com](https://officialdapscoin.com) Visit o AlgoPoW-PoA-PoS Block Time60 Seconds Difficulty RetargetingEvery Block -Max Coin Supply60,000,000,000 DAPS -Premine60 000 000 DAPS +Max Coin Supply70,000,000,000 DAPS +Premine60 000 000 000 DAPS From deabe1108a067380b429657c006e29047d614d63 Mon Sep 17 00:00:00 2001 From: DAPS_Spock <55909478+DAPS-Spock@users.noreply.github.com> Date: Fri, 3 Jan 2020 23:13:15 +1000 Subject: [PATCH 0085/1888] Update README.md --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index 6e10d38a97..762de68c0c 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,7 @@ DAPS is the world's first coin to implement Bulletproofs and RingCT & Ring Signa ## About this Project -DAPS is a non-ICO community driven project. The project has funded itself to deliver ground-breaking technology in the privacy coin industry and the main team consists of: - -Adel de Meyer – Leading DAPS -Andrew Huntley – CTO -Justin Da Silva - Development Lead -Charley van Laar - Senior Management -Stuart Gee -DAPS Council -Matt Howard - DAPS Community Manager -Dave van Muster - DAPS Community - International - +DAPS is a non-ICO community driven project. The project has funded itself to deliver ground-breaking technology in the privacy coin industry. DAPS Team The team consists of a total of 20 members located worldwide. From 056d3e5e57033ff3a4e2d597972b7630707afd06 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 3 Jan 2020 23:38:27 -0500 Subject: [PATCH 0086/1888] Adjust Disable Reserve Balance button --- src/qt/optionspage.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 3a32b42caf..d4bcf85b47 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -205,10 +205,9 @@ void OptionsPage::on_pushButtonSave_clicked() { void OptionsPage::on_pushButtonDisable_clicked() { ui->lineEditWithhold->setText("0"); - nReserveBalance = getValidatedAmount(); CWalletDB walletdb(pwalletMain->strWalletFile); - walletdb.WriteReserveAmount(nReserveBalance / COIN); + walletdb.WriteReserveAmount(0); emit model->stakingStatusChanged(nLastCoinStakeSearchInterval); QMessageBox msgBox; From 24f606c9108f2ac99ec0961438f49952c5c9c8a5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 3 Jan 2020 23:54:54 -0500 Subject: [PATCH 0087/1888] Hide Coin Control Frame until fully implemented --- src/qt/sendcoinsdialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index ffbc98afca..23b9cad9f3 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -87,6 +87,9 @@ SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent, Qt::WindowSy ui->labelBlockSize->setVisible(false); ui->labelBlockSizeText->setVisible(false); ui->labelCoinControlInsuffFunds->setVisible(false); + + // hide coin control frame + ui->frameCoinControl->hide(); } void SendCoinsDialog::setClientModel(ClientModel* clientModel) From a2afcc3beee3548a6114a0ad7fcf38b49914a2f4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 4 Jan 2020 00:06:34 -0500 Subject: [PATCH 0088/1888] Move excessive "Socket close failed" log behind net category --- src/netbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index e66bec33b4..b34eea880b 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1436,7 +1436,7 @@ bool CloseSocket(SOCKET& hSocket) int ret = close(hSocket); #endif if (ret) { - LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError())); + LogPrint("net", "Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError())); } hSocket = INVALID_SOCKET; return ret != SOCKET_ERROR; From 84578b22b2e0df0596dbc9170fe9614db5c88e48 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sat, 4 Jan 2020 14:24:49 +0100 Subject: [PATCH 0089/1888] Update checkpoints 221000 --- src/chainparams.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5c35632387..42bfbfaa1a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -107,11 +107,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (207000, uint256("173efe8f8cc450a83353c31c1d06d7b8c284eac46ed2d4c916cac29713a09abe")) (208000, uint256("995328748210f12b77700e5589cb5bb4d5b84353682647d1771cbc77e77ffa35")) (209577, uint256("5231320be89de8a0fdebbd45d4d0c58abb1ea7a134ba52a11a2036f32d90e66c")) + (215000, uint256("f114538988fbba92c21418e18dd8f32ed9579f0ee980949467044dfc8b5a444b")) + (221000, uint256("573a615b64089e31204b9ed642346179858cb4d31749be210f65c95b5e34a5c3")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1577399767, // * UNIX timestamp of last checkpoint block - 528235, // * total number of transactions between genesis and last checkpoint + 1578085486, // * UNIX timestamp of last checkpoint block + 555549, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 5c2f225eb460c8e78f9293b5739d4df2434f3ff7 Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Sun, 5 Jan 2020 02:37:20 +1000 Subject: [PATCH 0090/1888] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 762de68c0c..f7a35fa23a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ DAPS is a non-ICO community driven project. The project has funded itself to del DAPS Team The team consists of a total of 20 members located worldwide. +## How we Compare to Other Privacy Projects + +![Privacy Coin Chart](https://officialdapscoin.com/wp-content/uploads/2020/01/DAPS-Privacy-Coin-Chart-2.jpg) + ## Social From f0e34a6967c5c01a3b8d69069dc0ff4a19c32dbb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 4 Jan 2020 12:33:12 -0500 Subject: [PATCH 0091/1888] Minor splash screen adjustments --- src/qt/splashscreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 231f0afaca..5b46facf44 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -34,7 +34,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle* networkStyle) float fontFactor = 1.0; // define text to place - QString titleText = tr("DAPS"); + QString titleText = tr("DAPS Coin Keychain Wallet"); QString versionText = QString(tr("Version %1")).arg(QString::fromStdString(FormatFullVersion())); QString copyrightTextBtc = QChar(0xA9) + QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); QString copyrightTextDash = QChar(0xA9) + QString(" 2014-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Dash Core developers")); @@ -67,7 +67,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle* networkStyle) pixPaint.drawText(paddingLeft, paddingTop + titleVersionVSpace, versionText); // draw copyright stuff - pixPaint.setFont(QFont(font, 10 * fontFactor)); + pixPaint.setFont(QFont(font, 11 * fontFactor)); pixPaint.drawText(paddingLeft, paddingTop + titleCopyrightVSpace, copyrightTextBtc); pixPaint.drawText(paddingLeft, paddingTop + titleCopyrightVSpace + 12, copyrightTextDash); pixPaint.drawText(paddingLeft, paddingTop + titleCopyrightVSpace + 24, copyrightTextPivx); From 024eb38cf393de9c49c0ede535be759ecb98afb4 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 4 Jan 2020 12:57:53 -0500 Subject: [PATCH 0092/1888] Use 1 second GUI update time --- src/qt/guiconstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 8f7b682e47..89d51fbae5 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -9,7 +9,7 @@ #define BITCOIN_QT_GUICONSTANTS_H /* Milliseconds between model updates */ -static const int MODEL_UPDATE_DELAY = 250; +static const int MODEL_UPDATE_DELAY = 1000; /* AskPassphraseDialog -- Maximum passphrase length */ static const int MAX_PASSPHRASE_SIZE = 1024; From 6d223528f3ca27a2c23d6308a0ed39f8a8bb00bb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 4 Jan 2020 22:32:32 -0500 Subject: [PATCH 0093/1888] Update minimum MacOS --- share/qt/Info.plist.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index a32eba6eaa..a0c4745b9d 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -3,7 +3,7 @@ LSMinimumSystemVersion - 10.8.0 + 10.10.0 LSArchitecturePriority From 1e2ad31df8c4de61d5f93de0a29151d9cb21468d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 4 Jan 2020 22:36:13 -0500 Subject: [PATCH 0094/1888] [Startup][GUI][Performance] Optimizations for huge wallets. --- src/qt/transactiontablemodel.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index bb8d759bcd..5ecf171467 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -28,6 +28,11 @@ #define SINGLE_THREAD_MAX_TXES_SIZE 4000 +// Maximum amount of loaded records in ram in the first load. +// If the user has more and want to load them: +// TODO, add load on demand in pages (not every tx loaded all the time into the records list). +#define MAX_AMOUNT_LOADED_RECORDS 20000 + // Amount column is right-aligned it contains numbers static int column_alignments[] = { Qt::AlignLeft | Qt::AlignVCenter, /* status */ @@ -84,6 +89,20 @@ class TransactionTablePriv // Divide the work between multiple threads to speedup the process if the vector is larger than 4k txes std::size_t txesSize = walletTxes.size(); if (txesSize > SINGLE_THREAD_MAX_TXES_SIZE) { + // First check if the amount of txs exceeds the UI limit + if (txesSize > MAX_AMOUNT_LOADED_RECORDS) { + // Sort the txs by date just to be really really sure that them are ordered. + // (this extra calculation should be removed in the future if can ensure that + // txs are stored in order in the db, which is what should be happening) + sort(walletTxes.begin(), walletTxes.end(), + [](const CWalletTx & a, const CWalletTx & b) -> bool { + return a.GetComputedTxTime() < b.GetComputedTxTime(); + }); + + // Only latest ones. + walletTxes = std::vector(walletTxes.begin(), walletTxes.begin() + MAX_AMOUNT_LOADED_RECORDS); + txesSize = walletTxes.size(); + }; // Simple way to get the processors count std::size_t threadsCount = (QThreadPool::globalInstance()->maxThreadCount() / 2 ) + 1; From 05935faf4d9d25d1402626c12573f4c8d100ba9d Mon Sep 17 00:00:00 2001 From: Adel de Meyer <36526863+CapricornCandy@users.noreply.github.com> Date: Tue, 7 Jan 2020 21:07:30 +1000 Subject: [PATCH 0095/1888] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7a35fa23a..9497b2ae79 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The team consists of a total of 20 members located worldwide. ## How we Compare to Other Privacy Projects -![Privacy Coin Chart](https://officialdapscoin.com/wp-content/uploads/2020/01/DAPS-Privacy-Coin-Chart-2.jpg) +![Privacy Coin Chart](https://officialdapscoin.com/wp-content/uploads/2020/01/DAPS-Privacy-coin-chart-2020.jpg) ## Social From d2c9945c11671b89d9ddb8c4376974faae81fe96 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:25:45 +0100 Subject: [PATCH 0096/1888] Update poa.cpp --- src/poa.cpp | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) diff --git a/src/poa.cpp b/src/poa.cpp index 89b10135d5..054c8c8f7b 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -16,4 +16,435 @@ #include +unsigned int N_BITS = 0x1e1ffff0; +unsigned int N_BITS_SF = 0x1e050000; +bool CheckPoAMiningBlockHeight(const CBlockHeader* pblock) +{ + return false; +} +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock) +{ + if (N_BITS != 0 && pblock->IsPoABlockByVersion()) { + if (pindexLast->nHeight < 125000) { + return N_BITS; + } + return N_BITS_SF; + } + /* current difficulty formula, dapscoin - DarkGravity v3, written by Evan Duffield - evan@dashpay.io */ + const CBlockIndex* BlockLastSolved = pindexLast; + const CBlockIndex* BlockReading = pindexLast; + int64_t nActualTimespan = 0; + int64_t LastBlockTime = 0; + int64_t PastBlocksMin = 24; + int64_t PastBlocksMax = 24; + int64_t CountBlocks = 0; + uint256 PastDifficultyAverage; + uint256 PastDifficultyAveragePrev; + + if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { + return Params().ProofOfWorkLimit().GetCompact(); + } + + if (pindexLast->nHeight > Params().LAST_POW_BLOCK()) { + uint256 bnTargetLimit = (~uint256(0) >> 24); + int64_t nTargetSpacing = 60; + int64_t nTargetTimespan = 60 * 40; + + //finding last PoS block + CBlockIndex* pLastPoS = pindexLast->pprev; + while (!pLastPoS->IsProofOfStake() && pLastPoS->nHeight > Params().LAST_POW_BLOCK()) { + pLastPoS = pLastPoS->pprev; + } + int64_t nActualSpacing = 0; + //ig + if (pindexLast->nHeight != 0) + nActualSpacing = pindexLast->GetBlockTime() - pLastPoS->GetBlockTime(); + + if (nActualSpacing < 0) + nActualSpacing = 1; + + // ppcoin: target change every block + // ppcoin: retarget with exponential moving toward target spacing + uint256 bnNew; + if (pindexLast->nHeight < 125000) { + bnNew.SetCompact(pindexLast->nBits); + } else { + if (pindexLast->IsProofOfStake()) { + bnNew.SetCompact(pindexLast->nBits); + } else { + bnNew.SetCompact(pLastPoS->nBits); + } + } + + int64_t nInterval = nTargetTimespan / nTargetSpacing; + bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); + bnNew /= ((nInterval + 1) * nTargetSpacing); + + if (bnNew <= 0 || bnNew > bnTargetLimit) + bnNew = bnTargetLimit; + + return bnNew.GetCompact(); + } + + for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { + if (PastBlocksMax > 0 && i > PastBlocksMax) { + break; + } + CountBlocks++; + + if (CountBlocks <= PastBlocksMin) { + if (CountBlocks == 1) { + PastDifficultyAverage.SetCompact(BlockReading->nBits); + } else { + PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); + } + PastDifficultyAveragePrev = PastDifficultyAverage; + } + + if (LastBlockTime > 0) { + int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime()); + nActualTimespan += Diff; + } + LastBlockTime = BlockReading->GetBlockTime(); + + if (BlockReading->pprev == NULL) { + assert(BlockReading); + break; + } + BlockReading = BlockReading->pprev; + } + + uint256 bnNew(PastDifficultyAverage); + + int64_t _nTargetTimespan = CountBlocks * Params().TargetSpacing(); + + if (nActualTimespan < _nTargetTimespan / 3) + nActualTimespan = _nTargetTimespan / 3; + if (nActualTimespan > _nTargetTimespan * 3) + nActualTimespan = _nTargetTimespan * 3; + + // Retarget + bnNew *= nActualTimespan; + bnNew /= _nTargetTimespan; + + if (bnNew > Params().ProofOfWorkLimit()) { + bnNew = Params().ProofOfWorkLimit(); + } + + return bnNew.GetCompact(); +} + +bool CheckProofOfWork(uint256 hash, unsigned int nBits) +{ + bool fNegative; + bool fOverflow; + uint256 bnTarget; + + if (Params().SkipProofOfWorkCheck()) + return true; + + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + + // Check range + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) + return error("CheckProofOfWork() : nBits below minimum work"); + + // Check proof of work matches claimed amount + if (hash > bnTarget) + return error("CheckProofOfWork() : hash doesn't match nBits"); + + return true; +} + +uint256 GetBlockProof(const CBlockIndex& block) +{ + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; +} + +//If blockheight = -1, the to-be-checked block is not included yet in the chain, otherwise, that is the height of the poa block +bool CheckPoAContainRecentHash(const CBlock& block) +{ + //block.Merkle + CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; + if (!currentTip) { + return error("CheckPoAContainRecentHash() : Previous block not found"); + } + //Find the previous PoA block + CBlockIndex* pindex = currentTip; + while (pindex->nHeight >= Params().START_POA_BLOCK()) { + if (pindex->GetBlockHeader().IsPoABlockByVersion()) { + break; + } + pindex = pindex->pprev; + } + bool ret = true; + if (pindex->nHeight <= Params().START_POA_BLOCK()) { + //this is the first PoA block ==> check all PoS blocks from LAST_POW_BLOCK up to currentHeight - POA_BLOCK_PERIOD - 1 inclusive + int index = 0; + for (size_t i = Params().LAST_POW_BLOCK() + 1; i <= Params().LAST_POW_BLOCK() + block.posBlocksAudited.size(); i++) { + PoSBlockSummary pos = block.posBlocksAudited.at(index); + CBlockIndex* pidxInChain = mapBlockIndex[pos.hash]; + if (!pidxInChain) { + return error("CheckPoAContainRecentHash() : Audited blocks not found"); + } + if (pos.hash != pidxInChain->GetBlockHash() || pos.nTime != pidxInChain->nTime || pos.height != (uint32_t)pidxInChain->nHeight) { + ret = false; + break; + } + CBlockIndex* p = mapBlockIndex[pos.hash]; + bool auditResult = ReVerifyPoSBlock(p); + if (!auditResult) { + if (pos.nTime) { + ret = false; + break; + } + } + index++; + } + } else { + if (pindex->nHeight >= Params().START_POA_BLOCK()) { + CBlock prevPoablock; + CBlockIndex* pblockindex = pindex; + if (!ReadBlockFromDisk(prevPoablock, pblockindex)) + throw runtime_error("Can't read block from disk"); + PoSBlockSummary lastAuditedPoSBlockInfo = prevPoablock.posBlocksAudited.back(); + uint256 lastAuditedPoSHash = lastAuditedPoSBlockInfo.hash; + if (mapBlockIndex.count(lastAuditedPoSHash) < 1) { + return error("CheckPoAContainRecentHash() : Audited blocks not found"); + } + CBlockIndex* piterator = mapBlockIndex[lastAuditedPoSHash]->pnext; + uint32_t idxOfPoSInfo = 0; + if (!piterator) { + //check whether chainActive has + if (mapBlockIndex[lastAuditedPoSHash]->nHeight + 1 > chainActive.Height()) { + return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); + } + piterator = chainActive[mapBlockIndex[lastAuditedPoSHash]->nHeight + 1]; + if (!piterator) + return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); + if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != lastAuditedPoSHash) { + return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); + } + } + while (piterator->nHeight <= (uint32_t)currentTip->nHeight && idxOfPoSInfo < block.posBlocksAudited.size()) { + if (!piterator->GetBlockHeader().IsPoABlockByVersion() && piterator->nHeight > Params().LAST_POW_BLOCK()) { + PoSBlockSummary pos = block.posBlocksAudited[idxOfPoSInfo]; + CBlockIndex* posAudited = piterator; + if (pos.hash == *(posAudited->phashBlock) && pos.height == (uint32_t)posAudited->nHeight && pos.nTime == posAudited->GetBlockTime()) { + idxOfPoSInfo++; + } else { + //The PoA block is not satisfied the constraint + ret = false; + break; + } + + CBlockIndex* p = mapBlockIndex[pos.hash]; + bool auditResult = ReVerifyPoSBlock(p); + if (!auditResult) { + if (pos.nTime) { + ret = false; + break; + } + } + } + uint256 h = piterator->GetBlockHash(); + piterator = piterator->pnext; + + if (!piterator) { + if (mapBlockIndex[h]->nHeight + 1 > chainActive.Height()) { + return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); + } + piterator = chainActive[mapBlockIndex[h]->nHeight + 1]; + if (!piterator) + return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); + if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != h) { + return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); + } + } + } + + if (idxOfPoSInfo != block.posBlocksAudited.size()) { + //Not all PoS Blocks in PoA block have been checked, not satisfied + ret = false; + } + } else { + ret = block.hashPrevPoABlock.IsNull(); + } + } + return ret; +} + +bool CheckNumberOfAuditedPoSBlocks(const CBlock& block) +{ + if (block.posBlocksAudited.size() < (size_t)Params().MIN_NUM_POS_BLOCKS_AUDITED()) { + return false; + } + return true; +} + +//Check whether the block is successfully mined and the mined hash satisfy the difficulty +bool CheckPoABlockMinedHash(const CBlockHeader& block) +{ + const uint256 minedHash = block.minedHash; //block.ComputeMinedHash(); + if (minedHash == block.minedHash) { + //Check minedHash satisfy difficulty based on nbits + bool fNegative; + bool fOverflow; + uint256 bnTarget; + + //As of now, there is no PoA miner, this will let all emulated PoA blocks bypass the check + if (Params().SkipProofOfWorkCheck() || Params().NetworkID() == CBaseChainParams::TESTNET) + return true; + + //The current mainnet is at 10800 blocks, this check will ignore these first blocks + if (mapBlockIndex.count(block.hashPrevBlock) != 0) { + if (CheckPoAMiningBlockHeight(&block)) { + return true; + } + } + + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); + LogPrintf("Target:%s, minedHash:%s\n", bnTarget.GetHex(), minedHash.GetHex()); + + // Check proof of work matches claimed amount + if (minedHash > bnTarget) { + LogPrintf("Block mined hash not satisfied\n"); + return error("CheckProofOfWork() : hash doesn't match nBits"); + } + + return true; + } + return false; +} + +//A PoA block should contains previous PoA block hash +bool CheckPrevPoABlockHash(const CBlockHeader& block) +{ + CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; + if (!currentTip) { + return error("CheckPoAContainRecentHash() : Previous block not found"); + } + //Find the previous PoA block + CBlockIndex* pindex = currentTip; + while (pindex->nHeight > Params().START_POA_BLOCK()) { + if (pindex->GetBlockHeader().IsPoABlockByVersion()) { + break; + } + pindex = pindex->pprev; + } + bool ret = false; + + if (pindex->nHeight > Params().START_POA_BLOCK()) { + CBlockHeader header = pindex->GetBlockHeader(); + uint256 poaBlockHash = header.GetHash(); + if (poaBlockHash == block.hashPrevPoABlock) { + ret = true; + } + } else { + //This is the first poa block ==> previous poa hash = 0 + ret = block.hashPrevPoABlock.IsNull(); + } + + return ret; +} + +//Check whether the poa merkle root is correctly computed +bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate) +{ + uint256 expected = block.BuildPoAMerkleTree(fMutate); + if (expected == block.hashPoAMerkleRoot) { + return true; + } + return false; +} + +//A PoA block cannot contain information of any PoA block information (hash, height, timestamp) +bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block) +{ + uint32_t numOfPoSBlocks = block.posBlocksAudited.size(); + for (uint32_t i = 0; i < numOfPoSBlocks; i++) { + PoSBlockSummary pos = block.posBlocksAudited.at(i); + uint256 hash = pos.hash; + if (mapBlockIndex.count(hash) == 0) { + return false; + } + CBlockIndex* pblockindex = mapBlockIndex[hash]; + CBlockHeader header = pblockindex->GetBlockHeader(); + if (header.IsPoABlockByVersion()) { + return false; + } + } + return true; +} + +bool CheckPoAblockTime(const CBlock& block) +{ + bool ret = false; + + if (block.hashPrevPoABlock.IsNull()) { + ret = true; + } else { + LogPrint("debug", "%s: Previous PoA block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); + if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { + CBlockIndex* pindex = mapBlockIndex[block.hashPrevPoABlock]; + uint32_t prevPoATime = pindex->nTime; + if (block.nTime > prevPoATime && (block.nTime - pindex->nTime >= (uint32_t)Params().POA_BLOCK_TIME())) { + ret = true; + } + LogPrint("debug", "%s: PoA Block time: %d, Previous: %d, Current: %d, Distance: %d\n", __func__, + Params().POA_BLOCK_TIME(), prevPoATime, block.nTime, block.nTime - pindex->nTime); + } else { + LogPrint("debug", "%s: Cannot find block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); + } + } + return ret; +} + +bool CheckPoABlockNotAuditingOverlap(const CBlock& block) +{ + bool ret = false; + + if (block.hashPrevPoABlock.IsNull()) { + //First PoA block + LogPrint("debug", "%s: First PoA Block Hash: %s\n", __func__, block.GetHash().GetHex()); + ret = true; + } else { + if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { + CBlockIndex* pPrevPoAIndex = mapBlockIndex[block.hashPrevPoABlock]; + CBlock prevPoablock; + if (!ReadBlockFromDisk(prevPoablock, pPrevPoAIndex)) + throw runtime_error("Can't read block from disk"); + ret = true; + for (size_t i = 0; i < block.posBlocksAudited.size(); i++) { + bool isAlreadyAudited = false; + for (size_t j = 0; j < prevPoablock.posBlocksAudited.size(); j++) { + if (prevPoablock.posBlocksAudited[j].hash == block.posBlocksAudited[i].hash && prevPoablock.posBlocksAudited[j].nTime == block.posBlocksAudited[i].nTime && prevPoablock.posBlocksAudited[j].height == block.posBlocksAudited[i].height) { + isAlreadyAudited = true; + LogPrint("debug", "%s: PoA Block Hash: %s, is already auditted by Block %s\n", __func__, + block.posBlocksAudited[i].hash.GetHex(), + prevPoablock.GetHash().GetHex()); + break; + } + } + + if (isAlreadyAudited) { + ret = false; + break; + } + } + } + } + + return ret; +} From 08ed56db561d168f366d3b2725c18c9bd553b177 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:30:22 +0100 Subject: [PATCH 0097/1888] Update poa.h --- src/poa.h | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/poa.h b/src/poa.h index 2693fc5440..7742325bb4 100644 --- a/src/poa.h +++ b/src/poa.h @@ -1,11 +1,51 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 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 DAPSCOIN_POA_H #define DAPSCOIN_POA_H #include #include +class CBlockHeader; +class CBlockIndex; +class uint256; +class arith_uint256; + +// Define difficulty retarget algorithms +enum DiffMode { + DIFF_DEFAULT = 0, // Default to invalid 0 + DIFF_BTC = 1, // Retarget every x blocks (Bitcoin style) + DIFF_KGW = 2, // Retarget using Kimoto Gravity Well + DIFF_DGW = 3, // Retarget using Dark Gravity Wave v3 +}; + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock); + +/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ +bool CheckProofOfWork(uint256 hash, unsigned int nBits); +uint256 GetBlockProof(const CBlockIndex& block); + +extern const uint32_t POA_BLOCK_PERIOD; +extern unsigned int N_BITS; +//unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock); + +//Check PoA block header consensus rules +bool CheckPrevPoABlockHash(const CBlockHeader& block); + +bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate = NULL); + +/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ +bool CheckPoABlockMinedHash(const CBlockHeader& block); + +bool CheckPoAContainRecentHash(const CBlock& block); +bool CheckNumberOfAuditedPoSBlocks(const CBlock& block); +bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block); +bool CheckPoAblockTime(const CBlock& block); +bool CheckPoABlockNotAuditingOverlap(const CBlock& block); -//uint256 GetBlockProof(const CBlockIndex& block); #endif // DAPSCOIN_POA_H From 63671e2254e363fd250c02be2b34f7df28ae25de Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:30:55 +0100 Subject: [PATCH 0098/1888] Delete pow.cpp --- src/pow.cpp | 450 ---------------------------------------------------- 1 file changed, 450 deletions(-) delete mode 100644 src/pow.cpp diff --git a/src/pow.cpp b/src/pow.cpp deleted file mode 100644 index 59a7a85687..0000000000 --- a/src/pow.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "pow.h" - -#include "chain.h" -#include "chainparams.h" -#include "main.h" -#include "primitives/block.h" -#include "uint256.h" -#include "util.h" - -#include - -unsigned int N_BITS = 0x1e1ffff0; -unsigned int N_BITS_SF = 0x1e050000; -bool CheckPoAMiningBlockHeight(const CBlockHeader* pblock) -{ - return false; -} - -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock) -{ - if (N_BITS != 0 && pblock->IsPoABlockByVersion()) { - if (pindexLast->nHeight < 125000) { - return N_BITS; - } - return N_BITS_SF; - } - /* current difficulty formula, dapscoin - DarkGravity v3, written by Evan Duffield - evan@dashpay.io */ - const CBlockIndex* BlockLastSolved = pindexLast; - const CBlockIndex* BlockReading = pindexLast; - int64_t nActualTimespan = 0; - int64_t LastBlockTime = 0; - int64_t PastBlocksMin = 24; - int64_t PastBlocksMax = 24; - int64_t CountBlocks = 0; - uint256 PastDifficultyAverage; - uint256 PastDifficultyAveragePrev; - - if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { - return Params().ProofOfWorkLimit().GetCompact(); - } - - if (pindexLast->nHeight > Params().LAST_POW_BLOCK()) { - uint256 bnTargetLimit = (~uint256(0) >> 24); - int64_t nTargetSpacing = 60; - int64_t nTargetTimespan = 60 * 40; - - //finding last PoS block - CBlockIndex* pLastPoS = pindexLast->pprev; - while (!pLastPoS->IsProofOfStake() && pLastPoS->nHeight > Params().LAST_POW_BLOCK()) { - pLastPoS = pLastPoS->pprev; - } - int64_t nActualSpacing = 0; - //ig - if (pindexLast->nHeight != 0) - nActualSpacing = pindexLast->GetBlockTime() - pLastPoS->GetBlockTime(); - - if (nActualSpacing < 0) - nActualSpacing = 1; - - // ppcoin: target change every block - // ppcoin: retarget with exponential moving toward target spacing - uint256 bnNew; - if (pindexLast->nHeight < 125000) { - bnNew.SetCompact(pindexLast->nBits); - } else { - if (pindexLast->IsProofOfStake()) { - bnNew.SetCompact(pindexLast->nBits); - } else { - bnNew.SetCompact(pLastPoS->nBits); - } - } - - int64_t nInterval = nTargetTimespan / nTargetSpacing; - bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); - bnNew /= ((nInterval + 1) * nTargetSpacing); - - if (bnNew <= 0 || bnNew > bnTargetLimit) - bnNew = bnTargetLimit; - - return bnNew.GetCompact(); - } - - for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { - if (PastBlocksMax > 0 && i > PastBlocksMax) { - break; - } - CountBlocks++; - - if (CountBlocks <= PastBlocksMin) { - if (CountBlocks == 1) { - PastDifficultyAverage.SetCompact(BlockReading->nBits); - } else { - PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); - } - PastDifficultyAveragePrev = PastDifficultyAverage; - } - - if (LastBlockTime > 0) { - int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime()); - nActualTimespan += Diff; - } - LastBlockTime = BlockReading->GetBlockTime(); - - if (BlockReading->pprev == NULL) { - assert(BlockReading); - break; - } - BlockReading = BlockReading->pprev; - } - - uint256 bnNew(PastDifficultyAverage); - - int64_t _nTargetTimespan = CountBlocks * Params().TargetSpacing(); - - if (nActualTimespan < _nTargetTimespan / 3) - nActualTimespan = _nTargetTimespan / 3; - if (nActualTimespan > _nTargetTimespan * 3) - nActualTimespan = _nTargetTimespan * 3; - - // Retarget - bnNew *= nActualTimespan; - bnNew /= _nTargetTimespan; - - if (bnNew > Params().ProofOfWorkLimit()) { - bnNew = Params().ProofOfWorkLimit(); - } - - return bnNew.GetCompact(); -} - -bool CheckProofOfWork(uint256 hash, unsigned int nBits) -{ - bool fNegative; - bool fOverflow; - uint256 bnTarget; - - if (Params().SkipProofOfWorkCheck()) - return true; - - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - - // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) - return error("CheckProofOfWork() : nBits below minimum work"); - - // Check proof of work matches claimed amount - if (hash > bnTarget) - return error("CheckProofOfWork() : hash doesn't match nBits"); - - return true; -} - -uint256 GetBlockProof(const CBlockIndex& block) -{ - uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; -} - -//If blockheight = -1, the to-be-checked block is not included yet in the chain, otherwise, that is the height of the poa block -bool CheckPoAContainRecentHash(const CBlock& block) -{ - //block.Merkle - CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; - if (!currentTip) { - return error("CheckPoAContainRecentHash() : Previous block not found"); - } - //Find the previous PoA block - CBlockIndex* pindex = currentTip; - while (pindex->nHeight >= Params().START_POA_BLOCK()) { - if (pindex->GetBlockHeader().IsPoABlockByVersion()) { - break; - } - pindex = pindex->pprev; - } - bool ret = true; - if (pindex->nHeight <= Params().START_POA_BLOCK()) { - //this is the first PoA block ==> check all PoS blocks from LAST_POW_BLOCK up to currentHeight - POA_BLOCK_PERIOD - 1 inclusive - int index = 0; - for (size_t i = Params().LAST_POW_BLOCK() + 1; i <= Params().LAST_POW_BLOCK() + block.posBlocksAudited.size(); i++) { - PoSBlockSummary pos = block.posBlocksAudited.at(index); - CBlockIndex* pidxInChain = mapBlockIndex[pos.hash]; - if (!pidxInChain) { - return error("CheckPoAContainRecentHash() : Audited blocks not found"); - } - if (pos.hash != pidxInChain->GetBlockHash() || pos.nTime != pidxInChain->nTime || pos.height != (uint32_t)pidxInChain->nHeight) { - ret = false; - break; - } - CBlockIndex* p = mapBlockIndex[pos.hash]; - bool auditResult = ReVerifyPoSBlock(p); - if (!auditResult) { - if (pos.nTime) { - ret = false; - break; - } - } - index++; - } - } else { - if (pindex->nHeight >= Params().START_POA_BLOCK()) { - CBlock prevPoablock; - CBlockIndex* pblockindex = pindex; - if (!ReadBlockFromDisk(prevPoablock, pblockindex)) - throw runtime_error("Can't read block from disk"); - PoSBlockSummary lastAuditedPoSBlockInfo = prevPoablock.posBlocksAudited.back(); - uint256 lastAuditedPoSHash = lastAuditedPoSBlockInfo.hash; - if (mapBlockIndex.count(lastAuditedPoSHash) < 1) { - return error("CheckPoAContainRecentHash() : Audited blocks not found"); - } - CBlockIndex* piterator = mapBlockIndex[lastAuditedPoSHash]->pnext; - uint32_t idxOfPoSInfo = 0; - if (!piterator) { - //check whether chainActive has - if (mapBlockIndex[lastAuditedPoSHash]->nHeight + 1 > chainActive.Height()) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } - piterator = chainActive[mapBlockIndex[lastAuditedPoSHash]->nHeight + 1]; - if (!piterator) - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != lastAuditedPoSHash) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } - } - while (piterator->nHeight <= (uint32_t)currentTip->nHeight && idxOfPoSInfo < block.posBlocksAudited.size()) { - if (!piterator->GetBlockHeader().IsPoABlockByVersion() && piterator->nHeight > Params().LAST_POW_BLOCK()) { - PoSBlockSummary pos = block.posBlocksAudited[idxOfPoSInfo]; - CBlockIndex* posAudited = piterator; - if (pos.hash == *(posAudited->phashBlock) && pos.height == (uint32_t)posAudited->nHeight && pos.nTime == posAudited->GetBlockTime()) { - idxOfPoSInfo++; - } else { - //The PoA block is not satisfied the constraint - ret = false; - break; - } - - CBlockIndex* p = mapBlockIndex[pos.hash]; - bool auditResult = ReVerifyPoSBlock(p); - if (!auditResult) { - if (pos.nTime) { - ret = false; - break; - } - } - } - uint256 h = piterator->GetBlockHash(); - piterator = piterator->pnext; - - if (!piterator) { - if (mapBlockIndex[h]->nHeight + 1 > chainActive.Height()) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", lastAuditedPoSHash.GetHex()); - } - piterator = chainActive[mapBlockIndex[h]->nHeight + 1]; - if (!piterator) - return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); - if (piterator->pprev == NULL || piterator->pprev->GetBlockHash() != h) { - return error("CheckPoAContainRecentHash() : PoS block %s not found", h.GetHex()); - } - } - } - - if (idxOfPoSInfo != block.posBlocksAudited.size()) { - //Not all PoS Blocks in PoA block have been checked, not satisfied - ret = false; - } - } else { - ret = block.hashPrevPoABlock.IsNull(); - } - } - return ret; -} - -bool CheckNumberOfAuditedPoSBlocks(const CBlock& block) -{ - if (block.posBlocksAudited.size() < (size_t)Params().MIN_NUM_POS_BLOCKS_AUDITED()) { - return false; - } - return true; -} - -//Check whether the block is successfully mined and the mined hash satisfy the difficulty -bool CheckPoABlockMinedHash(const CBlockHeader& block) -{ - const uint256 minedHash = block.minedHash; //block.ComputeMinedHash(); - if (minedHash == block.minedHash) { - //Check minedHash satisfy difficulty based on nbits - bool fNegative; - bool fOverflow; - uint256 bnTarget; - - //As of now, there is no PoA miner, this will let all emulated PoA blocks bypass the check - if (Params().SkipProofOfWorkCheck() || Params().NetworkID() == CBaseChainParams::TESTNET) - return true; - - //The current mainnet is at 10800 blocks, this check will ignore these first blocks - if (mapBlockIndex.count(block.hashPrevBlock) != 0) { - if (CheckPoAMiningBlockHeight(&block)) { - return true; - } - } - - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - LogPrintf("Target:%s, minedHash:%s\n", bnTarget.GetHex(), minedHash.GetHex()); - - // Check proof of work matches claimed amount - if (minedHash > bnTarget) { - LogPrintf("Block mined hash not satisfied\n"); - return error("CheckProofOfWork() : hash doesn't match nBits"); - } - - return true; - } - return false; -} - -//A PoA block should contains previous PoA block hash -bool CheckPrevPoABlockHash(const CBlockHeader& block) -{ - CBlockIndex* currentTip = mapBlockIndex[block.hashPrevBlock]; - if (!currentTip) { - return error("CheckPoAContainRecentHash() : Previous block not found"); - } - //Find the previous PoA block - CBlockIndex* pindex = currentTip; - while (pindex->nHeight > Params().START_POA_BLOCK()) { - if (pindex->GetBlockHeader().IsPoABlockByVersion()) { - break; - } - pindex = pindex->pprev; - } - bool ret = false; - - if (pindex->nHeight > Params().START_POA_BLOCK()) { - CBlockHeader header = pindex->GetBlockHeader(); - uint256 poaBlockHash = header.GetHash(); - if (poaBlockHash == block.hashPrevPoABlock) { - ret = true; - } - } else { - //This is the first poa block ==> previous poa hash = 0 - ret = block.hashPrevPoABlock.IsNull(); - } - - return ret; -} - -//Check whether the poa merkle root is correctly computed -bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate) -{ - uint256 expected = block.BuildPoAMerkleTree(fMutate); - if (expected == block.hashPoAMerkleRoot) { - return true; - } - return false; -} - -//A PoA block cannot contain information of any PoA block information (hash, height, timestamp) -bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block) -{ - uint32_t numOfPoSBlocks = block.posBlocksAudited.size(); - for (uint32_t i = 0; i < numOfPoSBlocks; i++) { - PoSBlockSummary pos = block.posBlocksAudited.at(i); - uint256 hash = pos.hash; - if (mapBlockIndex.count(hash) == 0) { - return false; - } - CBlockIndex* pblockindex = mapBlockIndex[hash]; - CBlockHeader header = pblockindex->GetBlockHeader(); - if (header.IsPoABlockByVersion()) { - return false; - } - } - return true; -} - -bool CheckPoAblockTime(const CBlock& block) -{ - bool ret = false; - - if (block.hashPrevPoABlock.IsNull()) { - ret = true; - } else { - LogPrint("debug", "%s: Previous PoA block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); - if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { - CBlockIndex* pindex = mapBlockIndex[block.hashPrevPoABlock]; - uint32_t prevPoATime = pindex->nTime; - if (block.nTime > prevPoATime && (block.nTime - pindex->nTime >= (uint32_t)Params().POA_BLOCK_TIME())) { - ret = true; - } - LogPrint("debug", "%s: PoA Block time: %d, Previous: %d, Current: %d, Distance: %d\n", __func__, - Params().POA_BLOCK_TIME(), prevPoATime, block.nTime, block.nTime - pindex->nTime); - } else { - LogPrint("debug", "%s: Cannot find block hash %s\n", __func__, block.hashPrevPoABlock.GetHex()); - } - } - return ret; -} - -bool CheckPoABlockNotAuditingOverlap(const CBlock& block) -{ - bool ret = false; - - if (block.hashPrevPoABlock.IsNull()) { - //First PoA block - LogPrint("debug", "%s: First PoA Block Hash: %s\n", __func__, block.GetHash().GetHex()); - ret = true; - } else { - if (mapBlockIndex.count(block.hashPrevPoABlock) != 0) { - CBlockIndex* pPrevPoAIndex = mapBlockIndex[block.hashPrevPoABlock]; - CBlock prevPoablock; - if (!ReadBlockFromDisk(prevPoablock, pPrevPoAIndex)) - throw runtime_error("Can't read block from disk"); - ret = true; - for (size_t i = 0; i < block.posBlocksAudited.size(); i++) { - bool isAlreadyAudited = false; - for (size_t j = 0; j < prevPoablock.posBlocksAudited.size(); j++) { - if (prevPoablock.posBlocksAudited[j].hash == block.posBlocksAudited[i].hash && prevPoablock.posBlocksAudited[j].nTime == block.posBlocksAudited[i].nTime && prevPoablock.posBlocksAudited[j].height == block.posBlocksAudited[i].height) { - isAlreadyAudited = true; - LogPrint("debug", "%s: PoA Block Hash: %s, is already auditted by Block %s\n", __func__, - block.posBlocksAudited[i].hash.GetHex(), - prevPoablock.GetHash().GetHex()); - break; - } - } - - if (isAlreadyAudited) { - ret = false; - break; - } - } - } - } - - return ret; -} From 29b6948275de5da5ab9d766f2949675482fec81a Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:31:12 +0100 Subject: [PATCH 0099/1888] Delete pow.h --- src/pow.h | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 src/pow.h diff --git a/src/pow.h b/src/pow.h deleted file mode 100644 index ee501fcce7..0000000000 --- a/src/pow.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 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_POW_H -#define BITCOIN_POW_H - -#include -#include "primitives/block.h" - -class CBlockHeader; -class CBlockIndex; -class uint256; -class arith_uint256; - -// Define difficulty retarget algorithms -enum DiffMode { - DIFF_DEFAULT = 0, // Default to invalid 0 - DIFF_BTC = 1, // Retarget every x blocks (Bitcoin style) - DIFF_KGW = 2, // Retarget using Kimoto Gravity Well - DIFF_DGW = 3, // Retarget using Dark Gravity Wave v3 -}; - -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock); - -/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(uint256 hash, unsigned int nBits); -uint256 GetBlockProof(const CBlockIndex& block); - -extern const uint32_t POA_BLOCK_PERIOD; -extern unsigned int N_BITS; -//unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock); - -//Check PoA block header consensus rules -bool CheckPrevPoABlockHash(const CBlockHeader& block); - -bool CheckPoAMerkleRoot(const CBlock& block, bool* fMutate = NULL); - -/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckPoABlockMinedHash(const CBlockHeader& block); - -bool CheckPoAContainRecentHash(const CBlock& block); -bool CheckNumberOfAuditedPoSBlocks(const CBlock& block); -bool CheckPoABlockNotContainingPoABlockInfo(const CBlock& block); - -bool CheckPoAblockTime(const CBlock& block); -bool CheckPoABlockNotAuditingOverlap(const CBlock& block); - - -#endif // BITCOIN_POW_H From 59b85ee9c618a0b79e3c05000b92c18722efcdbe Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:34:04 +0100 Subject: [PATCH 0100/1888] Update dapscoin-qt.pro --- contrib/dapscoin-qt.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index af4c922058..1943a8bda8 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -114,7 +114,6 @@ HEADERS += src/activemasternode.h \ src/obfuscation-relay.h \ src/obfuscation.h \ src/poa.h \ - src/pow.h \ src/protocol.h \ src/pubkey.h \ src/random.h \ From b479be34208167f878e4c4af2b54434ebad85968 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:35:16 +0100 Subject: [PATCH 0101/1888] Update chain.h --- src/chain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chain.h b/src/chain.h index 32b85435a7..116c4ec7cd 100644 --- a/src/chain.h +++ b/src/chain.h @@ -8,7 +8,7 @@ #ifndef BITCOIN_CHAIN_H #define BITCOIN_CHAIN_H -#include "pow.h" +#include "poa.h" #include "primitives/block.h" #include "tinyformat.h" #include "uint256.h" From 03b0766d12d25bb64def1bbe55c2f0d82d2ac1b0 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:36:12 +0100 Subject: [PATCH 0102/1888] Update main.cpp --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index c58d5fdca0..9b54e6c50e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,6 @@ #include "net.h" #include "obfuscation.h" #include "poa.h" -#include "pow.h" #include "swifttx.h" #include "txdb.h" #include "txmempool.h" From 6cb08653d8e497cc1c21ab344449ffbd166150c1 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:37:39 +0100 Subject: [PATCH 0103/1888] Update main.h --- src/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.h b/src/main.h index 1cff3851f2..d50f8c7adc 100644 --- a/src/main.h +++ b/src/main.h @@ -18,7 +18,7 @@ #include "chainparams.h" #include "coins.h" #include "net.h" -#include "pow.h" +#include "poa.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "script/script.h" From 7da1b5d40023cac0aa755a7bbab12a29c0886157 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:38:36 +0100 Subject: [PATCH 0104/1888] Update Makefile.am --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0b45b1e272..e59b16f30a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -147,7 +147,7 @@ BITCOIN_CORE_H = \ netbase.h \ net.h \ noui.h \ - pow.h \ + poa.h \ protocol.h \ pubkey.h \ random.h \ From 3d5f43ee5592231ebb0f91771c234a50f8556c25 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:39:26 +0100 Subject: [PATCH 0105/1888] Update miner.cpp --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index e68b16608a..204425f3f6 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -15,7 +15,7 @@ #include "main.h" #include "masternode-sync.h" #include "net.h" -#include "pow.h" +#include "poa.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "timedata.h" From 8baf29137bb143b24c45f60ffe5734d700f3558f Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:40:51 +0100 Subject: [PATCH 0106/1888] Update Copyright DAPS --- src/poa.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/poa.h b/src/poa.h index 7742325bb4..1c5863fc55 100644 --- a/src/poa.h +++ b/src/poa.h @@ -1,10 +1,11 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2018-2019 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef DAPSCOIN_POA_H -#define DAPSCOIN_POA_H +#ifndef BITCOIN_POA_H +#define BITCOIN_POA_H #include #include From 16488efb52c495a512ecc183f13beeaf5a27a2d8 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:41:48 +0100 Subject: [PATCH 0107/1888] Update mining.cpp --- src/rpc/mining.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 82b3468ff8..ebe7e87384 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -14,7 +14,7 @@ #include "main.h" #include "miner.h" #include "net.h" -#include "pow.h" +#include "poa.h" #include "rpc/server.h" #include "util.h" #ifdef ENABLE_WALLET From f39dcd9876fc951c126c76830b07767de5053cc0 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:42:35 +0100 Subject: [PATCH 0108/1888] Update DoS_tests.cpp --- src/test/DoS_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index a88b7ffb5b..86e5f43c7e 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -11,7 +11,7 @@ #include "keystore.h" #include "main.h" #include "net.h" -#include "pow.h" +#include "poa.h" #include "script/sign.h" #include "serialize.h" #include "util.h" From fb1fd4e47ccccb04f2da839cd41257a7fea3b5a4 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:43:57 +0100 Subject: [PATCH 0109/1888] Update txdb.cpp --- src/txdb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index 05ca4773e1..966e224ed0 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -8,7 +8,7 @@ #include "txdb.h" #include "main.h" -#include "pow.h" +#include "poa.h" #include "uint256.h" #include From a27b69d1134522b25648062255a033e1da43592d Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:54:17 +0100 Subject: [PATCH 0110/1888] Update dapscoin-qt.pro --- contrib/dapscoin-qt.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index 1943a8bda8..a318b3944a 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -434,7 +434,6 @@ SOURCES += src/activemasternode.cpp \ src/obfuscation-relay.cpp \ src/obfuscation.cpp \ src/poa.cpp \ - src/pow.cpp \ src/protocol.cpp \ src/pubkey.cpp \ src/random.cpp \ From d244b92e3df36d4026f60e49d6371bfd493afb80 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 10:55:12 +0100 Subject: [PATCH 0111/1888] Update Makefile.am --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index e59b16f30a..947a7d63e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -213,7 +213,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ noui.cpp \ - pow.cpp \ + poa.cpp \ rest.cpp \ rpc/blockchain.cpp \ rpc/masternode.cpp \ From 3b0addd61668735f865e4ed1d2225d03b09ba5dc Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Wed, 8 Jan 2020 11:00:38 +0100 Subject: [PATCH 0112/1888] Update poa.h --- src/poa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/poa.h b/src/poa.h index 1c5863fc55..91a85f4d64 100644 --- a/src/poa.h +++ b/src/poa.h @@ -49,4 +49,4 @@ bool CheckPoAblockTime(const CBlock& block); bool CheckPoABlockNotAuditingOverlap(const CBlock& block); -#endif // DAPSCOIN_POA_H +#endif // BITCOIN_POA_H From 405dd4cc648bac1ea4a97af01b74cd572a71515b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 17:09:45 -0500 Subject: [PATCH 0113/1888] Delete __init__.py --- src/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/__init__.py diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 From 2077dd6d905ff701d22bf2069d74fcc54ef39d06 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 17:32:09 -0500 Subject: [PATCH 0114/1888] Remove excessive min age violation log --- src/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index f90a7e0175..e4bfa3499c 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -308,7 +308,7 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlockHeader blockFrom, cons return error("CheckStakeKernelHash() : nTime violation"); if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement - return error("CheckStakeKernelHash() : min age violation - nTimeBlockFrom=%d nStakeMinAge=%d nTimeTx=%d", nTimeBlockFrom, nStakeMinAge, nTimeTx); + return false; //grab difficulty uint256 bnTargetPerCoinDay; bnTargetPerCoinDay.SetCompact(nBits); From 6fb9520d89e23ce79eac4554dfd4d6a62d1828c3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 17:40:50 -0500 Subject: [PATCH 0115/1888] Update logging in main.cpp --- src/main.cpp | 72 ++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c58d5fdca0..a7162ded42 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1695,22 +1695,22 @@ bool CheckHaveInputs(const CCoinsViewCache& view, const CTransaction& tx) bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee, bool ignoreFees) { AssertLockHeld(cs_main); - if (tx.nTxFee <= BASE_FEE) - return state.DoS(100, error("AcceptToMemoryPool: Fee less than base fee 1 DAPS"), REJECT_INVALID, "fee-too-low"); if (pfMissingInputs) *pfMissingInputs = false; + + // Check transaction if (!CheckTransaction(tx, false, true, state)) - return state.DoS(100, error("AcceptToMemoryPool: : CheckTransaction failed"), REJECT_INVALID, "bad-tx"); + return state.DoS(100, error("%s : CheckTransaction failed", __func__), REJECT_INVALID, "bad-tx"); + // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.DoS(100, error("AcceptToMemoryPool: : coinbase as individual tx"), - REJECT_INVALID, "coinbase"); + return state.DoS(100, error("%s : coinbase as individual tx", + __func__), REJECT_INVALID, "coinbase"); + //Coinstake is also only valid in a block, not as a loose transaction - if (tx.IsCoinStake()) { - LogPrintf("%s: txRejected=%s\n", __func__, tx.GetHash().GetHex()); - return state.DoS(100, error("AcceptToMemoryPool: coinstake as individual tx"), - REJECT_INVALID, "coinstake"); - } + if (tx.IsCoinStake()) + return state.DoS(100, error("%s : coinstake as individual tx (id=%s): %s", + __func__, tx.GetHash().GetHex(), tx.ToString()), REJECT_INVALID, "coinstake"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; if (Params().RequireStandard() && !IsStandardTx(tx, reason)) @@ -1734,17 +1734,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa view.SetBackend(viewMemPool); // do we already have it? if (view.HaveCoins(hash)) { - LogPrintf("%s: Error: Hash exists in the mempool\n", __func__); return false; } // are the actual inputs available? - if (!CheckHaveInputs(view, tx)) { - //check input spents - - return state.Invalid(error("AcceptToMemoryPool : inputs already spent"), - REJECT_DUPLICATE, "bad-txns-inputs-spent"); - } + if (!view.HaveInputs(tx)) + return state.Invalid(error("%s: inputs already spent", + __func__), REJECT_DUPLICATE, "bad-txns-inputs-spent"); if (!tx.IsCoinStake() && !tx.IsCoinBase() && !tx.IsCoinAudit()) { if (!tx.IsCoinAudit()) { @@ -1962,9 +1958,9 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // are the actual inputs available? - if (!CheckHaveInputs(view, tx)) - return state.Invalid(error("AcceptableInputs : inputs already spent"), - REJECT_DUPLICATE, "bad-txns-inputs-spent"); + if (!view.HaveInputs(tx)) + return state.Invalid(error("%s : inputs already spent", + __func__), REJECT_DUPLICATE, "bad-txns-inputs-spent"); // Bring the best block into scope view.GetBestBlock(); @@ -4717,7 +4713,7 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis } - LogPrintf("%s : ACCEPTED in %ld milliseconds with size=%d, height=%d\n", __func__, GetTimeMillis() - nStartTime, + LogPrintf("%s: ACCEPTED in %ld milliseconds with size=%d, height=%d\n", __func__, GetTimeMillis() - nStartTime, pblock->GetSerializeSize(SER_DISK, CLIENT_VERSION), chainActive.Height()); return true; @@ -5041,39 +5037,30 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth CValidationState state; for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, - (int)(((double)(chainActive.Height() - - pindex->nHeight)) / - (double)nCheckDepth * - (nCheckLevel >= 4 ? 50 : 100))))); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); if (pindex->nHeight < chainActive.Height() - nCheckDepth) break; CBlock block; // check level 0: read from disk if (!ReadBlockFromDisk(block, pindex)) - return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, - pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity if (nCheckLevel >= 1 && !CheckBlock(block, state)) - return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, - pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { CBlockUndo undo; CDiskBlockPos pos = pindex->GetUndoPos(); if (!pos.IsNull()) { if (!undo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) - return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, - pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); } } // check level 3: check for inconsistencies during memory-only disconnect of tip blocks - if (nCheckLevel >= 3 && pindex == pindexState && - (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) { + if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) { bool fClean = true; if (!DisconnectBlock(block, state, pindex, coins, &fClean)) - return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", - pindex->nHeight, pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); pindexState = pindex->pprev; if (!fClean) { nGoodTransactions = 0; @@ -5085,9 +5072,7 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth return true; } if (pindexFailure) - return error( - "VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", - chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); + return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { @@ -5098,16 +5083,13 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex)) - return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, - pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); if (!ConnectBlock(block, state, pindex, coins, false)) - return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, - pindex->GetBlockHash().ToString()); + return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } - LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", - chainActive.Height() - pindexState->nHeight, nGoodTransactions); + LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); return true; } From 664924f0e8b7b9decb765dbbca2701bc6a5618cb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 17:52:36 -0500 Subject: [PATCH 0116/1888] Remove Boost dependency from the httpserver --- src/httpserver.cpp | 53 +++++++++++++++++++++++----------------------- src/httpserver.h | 10 ++++----- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index d6b4c77ed2..94a12e57f9 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -36,9 +37,6 @@ #endif #endif -#include // for to_lower() -#include - /** Maximum size of http request (request line + headers) */ static const size_t MAX_HEADERS_SIZE = 8192; @@ -55,7 +53,7 @@ class HTTPWorkItem : public HTTPClosure func(req.get(), path); } - boost::scoped_ptr req; + std::unique_ptr req; private: std::string path; @@ -70,8 +68,8 @@ class WorkQueue { private: /** Mutex protects entire object */ - CWaitableCriticalSection cs; - CConditionVariable cond; + std::mutex cs; + std::condition_variable cond; /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */ std::deque queue; bool running; @@ -85,12 +83,12 @@ class WorkQueue WorkQueue &wq; ThreadCounter(WorkQueue &w): wq(w) { - boost::lock_guard lock(wq.cs); + std::lock_guard lock(wq.cs); wq.numThreads += 1; } ~ThreadCounter() { - boost::lock_guard lock(wq.cs); + std::lock_guard lock(wq.cs); wq.numThreads -= 1; wq.cond.notify_all(); } @@ -115,7 +113,7 @@ class WorkQueue /** Enqueue a work item */ bool Enqueue(WorkItem* item) { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); if (queue.size() >= maxDepth) { return false; } @@ -130,7 +128,7 @@ class WorkQueue while (running) { WorkItem* i = 0; { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); while (running && queue.empty()) cond.wait(lock); if (!running) @@ -145,14 +143,14 @@ class WorkQueue /** Interrupt and exit loops */ void Interrupt() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); running = false; cond.notify_all(); } /** Wait for worker threads to exit */ void WaitExit() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); while (numThreads > 0) cond.wait(lock); } @@ -160,7 +158,7 @@ class WorkQueue /** Return current depth of queue */ size_t Depth() { - boost::unique_lock lock(cs); + std::unique_lock lock(cs); return queue.size(); } }; @@ -306,13 +304,14 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL); } /** Event dispatcher thread */ -static void ThreadHTTP(struct event_base* base, struct evhttp* http) +static bool ThreadHTTP(struct event_base* base, struct evhttp* http) { RenameThread("bitcoin-http"); LogPrint("http", "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() LogPrint("http", "Exited http event loop\n"); + return event_base_got_break(base) == 0; } /** Bind HTTP server to specified addresses */ @@ -441,17 +440,22 @@ bool InitHTTPServer() return true; } -boost::thread threadHTTP; +std::thread threadHTTP; +std::future threadResult; bool StartHTTPServer() { LogPrint("http", "Starting HTTP server\n"); int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L); LogPrintf("HTTP: starting %d worker threads\n", rpcThreads); - threadHTTP = boost::thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP)); + std::packaged_task task(ThreadHTTP); + threadResult = task.get_future(); + threadHTTP = std::thread(std::move(task), eventBase, eventHTTP); - for (int i = 0; i < rpcThreads; i++) - boost::thread(boost::bind(&HTTPWorkQueueRun, workQueue)); + for (int i = 0; i < rpcThreads; i++) { + std::thread rpc_worker(HTTPWorkQueueRun, workQueue); + rpc_worker.detach(); + } return true; } @@ -485,15 +489,12 @@ void StopHTTPServer() // master that appears to be solved, so in the future that solution // could be used again (if desirable). // (see discussion in https://github.com/bitcoin/bitcoin/pull/6990) -#if BOOST_VERSION >= 105000 - if (!threadHTTP.try_join_for(boost::chrono::milliseconds(2000))) { -#else - if (!threadHTTP.timed_join(boost::posix_time::milliseconds(2000))) { -#endif + if (threadResult.valid() && threadResult.wait_for(std::chrono::milliseconds(2000)) == std::future_status::timeout) { LogPrintf("HTTP event loop did not exit within allotted time, sending loopbreak\n"); event_base_loopbreak(eventBase); - threadHTTP.join(); + } + threadHTTP.join(); } if (eventHTTP) { evhttp_free(eventHTTP); @@ -520,7 +521,7 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data) delete self; } -HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function& handler): +HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler): deleteWhenTriggered(deleteWhenTriggered), handler(handler) { ev = event_new(base, -1, 0, httpevent_callback_fn, this); @@ -602,7 +603,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); HTTPEvent* ev = new HTTPEvent(eventBase, true, - boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); + std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL)); ev->trigger(0); replySent = true; req = 0; // transferred back to main thread diff --git a/src/httpserver.h b/src/httpserver.h index 20a119cc5c..0e30e666a6 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,9 +7,7 @@ #include #include -#include -#include -#include +#include static const int DEFAULT_HTTP_THREADS=4; static const int DEFAULT_HTTP_WORKQUEUE=16; @@ -35,7 +33,7 @@ void InterruptHTTPServer(); void StopHTTPServer(); /** Handler for requests to a certain HTTP path */ -typedef boost::function HTTPRequestHandler; +typedef std::function HTTPRequestHandler; /** Register handler for prefix. * If multiple handlers match a prefix, the first-registered one will * be invoked. @@ -132,7 +130,7 @@ class HTTPEvent * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called) * handler is the handler to call when the event is triggered. */ - HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function& handler); + HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler); ~HTTPEvent(); /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after @@ -141,7 +139,7 @@ class HTTPEvent void trigger(struct timeval* tv); bool deleteWhenTriggered; - boost::function handler; + std::function handler; private: struct event* ev; }; From 2a730dae9dc304f7fbb42b053ab5a44f71ad473b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 17:53:43 -0500 Subject: [PATCH 0117/1888] Missed line breaks in failed to load spend/view key logging --- src/wallet/wallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8016c1e26c..c1c7d63921 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -7027,7 +7027,7 @@ bool CWallet::mySpendPrivateKey(CKey& spend) const CAccount spendAccount; CWalletDB pDB(strWalletFile); if (!pDB.ReadAccount(spendAccountLabel, spendAccount)) { - LogPrintf("Cannot Load Spend private key, now create the master keys"); + LogPrintf("Cannot Load Spend private key, now create the master keys\n"); createMasterKey(); pDB.ReadAccount(spendAccountLabel, spendAccount); } @@ -7048,7 +7048,7 @@ bool CWallet::myViewPrivateKey(CKey& view) const CAccount viewAccount; CWalletDB pDB(strWalletFile); if (!pDB.ReadAccount(viewAccountLabel, viewAccount)) { - LogPrintf("Cannot Load view private key, now create the master keys"); + LogPrintf("Cannot Load view private key, now create the master keys\n"); createMasterKey(); pDB.ReadAccount(viewAccountLabel, viewAccount); } From 26b359ad8c8bc4a7a02217edda29183e813d0e36 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 18:46:06 -0500 Subject: [PATCH 0118/1888] Remove unused includes --- src/poa.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/poa.h b/src/poa.h index 91a85f4d64..cc430537a3 100644 --- a/src/poa.h +++ b/src/poa.h @@ -29,9 +29,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead bool CheckProofOfWork(uint256 hash, unsigned int nBits); uint256 GetBlockProof(const CBlockIndex& block); -extern const uint32_t POA_BLOCK_PERIOD; extern unsigned int N_BITS; -//unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock); //Check PoA block header consensus rules bool CheckPrevPoABlockHash(const CBlockHeader& block); From ffe4c927824fb47ad9adb3e7ed76971d112bba01 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 19:11:22 -0500 Subject: [PATCH 0119/1888] Remove CheckPoAMiningBlockHeight function that only returned false --- src/poa.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/poa.cpp b/src/poa.cpp index 054c8c8f7b..7664e05734 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -18,10 +18,6 @@ unsigned int N_BITS = 0x1e1ffff0; unsigned int N_BITS_SF = 0x1e050000; -bool CheckPoAMiningBlockHeight(const CBlockHeader* pblock) -{ - return false; -} unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock) { @@ -307,13 +303,6 @@ bool CheckPoABlockMinedHash(const CBlockHeader& block) if (Params().SkipProofOfWorkCheck() || Params().NetworkID() == CBaseChainParams::TESTNET) return true; - //The current mainnet is at 10800 blocks, this check will ignore these first blocks - if (mapBlockIndex.count(block.hashPrevBlock) != 0) { - if (CheckPoAMiningBlockHeight(&block)) { - return true; - } - } - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); LogPrintf("Target:%s, minedHash:%s\n", bnTarget.GetHex(), minedHash.GetHex()); From 26b0077b29ba04c7d76e45b54b03bbc4debc5245 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 8 Jan 2020 19:29:15 -0500 Subject: [PATCH 0120/1888] Update copyrights --- configure.ac | 2 +- qa/rpc-tests/util.py | 2 +- qa/rpc-tests/util.sh | 2 +- src/activemasternode.cpp | 2 +- src/activemasternode.h | 2 +- src/bignum.h | 2 +- src/bip38.cpp | 2 +- src/bip38.h | 2 +- src/blocksignature.cpp | 2 +- src/blocksignature.h | 2 +- src/chain.h | 2 +- src/chainparams.cpp | 2 +- src/chainparams.h | 2 +- src/checkpoints.cpp | 2 +- src/coincontrol.h | 2 +- src/coins.cpp | 2 +- src/core_read.cpp | 2 +- src/dapscoin-cli.cpp | 2 +- src/dapscoin-tx.cpp | 2 +- src/dapscoind.cpp | 2 +- src/hash.h | 2 +- src/httprpc.cpp | 2 +- src/httpserver.cpp | 2 +- src/init.cpp | 2 +- src/invalid.h | 2 +- src/kernel.cpp | 2 +- src/kernel.h | 2 +- src/key.h | 2 +- src/main.cpp | 2 +- src/main.h | 2 +- src/masternode-budget.cpp | 2 +- src/masternode-budget.h | 2 +- src/masternode-payments.cpp | 2 +- src/masternode-payments.h | 2 +- src/masternode-sync.cpp | 2 +- src/masternode-sync.h | 2 +- src/masternode.cpp | 2 +- src/masternode.h | 2 +- src/masternodeconfig.cpp | 2 +- src/masternodeconfig.h | 2 +- src/masternodeman.cpp | 2 +- src/masternodeman.h | 2 +- src/merkleblock.cpp | 2 +- src/miner.cpp | 2 +- src/mintpool.cpp | 2 +- src/mintpool.h | 2 +- src/net.cpp | 2 +- src/net.h | 2 +- src/noui.cpp | 2 +- src/obfuscation-relay.cpp | 2 +- src/obfuscation-relay.h | 2 +- src/obfuscation.cpp | 2 +- src/obfuscation.h | 2 +- src/poa.cpp | 2 +- src/pow.cpp | 2 +- src/primitives/block.cpp | 2 +- src/primitives/block.h | 2 +- src/primitives/transaction.cpp | 2 +- src/primitives/transaction.h | 2 +- src/qt/addressbookpage.cpp | 2 +- src/qt/addresstablemodel.cpp | 2 +- src/qt/askpassphrasedialog.cpp | 2 +- src/qt/bantablemodel.cpp | 2 +- src/qt/bantablemodel.h | 2 +- src/qt/bip38tooldialog.cpp | 2 +- src/qt/bitcoinaddressvalidator.cpp | 2 +- src/qt/bitcoingui.cpp | 2 +- src/qt/bitcoinunits.cpp | 2 +- src/qt/bitcoinunits.h | 2 +- src/qt/clientmodel.cpp | 2 +- src/qt/clientmodel.h | 2 +- src/qt/coincontroldialog.cpp | 2 +- src/qt/dapscoin.cpp | 2 +- src/qt/editaddressdialog.cpp | 2 +- src/qt/guiconstants.h | 2 +- src/qt/guiutil.cpp | 2 +- src/qt/intro.cpp | 2 +- src/qt/macnotificationhandler.mm | 2 +- src/qt/multisigdialog.cpp | 2 +- src/qt/multisigdialog.h | 2 +- src/qt/openuridialog.cpp | 2 +- src/qt/optionsmodel.cpp | 2 +- src/qt/overviewpage.cpp | 2 +- src/qt/paymentserver.cpp | 2 +- src/qt/rpcconsole.cpp | 2 +- src/qt/sendcoinsentry.cpp | 2 +- src/qt/signverifymessagedialog.cpp | 2 +- src/qt/splashscreen.cpp | 2 +- src/qt/test/test_main.cpp | 2 +- src/qt/togglebutton.cpp | 2 +- src/qt/transactiondesc.cpp | 2 +- src/qt/transactionrecord.cpp | 2 +- src/qt/txentry.cpp | 2 +- src/qt/utilitydialog.cpp | 2 +- src/qt/walletmodel.cpp | 2 +- src/reverse_iterate.h | 2 +- src/reverselock.h | 2 +- src/rpc/blockchain.cpp | 2 +- src/rpc/budget.cpp | 2 +- src/rpc/client.cpp | 2 +- src/rpc/masternode.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/rpc/misc.cpp | 2 +- src/rpc/net.cpp | 2 +- src/rpc/protocol.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/rpc/server.cpp | 2 +- src/rpc/server.h | 2 +- src/scheduler.cpp | 2 +- src/scheduler.h | 2 +- src/serialize.h | 2 +- src/stakeinput.cpp | 2 +- src/stakeinput.h | 2 +- src/swifttx.cpp | 2 +- src/swifttx.h | 2 +- src/test/budget_tests.cpp | 2 +- src/test/main_tests.cpp | 2 +- src/test/netbase_tests.cpp | 2 +- src/test/reverselock_tests.cpp | 2 +- src/test/scheduler_tests.cpp | 2 +- src/txdb.cpp | 2 +- src/txdb.h | 2 +- src/txmempool.cpp | 2 +- src/txmempool.h | 2 +- src/uint256.h | 2 +- src/uint512.h | 2 +- src/util.cpp | 2 +- src/util.h | 2 +- src/utilstrencodings.cpp | 2 +- src/utiltime.h | 2 +- src/version.h | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 2 +- src/wallet/wallet.h | 2 +- src/wallet/wallet_ismine.cpp | 2 +- src/wallet/walletdb.cpp | 2 +- src/wallet/walletdb.h | 2 +- 138 files changed, 138 insertions(+), 138 deletions(-) diff --git a/configure.ac b/configure.ac index 9caa50fe3c..c53a4fb7e6 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ define(_CLIENT_VERSION_REVISION, 5) define(_CLIENT_VERSION_BUILD, 6) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2019) +define(_COPYRIGHT_YEAR, 2020) AC_INIT([DAPScoin],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_REVISION, m4_if(_CLIENT_VERSION_BUILD, [0], [], _CLIENT_VERSION_BUILD))m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/DAPSCoin/DAPSCoin/issues],[dapscoin],[https://officialdapscoin.com]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/dapscoin-config.h]) diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index 5d3fd2a771..ba24faa296 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -1,6 +1,6 @@ # Copyright (c) 2014 The Bitcoin Core developers # Copyright (c) 2014-2015 The Dash developers -# Copyright (c) 2018-2019 The DAPS Project developers +# Copyright (c) 2018-2020 The DAPS Project developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh index aa63c64b3d..3561416859 100644 --- a/qa/rpc-tests/util.sh +++ b/qa/rpc-tests/util.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Copyright (c) 2014 The Bitcoin Core developers # Copyright (c) 2014-2015 The Dash developers -# Copyright (c) 2018-2019 The DAPS Project developers +# Copyright (c) 2018-2020 The DAPS Project developers # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 0e061c4f61..83c3c205cb 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2016 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/activemasternode.h b/src/activemasternode.h index 85a11f84ff..7b306e7bc2 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2016 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bignum.h b/src/bignum.h index 6347e6f28a..0b9c1098d4 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_BIGNUM_H diff --git a/src/bip38.cpp b/src/bip38.cpp index 58fac96ff6..434ca325c3 100644 --- a/src/bip38.cpp +++ b/src/bip38.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bip38.h b/src/bip38.h index 461495d426..e36f3bc3ba 100644 --- a/src/bip38.h +++ b/src/bip38.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blocksignature.cpp b/src/blocksignature.cpp index 99549790aa..6ca133c2f9 100644 --- a/src/blocksignature.cpp +++ b/src/blocksignature.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blocksignature.h b/src/blocksignature.h index 611b367816..899ef192da 100644 --- a/src/blocksignature.h +++ b/src/blocksignature.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/chain.h b/src/chain.h index 32b85435a7..37260420ee 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5c35632387..4c1197b071 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/chainparams.h b/src/chainparams.h index 8697e6f6b9..cd9ea30a2c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 73a6f70bfb..3654968a67 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/coincontrol.h b/src/coincontrol.h index 21666e0984..bc8f4515a0 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -1,7 +1,7 @@ // Copyright (c) 2011-2013 The Bitcoin developers // Copyright (c) 2014-2016 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/coins.cpp b/src/coins.cpp index e528835e39..678fd2b3fb 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2012-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_read.cpp b/src/core_read.cpp index 7229ed57eb..6f0f9c8cd9 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/dapscoin-cli.cpp b/src/dapscoin-cli.cpp index d3b7303047..0027cdbc54 100644 --- a/src/dapscoin-cli.cpp +++ b/src/dapscoin-cli.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2015 The Bitcoin developers // Copyright (c) 2009-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/dapscoin-tx.cpp b/src/dapscoin-tx.cpp index 5fbabacee0..0c7d7c461c 100644 --- a/src/dapscoin-tx.cpp +++ b/src/dapscoin-tx.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 3a926cf138..3b98d9032b 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/hash.h b/src/hash.h index 5c3a86fe74..45aecf343a 100644 --- a/src/hash.h +++ b/src/hash.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 0df8c344ce..fa6c7d0165 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2015-2017 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/httpserver.cpp b/src/httpserver.cpp index d6b4c77ed2..8d38041ade 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init.cpp b/src/init.cpp index 08064c4ac0..fbcfa5bb06 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/invalid.h b/src/invalid.h index 2c8918a721..8e547309ea 100644 --- a/src/invalid.h +++ b/src/invalid.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/kernel.cpp b/src/kernel.cpp index f90a7e0175..eb2a2aa7c7 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -1,7 +1,7 @@ /* @flow */ // Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/kernel.h b/src/kernel.h index 3a3a26cc9b..052b3c32d6 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -1,6 +1,6 @@ // Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KERNEL_H diff --git a/src/key.h b/src/key.h index 4d34faae06..808a690c01 100644 --- a/src/key.h +++ b/src/key.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/main.cpp b/src/main.cpp index c58d5fdca0..f8af41de38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/main.h b/src/main.h index 1cff3851f2..2f115d7110 100644 --- a/src/main.h +++ b/src/main.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 6a6f117b2e..fa6b234c6b 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 824cc9240b..4a458a6984 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 088a7000fa..7e2615b5e4 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 08db384b62..fb868e3a81 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index d834fdb400..963a30f897 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 569cb34e24..945d0084fc 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode.cpp b/src/masternode.cpp index 050c7e7d41..6b815688cc 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternode.h b/src/masternode.h index 97ec9f9653..ef76f1b401 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index 461da1d26a..2b40ffe292 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h index 25b20b746e..528c0b1ece 100644 --- a/src/masternodeconfig.h +++ b/src/masternodeconfig.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index fe0b7bb294..deb68a0d2d 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/masternodeman.h b/src/masternodeman.h index 5004683de4..6659e1ab48 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index f657934d7d..78ca6faca2 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/miner.cpp b/src/miner.cpp index e68b16608a..6ddd55122a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/mintpool.cpp b/src/mintpool.cpp index d2df79b604..e5533bef30 100644 --- a/src/mintpool.cpp +++ b/src/mintpool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/mintpool.h b/src/mintpool.h index d7e9ca5274..8f6eb72c07 100644 --- a/src/mintpool.h +++ b/src/mintpool.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/net.cpp b/src/net.cpp index b254602a4c..6f2863d22d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/net.h b/src/net.h index 417cf52bf7..68475d84c4 100644 --- a/src/net.h +++ b/src/net.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/noui.cpp b/src/noui.cpp index fb4bc7ce9a..147e3d4cd8 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/obfuscation-relay.cpp b/src/obfuscation-relay.cpp index 5340188068..15474c52d3 100644 --- a/src/obfuscation-relay.cpp +++ b/src/obfuscation-relay.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/obfuscation-relay.h b/src/obfuscation-relay.h index dba2d5b7e2..2c2d02f8fb 100644 --- a/src/obfuscation-relay.h +++ b/src/obfuscation-relay.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 9992ec6d43..2c6831dd89 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/obfuscation.h b/src/obfuscation.h index 87346a4a55..56268accd5 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/poa.cpp b/src/poa.cpp index 89b10135d5..2636e67717 100644 --- a/src/poa.cpp +++ b/src/poa.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/pow.cpp b/src/pow.cpp index 59a7a85687..008dfcdf81 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 79f6a2b8fc..f29ac929e0 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/block.h b/src/primitives/block.h index 8ce47333e8..ca62786f0b 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 08677b114c..a8e2643847 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 762a75ee81..4c3a4a1d61 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index e84676246c..1a45235f31 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 44c77b56b8..ab46a7ffe1 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 36d46fca52..bd42c51d4b 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index c6c2fbded2..9958f01179 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2011-2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index 1bddc3372c..bf54366e06 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -1,6 +1,6 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index 74ad5072b0..9b14fdca29 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp index b2723fd4e6..24dc0e1e01 100644 --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 2fb88502b6..6b6f962f27 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 75ee4e765c..78e44e49f9 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 194050efce..c470595cb2 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index dd1e9bf95e..e7a310346b 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 8a87012247..9f852f729c 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 3dd8c0fb67..2ce8f0c411 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 395116ce68..4c2ae6f5fd 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 347fdcdac3..5665b8b7d7 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 89d51fbae5..d1bf9bb056 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 37990949c8..2c3cd4a05d 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index c20c68f15e..da834bb35c 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm index 95207f5476..a24d60d635 100644 --- a/src/qt/macnotificationhandler.mm +++ b/src/qt/macnotificationhandler.mm @@ -1,6 +1,6 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index effd0dcd24..70ffd2bb29 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/multisigdialog.h b/src/qt/multisigdialog.h index b11fc3b44e..9cf7b3094a 100644 --- a/src/qt/multisigdialog.h +++ b/src/qt/multisigdialog.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index 1c59cef01f..ff32befc85 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 55486914c7..8667b6ad75 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 528806ea89..43cb018153 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 8d5fb2060a..774134605f 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e27382fe1d..4c5971b92c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index da706fe46a..e81a5e86e4 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 82f672dcc9..311f22f57e 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 5b46facf44..1cc531fef0 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index bc9ef552e8..2b8fd7267d 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/togglebutton.cpp b/src/qt/togglebutton.cpp index fe29b0df8e..caa53de773 100644 --- a/src/qt/togglebutton.cpp +++ b/src/qt/togglebutton.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index aeac075eb5..5721ada2a6 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 4a513211e3..36a62b388c 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/txentry.cpp b/src/qt/txentry.cpp index c9cd650a4d..9e2d3962f2 100644 --- a/src/qt/txentry.cpp +++ b/src/qt/txentry.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 0965149c47..cfde1b9bce 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0dab47577d..f1c6f14992 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers // Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/reverse_iterate.h b/src/reverse_iterate.h index 4792804fc2..8a86e0141d 100644 --- a/src/reverse_iterate.h +++ b/src/reverse_iterate.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/reverselock.h b/src/reverselock.h index 1ccac57370..81da0b895b 100644 --- a/src/reverselock.h +++ b/src/reverselock.h @@ -1,6 +1,6 @@ // Copyright (c) 2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9709c25124..68c18f71c2 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/budget.cpp b/src/rpc/budget.cpp index 14fc25dbc5..89ded7a2f7 100644 --- a/src/rpc/budget.cpp +++ b/src/rpc/budget.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2015 The Dash Developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index d73cbd0565..b57ad52ab4 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 01c6abfe20..14b352ed51 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 82b3468ff8..29d86d94a6 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 86fb5e9fed..36195dd025 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 670ded1cd7..cc9e9efe0e 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index b500fa4298..e4d585a210 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1060cbdfd4..47bf79a567 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 82e8ee56dd..0ad504b92b 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/server.h b/src/rpc/server.h index 8220da493e..5ded236275 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -1,7 +1,7 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/scheduler.cpp b/src/scheduler.cpp index de44b02514..5f6ca46579 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/scheduler.h b/src/scheduler.h index ded9625b4a..f06031715e 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -1,6 +1,6 @@ // Copyright (c) 2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/serialize.h b/src/serialize.h index 5fddaa7574..e5b909581d 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/stakeinput.cpp b/src/stakeinput.cpp index 4518aac83e..2b44c9a873 100644 --- a/src/stakeinput.cpp +++ b/src/stakeinput.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/stakeinput.h b/src/stakeinput.h index 9a8f826811..7c9899471f 100644 --- a/src/stakeinput.h +++ b/src/stakeinput.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/swifttx.cpp b/src/swifttx.cpp index c314368484..149e98f9e4 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2014-2016 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/swifttx.h b/src/swifttx.h index 3a787a7b1e..e9294903d6 100644 --- a/src/swifttx.h +++ b/src/swifttx.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2012 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/budget_tests.cpp b/src/test/budget_tests.cpp index 57ef03b572..6938cd1909 100644 --- a/src/test/budget_tests.cpp +++ b/src/test/budget_tests.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 4fff031fc0..bbf67219f8 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2014 The Bitcoin Core developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 6aef5dbaa5..126db21804 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2012-2014 The Bitcoin Core developers // Copyright (c) 2014-2015 The Dash Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index e5c0171033..88cc715573 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2015 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 91156251b2..9e1c01b3d5 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2012-2013 The Bitcoin Core developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txdb.cpp b/src/txdb.cpp index 05ca4773e1..8a1aeb395e 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txdb.h b/src/txdb.h index d58d69253d..8ffdaab9d9 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ec1258ee6c..9f0f4fc0b5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/txmempool.h b/src/txmempool.h index 778a724381..365139aaa5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/uint256.h b/src/uint256.h index 11b2e245af..d7f0ef36cb 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/uint512.h b/src/uint512.h index eabf1d9a2f..8186c8961a 100644 --- a/src/uint512.h +++ b/src/uint512.h @@ -1,5 +1,5 @@ // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util.cpp b/src/util.cpp index 61b8a2b95a..4104bb371f 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util.h b/src/util.h index 63267fb5b5..a5e28bd932 100644 --- a/src/util.h +++ b/src/util.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index a94cbd98d8..304b68aacb 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/utiltime.h b/src/utiltime.h index 1329518a19..afbdbd4c77 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/version.h b/src/version.h index 70f5c65bee..8f27bb2438 100644 --- a/src/version.h +++ b/src/version.h @@ -1,7 +1,7 @@ // Copyright (c) 2012-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index ae69b246ab..a78b51c09d 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ed5dd016de..0ea9e20b61 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8016c1e26c..79060f2320 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 1379733200..7c03d48a4b 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index 5e20bda655..98629a2297 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 077a9e9154..1df1cb2e51 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -2,7 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 4840287c1c..ee22ced4ca 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers // Copyright (c) 2015-2018 The PIVX developers -// Copyright (c) 2018-2019 The DAPS Project developers +// Copyright (c) 2018-2020 The DAPS Project developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. From f104d7fac09714da359d5637e6d9ddbab768456a Mon Sep 17 00:00:00 2001 From: DAPS_Spock <55909478+DAPS-Spock@users.noreply.github.com> Date: Fri, 10 Jan 2020 22:40:58 +1000 Subject: [PATCH 0121/1888] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9497b2ae79..5adbb439c9 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,12 @@ The team consists of a total of 20 members located worldwide. ![Privacy Coin Chart](https://officialdapscoin.com/wp-content/uploads/2020/01/DAPS-Privacy-coin-chart-2020.jpg) +## How to Contribute to DAPS + +We have an extensive ![Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. +Please have a look at this first before deciding to contribute to our codebase. + +We welcome developers from all backgrounds to take a look at our code and welcome all suggestions and changes. ## Social From 4d321a9d49d29de7f0462d1ef3bee4fde3321ce3 Mon Sep 17 00:00:00 2001 From: DAPS_Spock <55909478+DAPS-Spock@users.noreply.github.com> Date: Fri, 10 Jan 2020 22:41:20 +1000 Subject: [PATCH 0122/1888] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5adbb439c9..ce410d35be 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The team consists of a total of 20 members located worldwide. ## How to Contribute to DAPS -We have an extensive ![Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. +We have an extensive [Contributing.md](https://github.com/DAPSCoin/DAPSCoin/blob/master/CONTRIBUTING.md) guide on how to contribute to DAPS source code. Please have a look at this first before deciding to contribute to our codebase. We welcome developers from all backgrounds to take a look at our code and welcome all suggestions and changes. From ada6d431c5b015223d7af6645708dcc271126bdd Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 10 Jan 2020 09:53:51 -0500 Subject: [PATCH 0123/1888] Potential fix for incorrect reserve balance error when trying to send --- src/wallet/wallet.cpp | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0ba06ab994..619ce25159 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3099,28 +3099,23 @@ bool CWallet::CreateTransactionBulletProof(const CKey& txPrivDes, const CPubKey& if (!SelectCoins(true, estimateFee, ringSize, 2, nTotalValue, setCoins, nValueIn, coinControl, coin_type, useIX)) { if (coin_type == ALL_COINS) { if (nSpendableBalance < nTotalValue + estimateFee) { - if (estimateFee > 0) + //spendable is less than total + fee + if (estimateFee > 0) + //fee is greater than 0, causing insufficient funds strFailReason = "Insufficient funds. Transaction requires a fee of " + ValueFromAmountToString(estimateFee); - else if (nReserveBalance <= nTotalValue) + else if (nReserveBalance <= nTotalValue && nReserveBalance != 0) + //reserve less than/equal total value strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); - } else if (nTotalValue >= nReserveBalance) { + } else if (nTotalValue >= nReserveBalance && nReserveBalance != 0) { + //total greater than equal to reserve strFailReason = "Insufficient reserved funds! Your wallet is staking with a reserve balance of " + ValueFromAmountToString(nReserveBalance) + " less than the sending amount " + ValueFromAmountToString(nTotalValue); } else if (setCoins.size() > MAX_TX_INPUTS) { + //max inputs strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount."); - } else if (nValueIn == 0) { - strFailReason = _("You have attempted to send more than 50 UTXOs in a single transaction. This is a rare occurrence, and to work around this limitation, please either lower the total amount of the transaction, or send two separate transactions with 50% of your total desired amount."); + } else { + //other + strFailReason = _("Error in CreateTransactionBulletProof. Please try again."); } - } else if (coin_type == ONLY_NOT1000000IFMN) { - strFailReason = _("Unable to locate enough funds for this transaction that are not equal 10000 DAPS."); - } else if (coin_type == ONLY_NONDENOMINATED_NOT1000000IFMN) { - strFailReason = _("Unable to locate enough Obfuscation non-denominated funds for this transaction that are not equal 1000000 DAPS."); - } else { - strFailReason = _("Unable to locate enough Obfuscation denominated funds for this transaction."); - strFailReason += " " + _("Obfuscation uses exact denominated amounts to send funds, you might simply need to anonymize some more coins."); - } - - if (useIX) { - strFailReason += " " + _("SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again."); } ret = false; @@ -3306,15 +3301,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, strFailReason = _("Insufficient funds."); } else if (coin_type == ONLY_NOT1000000IFMN) { strFailReason = _("Unable to locate enough funds for this transaction that are not equal 10000 DAPS."); - } else if (coin_type == ONLY_NONDENOMINATED_NOT1000000IFMN) { - strFailReason = _("Unable to locate enough Obfuscation non-denominated funds for this transaction that are not equal 10000 DAPS."); } else { - strFailReason = _("Unable to locate enough Obfuscation denominated funds for this transaction."); - strFailReason += " " + _("Obfuscation uses exact denominated amounts to send funds, you might simply need to anonymize some more coins."); - } - - if (useIX) { - strFailReason += " " + _("SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again."); + strFailReason = _("Error in CreateTransaction. Please try again."); } return false; From 54e51d72d4fcda7302003e583fbb478bb6ff84d6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 10 Jan 2020 21:53:47 -0500 Subject: [PATCH 0124/1888] [Wallet] Graceful shutdown in the unlock corrupted wallet. --- src/crypter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypter.cpp b/src/crypter.cpp index f94d6e27a3..3b5d579376 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -246,8 +246,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) break; } if (keyPass && keyFail) { - LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all."); - assert(false); + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); + throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); } if (keyFail || !keyPass) return false; From 9e808a0573eb95667a605aba07e69824d1bbcb2a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 10 Jan 2020 22:58:49 -0500 Subject: [PATCH 0125/1888] [Model][Backport] Remove mapWallet not needed call + stop treating coinbase differently --- src/qt/transactionrecord.cpp | 13 ------------- src/qt/transactionrecord.h | 1 - src/qt/transactiontablemodel.cpp | 21 +++++++-------------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 36a62b388c..ed7709c114 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -15,19 +15,6 @@ #include -/* Return positive answer if transaction should be shown in list. - */ -bool TransactionRecord::showTransaction(const CWalletTx& wtx) -{ - if (wtx.IsCoinBase()) { - // Ensures we show generated coins / mined transactions at depth 1 - if (!wtx.IsInMainChain()) { - return false; - } - } - return true; -} - /* * Decompose CWallet transaction to model transaction records. */ diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 04bd5a9a48..80479d06bc 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -108,7 +108,6 @@ class TransactionRecord /** Decompose CWallet transaction to model transaction records. */ - static bool showTransaction(const CWalletTx& wtx); static QList decomposeTransaction(const CWallet* wallet, const CWalletTx& wtx); /** @name Immutable transaction attributes diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 5ecf171467..27a4abdadd 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -144,10 +144,8 @@ class TransactionTablePriv static QList convertTxToRecords(TransactionTablePriv* tablePriv, const CWallet* wallet, const std::vector& walletTxes) { QList cachedWallet; for (const auto &tx : walletTxes) { - if (TransactionRecord::showTransaction(tx)) { - QList records = TransactionRecord::decomposeTransaction(wallet, tx); - cachedWallet.append(records); - } + QList records = TransactionRecord::decomposeTransaction(wallet, tx); + cachedWallet.append(records); } return cachedWallet; @@ -725,7 +723,7 @@ void TransactionTableModel::updateDisplayUnit() struct TransactionNotification { public: TransactionNotification() {} - TransactionNotification(uint256 hash, ChangeType status, bool showTransaction) : hash(hash), status(status), showTransaction(showTransaction) {} + TransactionNotification(uint256 hash, ChangeType status) : hash(hash), status(status) {} void invoke(QObject* ttm) { @@ -734,13 +732,12 @@ struct TransactionNotification { QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, Q_ARG(QString, strHash), Q_ARG(int, status), - Q_ARG(bool, showTransaction)); + Q_ARG(bool, true)); } private: uint256 hash; ChangeType status; - bool showTransaction; }; static bool fQueueNotifications = false; @@ -748,15 +745,11 @@ static std::vector vQueueNotifications; static void NotifyTransactionChanged(TransactionTableModel* ttm, CWallet* wallet, const uint256& hash, ChangeType status) { - // Find transaction in wallet - std::map::iterator mi = wallet->mapWallet.find(hash); - // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread) - bool inWallet = mi != wallet->mapWallet.end(); - bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second)); - TransactionNotification notification(hash, status, showTransaction); + TransactionNotification notification(hash, status); - if (fQueueNotifications) { + if (fQueueNotifications) + { vQueueNotifications.push_back(notification); return; } From 6b911fdc90e40384c198125a515a30076ac7dcc9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 10 Jan 2020 23:22:23 -0500 Subject: [PATCH 0126/1888] [Wallet][Startup][DB][Backport] Remove vchDefaultKey from wallet.h --- src/crypter.h | 3 ++- src/init.cpp | 12 +++++++----- src/wallet/wallet.cpp | 16 ++++------------ src/wallet/wallet.h | 4 ---- src/wallet/walletdb.cpp | 19 +++++++++---------- src/wallet/walletdb.h | 2 -- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/crypter.h b/src/crypter.h index dee3dddac4..412ab4f75f 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -121,7 +121,6 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con class CCryptoKeyStore : public CBasicKeyStore { private: - CryptedKeyMap mapCryptedKeys; CHDChain cryptedHDChain; CKeyingMaterial vMasterKey; @@ -146,6 +145,8 @@ class CCryptoKeyStore : public CBasicKeyStore bool Unlock(const CKeyingMaterial& vMasterKeyIn); + CryptedKeyMap mapCryptedKeys; + public: CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) { diff --git a/src/init.cpp b/src/init.cpp index fbcfa5bb06..e7899e0c72 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1553,16 +1553,18 @@ bool AppInit2(bool isDaemon) } CPubKey newDefaultKey; - if (pwalletMain->GetKeyFromPool(newDefaultKey)) { - pwalletMain->SetDefaultKey(newDefaultKey); - if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) - strErrors << _("Cannot write default address") << "\n"; + // Top up the keypool + if (!pwalletMain->TopUpKeyPool()) { + // Error generating keys + InitError(_("Unable to generate initial key") += "\n"); + LogPrintf("%s %s\n", __func__ , "Unable to generate initial key"); + return false; } pwalletMain->SetBestChain(chainActive.GetLocator()); } - LogPrintf("%s", strErrors.str()); + LogPrintf("Init errors: %s\n", strErrors.str()); LogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nWalletStartTime); RegisterValidationInterface(pwalletMain); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0ba06ab994..32a0255b0c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4850,7 +4850,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) return DB_LOAD_OK; - fFirstRunRet = false; + DBErrors nLoadWalletRet = CWalletDB(strWalletFile, "cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { @@ -4862,9 +4862,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } } + // This wallet is in its first run if all of these are empty + fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapMasterKeys.empty() && setWatchOnly.empty() && mapScripts.empty(); + if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; - fFirstRunRet = !vchDefaultKey.IsValid(); uiInterface.LoadWallet(this); ScanWalletKeyImages(); @@ -4938,16 +4940,6 @@ bool CWallet::DelAddressBook(const CTxDestination& address) return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } -bool CWallet::SetDefaultKey(const CPubKey& vchPubKey) -{ - if (fFileBacked) { - if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) - return false; - } - vchDefaultKey = vchPubKey; - return true; -} - /** * Mark old keypool keys as used, * and generate all new keys diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7c03d48a4b..21b42227b7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -401,8 +401,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map addrToTxHashMap; std::vector txPrivKeys; //only for temporary storing tx private keys for user transactions, dont care staking transactions - CPubKey vchDefaultKey; - std::set setLockedCoins; bool walletStakingInProgress; std::map mapHdPubKeys; //nTimeFirstKey)) pwallet->nTimeFirstKey = keyMeta.nCreateTime; } else if (strType == "defaultkey") { - ssValue >> pwallet->vchDefaultKey; + // We don't want or need the default key, but if there is one set, + // we want to make sure that it is valid so that we can detect corruption + CPubKey vchPubKey; + ssValue >> vchPubKey; + if (!vchPubKey.IsValid()) { + strErr = "Error reading wallet database: Default Key corrupt"; + return false; + } } else if (strType == "pool") { int64_t nIndex; ssKey >> nIndex; @@ -819,7 +820,6 @@ static bool IsKeyType(string strType) DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { - pwallet->vchDefaultKey = CPubKey(); CWalletScanState wss; bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; @@ -857,7 +857,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: - if (IsKeyType(strType)) + if (IsKeyType(strType) || strType == "defaultkey") result = DB_CORRUPT; else { // Leave other errors alone, if we try to fix them we might make things worse. @@ -918,7 +918,6 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vector& vWtx) { - pwallet->vchDefaultKey = CPubKey(); bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index ee22ced4ca..4f195ed2f0 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -146,8 +146,6 @@ class CWalletDB : public CDB bool EraseMSDisabledAddresses(std::vector vDisabledAddresses); bool WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold); - bool WriteDefaultKey(const CPubKey& vchPubKey); - bool ReadPool(int64_t nPool, CKeyPool& keypool); bool WritePool(int64_t nPool, const CKeyPool& keypool); bool ErasePool(int64_t nPool); From c508139a98a0993fed0a83642b967e6a03de34ae Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 12:27:22 -0500 Subject: [PATCH 0127/1888] Update tooltip, add strikethrough for disabled autoconsolidate feature --- src/qt/optionspage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index d4bcf85b47..e653fc6cfe 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -120,6 +120,10 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu } else { ui->addNewFunds->setChecked(false); ui->addNewFunds->setEnabled(false); + QFont font = ui->addNewFunds->font(); + font.setStrikeOut(true); + ui->addNewFunds->setFont(font); + ui->addNewFunds->setToolTip("Disabled by default due to controlling Masternode(s) from this wallet.\nEnabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking."); } connect(ui->addNewFunds, SIGNAL(stateChanged(int)), this, SLOT(setAutoConsolidate(int))); } From 6835823c0b205ad5b175a89c503aac8d539e97d7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 13:40:37 -0500 Subject: [PATCH 0128/1888] Fix light theme QMenu(Bar) --- src/qt/res/css/Light.css | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css index 948ef84a39..d88268406f 100644 --- a/src/qt/res/css/Light.css +++ b/src/qt/res/css/Light.css @@ -175,13 +175,32 @@ QTextEdit { QAbstractSpinBox:focus, QComboBox:focus, QComboBox::item:selected, -QMenuBar::item:selected, QMenu::item:selected, QTextEdit:focus { border-width: 4px; background: #a7a7a7; } +QMenuBar { + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 lightgray, stop:1 darkgray); + spacing: 3px; /* spacing between menu bar items */ +} + +QMenuBar::item { + padding: 1px 4px; + background: transparent; + border-radius: 4px; +} + +QMenuBar::item:selected { /* when selected using mouse or keyboard */ + background: #a7a7a7; +} + +QMenuBar::item:pressed { + background: #888888; +} + QToolTip { color: white; background-color: #5E1C5A; @@ -193,7 +212,14 @@ QMenu::item { padding: 2px 25px 2px 20px; border: 1px solid transparent; /* reserve space for selection border */ color: black; - background: white; + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 lightgray, stop:1 darkgray); +} + +QMenu::separator { + background: black; + width: 1px; /* when vertical */ + height: 1px; /* when horizontal */ } QComboBox:checked { From 510afc06640a98fe33373e82b249a6a0a01b1219 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 15:06:47 -0500 Subject: [PATCH 0129/1888] Update selected text color on Dark Theme -> RPC Console --- src/qt/res/css/Dark.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index 14da4d5609..e5d6e529ee 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -220,6 +220,12 @@ QTextEdit:focus { background: #31398c; } +#messagesWidget { + border-width: 4px; + background: #1e223a; + selection-color: yellow; +} + QToolTip { color: white; background-color: #5E1C5A; From 7ed5103ed5a69a775033997800f89bd1786e1142 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 15:09:01 -0500 Subject: [PATCH 0130/1888] Remove extra 30sec sleep --- src/miner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 4119cce24e..6a86392788 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -701,7 +701,6 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) } } - MilliSleep(30000); // // Create new block // From 6701cb660eac5c29c299eb4ec64f84f4e6340989 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 15:13:08 -0500 Subject: [PATCH 0131/1888] Remove unnecessary "Start staking" log --- src/wallet/wallet.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0ba06ab994..cec0036f63 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4154,8 +4154,6 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int txNew.txType = TX_TYPE_REVEAL_BOTH; // Choose coins to use - LogPrintf("%s: Start staking\n", __func__); - CAmount nSpendableBalance = 0; CAmount nTargetAmount = 9223372036854775807; if (nReserveBalance > 0) { From fa9dd4323cb51d6b4e626d8e303f1c9066516f69 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 19:50:23 -0500 Subject: [PATCH 0132/1888] Add "No Active Peers"/"Syncing..." status' to setStakingStatus Different from !masternodeSync.IsSynced() - Syncing will check for IsInitialBlockDownload --- src/qt/bitcoingui.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 6b6f962f27..6693414d06 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1237,25 +1237,33 @@ void BitcoinGUI::setStakingStatus() fMultiSend = pwalletMain->isMultiSendEnabled(); stkStatus = pwalletMain->ReadStakingStatus(); } - if (!stkStatus || pwalletMain->stakingMode == StakingMode::STOPPED || pwalletMain->IsLocked()) { stakingState->setText(tr("Staking Disabled")); stakingState->setToolTip("Staking Disabled"); stakingAction->setIcon(QIcon(":/icons/staking_inactive")); return; } - + if (vNodes.empty()) { + stakingState->setText(tr("No Active Peers")); + stakingState->setToolTip("No Active Peers"); + stakingAction->setIcon(QIcon(":/icons/staking_inactive")); + return; + } + if (IsInitialBlockDownload()) { + stakingState->setText(tr("Syncing...")); + stakingState->setToolTip("Syncing"); + stakingAction->setIcon(QIcon(":/icons/staking_waiting")); + return; + } if (!masternodeSync.IsSynced()) { stakingState->setText(tr("Syncing MN List...")); stakingState->setToolTip("Syncing Masternode List"); stakingAction->setIcon(QIcon(":/icons/staking_waiting")); return; } - if (stakingState->text().contains("Enabling")) { if (!nLastCoinStakeSearchInterval) return; } - if (nLastCoinStakeSearchInterval) { stakingState->setText(tr("Staking Enabled")); stakingState->setToolTip("Staking Enabled"); From 31a490dcd5f2b9a76e0f1cc6b1d330f509f26ca0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 19:51:28 -0500 Subject: [PATCH 0133/1888] Move reserveBalance within #ifdef ENABLE_WALLET (requires wallet) --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index fbcfa5bb06..823f451812 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1846,12 +1846,12 @@ bool AppInit2(bool isDaemon) //read decoy confirmation min pwalletMain->DecoyConfirmationMinimum = GetArg("-decoyconfirm", 15); } -#endif CWalletDB walletdb(strWalletFile); double reserveBalance; if (walletdb.ReadReserveAmount(reserveBalance)) nReserveBalance = reserveBalance * COIN; +#endif return !fRequestShutdown; } From 410e4a1d1b9000e7f70ef508cb6be7133516b52e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 11 Jan 2020 21:31:44 -0500 Subject: [PATCH 0134/1888] Remove excessive logs re: staking/nTime violations --- src/kernel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index ac041aa29d..c179354f46 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -305,7 +305,7 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlockHeader blockFrom, cons unsigned int nTimeBlockFrom = blockFrom.GetBlockTime(); if (nTimeTx < nTimeBlockFrom) // Transaction timestamp violation - return error("CheckStakeKernelHash() : nTime violation"); + return false; if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement return false; @@ -348,8 +348,6 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlockHeader blockFrom, cons // if stake hash does not meet the target then continue to next iteration if (!stakeTargetHit(hashProofOfStake, nValueIn, bnTargetPerCoinDay)) { - if (fDebug) - LogPrintf("CheckStakeKernelHash() : staking not found, you're not lucky enough\n"); continue; } From 91cde2e44630d041d541e1a8903bffbe25bf4d7c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 19:54:59 -0500 Subject: [PATCH 0135/1888] Remove unnecessary check in Miner --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 6a86392788..2204cb3fc5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -668,7 +668,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) continue; } - while (chainActive.Tip()->nTime < 1471482000 || vNodes.empty() || pwallet->IsLocked() || !fMintableCoins || nReserveBalance >= pwallet->GetBalance() || !masternodeSync.IsSynced()) { + while (vNodes.empty() || pwallet->IsLocked() || !fMintableCoins || nReserveBalance >= pwallet->GetBalance() || !masternodeSync.IsSynced()) { nLastCoinStakeSearchInterval = 0; if (!fMintableCoins) { if (GetTime() - nMintableLastCheck > 1 * 60) // 1 minute check time From 7e5f801a0f03d7e6e0197ae7013d57ffc32d620b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 20:00:53 -0500 Subject: [PATCH 0136/1888] Bump version to v1.0.5.7 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c53a4fb7e6..5d72f6ea9b 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 6) +define(_CLIENT_VERSION_BUILD, 7) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From df9214b82fcdfd2c6536c37c90a0fb1128441cbf Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 20:50:45 -0500 Subject: [PATCH 0137/1888] Restore sleep timer in miner with setting in conf file 'minersleep', 30sec default --- src/miner.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 2204cb3fc5..7709d21a8f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -61,6 +61,7 @@ class COrphan uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; int64_t nLastCoinStakeSearchInterval = 0; +int64_t nDefaultMinerSleep = 0; //int64_t nConsolidationTime = 0; // We want to sort transactions by priority and fee rate, so: @@ -642,7 +643,8 @@ bool fGenerateDapscoins = false; void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) { - LogPrintf("DAPScoinMiner started\n"); + nDefaultMinerSleep = GetArg("-minersleep", 30000); + LogPrintf("DAPScoinMiner started with %sms sleep time\n", nDefaultMinerSleep); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("dapscoin-miner"); fGenerateDapscoins = true; @@ -701,6 +703,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) } } + MilliSleep(nDefaultMinerSleep); // // Create new block // From 6946aa67b0ba8f718a608b22448fe8abb28c576b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 20:51:11 -0500 Subject: [PATCH 0138/1888] Change timerBlockHeightLabel from 45s->60s --- src/qt/overviewpage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 43cb018153..8a8a59ae0d 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -133,7 +133,7 @@ OverviewPage::OverviewPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMe QTimer* timerBlockHeightLabel = new QTimer(this); connect(timerBlockHeightLabel, SIGNAL(timeout()), this, SLOT(showBlockCurrentHeight())); - timerBlockHeightLabel->start(45000); + timerBlockHeightLabel->start(60000); connect(ui->btnLockUnlock, SIGNAL(clicked()), this, SLOT(on_lockUnlock())); } From 67ecb27e2a22dbee104a1bada4f676b0690d3c78 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 21:00:44 -0500 Subject: [PATCH 0139/1888] Add debug=staking logs for setStakingStatus() --- src/qt/bitcoingui.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 6693414d06..b4c48b03c2 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1238,24 +1238,28 @@ void BitcoinGUI::setStakingStatus() stkStatus = pwalletMain->ReadStakingStatus(); } if (!stkStatus || pwalletMain->stakingMode == StakingMode::STOPPED || pwalletMain->IsLocked()) { + LogPrint("staking","Checking Staking Status: Disabled.\n"); stakingState->setText(tr("Staking Disabled")); stakingState->setToolTip("Staking Disabled"); stakingAction->setIcon(QIcon(":/icons/staking_inactive")); return; } if (vNodes.empty()) { + LogPrint("staking","Checking Staking Status: No Active Peers...\n"); stakingState->setText(tr("No Active Peers")); stakingState->setToolTip("No Active Peers"); stakingAction->setIcon(QIcon(":/icons/staking_inactive")); return; } if (IsInitialBlockDownload()) { + LogPrint("staking","Checking Staking Status: Syncing...\n"); stakingState->setText(tr("Syncing...")); stakingState->setToolTip("Syncing"); stakingAction->setIcon(QIcon(":/icons/staking_waiting")); return; } if (!masternodeSync.IsSynced()) { + LogPrint("staking","Checking Staking Status: Syncing MN List...\n"); stakingState->setText(tr("Syncing MN List...")); stakingState->setToolTip("Syncing Masternode List"); stakingAction->setIcon(QIcon(":/icons/staking_waiting")); @@ -1265,6 +1269,7 @@ void BitcoinGUI::setStakingStatus() if (!nLastCoinStakeSearchInterval) return; } if (nLastCoinStakeSearchInterval) { + LogPrint("staking","Checking Staking Status: Enabled.\n"); stakingState->setText(tr("Staking Enabled")); stakingState->setToolTip("Staking Enabled"); stakingAction->setIcon(QIcon(":/icons/staking_active")); @@ -1274,6 +1279,7 @@ void BitcoinGUI::setStakingStatus() stakingState->setToolTip("Consolidating Transactions… Please wait few minutes for it to be consolidated."); stakingAction->setIcon(QIcon(":/icons/staking_active"));*/ } else { + LogPrint("staking","Checking Staking Status: Enabling...\n"); stakingState->setText(tr("Enabling Staking...")); stakingState->setToolTip("Enabling Staking... Please wait up to 1.5 hours for it to be properly enabled after consolidation."); stakingAction->setIcon(QIcon(":/icons/staking_active")); From b8fe962abc66138c58ddbca8ba4f21b13088064c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 12 Jan 2020 21:22:15 -0500 Subject: [PATCH 0140/1888] vector -> std::vector --- src/activemasternode.cpp | 8 ++++---- src/activemasternode.h | 2 +- src/qt/coincontroldialog.cpp | 4 ++-- src/rpc/masternode.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/test/wallet_tests.cpp | 2 +- src/wallet/test/wallet_tests.cpp | 2 +- src/wallet/wallet.cpp | 28 ++++++++++++++-------------- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 83c3c205cb..7b2a6a046b 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -340,7 +340,7 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr TRY_LOCK(pwalletMain->cs_wallet, fWallet); if (!fWallet) return false; - vector possibleCoins = SelectCoinsMasternode(); + std::vector possibleCoins = SelectCoinsMasternode(); COutput* selectedOutput; // Find the vin @@ -465,9 +465,9 @@ bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubke // get all possible outputs for running Masternode vector CActiveMasternode::SelectCoinsMasternode() { - vector vCoins; - vector filteredCoins; - vector confLockedCoins; + std::vector vCoins; + std::vector filteredCoins; + std::vector confLockedCoins; // Temporary unlock MN coins from masternode.conf if (GetBoolArg("-mnconflock", true)) { diff --git a/src/activemasternode.h b/src/activemasternode.h index 7b306e7bc2..f2ab25976a 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -64,7 +64,7 @@ class CActiveMasternode /// Get 1000000 DAPS input that can be used for the Masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey); - vector SelectCoinsMasternode(); + std::vector SelectCoinsMasternode(); /// Enable cold wallet mode (run a Masternode with no funds) bool EnableHotColdMasterNode(CTxIn& vin, CService& addr); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 2ce8f0c411..bd2c3ca783 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -499,7 +499,7 @@ void CoinControlDialog::updateDialogLabels() } vector vCoinControl; - vector vOutputs; + std::vector vOutputs; coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); @@ -560,7 +560,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) bool fAllowFree = false; vector vCoinControl; - vector vOutputs; + std::vector vOutputs; coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 14b352ed51..3b01e1cba3 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -607,7 +607,7 @@ UniValue getmasternodeoutputs (const UniValue& params, bool fHelp) HelpExampleCli("getmasternodeoutputs", "") + HelpExampleRpc("getmasternodeoutputs", "")); // Find possible candidates - vector possibleCoins = activeMasternode.SelectCoinsMasternode(); + std::vector possibleCoins = activeMasternode.SelectCoinsMasternode(); UniValue ret(UniValue::VARR); for (COutput& out : possibleCoins) { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 47bf79a567..76a5980f64 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -382,7 +382,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) } UniValue results(UniValue::VARR); - vector vecOutputs; + std::vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false); diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index 961a1d209b..9bfc92742d 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -67,7 +67,7 @@ static void generate_block(int count) { #ifdef DISABLE_FAILED_TEST static CWallet wallet; -static vector vCoins; +static std::vector vCoins; static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 5a8f80a76a..cac4e6fd02 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -67,7 +67,7 @@ static void generate_block(int count) { #ifdef DISABLE_FAILED_TEST static CWallet wallet; -static vector vCoins; +static std::vector vCoins; static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cec0036f63..063508d184 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2050,7 +2050,7 @@ bool CWallet::AvailableCoins(const uint256 wtxid, const CWalletTx* pcoin, vector map > CWallet::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue) { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, fConfirmed); map > mapCoins; @@ -2136,7 +2136,7 @@ bool less_then_denom(const COutput& out1, const COutput& out2) bool CWallet::SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, NULL, false, STAKABLE_COINS); CAmount nAmountSelected = 0; @@ -2165,7 +2165,7 @@ bool CWallet::SelectStakeCoins(std::set vCoins; + std::vector vCoins; { LOCK2(cs_main, cs_wallet); @@ -2207,7 +2207,7 @@ StakingStatusError CWallet::StakingCoinStatus(CAmount& minFee, CAmount& maxFee) return StakingStatusError::UNSTAKABLE_BALANCE_RESERVE_TOO_HIGH; } - vector vCoins, coinsUnderThreshold, coinsOverThreshold; + std::vector vCoins, coinsUnderThreshold, coinsOverThreshold; StakingStatusError ret = StakingStatusError::STAKING_OK; CAmount nSpendableBalance = GetSpendableBalance(); @@ -2341,7 +2341,7 @@ StakingStatusError CWallet::StakingCoinStatus(CAmount& minFee, CAmount& maxFee) return ret; } -bool CWallet::SelectCoinsMinConf(bool needFee, CAmount& feeNeeded, int ringSize, int numOut, const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, CAmount& nValueRet) +bool CWallet::SelectCoinsMinConf(bool needFee, CAmount& feeNeeded, int ringSize, int numOut, const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, set >& setCoinsRet, CAmount& nValueRet) { setCoinsRet.clear(); nValueRet = 0; @@ -2521,7 +2521,7 @@ void CWallet::resetPendingOutPoints() bool CWallet::SelectCoins(bool needFee, CAmount& estimatedFee, int ringSize, int numOut, const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl, AvailableCoinsType coin_type, bool useIX) { // Note: this function should never be used for "always free" tx types like dstx - vector vCoins; + std::vector vCoins; vCoins.clear(); { @@ -2613,7 +2613,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueRet = 0; vCoinsRet2.clear(); - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, NULL, false, ONLY_DENOMINATED); std::random_shuffle(vCoins.rbegin(), vCoins.rend()); @@ -2733,7 +2733,7 @@ bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector< setCoinsRet.clear(); nValueRet = 0; - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, coinControl, false, nObfuscationRoundsMin < 0 ? ONLY_NONDENOMINATED_NOT1000000IFMN : ONLY_DENOMINATED); set > setCoinsRet2; @@ -2772,7 +2772,7 @@ bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector< bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins); @@ -2824,7 +2824,7 @@ int CWallet::CountInputsWithAmount(CAmount nInputAmount) bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, fOnlyConfirmed); int nFound = 0; @@ -4196,7 +4196,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int // Make sure the wallet is unlocked and shutdown hasn't been requested if (IsLocked() || ShutdownRequested()) return false; - vector vCoins; + std::vector vCoins; int cannotSpend = 0; { AvailableCoins(wtxid, pcoin, vCoins, cannotSpend, true, NULL, false, STAKABLE_COINS, false); @@ -5584,7 +5584,7 @@ bool CWallet::SendAll(std::string des) } CAmount total = 0; - vector vCoins; + std::vector vCoins; vCoins.clear(); std::string strFailReason; bool ret = true; @@ -5779,7 +5779,7 @@ bool CWallet::CreateSweepingTransaction(CAmount target, CAmount threshold, uint3 return false; } CAmount total = 0; - vector vCoins; + std::vector vCoins; COutput lowestLarger(NULL, 0, 0, false); CAmount currentLowestLargerAmount = 0; vCoins.clear(); @@ -6057,7 +6057,7 @@ void CWallet::AutoCombineDust() bool CWallet::estimateStakingConsolidationFees(CAmount& minFee, CAmount& maxFee) { //finding all spendable UTXOs < MIN_STAKING CAmount total = 0; - vector vCoins, underStakingThresholdCoins; + std::vector vCoins, underStakingThresholdCoins; { LOCK2(cs_main, cs_wallet); { From a8c722aa97617408fe624c01eca4014756d0d53a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 14 Jan 2020 17:31:27 -0500 Subject: [PATCH 0141/1888] Add more output when launching daemon (version, masternode=1 or not) Update other minor texts --- src/dapscoin-cli.cpp | 4 ++-- src/dapscoin-tx.cpp | 2 +- src/dapscoind.cpp | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/dapscoin-cli.cpp b/src/dapscoin-cli.cpp index 0027cdbc54..39f80d9527 100644 --- a/src/dapscoin-cli.cpp +++ b/src/dapscoin-cli.cpp @@ -73,10 +73,10 @@ static bool AppInitRPC(int argc, char* argv[]) // ParseParameters(argc, argv); if (argc < 2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) { - std::string strUsage = _("Dapscoin Core RPC client version") + " " + FormatFullVersion() + "\n"; + std::string strUsage = _("DAPS RPC client version") + " " + FormatFullVersion() + "\n"; if (!mapArgs.count("-version")) { strUsage += "\n" + _("Usage:") + "\n" + - " dapscoin-cli [options] [params] " + _("Send command to Dapscoin Core") + "\n" + + " dapscoin-cli [options] [params] " + _("Send command to DAPS") + "\n" + " dapscoin-cli [options] help " + _("List commands") + "\n" + " dapscoin-cli [options] help " + _("Get help for a command") + "\n"; diff --git a/src/dapscoin-tx.cpp b/src/dapscoin-tx.cpp index 0c7d7c461c..8fc4769a66 100644 --- a/src/dapscoin-tx.cpp +++ b/src/dapscoin-tx.cpp @@ -50,7 +50,7 @@ static bool AppInitRawTx(int argc, char* argv[]) if (argc < 2 || mapArgs.count("-?") || mapArgs.count("-help")) { // First part of help message is specific to this utility - std::string strUsage = _("Dapscoin Core dapscoin-tx utility version") + " " + FormatFullVersion() + "\n\n" + + std::string strUsage = _("DAPS dapscoin-tx utility version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + " dapscoin-tx [options] [commands] " + _("Update hex-encoded dapscoin transaction") + "\n" + " dapscoin-tx [options] -create [commands] " + _("Create hex-encoded dapscoin transaction") + "\n" + diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 3b98d9032b..256311ebad 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -41,6 +41,7 @@ */ static bool fDaemon; +static bool fMasternode; void WaitForShutdown() { @@ -70,13 +71,13 @@ bool AppInit(int argc, char* argv[]) // Process help and version before taking care about datadir if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) { - std::string strUsage = _("Dapscoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; + std::string strUsage = _("DAPS Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n"; if (mapArgs.count("-version")) { strUsage += LicenseInfo(); } else { strUsage += "\n" + _("Usage:") + "\n" + - " dapscoind [options] " + _("Start Dapscoin Core Daemon") + "\n"; + " dapscoind [options] " + _("Start DAPS Daemon") + "\n"; strUsage += "\n" + HelpMessage(HMM_BITCOIND); } @@ -121,9 +122,14 @@ bool AppInit(int argc, char* argv[]) } #ifndef WIN32 fDaemon = GetBoolArg("-daemon", false); + fMasternode = GetBoolArg("-masternode", false); if (fDaemon) { + std::string strUsage = _("DAPS Daemon") + " " + FormatFullVersion() + "\n"; + fprintf(stdout, "%s", strUsage.c_str()); fprintf(stdout, "DAPS server starting\n"); - + if (fMasternode) { + fprintf(stdout, "Masternode = 1 - This is a masternode\n"); + } // Daemonize pid_t pid = fork(); if (pid < 0) { From 728211840fb923b0ea66821e711672c26bcb9a0a Mon Sep 17 00:00:00 2001 From: JD Date: Tue, 14 Jan 2020 18:06:22 -0500 Subject: [PATCH 0142/1888] [Qt][Bug] Load the most recent instead of the first transactions (#66) --- src/qt/transactiontablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 27a4abdadd..3c7caad840 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -96,7 +96,7 @@ class TransactionTablePriv // txs are stored in order in the db, which is what should be happening) sort(walletTxes.begin(), walletTxes.end(), [](const CWalletTx & a, const CWalletTx & b) -> bool { - return a.GetComputedTxTime() < b.GetComputedTxTime(); + return a.GetComputedTxTime() > b.GetComputedTxTime(); }); // Only latest ones. From 4635d0121403af10a615927e96f7dbf3c08e032c Mon Sep 17 00:00:00 2001 From: JD Date: Tue, 14 Jan 2020 20:13:01 -0500 Subject: [PATCH 0143/1888] Add Basic Litemode (#64) * Add a basic Lite Mode (litemode=1) This hides the masternode tab and disables staking (button and function) for a "Lite" wallet. This will be expanded on in the future. * Hide Staking Status on litemode --- src/qt/bitcoingui.cpp | 23 +++++++++++++++++------ src/qt/forms/optionspage.ui | 4 ++-- src/qt/optionspage.cpp | 36 +++++++++++++++++++++++++++++------- src/qt/splashscreen.cpp | 4 ++++ 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b4c48b03c2..1c0add86a4 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -119,6 +119,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai GUIUtil::restoreWindowGeometry("nWindow", QSize(1147, 768), this); QString windowTitle = tr("DAPS Coin") + " "; + fLiteMode = GetBoolArg("-litemode", false); #ifdef ENABLE_WALLET /* if compiled with wallet support, -disablewallet can still disable the wallet */ enableWallet = !GetBoolArg("-disablewallet", false); @@ -130,6 +131,9 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai } else { windowTitle += tr("Node"); } + if (fLiteMode) { + windowTitle += tr(" - Lite Mode"); + } QString userWindowTitle = QString::fromStdString(GetArg("-windowtitle", "")); if (!userWindowTitle.isEmpty()) windowTitle += " - " + userWindowTitle; windowTitle += " " + networkStyle->getTitleAddText(); @@ -329,7 +333,9 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) #else masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); #endif - tabGroup->addAction(masternodeAction); + if (!fLiteMode) { + tabGroup->addAction(masternodeAction); + } connect(masternodeAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(gotoMasternodePage())); @@ -603,8 +609,9 @@ void BitcoinGUI::createToolBars() toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); - toolbar->addAction(masternodeAction); - + if (!fLiteMode) { + toolbar->addAction(masternodeAction); + } toolbar->setMovable(false); // remove unused icon in upper left corner overviewAction->setChecked(true); toolbar->setStyleSheet("QToolBar{spacing:25px;}"); @@ -616,8 +623,10 @@ void BitcoinGUI::createToolBars() bottomToolbar->setOrientation(Qt::Vertical); bottomToolbar->addAction(optionsAction); bottomToolbar->addSeparator(); - bottomToolbar->addAction(stakingAction); - bottomToolbar->addWidget(stakingState); + if (!fLiteMode) { + bottomToolbar->addAction(stakingAction); + bottomToolbar->addWidget(stakingState); + } bottomToolbar->addAction(networkAction); bottomToolbar->addWidget(connectionCount); bottomToolbar->setStyleSheet("QToolBar{spacing:5px;}"); @@ -788,7 +797,9 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addAction(sendCoinsAction); trayIconMenu->addAction(receiveCoinsAction); trayIconMenu->addAction(historyAction); - trayIconMenu->addAction(masternodeAction); + if (!fLiteMode) { + trayIconMenu->addAction(masternodeAction); + } trayIconMenu->addSeparator(); trayIconMenu->addAction(optionsAction); trayIconMenu->addSeparator(); diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 77a0ab8b16..7792b0b660 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -311,7 +311,7 @@ QLayout::SetDefaultConstraint - + 0 @@ -608,7 +608,7 @@ - + true diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index e653fc6cfe..4e650532ed 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -64,7 +64,8 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->lineEditWithhold->setText(BitcoinUnits::format(0, nReserveBalance).toUtf8()); bool stkStatus = pwalletMain->ReadStakingStatus(); - if (stkStatus){ + fLiteMode = GetBoolArg("-litemode", false); + if (stkStatus && !fLiteMode){ if (chainActive.Height() < Params().LAST_POW_BLOCK()) { stkStatus = false; pwalletMain->walletStakingInProgress = false; @@ -82,8 +83,33 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu } } - ui->toggleStaking->setState(nLastCoinStakeSearchInterval | stkStatus); - connect(ui->toggleStaking, SIGNAL(stateChanged(ToggleButton*)), this, SLOT(on_EnableStaking(ToggleButton*))); + if (!fLiteMode) { + //Staking related items and functions + ui->toggleStaking->setState(nLastCoinStakeSearchInterval | stkStatus); + connect(ui->toggleStaking, SIGNAL(stateChanged(ToggleButton*)), this, SLOT(on_EnableStaking(ToggleButton*))); + timerStakingToggleSync = new QTimer(); + connect(timerStakingToggleSync, SIGNAL(timeout()), this, SLOT(setStakingToggle())); + timerStakingToggleSync->start(10000); + ui->labelStaking->show(); + ui->toggleStaking->show(); + ui->quantityLabel->show(); + ui->lineEditWithhold->show(); + ui->addNewFunds->show(); + ui->pushButtonSave->show(); + ui->pushButtonDisable->show(); + ui->line_3->show(); + } else { + //Staking related items and functions hidden/removed in litemode + ui->labelStaking->hide(); + ui->toggleStaking->hide(); + ui->quantityLabel->hide(); + ui->lineEditWithhold->hide(); + ui->addNewFunds->hide(); + ui->pushButtonSave->hide(); + ui->pushButtonDisable->hide(); + ui->line_3->hide(); + } + connect(ui->pushButtonRecovery, SIGNAL(clicked()), this, SLOT(onShowMnemonic())); @@ -108,10 +134,6 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->code_5->setVisible(false); ui->code_6->setVisible(false); - timerStakingToggleSync = new QTimer(); - connect(timerStakingToggleSync, SIGNAL(timeout()), this, SLOT(setStakingToggle())); - timerStakingToggleSync->start(10000); - if (!pwalletMain->IsMasternodeController()) { if (pwalletMain) { bool isConsolidatedOn = pwalletMain->IsAutoConsolidateOn(); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 1cc531fef0..7d986229f1 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -35,6 +35,10 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle* networkStyle) // define text to place QString titleText = tr("DAPS Coin Keychain Wallet"); + fLiteMode = GetBoolArg("-litemode", false); + if (fLiteMode) { + titleText = tr("DAPS Coin Lite Mode Wallet"); + } QString versionText = QString(tr("Version %1")).arg(QString::fromStdString(FormatFullVersion())); QString copyrightTextBtc = QChar(0xA9) + QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); QString copyrightTextDash = QChar(0xA9) + QString(" 2014-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Dash Core developers")); From 5f322d190cf6385f18bded8331a34eaabc878be2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Jan 2020 19:01:17 -0500 Subject: [PATCH 0144/1888] Fixes for Lite Mode - Fix "Staking" word randomly stuck in the file menu - Fix "Enabling Staking" still displaying on Overview - Disable staking icon timer - Force WriteStakingStatus(false) after unlock to disable staking --- src/qt/bitcoingui.cpp | 21 ++++++++++++--------- src/qt/dapscoin.cpp | 3 +++ src/qt/overviewpage.cpp | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 1c0add86a4..fcacd1ca37 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -250,10 +250,12 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai // Subscribe to notifications from core subscribeToCoreSignals(); - QTimer* timerStakingIcon = new QTimer(labelStakingIcon); - connect(timerStakingIcon, SIGNAL(timeout()), this, SLOT(setStakingStatus())); - timerStakingIcon->start(10000); - setStakingStatus(); + if (!fLiteMode) { + QTimer* timerStakingIcon = new QTimer(labelStakingIcon); + connect(timerStakingIcon, SIGNAL(timeout()), this, SLOT(setStakingStatus())); + timerStakingIcon->start(10000); + setStakingStatus(); + } } BitcoinGUI::~BitcoinGUI() @@ -623,15 +625,16 @@ void BitcoinGUI::createToolBars() bottomToolbar->setOrientation(Qt::Vertical); bottomToolbar->addAction(optionsAction); bottomToolbar->addSeparator(); - if (!fLiteMode) { - bottomToolbar->addAction(stakingAction); - bottomToolbar->addWidget(stakingState); - } + bottomToolbar->addAction(stakingAction); + bottomToolbar->addWidget(stakingState); bottomToolbar->addAction(networkAction); bottomToolbar->addWidget(connectionCount); bottomToolbar->setStyleSheet("QToolBar{spacing:5px;}"); - bottomToolbar->setObjectName("bottomToolbar"); + if (fLiteMode) { + stakingAction->setVisible(false); + stakingState->setVisible(false); + } QHBoxLayout* layout = new QHBoxLayout(this); QVBoxLayout* navLayout = new QVBoxLayout(this); diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 4c2ae6f5fd..33250e1d11 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -526,6 +526,9 @@ void BitcoinApplication::initializeResult(int retval) unlockdlg.setStyleSheet(GUIUtil::loadStyleSheet()); if (unlockdlg.exec() == QDialog::Accepted) { walletUnlocked = true; + if (fLiteMode) { + pwalletMain->WriteStakingStatus(false); + } } emit requestedRegisterNodeSignal(); } diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 8a8a59ae0d..b85ae7d634 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -187,7 +187,7 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed ui->labelUnconfirmed->setText("Locked; Hidden"); ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/lock) 0 0 0 0 stretch stretch; width: 20px;"); } else { - if (stkStatus && !nLastCoinStakeSearchInterval) { + if (stkStatus && !nLastCoinStakeSearchInterval && !fLiteMode) { ui->labelBalance_2->setText("Enabling Staking..."); ui->labelBalance_2->setToolTip("Enabling Staking... Please wait up to 1.5 hours for it to be properly enabled after consolidation."); ui->labelBalance->setText("Enabling Staking..."); From c62a405f1b78319d12ba947596ec7ab09843b83d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Jan 2020 19:44:38 -0500 Subject: [PATCH 0145/1888] Remove extra log --- src/qt/overviewpage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index b85ae7d634..2ad7b222b0 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -246,7 +246,6 @@ void OverviewPage::setWalletModel(WalletModel* model) this->walletModel = model; if (model && model->getOptionsModel()) { // Set up transaction list - LogPrintf("%s:setWalletModel\n", __func__); filter = new TransactionFilterProxy(this); filter->setSourceModel(model->getTransactionTableModel()); filter->setLimit(NUM_ITEMS); From f7d8fa71b88722ee56859ba242d0e818aab8c277 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 15 Jan 2020 21:13:25 -0500 Subject: [PATCH 0146/1888] Fix "GUI: QLayout: Attempting to add QLayout $$ to WalletView/BitcoinGUI $$, which already has a layout" --- src/qt/bitcoingui.cpp | 4 ++-- src/qt/walletview.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index fcacd1ca37..54237e823a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -636,8 +636,8 @@ void BitcoinGUI::createToolBars() stakingState->setVisible(false); } - QHBoxLayout* layout = new QHBoxLayout(this); - QVBoxLayout* navLayout = new QVBoxLayout(this); + QHBoxLayout* layout = new QHBoxLayout(); + QVBoxLayout* navLayout = new QVBoxLayout(); QWidget* navWidget = new QWidget(this); navWidget->setObjectName("navLayout"); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 526093b24a..6a90e1ad2f 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -45,7 +45,7 @@ WalletView::WalletView(QWidget* parent) : QStackedWidget(parent), overviewPage = new OverviewPage(); explorerWindow = new BlockExplorer(this); transactionsPage = new QWidget(this); - QVBoxLayout* vbox = new QVBoxLayout(this); + QVBoxLayout* vbox = new QVBoxLayout(); QHBoxLayout* hbox_buttons = new QHBoxLayout(); transactionView = new TransactionView(this); vbox->addWidget(transactionView); From 254f38c775b6edca9561f7ba9fb24094d6e821c1 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Thu, 16 Jan 2020 23:23:09 +0100 Subject: [PATCH 0147/1888] Update CheckPoints to 239830 (#70) Update CheckPoints to 239830 --- src/chainparams.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 058d169134..bf05083cd9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -109,11 +109,15 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (209577, uint256("5231320be89de8a0fdebbd45d4d0c58abb1ea7a134ba52a11a2036f32d90e66c")) (215000, uint256("f114538988fbba92c21418e18dd8f32ed9579f0ee980949467044dfc8b5a444b")) (221000, uint256("573a615b64089e31204b9ed642346179858cb4d31749be210f65c95b5e34a5c3")) + (225000, uint256("87cabfee989514eeebc1b1b15baf91caade99444ae66cda36705161123a04bd0")) + (230000, uint256("578a5eeee8d8d2d5c9f961db6f4ad42dcc830aaadf103b7bd4dfc6384ddd5d68")) + (235000, uint256("f91427c4ae7e75c7630c2e3fade78db8ce3aa830b07861435d90a8e2a26222a7")) + (239830, uint256("a17a68a3399dc67992815f5e0ee3fbac7bb0b3777e64a5446b728dc25bc3b113")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1578085486, // * UNIX timestamp of last checkpoint block - 555549, // * total number of transactions between genesis and last checkpoint + 1579208143, // * UNIX timestamp of last checkpoint block + 599166, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 8556fec1aabcd093f80a6300c3b84ac2c330c58e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 16 Jan 2020 17:34:24 -0500 Subject: [PATCH 0148/1888] Update QT to 5.9.9 LTS --- depends/packages/qt.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index e61589628a..d6cb26ce2a 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,9 +1,9 @@ PACKAGE=qt -$(package)_version=5.9.8 +$(package)_version=5.9.9 $(package)_download_path=https://download.qt.io/official_releases/qt/5.9/$($(package)_version)/submodules $(package)_suffix=opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352da0907d +$(package)_sha256_hash=d5a97381b9339c0fbaf13f0c05d599a5c999dcf94145044058198987183fed65 $(package)_dependencies=openssl zlib $(package)_linux_dependencies=freetype fontconfig libxcb libX11 xproto libXext $(package)_build_subdir=qtbase @@ -11,10 +11,10 @@ $(package)_qt_libs=corelib network widgets gui plugins testlib concurrent $(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch fix_rcc_determinism.patch fix_riscv64_arch.patch fix_s390x_powerpc_mips_mipsel_architectures.patch xkb-default.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=fb5a47799754af73d3bf501fe513342cfe2fc37f64e80df5533f6110e804220c +$(package)_qttranslations_sha256_hash=f7474f260a1382549720081bf2359a3d425ec3bf7d31976c512834303d30d73b $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=a97556eb7b2f30252cdd8a598c396cfce2b2f79d2bae883af6d3b26a2cdcc63c +$(package)_qttools_sha256_hash=fce6e0fd39a40bcef880c669080087dba94af1ec442296222210472e0852bf98 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) From 53d11653b26c60c0bf041cd11778d98d29888cb2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 17 Jan 2020 15:44:35 -0500 Subject: [PATCH 0149/1888] Fix "Network Traffic" tab labels overlap --- src/qt/forms/rpcconsole.ui | 121 +++---------------------------------- 1 file changed, 8 insertions(+), 113 deletions(-) diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index c394b29b0a..91acfeab51 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -17,7 +17,7 @@ - 4 + 0 @@ -539,64 +539,15 @@ Totals + + + + Qt::Horizontal + + + - - - - - 0 - 0 - - - - - 10 - 0 - - - - - - - - - 0 - 255 - 0 - - - - - - - - - 0 - 255 - 0 - - - - - - - - - 0 - 255 - 0 - - - - - - - - Qt::Horizontal - - - @@ -621,62 +572,6 @@ - - - - - 0 - 0 - - - - - 10 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - - Qt::Horizontal - - - From fa54eb97e2941fe78907b3b1e7b6ea09143af2d0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 17 Jan 2020 15:49:07 -0500 Subject: [PATCH 0150/1888] Add walletunlocked to getwalletinfo --- src/wallet/rpcwallet.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0ea9e20b61..3f3160b3c1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2013,13 +2013,14 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) "Returns an object containing various wallet state info.\n" "\nResult:\n" "{\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total DAPS balance of the wallet\n" - " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" - " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in DAPS/kB\n" + " \"walletversion\": xxxxx, (numeric) the wallet version\n" + " \"balance\": xxxxxxx, (numeric) the total DAPS balance of the wallet\n" + " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" + " \"walletunlocked\": true|false,(boolean) if the wallet is unlocked\n" + " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in DAPS/kB\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); @@ -2033,6 +2034,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); if (pwalletMain->IsCrypted()) + obj.push_back(Pair("walletunlocked", !pwalletMain->IsLocked())); obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); return obj; From c25512039a4982e246bd45155a6bc231fab0ca8d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 17 Jan 2020 17:56:23 -0500 Subject: [PATCH 0151/1888] Update Syncing -> Syncing Blocks Staking Status --- src/qt/bitcoingui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 54237e823a..db35cb4db2 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1267,8 +1267,8 @@ void BitcoinGUI::setStakingStatus() } if (IsInitialBlockDownload()) { LogPrint("staking","Checking Staking Status: Syncing...\n"); - stakingState->setText(tr("Syncing...")); - stakingState->setToolTip("Syncing"); + stakingState->setText(tr("Syncing Blocks...")); + stakingState->setToolTip("Syncing Blocks"); stakingAction->setIcon(QIcon(":/icons/staking_waiting")); return; } From 30da329cc5ebb30f75c5eff361f4aa1020a02476 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 18 Jan 2020 16:57:23 -0500 Subject: [PATCH 0152/1888] Bump version to v1.0.5.8 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5d72f6ea9b..8de5ccb393 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 7) +define(_CLIENT_VERSION_BUILD, 8) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From ca4f9034319909323ed52feeb4de90c91c6f05bd Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 19 Jan 2020 17:53:58 -0500 Subject: [PATCH 0153/1888] Fix sizing issue --- src/qt/dapscoin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 33250e1d11..7e4dd56eba 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -612,6 +612,7 @@ int main(int argc, char* argv[]) Q_INIT_RESOURCE(dapscoin_locale); Q_INIT_RESOURCE(dapscoin); + BitcoinApplication app(argc, argv); #if QT_VERSION > 0x050100 // Generate high-dpi pixmaps QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); @@ -622,7 +623,6 @@ int main(int argc, char* argv[]) #ifdef Q_OS_MAC QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); #endif - BitcoinApplication app(argc, argv); // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType(); From 77210f721f8277a8886efee862f8cb1e1b849239 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 19 Jan 2020 21:26:35 -0500 Subject: [PATCH 0154/1888] Remove TxCompare, Sorting done by QT --- src/qt/historypage.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 61be691895..0c3305c947 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -31,15 +31,6 @@ #include #include -bool TxCompare (std::map i, std::map j) { - QString str_i = i.at("date"); - QString str_j = j.at("date"); - QDateTime date_i = QDateTime::fromString(str_i,"MM/dd/yy hh:mm"); - QDateTime date_j = QDateTime::fromString(str_j,"MM/dd/yy hh:mm"); - - return date_i > date_j; -} - HistoryPage::HistoryPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::HistoryPage), // m_SizeGrip(this), @@ -237,7 +228,6 @@ void HistoryPage::updateTableData(CWallet* wallet) } else { txs = WalletUtil::getTXs(wallet); } - std::sort (txs.begin(), txs.end(), TxCompare); for (int row = 0; row < (short)txs.size(); row++) { ui->tableView->insertRow(row); int col = 0; From f618ec5ce8cb12c7966c4ae03a962729286d000a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 21 Jan 2020 12:15:39 -0500 Subject: [PATCH 0155/1888] Fix "warning: control reaches end of non-void function" --- src/wallet/wallet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ab13e71e88..19c8956f3f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -802,6 +802,8 @@ std::string CWallet::GetTransactionType(const CTransaction& tx) } if (fToMe) return "deposit"; + + return "other"; } void CWallet::AddToSpends(const uint256& wtxid) @@ -6091,17 +6093,15 @@ bool CWallet::estimateStakingConsolidationFees(CAmount& minFee, CAmount& maxFee) minFee = 0; maxFee = 0; - if (total < MINIMUM_STAKE_AMOUNT) false; //no staking sweeping will be created + if (total < MINIMUM_STAKE_AMOUNT) return false; //no staking sweeping will be created size_t numUTXOs = vCoins.size(); - - + return true; } int CWallet::MaxTxSizePerTx() { return ComputeTxSize(50, 2, 15); } - bool CWallet::MultiSend() { // Stop the old blocks from sending multisends From 413c1f12549daa4b0e3cf13475d7b0bbb6ec990d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 21 Jan 2020 12:30:24 -0500 Subject: [PATCH 0156/1888] Remove `WriteBlockIndex` in the middle of `ConnectBlock()` Remove a `WriteBlockIndex` that was in the middle of `ConnectBlock()`. This really shouldn't be in this code at all because the index is written by adding it to a list of dirty. This is very likely what has caused the wallet to be especially likely to corrupt on force close. --- src/main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 212a675e14..61c9679c3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3110,9 +3110,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin //LogPrintf("%s: nValueOut=%d, nValueIn=%d, nMoneySupplyPrev=%d, pindex->nMoneySupply=%d, nFees=%d", __func__, nValueOut, nValueIn, nMoneySupplyPrev, pindex->nMoneySupply, nFees); pindex->nMint = pindex->nMoneySupply - nMoneySupplyPrev + nFees; - if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) - return error("Connect() : WriteBlockIndex for pindex failed"); - int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", From 66843f217d621c4bf46bc66fcb97894718ca7652 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 21 Jan 2020 12:31:08 -0500 Subject: [PATCH 0157/1888] Remove the auto-repair db code on init. Remove the auto-repair db code on init. This seems to actually cause more problems than it fixes. --- src/main.cpp | 67 ---------------------------------------------------- 1 file changed, 67 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 61c9679c3f..d2d29f0007 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4908,73 +4908,6 @@ bool static LoadBlockIndexDB(string& strError) pblocktree->ReadFlag("shutdown", fLastShutdownWasPrepared); LogPrintf("%s: Last shutdown was prepared: %s\n", __func__, fLastShutdownWasPrepared); - //Check for inconsistency with block file info and internal state - if (!fLastShutdownWasPrepared && !GetBoolArg("-forcestart", false) && !GetBoolArg("-reindex", false)) { - unsigned int nHeightLastBlockFile = vinfoBlockFile[nLastBlockFile].nHeightLast + 1; - if (vSortedByHeight.size() > nHeightLastBlockFile && - pcoinsTip->GetBestBlock() != vSortedByHeight[nHeightLastBlockFile].second->GetBlockHash()) { - //The database is in a state where a block has been accepted and written to disk, but the - //transaction database (pcoinsTip) was not flushed to disk, and is therefore not in sync with - //the block index database. - - if (!mapBlockIndex.count(pcoinsTip->GetBestBlock())) { - strError = "The wallet has been not been closed gracefully, causing the transaction database to be out of sync with the block database"; - return false; - } - LogPrintf("%s : pcoinstip synced to block height %d, block index height %d\n", __func__, - mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, vSortedByHeight.size()); - - //get the index associated with the point in the chain that pcoinsTip is synced to - CBlockIndex* pindexLastMeta = vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second; - CBlockIndex* pindex = vSortedByHeight[0].second; - unsigned int nSortedPos = 0; - for (unsigned int i = 0; i < vSortedByHeight.size(); i++) { - nSortedPos = i; - if (vSortedByHeight[i].first == mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight + 1) { - pindex = vSortedByHeight[i].second; - break; - } - } - - // Start at the last block that was successfully added to the txdb (pcoinsTip) and manually add all transactions that occurred for each block up until - // the best known block from the block index db. - CCoinsViewCache view(pcoinsTip); - while (nSortedPos < vSortedByHeight.size()) { - CBlock block; - if (!ReadBlockFromDisk(block, pindex)) { - strError = "The wallet has been not been closed gracefully and has caused corruption of blocks stored to disk. Data directory is in an unusable state"; - return false; - } - - vector vtxundo; - vtxundo.reserve(block.vtx.size() - 1); - uint256 hashBlock = block.GetHash(); - for (unsigned int i = 0; i < block.vtx.size(); i++) { - CValidationState state; - CTxUndo undoDummy; - if (i > 0) - vtxundo.push_back(CTxUndo()); - UpdateCoins(block.vtx[i], state, view, i == 0 ? undoDummy : vtxundo.back(), pindex->nHeight); - view.SetBestBlock(hashBlock); - } - - if (pindex->nHeight >= pindexLastMeta->nHeight) - break; - - pindex = vSortedByHeight[++nSortedPos].second; - } - - // Save the updates to disk - if (!view.Flush() || !pcoinsTip->Flush()) - LogPrintf("%s : failed to flush view\n", __func__); - - LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, - pindexLastMeta->GetBlockHash().ToString().c_str()); - LogPrintf("%s : pcoinstip=%d %s\n", __func__, mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, - pcoinsTip->GetBestBlock().GetHex()); - } - } - // Check whether we need to continue reindexing bool fReindexing = false; pblocktree->ReadReindexing(fReindexing); From 3f88dd3f990ac243208b84e8cdcbf2458bf9f659 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 21 Jan 2020 17:33:25 -0500 Subject: [PATCH 0158/1888] Fix Date sorting --- src/qt/historypage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 0c3305c947..d6947842fd 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -233,10 +233,11 @@ void HistoryPage::updateTableData(CWallet* wallet) int col = 0; for (QString dataName : {"date", "type", "address", "amount", "confirmations"}) { QString data = txs[row].at(dataName); - QString date = data; + QDateTime date; QTableWidgetItem* cell = new QTableWidgetItem(); switch (col) { case 0: /*date*/ + date = QDateTime::fromString(data, "MM/dd/yy hh:mm:ss").addYears(100); cell->setData(0, date); break; case 3: /*amount*/ From d0bacf1d07c1e801a22fe48fff4f53209aeb71b7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 22 Jan 2020 12:49:47 -0500 Subject: [PATCH 0159/1888] Add UPNP checkbox to Settings page --- src/qt/forms/optionspage.ui | 29 +++++++++++++++++++++++++++++ src/qt/optionspage.cpp | 18 ++++++++++++++++++ src/qt/optionspage.h | 1 + 3 files changed, 48 insertions(+) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 7792b0b660..6fc960c11f 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -627,6 +627,35 @@ + + + + Automatically open the DAPS client port on the router. This only works when your router supports UPnP and it is enabled. + + + Map port using &UPnP + + + + + + + true + + + + 16777215 + 5 + + + + QFrame::NoFrame + + + + + + diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 4e650532ed..7ba95563ee 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -147,7 +147,10 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->addNewFunds->setFont(font); ui->addNewFunds->setToolTip("Disabled by default due to controlling Masternode(s) from this wallet.\nEnabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking."); } + ui->mapPortUpnp->setChecked(settings.value("fUseUPnP", false).toBool()); connect(ui->addNewFunds, SIGNAL(stateChanged(int)), this, SLOT(setAutoConsolidate(int))); + connect(ui->mapPortUpnp, SIGNAL(stateChanged(int)), this, SLOT(mapPortUpnp_clicked(int))); + } void OptionsPage::setStakingToggle() @@ -897,3 +900,18 @@ void OptionsPage::saveConsolidationSettingTime(bool autoConsolidate) pwalletMain->WriteAutoConsolidateSettingTime(GetAdjustedTime()); } } + +void OptionsPage::mapPortUpnp_clicked(int state) +{ + if (ui->mapPortUpnp->isChecked()) { + settings.setValue("fUseUPnP", true); + } else { + settings.setValue("fUseUPnP", false); + } + QMessageBox msgBox; + msgBox.setWindowTitle("UPNP Settings"); + msgBox.setIcon(QMessageBox::Information); + msgBox.setText("UPNP Settings successfully changed. Please restart the wallet for changes to take effect."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); +} diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 527b435272..4067194395 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -97,6 +97,7 @@ private slots: void onShowMnemonic(); void setStakingToggle(); void setAutoConsolidate(int); + void mapPortUpnp_clicked(int); }; #endif // BITCOIN_QT_OPTIONSPAGE_H From 5dce3867e1e834089bc9ac293a0ab99eed85aab2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 22 Jan 2020 18:59:20 -0500 Subject: [PATCH 0160/1888] [GUI] Adding the capability to decrease the screen size for smaller screens support https://github.com/PIVX-Project/PIVX/commit/1493b4a52b9989825b51abe7a90f0e4c68b3146 --- src/qt/bitcoingui.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 54237e823a..599291c86d 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -68,6 +68,10 @@ #include #endif +#define BASE_WINDOW_WIDTH 1147 +#define BASE_WINDOW_HEIGHT 768 +#define BASE_WINDOW_MIN_HEIGHT 720 + const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMainWindow(parent), @@ -115,8 +119,8 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); - this->setMinimumSize(1147, 768); - GUIUtil::restoreWindowGeometry("nWindow", QSize(1147, 768), this); + this->setMinimumSize(BASE_WINDOW_WIDTH, BASE_WINDOW_MIN_HEIGHT); + GUIUtil::restoreWindowGeometry("nWindow", QSize(BASE_WINDOW_WIDTH, BASE_WINDOW_HEIGHT), this); QString windowTitle = tr("DAPS Coin") + " "; fLiteMode = GetBoolArg("-litemode", false); From 217bf3878ed15098196ad62b95b18d3b89237cba Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 23 Jan 2020 18:31:56 -0500 Subject: [PATCH 0161/1888] Add minimizeToTray / minimizeOnClose on Settings screen --- src/qt/forms/optionspage.ui | 61 ++++++++++++++++++++++--------------- src/qt/optionspage.cpp | 23 +++++++++++++- src/qt/optionspage.h | 2 ++ src/qt/res/css/Dark.css | 16 +++++++++- src/qt/res/css/Light.css | 16 +++++++++- 5 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index 6fc960c11f..fbda67595a 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -32,9 +32,9 @@ 0 - 0 - 823 - 513 + -22 + 806 + 535 @@ -628,32 +628,45 @@ - - - Automatically open the DAPS client port on the router. This only works when your router supports UPnP and it is enabled. - - - Map port using &UPnP + + + Network Settings + + + + + Automatically open the DAPS client port on the router. This only works when your router supports UPnP and it is enabled. + + + Map port using &UPnP + + + + - - - true - - - - 16777215 - 5 - - - - QFrame::NoFrame - - - + + + Window Settings + + + + + &Minimize to the tray instead of the taskbar + + + + + + + M&inimize on close + + + + diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 7ba95563ee..83d0d2e74e 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -148,9 +148,12 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu ui->addNewFunds->setToolTip("Disabled by default due to controlling Masternode(s) from this wallet.\nEnabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking."); } ui->mapPortUpnp->setChecked(settings.value("fUseUPnP", false).toBool()); + ui->minimizeToTray->setChecked(settings.value("fMinimizeToTray", false).toBool()); + ui->minimizeOnClose->setChecked(settings.value("fMinimizeOnClose", false).toBool()); connect(ui->addNewFunds, SIGNAL(stateChanged(int)), this, SLOT(setAutoConsolidate(int))); connect(ui->mapPortUpnp, SIGNAL(stateChanged(int)), this, SLOT(mapPortUpnp_clicked(int))); - + connect(ui->minimizeToTray, SIGNAL(stateChanged(int)), this, SLOT(minimizeToTray_clicked(int))); + connect(ui->minimizeOnClose, SIGNAL(stateChanged(int)), this, SLOT(minimizeOnClose_clicked(int))); } void OptionsPage::setStakingToggle() @@ -915,3 +918,21 @@ void OptionsPage::mapPortUpnp_clicked(int state) msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.exec(); } + +void OptionsPage::minimizeToTray_clicked(int state) +{ + if (ui->minimizeToTray->isChecked()) { + settings.setValue("fMinimizeToTray", true); + } else { + settings.setValue("fMinimizeToTray", false); + } +} + +void OptionsPage::minimizeOnClose_clicked(int state) +{ + if (ui->minimizeOnClose->isChecked()) { + settings.setValue("fMinimizeOnClose", true); + } else { + settings.setValue("fMinimizeOnClose", false); + } +} diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 4067194395..265a6dbe58 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -98,6 +98,8 @@ private slots: void setStakingToggle(); void setAutoConsolidate(int); void mapPortUpnp_clicked(int); + void minimizeToTray_clicked(int); + void minimizeOnClose_clicked(int); }; #endif // BITCOIN_QT_OPTIONSPAGE_H diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index e5d6e529ee..c2a3e66b66 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -59,7 +59,8 @@ QDialog { border-image: url(':/images/background') 0 0 0 0 stretch stretch; } -#line_1, #line_2, #line_3, #line_4 { +#line_1, #line_2, #line_3, +#line_4, #line_5, #line_6 { border-bottom: 1px solid gray; max-height: 5px; margin: 5px; @@ -183,6 +184,19 @@ QCheckBox::indicator:checked { margin: 7px; } +QGroupBox { + font: bold; + border: 1px solid white; + border-radius: 6px; + margin-top: 6px; +} + +QGroupBox::title { + subcontrol-origin: margin; + left: 7px; + padding: 0px 5px 0px 5px; +} + /*** Line Edits, ComboBoxes ***/ .QValidatedLineEdit, .QLineEdit, diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css index d88268406f..db9cec26fb 100644 --- a/src/qt/res/css/Light.css +++ b/src/qt/res/css/Light.css @@ -27,7 +27,8 @@ QComboBox:disabled, border: 1px solid rgb(51, 54, 54); }*/ -#line_1, #line_2, #line_3, #line_4 { +#line_1, #line_2, #line_3, +#line_4, #line_5, #line_6 { border-bottom: 1px solid gray; max-height: 5px; margin: 5px; @@ -145,6 +146,19 @@ QCheckBox::indicator:checked { margin: 7px; } +QGroupBox { + font: bold; + border: 1px solid black; + border-radius: 6px; + margin-top: 6px; +} + +QGroupBox::title { + subcontrol-origin: margin; + left: 7px; + padding: 0px 5px 0px 5px; +} + /*** Line Edits, ComboBoxes ***/ .QValidatedLineEdit, .QLineEdit, From eb24bf7b0a1fd6a38f1e1149985409862d755fc5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 23 Jan 2020 19:38:37 -0500 Subject: [PATCH 0162/1888] Add GroupBoxes to Settings --- src/qt/forms/optionspage.ui | 752 ++++++++++++++++-------------------- src/qt/optionspage.cpp | 8 +- 2 files changed, 335 insertions(+), 425 deletions(-) diff --git a/src/qt/forms/optionspage.ui b/src/qt/forms/optionspage.ui index fbda67595a..ede9bf0864 100644 --- a/src/qt/forms/optionspage.ui +++ b/src/qt/forms/optionspage.ui @@ -32,9 +32,9 @@ 0 - -22 + 0 806 - 535 + 541 @@ -201,434 +201,348 @@ - - - - - - 0 - 0 - - - - Change current passphrase - - - - - - - QLineEdit::Password - - - Old passphrase - - - - - - - QLineEdit::Password - - - New passphrase - - - - - - - QLineEdit::Password - - - Repeat new passphrase - - - - - - - 100 - - - 0 - - - - - - 0 - 0 - - - - Submit - - - - - - - - 0 - 0 - - - - Clear All - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 5 - - - - QFrame::NoFrame - - - + + + Two Factor Authentication + + + + + + + + 0 + 0 + + + + On + + + Off + + + + 100 + 55 + + + + + + + + Remember my authentication code for + + + + + + + 100 + + + 0 + + + + + 1 Day + + + + + + + 1 Week + + + + + + + 1 Month + + + + + + + + + Current Authentication Code + + + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + - - - QLayout::SetDefaultConstraint - - - - - - 0 - 0 - - - - Quantity of DAPS to keep as spendable (not staking) - - - - - - - - - - - - Enabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking. - - - Automatically add any new deposits received to your staked balance - - - - - - - - - 100 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - - 0 - 0 - - - - Save - - - - - - - Disable - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - true - - - - 0 - 0 - - - - - 16777215 - 5 - - - - - 11 - - - - QFrame::NoFrame - - - + + + Change current passphrase + + + + + + + QLineEdit::Password + + + Old passphrase + + + + + + + QLineEdit::Password + + + New passphrase + + + + + + + QLineEdit::Password + + + Repeat new passphrase + + + + + + + 100 + + + 0 + + + + + + 0 + 0 + + + + Submit + + + + + + + + 0 + 0 + + + + Clear All + + + + + + + + - - - - - true - - - - 0 - 0 - - - - Two Factor Authentication - - - - - - - - 0 - 0 - - - - On - - - Off - - - - 100 - 55 - - - - - - - - Remember my authentication code for - - - - - - - 100 - - - 0 - - - - - 1 Day - - - - - - - 1 Week - - - - - - - 1 Month - - - - - - - - - Current Authentication Code - - - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - - true - - - - 16777215 - 5 - - - - QFrame::NoFrame - - - + + + Quantity of DAPS to keep as spendable (not staking) + + + + + QLayout::SetDefaultConstraint + + + + + + + + + + Enabling this will incur a minimum 1 DAPS fee each time you receive a new deposit that needs to be consolidated for staking. + + + Automatically add any new deposits received to your staked balance + + + + + + + + + 100 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + + 0 + 0 + + + + Save + + + + + + + Disable + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + - + Network Settings @@ -647,7 +561,7 @@ - + Window Settings diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 83d0d2e74e..c6c3a91c46 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -92,22 +92,20 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu timerStakingToggleSync->start(10000); ui->labelStaking->show(); ui->toggleStaking->show(); - ui->quantityLabel->show(); + ui->reservegroupBox->show(); ui->lineEditWithhold->show(); ui->addNewFunds->show(); ui->pushButtonSave->show(); ui->pushButtonDisable->show(); - ui->line_3->show(); } else { //Staking related items and functions hidden/removed in litemode ui->labelStaking->hide(); ui->toggleStaking->hide(); - ui->quantityLabel->hide(); + ui->reservegroupBox->hide(); ui->lineEditWithhold->hide(); ui->addNewFunds->hide(); ui->pushButtonSave->hide(); ui->pushButtonDisable->hide(); - ui->line_3->hide(); } @@ -704,7 +702,6 @@ void OptionsPage::disable2FA() { ui->label_3->setEnabled(false); ui->lblAuthCode->setEnabled(false); - ui->label->setEnabled(false); ui->btn_day->setEnabled(false); ui->btn_week->setEnabled(false); ui->btn_month->setEnabled(false); @@ -718,7 +715,6 @@ void OptionsPage::disable2FA() { void OptionsPage::enable2FA() { ui->label_3->setEnabled(true); ui->lblAuthCode->setEnabled(true); - ui->label->setEnabled(true); ui->btn_day->setEnabled(true); ui->btn_week->setEnabled(true); ui->btn_month->setEnabled(true); From 01ce933143ba9943a42c9d02fadf3b61c04fd706 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 23 Jan 2020 22:38:05 -0500 Subject: [PATCH 0163/1888] Add conf settings for TX Threading Limit (txthreadinglimit) and Max UI TX Limit (maxtxuilimit) TX Threading Limit (txthreadinglimit= in .conf) - Max Transactions loaded per thread - default 4000 Max UI TX Limit (maxtxuilimit= in .conf) - Maximum Transactions loaded into the UI - default 20000 --- src/qt/transactiontablemodel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 3c7caad840..6a9cb28c03 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -83,14 +83,20 @@ class TransactionTablePriv { if (wallet->IsLocked()) return; cachedWallet.clear(); + //Use defined values + int customThreadLimit = SINGLE_THREAD_MAX_TXES_SIZE; + int maxTXUIlLimit = MAX_AMOUNT_LOADED_RECORDS; + //Change to user values if set + customThreadLimit = GetArg("-txthreadinglimit", 4000); + maxTXUIlLimit = GetArg("-maxtxuilimit", 20000); std::vector walletTxes = wallet->getWalletTxs(); // Divide the work between multiple threads to speedup the process if the vector is larger than 4k txes std::size_t txesSize = walletTxes.size(); - if (txesSize > SINGLE_THREAD_MAX_TXES_SIZE) { + if (txesSize > customThreadLimit && GetBoolArg("-txthreading", true)) { // First check if the amount of txs exceeds the UI limit - if (txesSize > MAX_AMOUNT_LOADED_RECORDS) { + if (txesSize > maxTXUIlLimit) { // Sort the txs by date just to be really really sure that them are ordered. // (this extra calculation should be removed in the future if can ensure that // txs are stored in order in the db, which is what should be happening) From 250ae600d3cafafe410d3896e483f457c838ac01 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 25 Jan 2020 13:46:42 -0500 Subject: [PATCH 0164/1888] Add shortcut to open .conf files (CTRL+D dapscoin.conf / CTRL + M masternode.conf) --- src/qt/bitcoingui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 599291c86d..3bf5d25ff7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -422,8 +422,10 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openRepairAction->setStatusTip(tr("Show wallet repair options")); openConfEditorAction = new QAction(QIcon(":/icons/edit"), tr("Open Wallet &Configuration File"), this); openConfEditorAction->setStatusTip(tr("Open configuration file")); + openConfEditorAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); openMNConfEditorAction = new QAction(QIcon(":/icons/edit"), tr("Open &Masternode Configuration File"), this); openMNConfEditorAction->setStatusTip(tr("Open Masternode configuration file")); + openMNConfEditorAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M)); showDataDirAction = new QAction(QIcon(":/icons/browse"), tr("Show &DAPScoin Folder"), this); showDataDirAction->setStatusTip(tr("Show the DAPScoin folder")); showDataDirAction->setShortcut(Qt::Key_F2); From 4452c198a7e332df034dbd1bd8bc3f291cbc247d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 29 Jan 2020 21:16:43 -0500 Subject: [PATCH 0165/1888] Remove CreateCoinAudit (unused) --- src/wallet/wallet.cpp | 177 ------------------------------------------ src/wallet/wallet.h | 1 - 2 files changed, 178 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 19c8956f3f..748628b5a5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4424,183 +4424,6 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int return false; } -bool CWallet::CreateCoinAudit(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime) -{ - // The following split & combine thresholds are important to security - // Should not be adjusted if you don't understand the consequences - - txNew.vin.clear(); - txNew.vout.clear(); - - // Mark coin stake transaction - CScript scriptEmpty; - scriptEmpty.clear(); - txNew.vout.push_back(CTxOut(0, scriptEmpty)); - - // Choose coins to use - CAmount nBalance = GetBalance(); - - if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) - return error("CreateCoinStake : invalid reserve balance amount"); - - if (nBalance > 0 && nBalance <= nReserveBalance) - return false; - - // presstab HyperStake - Initialize as static and don't update the set on every run of CreateCoinAudit() in order to lighten resource use - static std::set > setAuditCoins; - static int nLastStakeSetUpdate = 0; - - if (GetTime() - nLastStakeSetUpdate > nStakeSetUpdateTime) { - setAuditCoins.clear(); - if (!SelectStakeCoins(setAuditCoins, nBalance - nReserveBalance)) - return false; - - nLastStakeSetUpdate = GetTime(); - } - - if (setAuditCoins.empty()) - return false; - - vector vwtxPrev; - - CAmount nCredit = 0; - CScript scriptPubKeyKernel; - - //prevent staking a time that won't be accepted - if (GetAdjustedTime() <= chainActive.Tip()->nTime) - MilliSleep(10000); - - for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setAuditCoins) { - // Make sure the wallet is unlocked and shutdown hasn't been requested - if (IsLocked() || ShutdownRequested()) - return false; - - //make sure that enough time has elapsed between - CBlockIndex* pindex = NULL; - BlockMap::iterator it = mapBlockIndex.find(pcoin.first->hashBlock); - if (it != mapBlockIndex.end()) - pindex = it->second; - else { - if (fDebug) - LogPrintf("CreateCoinStake() failed to find block index \n"); - continue; - } - - // Read block header - CBlockHeader block = pindex->GetBlockHeader(); - - bool fKernelFound = false; - uint256 hashProofOfStake = 0; - COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - nTxNewTime = GetAdjustedTime(); - - //iterates each utxo inside of CheckStakeKernelHash() - if (CheckStakeKernelHash(nBits, block, *pcoin.first, prevoutStake, NULL, nTxNewTime, nHashDrift, false, hashProofOfStake, true)) { - //Double check that this will pass time requirements - if (nTxNewTime <= chainActive.Tip()->GetMedianTimePast()) { - LogPrintf("CreateCoinStake() : kernel found, but it is too far in the past \n"); - continue; - } - - // Found a kernel - if (fDebug && GetBoolArg("-printcoinstake", false)) - LogPrintf("CreateCoinStake : kernel found\n"); - - vector vSolutions; - txnouttype whichType; - CScript scriptPubKeyOut; - scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey; - if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) { - LogPrintf("CreateCoinStake : failed to parse kernel\n"); - break; - } - if (fDebug && GetBoolArg("-printcoinstake", false)) - LogPrintf("CreateCoinStake : parsed kernel type=%d\n", whichType); - if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH) { - if (fDebug && GetBoolArg("-printcoinstake", false)) - LogPrintf("CreateCoinStake : no support for kernel type=%d\n", whichType); - break; // only support pay to public key and pay to address - } - if (whichType == TX_PUBKEYHASH) // pay to address type - { - //convert to pay to public key type - CKey key; - if (!keystore.GetKey(uint160(vSolutions[0]), key)) { - if (fDebug && GetBoolArg("-printcoinstake", false)) - LogPrintf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType); - break; // unable to find corresponding public key - } - - scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; - } else - scriptPubKeyOut = scriptPubKeyKernel; - - txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); - nCredit += pcoin.first->vout[pcoin.second].nValue; - vwtxPrev.push_back(pcoin.first); - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); - - //presstab HyperStake - calculate the total size of our new output including the stake reward so that we can use it to decide whether to split the stake outputs - const CBlockIndex* pIndex0 = chainActive.Tip(); - uint64_t nTotalSize = pcoin.first->vout[pcoin.second].nValue + GetBlockValue(pIndex0); - - //presstab HyperStake - if MultiSend is set to send in coinstake we will add our outputs here (values asigned further down) - if (nTotalSize / 2 > nStakeSplitThreshold * COIN) - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake - - if (fDebug && GetBoolArg("-printcoinstake", false)) - LogPrintf("CreateCoinStake : added kernel type=%d\n", whichType); - fKernelFound = true; - } - if (fKernelFound) - break; // if kernel is found stop searching - } - if (nCredit == 0 || nCredit > nBalance - nReserveBalance) - return false; - - // Calculate reward - CAmount nReward; - const CBlockIndex* pIndex0 = chainActive.Tip(); - nReward = GetBlockValue(pIndex0); - - CAmount nMinFee = 0; - if (txNew.vout.size() == 3) { - txNew.vout[1].nValue = ((nCredit - nMinFee) / 2 / CENT) * CENT; - txNew.vout[2].nValue = nCredit - nMinFee - txNew.vout[1].nValue; - } else - txNew.vout[1].nValue = nCredit - nMinFee; - - if (Params().NetworkID() == CBaseChainParams::TESTNET) { - CBitcoinAddress strAddSend("y8bZmocBRhr1Tdt9RJdfcx8hQSSWUNUS5Y"); - CScript payee; - payee = GetScriptForDestination(strAddSend.Get()); - txNew.vout.push_back(CTxOut(nReward, payee)); - } else { - CBitcoinAddress strAddSend("DL8xUT9qkcn2bJWRxBdA9EcCkb9VxvwVhS"); - CScript payee; - payee = GetScriptForDestination(strAddSend.Get()); - txNew.vout.push_back(CTxOut(nReward, payee)); - } - - - // Limit size - unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= DEFAULT_BLOCK_MAX_SIZE / 5) - return error("CreateCoinStake : exceeded coinstake size limit"); - - - // Sign - int nIn = 0; - for (const CWalletTx* pcoin : vwtxPrev) { - if (!SignSignature(*this, *pcoin, txNew, nIn++)) - return error("CreateCoinStake : failed to sign coinstake"); - } - - // Successfully generated coinstake - nLastStakeSetUpdate = 0; //this will trigger stake set to repopulate next round - return true; -} - /** * Call after CreateTransaction unless you want to abort */ diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 21b42227b7..5129333794 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -593,7 +593,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); bool ConvertList(std::vector vCoins, std::vector& vecAmounts); bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); - bool CreateCoinAudit(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); bool MultiSend(); void AutoCombineDust(); From b137a3650d8a0f96c9ef43d30d977a5f7680ece6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 30 Jan 2020 17:22:11 -0500 Subject: [PATCH 0166/1888] Update checkpoints every 5k from 240000 to 260000 --- src/chainparams.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index bf05083cd9..a54dbb8be3 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -113,11 +113,16 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (230000, uint256("578a5eeee8d8d2d5c9f961db6f4ad42dcc830aaadf103b7bd4dfc6384ddd5d68")) (235000, uint256("f91427c4ae7e75c7630c2e3fade78db8ce3aa830b07861435d90a8e2a26222a7")) (239830, uint256("a17a68a3399dc67992815f5e0ee3fbac7bb0b3777e64a5446b728dc25bc3b113")) + (240000, uint256("404633fe3349ee3b8fb6d615ba25646532823f35cd0863f7029d90f9fb00f804")) + (245000, uint256("0541e509e049e02ce17cff6c1d4178c98a5ac0f3ee2a7db41008db8997389686")) + (250000, uint256("d4a1b457984d818d728288d2b1fb30355feb3e8e9309b99e165dfc0a22523216")) + (255000, uint256("a7e29e83aee66c7e2eb097ef8f729dcc44d5235a5533fb357e70fa14cf345bd6")) + (260000, uint256("556f5deedff1c551551b6fda517fe939e0fb6810d35664fd55b5c5c2b6ec33c7")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1579208143, // * UNIX timestamp of last checkpoint block - 599166, // * total number of transactions between genesis and last checkpoint + 1580415389, // * UNIX timestamp of last checkpoint block + 646035, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 427b7beda28311f691c0ba9a3dda4d5dc0b5bcdb Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 3 Feb 2020 20:08:44 -0500 Subject: [PATCH 0167/1888] Add "Check For Updates" feature (first implementation) Added version.txt to root of source tree as comparison text for this feature - can continue to be used (perhaps automating it in the future to output the version to this .txt automatically for future) --- src/qt/bitcoingui.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++ src/qt/bitcoingui.h | 4 ++++ version.txt | 1 + 3 files changed, 54 insertions(+) create mode 100644 version.txt diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3bf5d25ff7..2f19ba6666 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #if QT_VERSION < 0x050000 #include @@ -485,6 +486,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) openTGMNSupportAction->setStatusTip(tr("Telegram Masternode Support")); openDiscordSupportAction = new QAction(QIcon(":/icons/discord"), tr("&Discord Tech Support"), this); openDiscordSupportAction->setStatusTip(tr("Discord Tech Support")); + checkForUpdatesAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Check For Updates"), this); + checkForUpdatesAction->setStatusTip(tr("Check For Updates")); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); @@ -498,6 +501,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(openTGTechSupportAction, SIGNAL(triggered()), this, SLOT(openTGTechSupportClicked())); connect(openTGMNSupportAction, SIGNAL(triggered()), this, SLOT(openTGMNSupportClicked())); connect(openDiscordSupportAction, SIGNAL(triggered()), this, SLOT(openDiscordSupportClicked())); + connect(checkForUpdatesAction, SIGNAL(triggered()), this, SLOT(checkForUpdatesClicked())); #ifdef ENABLE_WALLET if (walletFrame) { connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); @@ -601,6 +605,8 @@ void BitcoinGUI::createMenuBar() help->addSeparator(); help->addAction(openDiscordSupportAction); help->addSeparator(); + help->addAction(checkForUpdatesAction); + help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); appMenuBar->setVisible(true); @@ -932,6 +938,49 @@ void BitcoinGUI::openDiscordSupportClicked() QDesktopServices::openUrl(QUrl("https://discord.gg/8vbXJMf")); } +void BitcoinGUI::checkForUpdatesClicked() +{ + QUrl serviceUrl = QUrl("https://raw.githubusercontent.com/DAPSCoin/DAPSCoin/master/version.txt"); + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(serviceRequestFinished(QNetworkReply*))); + QNetworkRequest request; + request.setUrl(serviceUrl); + QNetworkReply* reply = manager->get(request); +} + +void BitcoinGUI::serviceRequestFinished(QNetworkReply* reply) +{ + QString currentVersion = QString::number(CLIENT_VERSION_MAJOR) + "." + QString::number(CLIENT_VERSION_MINOR)+ "." + QString::number(CLIENT_VERSION_REVISION)+ "." + QString::number(CLIENT_VERSION_BUILD); + reply->deleteLater(); + if(reply->error() == QNetworkReply::NoError) { + QByteArray data = reply->readAll(); + if (data != currentVersion) { + QMessageBox::StandardButton msgReply; + msgReply = QMessageBox::question(this, "Wallet Update Available!", "Wallet update available.\n\nWould you like to go to the GitHub Releases page to download v" + data.trimmed() + "?", QMessageBox::Yes|QMessageBox::No); + if (msgReply == QMessageBox::Yes) { + QDesktopServices::openUrl(QUrl("https://github.com/DAPSCoin/DAPSCoin/releases/latest")); + } else { + return; + } + } else { + QMessageBox msgBox; + msgBox.setWindowTitle("No Update Available"); + msgBox.setText("No update available.\n\nYour wallet is up to date."); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.setIcon(QMessageBox::Information); + msgBox.exec(); + } + } else { + QByteArray error = reply->readAll(); + QMessageBox msgBox; + msgBox.setWindowTitle("Error"); + msgBox.setText("Error checking for updates.\n\n" + error); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.setIcon(QMessageBox::Critical); + msgBox.exec(); + } +} + #ifdef ENABLE_WALLET void BitcoinGUI::openClicked() { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 793bd2899a..dbe0a4d644 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -19,6 +19,7 @@ #include #include #include +#include class ClientModel; class NetworkStyle; @@ -138,6 +139,7 @@ class BitcoinGUI : public QMainWindow QAction* openTGTechSupportAction; QAction* openTGMNSupportAction; QAction* openDiscordSupportAction; + QAction* checkForUpdatesAction; QAction* multiSendAction; QFrame* frameBlocks; QLabel *stakingState; @@ -266,6 +268,8 @@ private slots: void openTGTechSupportClicked(); void openTGMNSupportClicked(); void openDiscordSupportClicked(); + void checkForUpdatesClicked(); + void serviceRequestFinished(QNetworkReply* reply); #ifndef Q_OS_MAC /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); diff --git a/version.txt b/version.txt new file mode 100644 index 0000000000..6990b2ceea --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.0.6.0 \ No newline at end of file From 49fafa3cadbd0799d147f9bb8db6c0e4199d6054 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 3 Feb 2020 21:31:14 -0500 Subject: [PATCH 0168/1888] Remove setWindowless from History Page ComboBoxes --- src/qt/historypage.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index d6947842fd..fac11b18b5 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -69,11 +69,6 @@ void HistoryPage::initWidgets() timeEditFrom = new QTimeEdit(ui->dateTimeEditFrom); ui->dateTimeEditTo->calendarWidget()->parentWidget()->layout()->addWidget(timeEditTo); ui->dateTimeEditFrom->calendarWidget()->parentWidget()->layout()->addWidget(timeEditFrom); - //remove window frames from widgets - GUIUtil::setWindowless(ui->dateTimeEditTo->calendarWidget()->parentWidget()); - GUIUtil::setWindowless(ui->dateTimeEditFrom->calendarWidget()->parentWidget()); - GUIUtil::setWindowless(ui->comboBoxType->view()->parentWidget()); - GUIUtil::setWindowless(ui->lineEditDesc->view()->parentWidget()); //color calendarwidgets GUIUtil::colorCalendarWidgetWeekends(ui->dateTimeEditTo->calendarWidget(), QColor("gray")); GUIUtil::colorCalendarWidgetWeekends(ui->dateTimeEditFrom->calendarWidget(), QColor("gray")); From 10558ccad15bb671348f14049237db78e20238e1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 3 Feb 2020 21:31:36 -0500 Subject: [PATCH 0169/1888] Update duplicate syncTime --- src/qt/historypage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index fac11b18b5..5a3bb8fe9f 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -273,7 +273,7 @@ void HistoryPage::updateAddressBookData(CWallet* wallet) void HistoryPage::updateFilter() { syncTime(ui->dateTimeEditFrom, timeEditFrom); - syncTime(ui->dateTimeEditFrom, timeEditFrom); + syncTime(ui->dateTimeEditTo, timeEditTo); auto selectedAmount = ui->lineEditAmount->text().toFloat(); QString selectedType = ui->comboBoxType->currentText(); QList selectedAddresses = ui->lineEditDesc->lineEdit()->text().split(" | "); From ba0ffa9f41742a3f57aded2f57b63bfee07ac74b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 4 Feb 2020 19:36:00 -0500 Subject: [PATCH 0170/1888] Updated logging --- src/wallet/wallet.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 748628b5a5..ab24b074be 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3447,7 +3447,7 @@ bool CWallet::generateBulletProofAggregate(CTransaction& tx) bool CWallet::makeRingCT(CTransaction& wtxNew, int ringSize, std::string& strFailReason) { - LogPrintf("making ringCT, ringsize=%d\n", ringSize); + LogPrintf("Making RingCT using ring size=%d\n", ringSize); int myIndex; if (!selectDecoysAndRealIndex(wtxNew, myIndex, ringSize)) { return false; @@ -3898,7 +3898,7 @@ bool CWallet::MakeShnorrSignatureTxIn(CTxIn& txin, uint256 cts) bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringSize) { - LogPrintf("Selecting coinbase decoys\n"); + LogPrintf("Selecting coinbase decoys for transaction\n"); if (coinbaseDecoysPool.size() <= 100) { for (int i = chainActive.Height() - Params().COINBASE_MATURITY(); i > 0; i--) { if (coinbaseDecoysPool.size() > 100) break; @@ -3959,7 +3959,7 @@ bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringS CKeyImage ki; if (!generateKeyImage(txPrev.vout[tx.vin[i].prevout.n].scriptPubKey, ki)) { - LogPrintf("Cannot generate key image"); + LogPrintf("Cannot generate key image\n"); return false; } else { tx.vin[i].keyImage = ki; @@ -4004,7 +4004,7 @@ bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringS if (numDecoys == ringSize) break; } } else { - LogPrintf("Dont have enough decoys, please wait for around 10 minutes and re-try\n"); + LogPrintf("Not enough decoys. Please wait approximately 10 minutes and try again.\n"); return false; } } else { @@ -4046,7 +4046,7 @@ bool CWallet::selectDecoysAndRealIndex(CTransaction& tx, int& myIndex, int ringS if (numDecoys == ringSize) break; } } else { - LogPrintf("Dont have enough decoys, please wait for around 10 minutes and re-try\n"); + LogPrintf("Not enough decoys. Please wait approximately 10 minutes and try again.\n"); return false; } } @@ -4240,7 +4240,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int pindex = it->second; } else { if (fDebug) { - LogPrintf("CreateCoinStake() failed to find block index \n"); + LogPrintf("CreateCoinStake() failed to find block index\n"); } continue; } @@ -4261,7 +4261,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (CheckStakeKernelHash(nBits, block, *pcoin.first, prevoutStake, sharedSec.begin(), nTxNewTime, nHashDrift, false, hashProofOfStake, true)) { //Double check that this will pass time requirements if (nTxNewTime <= chainActive.Tip()->GetMedianTimePast()) { - LogPrintf("CreateCoinStake() : kernel found, but it is too far in the past \n"); + LogPrintf("CreateCoinStake() : kernel found, but it is too far in the past\n"); continue; } @@ -4301,7 +4301,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int CTxIn in(pcoin.first->GetHash(), pcoin.second); if (!generateKeyImage(scriptPubKeyKernel, in.keyImage)) { - LogPrintf("CreateCoinStake : cannot generate key image"); + LogPrintf("CreateCoinStake : cannot generate key image\n"); break; } //copy encryption key so that full nodes can decode the amount in the txin @@ -4341,7 +4341,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int break; } if (fKernelFound) { - LogPrintf("CreateCoinStake: Kernel is found"); + LogPrintf("CreateCoinStake: Kernel is found\n"); break; // if kernel is found stop searching } } @@ -5678,7 +5678,7 @@ bool CWallet::CreateSweepingTransaction(CAmount target, CAmount threshold, uint3 try { SendToStealthAddress(masterAddr, ComputeReserveUTXOAmount(), wtx); } catch (const std::exception& err) { - LogPrintf("failed to create reserve UTXO"); + LogPrintf("failed to create reserve UTXO\n"); } return false; } else { @@ -5708,7 +5708,7 @@ bool CWallet::CreateSweepingTransaction(CAmount target, CAmount threshold, uint3 } } } - LogPrintf("Generate consolidation, total = %d\n", total); + LogPrintf("Generating consolidation transaction, total = %d DAPS\n", total); // Generate transaction public key CWalletTx wtxNew; CKey secret; @@ -5850,7 +5850,7 @@ void CWallet::AutoCombineDust() } uint32_t nTime = ReadAutoConsolidateSettingTime(); nTime = (nTime == 0)? GetAdjustedTime() : nTime; - LogPrintf("Creating a consolidation transaction for a larger UTXO for staking\n"); + LogPrintf("Attempting to create a consolidation transaction for a larger UTXO for staking\n"); CreateSweepingTransaction(MINIMUM_STAKE_AMOUNT, max + COIN, nTime); } return; @@ -6458,7 +6458,7 @@ bool CWallet::SendToStealthAddress(const std::string& stealthAddr, const CAmount string strError; if (this->IsLocked()) { strError = "Error: Wallet locked, unable to create transaction!"; - LogPrintf("SendToStealthAddress() : %s", strError); + LogPrintf("SendToStealthAddress() : %s\n", strError); throw runtime_error(strError); } @@ -6810,7 +6810,7 @@ void CWallet::createMasterKey() const i++; continue; } - LogPrintf("Created master account"); + LogPrintf("Created master account\n"); break; } } From ea85a5435fc7c820f34ac57f768f7d4a56a208b0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 4 Feb 2020 22:42:51 -0500 Subject: [PATCH 0171/1888] Add Block Count under Network Status --- src/qt/bitcoingui.cpp | 9 +++++++++ src/qt/bitcoingui.h | 1 + src/qt/res/css/Dark.css | 5 +++++ src/qt/res/css/Light.css | 6 ++++++ 4 files changed, 21 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 42fe5a0fbd..b17bac5b61 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -392,6 +392,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) networkAction->setIconText(" Network Status"); connectionCount = new QLabel(this); connectionCount->setObjectName("connectionCount"); + blockCount = new QLabel(this); + blockCount->setObjectName("blockCount"); toggleHideAction = new QAction(networkStyle->getAppIcon(), tr("&Show / Hide"), this); toggleHideAction->setStatusTip(tr("Show or hide the main Window")); @@ -641,6 +643,7 @@ void BitcoinGUI::createToolBars() bottomToolbar->addWidget(stakingState); bottomToolbar->addAction(networkAction); bottomToolbar->addWidget(connectionCount); + bottomToolbar->addWidget(blockCount); bottomToolbar->setStyleSheet("QToolBar{spacing:5px;}"); bottomToolbar->setObjectName("bottomToolbar"); if (fLiteMode) { @@ -1167,6 +1170,12 @@ void BitcoinGUI::setNumBlocks(int count) tooltip += QString("
    "); tooltip += tr("Transactions after this will not yet be visible."); } + + if (IsInitialBlockDownload()) { + blockCount->setText(tr("Syncing Blocks...")); + } else { + blockCount->setText(tr("%n Blocks", "", count)); + } } void BitcoinGUI::message(const QString& title, const QString& message, unsigned int style, bool* ret) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index dbe0a4d644..b7cda24f98 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -144,6 +144,7 @@ class BitcoinGUI : public QMainWindow QFrame* frameBlocks; QLabel *stakingState; QLabel* connectionCount; + QLabel* blockCount; QProgressDialog* progressDialog = nullptr; diff --git a/src/qt/res/css/Dark.css b/src/qt/res/css/Dark.css index c2a3e66b66..9ff09c7c31 100644 --- a/src/qt/res/css/Dark.css +++ b/src/qt/res/css/Dark.css @@ -76,6 +76,11 @@ QDialog { font-style: italic; padding-left: 52px; } +#blockCount { + font-size: 11px; + font-style: italic; + padding-left: 68px; +} QDialog .QTabWidget QTabBar::tab { background-color:#FFFFFF; diff --git a/src/qt/res/css/Light.css b/src/qt/res/css/Light.css index db9cec26fb..79cb841962 100644 --- a/src/qt/res/css/Light.css +++ b/src/qt/res/css/Light.css @@ -46,6 +46,12 @@ QComboBox:disabled, padding-left: 52px; color: white; } +#blockCount { + font-size: 11px; + font-style: italic; + padding-left: 68px; + color: white; +} QDialog { min-width: 500px; From d86c92e3323d0693d2b8d89dea7e2e757fc6fcfe Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 4 Feb 2020 22:43:10 -0500 Subject: [PATCH 0172/1888] Add checkpoint for 265000 --- src/chainparams.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a54dbb8be3..75b24fb721 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -118,11 +118,12 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (250000, uint256("d4a1b457984d818d728288d2b1fb30355feb3e8e9309b99e165dfc0a22523216")) (255000, uint256("a7e29e83aee66c7e2eb097ef8f729dcc44d5235a5533fb357e70fa14cf345bd6")) (260000, uint256("556f5deedff1c551551b6fda517fe939e0fb6810d35664fd55b5c5c2b6ec33c7")) + (265000, uint256("84598b4790a1df395e5ef724c4a2784b27679ef07d9e864ff2fa1b91fcca0751")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1580415389, // * UNIX timestamp of last checkpoint block - 646035, // * total number of transactions between genesis and last checkpoint + 1580714982, // * UNIX timestamp of last checkpoint block + 657750, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 18c70b34bb89ad6cc73eddcc50cb0f4bb79c6613 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 4 Feb 2020 22:50:16 -0500 Subject: [PATCH 0173/1888] [Model][Performance] Unnecessary double cs_wallet and cs_main lock. from https://github.com/PIVX-Project/PIVX/pull/1298 --- src/qt/addresstablemodel.cpp | 2 +- src/qt/transactiontablemodel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index ab46a7ffe1..c0b82da50e 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -302,7 +302,7 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex& par Q_UNUSED(parent); AddressTableEntry* data = priv->index(row); if (data) { - return createIndex(row, column, priv->index(row)); + return createIndex(row, column, data); } else { return QModelIndex(); } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 6a9cb28c03..89f1349628 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -713,7 +713,7 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex& Q_UNUSED(parent); TransactionRecord* data = priv->index(row); if (data) { - return createIndex(row, column, priv->index(row)); + return createIndex(row, column, data); } return QModelIndex(); } From 6aaa247d49311bdb758a1edd3ba7a8a5fde15653 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 5 Feb 2020 21:51:19 -0500 Subject: [PATCH 0174/1888] Bump version to v1.0.6 --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 8de5ccb393..17074e2339 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 8) +define(_CLIENT_VERSION_REVISION, 6) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From 59df74d85eefdd88742d1713a4ecc40089c51936 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 7 Feb 2020 21:29:28 -0500 Subject: [PATCH 0175/1888] Add WITH_LOCK macro: run code while locking a mutex. --- src/sync.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sync.h b/src/sync.h index e018ec4e23..1a71cd6136 100644 --- a/src/sync.h +++ b/src/sync.h @@ -183,6 +183,16 @@ typedef CMutexLock CCriticalBlock; LeaveCritical(); \ } +//! Run code while locking a mutex. +//! +//! Examples: +//! +//! WITH_LOCK(cs, shared_val = shared_val + 1); +//! +//! int val = WITH_LOCK(cs, return shared_val); +//! +#define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }() + class CSemaphore { private: From 77c8c1a059f8fe71015fc1c3d2710203f262d535 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 8 Feb 2020 17:07:04 -0500 Subject: [PATCH 0176/1888] Use NUM_ITEMS variable in Overview --- src/qt/overviewpage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 2ad7b222b0..af58009dd5 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -483,10 +483,10 @@ void OverviewPage::updateRecentTransactions(){ for (int i = 0; i < (int)latestTxes.size(); i++) { txs.push_back(WalletUtil::getTx(pwalletMain, latestTxes[i])); - if (txs.size() >= 5) break; + if (txs.size() >= NUM_ITEMS) break; } - int length = (txs.size()>5)? 5:txs.size(); + int length = (txs.size()>NUM_ITEMS)? NUM_ITEMS:txs.size(); for (int i = 0; i< length; i++){ uint256 txHash; txHash.SetHex(txs[i]["id"].toStdString()); From 041d641e8985348194de44fb547990f07bb7a11a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 8 Feb 2020 22:43:04 -0500 Subject: [PATCH 0177/1888] Switch to signal based showBlockCurrentHeight function vs QTimer This allows for more accurate display of Blocks on Overview screen --- src/qt/overviewpage.cpp | 10 ++++------ src/qt/overviewpage.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index af58009dd5..6c44a9044d 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -131,10 +131,6 @@ OverviewPage::OverviewPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMe initSyncCircle(.8); - QTimer* timerBlockHeightLabel = new QTimer(this); - connect(timerBlockHeightLabel, SIGNAL(timeout()), this, SLOT(showBlockCurrentHeight())); - timerBlockHeightLabel->start(60000); - connect(ui->btnLockUnlock, SIGNAL(clicked()), this, SLOT(on_lockUnlock())); } @@ -221,6 +217,8 @@ void OverviewPage::setClientModel(ClientModel* model) // Show warning if this is a prerelease version connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString))); updateAlerts(model->getStatusBarWarnings()); + connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(showBlockCurrentHeight(int))); + showBlockCurrentHeight(clientModel->getNumBlocks()); } } @@ -339,12 +337,12 @@ void OverviewPage::showBlockSync(bool fShow) } } -void OverviewPage::showBlockCurrentHeight() +void OverviewPage::showBlockCurrentHeight(int count) { TRY_LOCK(cs_main, lockMain); if (!lockMain) return; - ui->labelBlockCurrent->setText(QString::number(chainActive.Height())); + ui->labelBlockCurrent->setText(QString::number(count)); } void OverviewPage::initSyncCircle(float ratioToParent) diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 44a58e597a..e5c8a3651b 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -54,7 +54,7 @@ public slots: void updateRecentTransactions(); void refreshRecentTransactions(); void setSpendableBalance(bool isStaking); - void showBlockCurrentHeight(); + void showBlockCurrentHeight(int count); void updateBalance(); signals: From b8cfaa65460aac7a87ba538bcb5c91f16013ccdf Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 8 Feb 2020 23:28:14 -0500 Subject: [PATCH 0178/1888] Restore tooltip for Block Count --- src/qt/bitcoingui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b17bac5b61..ce03b81720 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1176,6 +1176,7 @@ void BitcoinGUI::setNumBlocks(int count) } else { blockCount->setText(tr("%n Blocks", "", count)); } + blockCount->setToolTip(tooltip); } void BitcoinGUI::message(const QString& title, const QString& message, unsigned int style, bool* ret) From 4c6fb64c68b96713e2e53e8dac8d22729bab7384 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 12:36:16 -0500 Subject: [PATCH 0179/1888] Disconnect from v1.0.3.4 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d2d29f0007..8c1bbb2069 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5735,7 +5735,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); } - if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/") { + if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/") { // disconnect from peers other than these sub versions LogPrintf("partner %s using obsolete version %s; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); pfrom->fDisconnect = true; From cb12ecbe92e6c2ca64be63bb2674aed13e0bd6ab Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 13:08:20 -0500 Subject: [PATCH 0180/1888] Update createMenuBar - add CSS name / cleanup unused code --- src/qt/bitcoingui.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ce03b81720..a9fe5c2bd7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -619,6 +619,7 @@ void BitcoinGUI::createToolBars() if (walletFrame) { QToolBar* toolbar = new QToolBar(this); toolbar->setOrientation(Qt::Vertical); + toolbar->setObjectName("Main-Toolbar"); // Name for CSS addressing toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toolbar->addAction(overviewAction); @@ -674,10 +675,6 @@ void BitcoinGUI::createToolBars() QWidget* containerWidget = new QWidget(); containerWidget->setLayout(layout); setCentralWidget(containerWidget); - - auto toolLayout = toolbar->layout(); - for (int i = 0; i < toolLayout->count(); i++) - toolLayout->itemAt(i)->setAlignment(Qt::AlignLeft); } } From 5094c62584d7d7ba90b37539e857eab82059c5aa Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 13:08:46 -0500 Subject: [PATCH 0181/1888] Cleanup jumbled pingNetworkInterval code --- src/qt/overviewpage.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 6c44a9044d..310bbeb9bb 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -125,9 +125,8 @@ OverviewPage::OverviewPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMe pingNetworkInterval = new QTimer(this); connect(pingNetworkInterval, SIGNAL(timeout()), this, SLOT(tryNetworkBlockCount())); - pingNetworkInterval->setInterval(3000); pingNetworkInterval->start(); - - pingNetworkInterval = new QTimer(); + pingNetworkInterval->setInterval(3000); + pingNetworkInterval->start(); initSyncCircle(.8); From 40cbb51dcf7cdb9094af1d03a4a48777cb0ddd89 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 13:13:40 -0500 Subject: [PATCH 0182/1888] Adjust tooltips, removing unneeded special cursor --- src/qt/forms/overviewpage.ui | 12 ------------ src/qt/overviewpage.cpp | 11 ++++++++++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 72e632d05c..529ad8c053 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -155,12 +155,6 @@
    - - WhatsThisCursor - - - The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet. - (syncing) @@ -421,12 +415,6 @@ true - - WhatsThisCursor - - - The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet. - (syncing) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 310bbeb9bb..956bfc8163 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -316,11 +316,18 @@ void OverviewPage::showBalanceSync(bool fShow){ ui->labelUnconfirmed->setVisible(true); ui->labelBalanceText->setVisible(true); isSyncingBalance = fShow; + if (isSyncingBalance){ + QString tooltip = "The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."; + ui->labelUnconfirmed->setToolTip(tooltip); + ui->labelBalance->setToolTip(tooltip); + } else { + ui->labelUnconfirmed->setToolTip("Your pending balance"); + ui->labelBalance->setToolTip("Your current balance"); + } } void OverviewPage::showBlockSync(bool fShow) { - ui->labelBlockStatus->setVisible(true); ui->labelBlockOf->setVisible(fShow); ui->labelBlocksTotal->setVisible(fShow); @@ -329,9 +336,11 @@ void OverviewPage::showBlockSync(bool fShow) ui->labelBlockCurrent->setText(QString::number(clientModel->getNumBlocks())); if (isSyncingBlocks){ ui->labelBlockStatus->setText("(syncing)"); + ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); } else { ui->labelBlockStatus->setText("(synced)"); + ui->labelBlockStatus->setToolTip("Your wallet is fully synchronized with the DAPS network."); ui->labelBlockCurrent->setAlignment((Qt::AlignHCenter|Qt::AlignVCenter)); } } From 3950920d28780244958899a5cab0f3ec9b11edc7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 25 Jan 2020 12:09:08 -0500 Subject: [PATCH 0183/1888] Add old signals from main and mark unused signals with `XX42` --- src/validationinterface.cpp | 6 +++--- src/validationinterface.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 5897341cd2..676873737f 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -21,13 +21,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); - g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); +// XX42 g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); - g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); +// XX42 g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -40,7 +40,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { void UnregisterAllValidationInterfaces() { g_signals.BlockFound.disconnect_all_slots(); - g_signals.ScriptForMining.disconnect_all_slots(); +// XX42 g_signals.ScriptForMining.disconnect_all_slots(); g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index 0d1bbd48e9..7599165b51 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -40,7 +40,7 @@ class CValidationInterface { // XX42 virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void ResendWalletTransactions() {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} - virtual void GetScriptForMining(boost::shared_ptr&) {}; +// XX42 virtual void GetScriptForMining(boost::shared_ptr&) {}; virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); @@ -61,11 +61,12 @@ struct CMainSignals { /** Notifies listeners about an inventory item being seen on the network. */ boost::signals2::signal Inventory; /** Tells listeners to broadcast their data. */ - boost::signals2::signal Broadcast; +// XX42 oost::signals2::signal Broadcast; + boost::signals2::signal Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; /** Notifies listeners that a key for mining is required (coinbase) */ - boost::signals2::signal&)> ScriptForMining; +// XX42 boost::signals2::signal&)> ScriptForMining; /** Notifies listeners that a block has been successfully mined */ boost::signals2::signal BlockFound; }; From 1f4412ca73bb86bbf6740732bda32e37848b7810 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 25 Jan 2020 12:21:52 -0500 Subject: [PATCH 0184/1888] Remove old `g_signals` code and replace with `GetMainSignals` --- src/main.cpp | 78 ++++++---------------------------------------------- 1 file changed, 9 insertions(+), 69 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d2d29f0007..d8fd8da3cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ #include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" +#include "validationinterface.h" #include @@ -185,69 +186,6 @@ set setDirtyBlockIndex; set setDirtyFileInfo; } // namespace -////////////////////////////////////////////////////////////////////////////// -// -// dispatching functions -// - -// These functions dispatch to one or all registered wallets - -namespace -{ -struct CMainSignals { - /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal SyncTransaction; - /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */ - // XX42 boost::signals2::signal EraseTransaction; - /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ - boost::signals2::signal UpdatedTransaction; - /** Notifies listeners of a new active block chain. */ - boost::signals2::signal SetBestChain; - /** Notifies listeners about an inventory item being seen on the network. */ - boost::signals2::signal Inventory; - /** Tells listeners to broadcast their data. */ - boost::signals2::signal Broadcast; - /** Notifies listeners of a block validation result */ - boost::signals2::signal BlockChecked; -} g_signals; - -} // namespace - -void RegisterValidationInterface(CValidationInterface* pwalletIn) -{ - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); - g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); - g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); - g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); -} - -void UnregisterValidationInterface(CValidationInterface* pwalletIn) -{ - g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); - g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); - g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); - g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); -} - -void UnregisterAllValidationInterfaces() -{ - g_signals.BlockChecked.disconnect_all_slots(); - g_signals.Broadcast.disconnect_all_slots(); - g_signals.Inventory.disconnect_all_slots(); - g_signals.SetBestChain.disconnect_all_slots(); - g_signals.UpdatedTransaction.disconnect_all_slots(); - g_signals.SyncTransaction.disconnect_all_slots(); -} - -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock) -{ - g_signals.SyncTransaction(tx, pblock); -} - CAmount GetValueIn(CCoinsViewCache view, const CTransaction& tx) { if (tx.IsCoinBase()) @@ -3170,7 +3108,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Watch for changes to the previous coinbase transaction. static uint256 hashPrevBestCoinBase; - g_signals.UpdatedTransaction(hashPrevBestCoinBase); + GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.vtx[0].GetHash(); int64_t nTime4 = GetTimeMicros(); @@ -3232,7 +3170,7 @@ bool static FlushStateToDisk(CValidationState& state, FlushStateMode mode) return state.Abort("Failed to write to coin database"); // Update best block in wallet (so we can detect restored wallets). if (mode != FLUSH_STATE_IF_NEEDED) { - g_signals.SetBestChain(chainActive.GetLocator()); + GetMainSignals().SetBestChain(chainActive.GetLocator()); } nLastWrite = GetTimeMicros(); } @@ -3364,7 +3302,7 @@ bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* { CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, fAlreadyChecked); - g_signals.BlockChecked(*pblock, state); + GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); @@ -3744,7 +3682,9 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } // Notify external listeners about the new tip. + // Note: uiInterface, should switch main signals. uiInterface.NotifyBlockTip(hashNewTip); + GetMainSignals().UpdatedBlockTip(pindexNewTip); } } while (pindexMostWork != chainActive.Tip()); CheckBlockIndex(); @@ -5680,7 +5620,7 @@ void static ProcessGetData(CNode* pfrom) } // Track requests for our stuff. - g_signals.Inventory(inv.hash); + GetMainSignals().Inventory(inv.hash); if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) break; @@ -5947,7 +5887,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Track requests for our stuff - g_signals.Inventory(inv.hash); + GetMainSignals().Inventory(inv.hash); if (pfrom->nSendSize > (SendBufferSize() * 2)) { Misbehaving(pfrom->GetId(), 50); return error("send buffer size() = %u", pfrom->nSendSize); @@ -6732,7 +6672,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Except during reindex, importing and IBD, when old wallet // transactions become unconfirmed and spams other nodes. if (!fReindex) { - g_signals.Broadcast(); + GetMainSignals().Broadcast(); } // From bc91167ca65624dc3935339ab59431abaa8f2f19 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 25 Jan 2020 12:27:42 -0500 Subject: [PATCH 0185/1888] Add `GetMainSignals` events to Miner and SwiftX --- src/miner.cpp | 4 ++++ src/swifttx.cpp | 22 ++++++++++++++++++++++ src/swifttx.h | 3 +++ 3 files changed, 29 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index 7709d21a8f..ffde93cd51 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -25,6 +25,7 @@ #include "wallet/wallet.h" extern CWallet *pwalletMain; #endif +#include "validationinterface.h" #include "masternode-payments.h" #include @@ -625,6 +626,9 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) wallet.mapRequestCount[pblock->GetHash()] = 0; } + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); + // Process this block the same as if we had received it from another node CValidationState state; if (!ProcessNewBlock(state, NULL, pblock)) diff --git a/src/swifttx.cpp b/src/swifttx.cpp index 149e98f9e4..ef5fbf1c6e 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "swifttx.h" + #include "activemasternode.h" #include "base58.h" #include "key.h" @@ -14,6 +15,8 @@ #include "protocol.h" #include "sync.h" #include "util.h" +#include "validationinterface.h" + #include using namespace std; @@ -46,6 +49,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v CInv inv(MSG_TXLOCK_REQUEST, tx.GetHash()); pfrom->AddInventoryKnown(inv); + GetMainSignals().Inventory(inv.hash); if (mapTxLockReq.count(tx.GetHash()) || mapTxLockReqRejected.count(tx.GetHash())) { return; @@ -85,6 +89,10 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), tx.GetHash().ToString().c_str()); + if (GetTransactionLockSignatures(tx.GetHash()) == SWIFTTX_SIGNATURES_REQUIRED) { + GetMainSignals().NotifyTransactionLock(tx); + } + return; } else { @@ -157,6 +165,10 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v RelayInv(inv); } + if (mapTxLockReq.count(ctx.txHash) && GetTransactionLockSignatures(ctx.txHash) == SWIFTTX_SIGNATURES_REQUIRED) { + GetMainSignals().NotifyTransactionLock(mapTxLockReq[ctx.txHash]); + } + return; } } @@ -440,6 +452,16 @@ void CleanTransactionLocksList() } } +int GetTransactionLockSignatures(uint256 txHash) +{ + if(fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2; + + std::map::iterator it = mapTxLocks.find(txHash); + if(it != mapTxLocks.end()) return it->second.CountSignatures(); + + return -1; +} + uint256 CConsensusVote::GetHash() const { return vinMasternode.prevout.hash + vinMasternode.prevout.n + txHash; diff --git a/src/swifttx.h b/src/swifttx.h index e9294903d6..f7402e07f2 100644 --- a/src/swifttx.h +++ b/src/swifttx.h @@ -61,6 +61,9 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx); // keep transaction locks in memory for an hour void CleanTransactionLocksList(); +// get the accepted transaction lock signatures +int GetTransactionLockSignatures(uint256 txHash); + int64_t GetAverageVoteTime(); class CConsensusVote From 77a0f65b15e0b6563cc84f890dcaad8ab0d94505 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 5 Feb 2020 20:32:52 -0500 Subject: [PATCH 0186/1888] [Qt] Remove Qt4 build support & code fallbacks There were surprisingly many `#ifdef` fallbacks for Qt 4. Removing them simplifies maintenance, as well as adding new GUI functionality. (cherry picked from commit https://github.com/PIVX-Project/PIVX/commit/907f73bbc5b6c98b01d7c6088a294dea66634a3f) --- src/qt/2faqrdialog.cpp | 3 --- src/qt/addressbookpage.cpp | 7 +---- src/qt/bip38tooldialog.cpp | 2 -- src/qt/bitcoingui.cpp | 16 ------------ src/qt/coincontroldialog.cpp | 18 +++++-------- src/qt/dapscoin.cpp | 33 +---------------------- src/qt/guiutil.cpp | 42 ++++++------------------------ src/qt/guiutil.h | 21 +++++++-------- src/qt/macdockiconhandler.mm | 12 +++------ src/qt/openuridialog.cpp | 2 -- src/qt/optionsdialog.cpp | 19 ++++---------- src/qt/paymentserver.cpp | 15 +++-------- src/qt/peertablemodel.cpp | 3 +-- src/qt/receiverequestdialog.cpp | 3 --- src/qt/rpcconsole.cpp | 4 --- src/qt/signverifymessagedialog.cpp | 2 -- src/qt/test/test_main.cpp | 18 +++++++++---- src/qt/transactionview.cpp | 4 --- src/qt/winshutdownmonitor.cpp | 2 +- src/qt/winshutdownmonitor.h | 2 -- 20 files changed, 52 insertions(+), 176 deletions(-) diff --git a/src/qt/2faqrdialog.cpp b/src/qt/2faqrdialog.cpp index b3a9a364bd..3dfb74f6a3 100644 --- a/src/qt/2faqrdialog.cpp +++ b/src/qt/2faqrdialog.cpp @@ -13,9 +13,6 @@ #include #include #include -#if QT_VERSION < 0x050000 -#include -#endif // #define USE_QRCODE diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 1a45235f31..248084d76d 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -132,14 +132,9 @@ void AddressBookPage::setModel(AddressTableModel* model) } ui->tableView->setModel(proxyModel); -// Set column widths -#if QT_VERSION < 0x050000 - ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch); - ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); -#else + // Set column widths ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); -#endif connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged())); diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index 9b14fdca29..dbc3ecf38f 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -28,9 +28,7 @@ Bip38ToolDialog::Bip38ToolDialog(QWidget* parent) : QDialog(parent, Qt::WindowSy { ui->setupUi(this); -#if QT_VERSION >= 0x040700 ui->decryptedKeyOut_DEC->setPlaceholderText(tr("Click \"Decrypt Key\" to compute key")); -#endif GUIUtil::setupAddressWidget(ui->addressIn_ENC, this); ui->addressIn_ENC->installEventFilter(this); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b17bac5b61..6055503f79 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -61,13 +61,7 @@ #include #include #include - -#if QT_VERSION < 0x050000 -#include -#include -#else #include -#endif #define BASE_WINDOW_WIDTH 1147 #define BASE_WINDOW_HEIGHT 768 @@ -150,12 +144,6 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai #endif setWindowTitle(windowTitle); -#if defined(Q_OS_MAC) && QT_VERSION < 0x050000 - // This property is not implemented in Qt 5. Setting it has no effect. - // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras. - setUnifiedTitleAndToolBarOnMac(true); -#endif - rpcConsole = new RPCConsole(enableWallet ? this : 0); #ifdef ENABLE_WALLET if (enableWallet) { @@ -365,11 +353,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) aboutAction = new QAction(networkStyle->getAppIcon(), tr("&About DAPS"), this); aboutAction->setStatusTip(tr("Show information about DAPS")); aboutAction->setMenuRole(QAction::AboutRole); -#if QT_VERSION < 0x050000 - aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#else aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); -#endif aboutQtAction->setStatusTip(tr("Show information about Qt")); aboutQtAction->setMenuRole(QAction::AboutQtRole); optionsAction = new QAction(QIcon(":/icons/options"), tr("&Settings"), this); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index bd2c3ca783..45229a3f38 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -117,12 +117,8 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q // click on checkbox connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int))); -// click on header -#if QT_VERSION < 0x050000 - ui->treeWidget->header()->setClickable(true); -#else + // click on header ui->treeWidget->header()->setSectionsClickable(true); -#endif connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); // ok button @@ -438,16 +434,14 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) updateDialogLabels(); } } -// todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node -// including all childs are partially selected. But the parent node should be fully selected -// as well as the childs. Childs should never be partially selected in the first place. -// Please remove this ugly fix, once the bug is solved upstream. -#if QT_VERSION >= 0x050000 - else if (column == COLUMN_CHECKBOX && item->childCount() > 0) { + + // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used. + // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473 + else if (column == COLUMN_CHECKBOX && item->childCount() > 0) + { if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked) item->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } -#endif } // return human readable label for priority number diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 7e4dd56eba..851293ed59 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -68,13 +68,6 @@ #if defined(QT_STATICPLUGIN) #include -#if QT_VERSION < 0x050000 -Q_IMPORT_PLUGIN(qcncodecs) -Q_IMPORT_PLUGIN(qjpcodecs) -Q_IMPORT_PLUGIN(qtwcodecs) -Q_IMPORT_PLUGIN(qkrcodecs) -Q_IMPORT_PLUGIN(qtaccessiblewidgets) -#else #if QT_VERSION < 0x050400 Q_IMPORT_PLUGIN(AccessibleFactory) #endif @@ -86,11 +79,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif #endif -#endif - -#if QT_VERSION < 0x050000 -#include -#endif #define DEBUG_BACKTRACE 1 @@ -172,20 +160,12 @@ static void initTranslations(QTranslator& qtTranslatorBase, QTranslator& qtTrans } /* qDebug() message handler --> debug.log */ -#if QT_VERSION < 0x050000 -void DebugMessageHandler(QtMsgType type, const char* msg) -{ - const char* category = (type == QtDebugMsg) ? "qt" : NULL; - LogPrint(category, "GUI: %s\n", msg); -} -#else void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) { Q_UNUSED(context); const char* category = (type == QtDebugMsg) ? "qt" : NULL; LogPrint(category, "GUI: %s\n", msg.toStdString()); } -#endif /** Class encapsulating DAPS startup and shutdown. * Allows running startup and shutdown in a different thread from the UI thread. @@ -603,12 +583,6 @@ int main(int argc, char* argv[]) // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory /// 2. Basic Qt initialization (not dependent on parameters or configuration) -#if QT_VERSION < 0x050000 - // Internal string conversion is all UTF-8 - QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); - QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); -#endif - Q_INIT_RESOURCE(dapscoin_locale); Q_INIT_RESOURCE(dapscoin); @@ -721,17 +695,12 @@ int main(int argc, char* argv[]) /// 9. Main GUI initialization // Install global event filter that makes sure that long tooltips can be word-wrapped app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); -#if QT_VERSION < 0x050000 - // Install qDebug() message handler to route to debug.log - qInstallMsgHandler(DebugMessageHandler); -#else #if defined(Q_OS_WIN) // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION) qApp->installNativeEventFilter(new WinShutdownMonitor()); #endif // Install qDebug() message handler to route to debug.log qInstallMessageHandler(DebugMessageHandler); -#endif // Load GUI settings from QSettings app.createOptionsModel(); @@ -745,7 +714,7 @@ int main(int argc, char* argv[]) try { app.createWindow(networkStyle.data()); app.requestInitialize(); -#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 +#if defined(Q_OS_WIN) WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("DAPS didn't yet exit safely..."), (HWND)app.getMainWinId()); #endif app.exec(); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 2c3cd4a05d..4c74b9747b 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -63,15 +63,11 @@ #include // for Qt::mightBeRichText #include #include +#include +#include void ForceActivation(); -#if QT_VERSION < 0x050000 -#include -#else -#include -#endif - #if BOOST_FILESYSTEM_VERSION >= 3 static boost::filesystem::detail::utf8_codecvt_facet utf8; #endif @@ -104,11 +100,7 @@ QString dateTimeStr(qint64 nTime) QFont bitcoinAddressFont() { QFont font("Monospace"); -#if QT_VERSION >= 0x040800 font.setStyleHint(QFont::Monospace); -#else - font.setStyleHint(QFont::TypeWriter); -#endif return font; } @@ -116,11 +108,9 @@ void setupAddressWidget(QValidatedLineEdit* widget, QWidget* parent) { parent->setFocusProxy(widget); -#if QT_VERSION >= 0x040700 // We don't want translators to use own addresses in translations // and this is the only place, where this address is supplied. -#endif } void setupAmountWidget(QLineEdit* widget, QWidget* parent) @@ -146,13 +136,11 @@ bool parseBitcoinURI(const QUrl& uri, SendCoinsRecipient* out) } rv.amount = 0; -#if QT_VERSION < 0x050000 - QList > items = uri.queryItems(); -#else QUrlQuery uriQuery(uri); QList > items = uriQuery.queryItems(); -#endif - for (QList >::iterator i = items.begin(); i != items.end(); i++) { + + for (QList >::iterator i = items.begin(); i != items.end(); i++) + { bool fShouldReturnFalse = false; if (i->first.startsWith("req-")) { i->first.remove(0, 4); @@ -232,11 +220,7 @@ bool isDust(const QString& address, const CAmount& amount) QString HtmlEscape(const QString& str, bool fMultiLine) { -#if QT_VERSION < 0x050000 - QString escaped = Qt::escape(str); -#else QString escaped = str.toHtmlEscaped(); -#endif escaped = escaped.replace(" ", " "); if (fMultiLine) { escaped = escaped.replace("\n", "
    \n"); @@ -279,11 +263,7 @@ QString getSaveFileName(QWidget* parent, const QString& caption, const QString& QString myDir; if (dir.isEmpty()) // Default to user documents location { -#if QT_VERSION < 0x050000 - myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#else myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif } else { myDir = dir; } @@ -321,12 +301,10 @@ QString getOpenFileName(QWidget* parent, const QString& caption, const QString& QString myDir; if (dir.isEmpty()) // Default to user documents location { -#if QT_VERSION < 0x050000 - myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); -#else myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif - } else { + } + else + { myDir = dir; } /* Directly convert path to native OS path separators */ @@ -485,11 +463,7 @@ void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals() // Refactored here for readability. void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode) { -#if QT_VERSION < 0x050000 - tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode); -#else tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode); -#endif } void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 0fadd11288..c195c06c23 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -260,19 +260,18 @@ QString formatPingTime(double dPingTime); /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); -#if defined(Q_OS_MAC) && QT_VERSION >= 0x050000 -// workaround for Qt OSX Bug: -// https://bugreports.qt-project.org/browse/QTBUG-15631 -// QProgressBar uses around 10% CPU even when app is in background -class ProgressBar : public QProgressBar -{ - bool event(QEvent* e) +#if defined(Q_OS_MAC) + // workaround for Qt OSX Bug: + // https://bugreports.qt-project.org/browse/QTBUG-15631 + // QProgressBar uses around 10% CPU even when app is in background + class ProgressBar : public QProgressBar { - return (e->type() != QEvent::StyleAnimationUpdate) ? QProgressBar::event(e) : false; - } -}; + bool event(QEvent *e) { + return (e->type() != QEvent::StyleAnimationUpdate) ? QProgressBar::event(e) : false; + } + }; #else -typedef QProgressBar ProgressBar; + typedef QProgressBar ProgressBar; #endif } // namespace GUIUtil diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index bb16bdc332..6acde903e4 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -14,11 +14,7 @@ #include #include -#if QT_VERSION < 0x050000 -extern void qt_mac_set_dock_menu(QMenu *); -#endif - -static MacDockIconHandler *s_instance = NULL; +static MacDockIconHandler *s_instance = nullptr; bool dockClickHandler(id self,SEL _cmd,...) { Q_UNUSED(self) @@ -50,10 +46,8 @@ void setupDockClickHandler() { setupDockClickHandler(); this->m_dummyWidget = new QWidget(); this->m_dockMenu = new QMenu(this->m_dummyWidget); - this->setMainWindow(NULL); -#if QT_VERSION < 0x050000 - qt_mac_set_dock_menu(this->m_dockMenu); -#elif QT_VERSION >= 0x050200 + this->setMainWindow(nullptr); +#if QT_VERSION >= 0x050200 this->m_dockMenu->setAsDockMenu(); #endif [pool release]; diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index ff32befc85..d12ae3fbb2 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -17,9 +17,7 @@ OpenURIDialog::OpenURIDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem ui(new Ui::OpenURIDialog) { ui->setupUi(this); -#if QT_VERSION >= 0x040700 ui->uriEdit->setPlaceholderText("dapscoin:"); -#endif } OpenURIDialog::~OpenURIDialog() diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index bd4e8a46b5..8fd5f24e9a 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -88,27 +88,18 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren QLocale locale(langStr); /** check if the locale name consists of 2 parts (language_country) */ - if (langStr.contains("_")) { -#if QT_VERSION >= 0x040800 + if(langStr.contains("_")) + { /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#else - /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */ - ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#endif - } else { -#if QT_VERSION >= 0x040800 + } + else + { /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */ ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#else - /** display language strings as "language (locale name)", e.g. "German (de)" */ - ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); -#endif } } -#if QT_VERSION >= 0x040700 ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s"); -#endif ui->unit->setModel(new BitcoinUnits(this)); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 774134605f..3372c26e3d 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -42,12 +42,7 @@ #include #include #include - -#if QT_VERSION < 0x050000 -#include -#else #include -#endif using namespace boost; using namespace std; @@ -107,7 +102,7 @@ static QList savedPaymentRequests; static void ReportInvalidCertificate(const QSslCertificate& cert) { - qDebug() << "ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); + qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName); } // @@ -147,12 +142,12 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) ReportInvalidCertificate(cert); continue; } -#if QT_VERSION >= 0x050000 + + // Blacklisted certificate if (cert.isBlacklisted()) { ReportInvalidCertificate(cert); continue; } -#endif QByteArray certData = cert.toDer(); const unsigned char* data = (const unsigned char*)certData.data(); @@ -375,11 +370,7 @@ void PaymentServer::handleURIOrFile(const QString& s) if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // dapscoin: URI { -#if QT_VERSION < 0x050000 - QUrl uri(s); -#else QUrlQuery uri((QUrl(s))); -#endif SendCoinsRecipient recipient; if (GUIUtil::parseBitcoinURI(s, &recipient)) { CBitcoinAddress address(recipient.address.toStdString()); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index d8f3928035..2c71796098 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -58,9 +58,8 @@ class PeerTablePriv return; } cachedNodeStats.clear(); -#if QT_VERSION >= 0x040700 + cachedNodeStats.reserve(vNodes.size()); -#endif for (CNode* pnode : vNodes) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index fb906fb836..f71a11ee5a 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -17,9 +17,6 @@ #include #include #include -#if QT_VERSION < 0x050000 -#include -#endif // #define USE_QRCODE diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4c5971b92c..6e9dcf0473 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -36,10 +36,6 @@ #include #include -#if QT_VERSION < 0x050000 -#include -#endif - // TODO: add a scrollback limit, as there is currently none // TODO: make it possible to filter out categories (esp debug messages when implemented) // TODO: receive errors and debug messages through ClientModel diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 311f22f57e..6b74d17649 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -27,9 +27,7 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget* parent) : QDialog(pare { ui->setupUi(this); -#if QT_VERSION >= 0x040700 ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); -#endif GUIUtil::setupAddressWidget(ui->addressIn_SM, this); GUIUtil::setupAddressWidget(ui->addressIn_VM, this); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 2b8fd7267d..6b0444a6b2 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -22,13 +22,21 @@ #include -#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000 +#if defined(QT_STATICPLUGIN) #include -Q_IMPORT_PLUGIN(qcncodecs) -Q_IMPORT_PLUGIN(qjpcodecs) -Q_IMPORT_PLUGIN(qtwcodecs) -Q_IMPORT_PLUGIN(qkrcodecs) +#if defined(QT_QPA_PLATFORM_MINIMAL) +Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin); #endif +#if defined(QT_QPA_PLATFORM_XCB) +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_WINDOWS) +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_COCOA) +Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); +#endif +#endif + +extern void noui_connect(); // This is all you need to run all the tests int main(int argc, char *argv[]) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 8f5ccc9c3d..fa2a97e73f 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -101,15 +101,11 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t hlayout->addWidget(typeWidget); addressWidget = new QLineEdit(this); -#if QT_VERSION >= 0x040700 addressWidget->setPlaceholderText(tr("Enter address or label to search")); -#endif hlayout->addWidget(addressWidget); amountWidget = new QLineEdit(this); -#if QT_VERSION >= 0x040700 amountWidget->setPlaceholderText(tr("Min amount")); -#endif #ifdef Q_OS_MAC amountWidget->setFixedWidth(97); #else diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 3190d92e22..e960037ac0 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -4,7 +4,7 @@ #include "winshutdownmonitor.h" -#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 +#if defined(Q_OS_WIN) #include "init.h" #include "util.h" diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h index f24f47e80c..4d72d0ff78 100644 --- a/src/qt/winshutdownmonitor.h +++ b/src/qt/winshutdownmonitor.h @@ -9,7 +9,6 @@ #include #include -#if QT_VERSION >= 0x050000 #include // for HWND #include @@ -24,6 +23,5 @@ class WinShutdownMonitor : public QAbstractNativeEventFilter static void registerShutdownBlockReason(const QString& strReason, const HWND& mainWinId); }; #endif -#endif #endif // BITCOIN_QT_WINSHUTDOWNMONITOR_H From 062fd471d2485fd6ab3103cbee31a988ed452d36 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 5 Feb 2020 21:46:15 -0500 Subject: [PATCH 0187/1888] Fixed Multisend dialog to show settings properly --- src/qt/multisenddialog.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qt/multisenddialog.cpp b/src/qt/multisenddialog.cpp index 76200d0998..40a4651870 100644 --- a/src/qt/multisenddialog.cpp +++ b/src/qt/multisenddialog.cpp @@ -62,9 +62,11 @@ void MultiSendDialog::on_viewButton_clicked() std::pair pMultiSend; std::string strMultiSendPrint = ""; if (pwalletMain->isMultiSendEnabled()) { - if (pwalletMain->fMultiSendStake) - strMultiSendPrint += "MultiSend Active for Stakes\n"; + if (pwalletMain->fMultiSendStake && pwalletMain->fMultiSendMasternodeReward) + strMultiSendPrint += "MultiSend Active for Stakes and Masternode Rewards\n"; else if (pwalletMain->fMultiSendStake) + strMultiSendPrint += "MultiSend Active for Stakes\n"; + else if (pwalletMain->fMultiSendMasternodeReward) strMultiSendPrint += "MultiSend Active for Masternode Rewards\n"; } else strMultiSendPrint += "MultiSend Not Active\n"; From f41ebb3baf00083e92de48c9fd98f8646af21ad3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 18:33:35 -0500 Subject: [PATCH 0188/1888] Clean up lockorder data of destroyed mutexes --- src/sync.cpp | 100 +++++++++++++++++++++++++++++++++------------------ src/sync.h | 72 ++++++++++++++++++++----------------- 2 files changed, 104 insertions(+), 68 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 79f33f9944..3eac5d831f 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -32,20 +32,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine) // struct CLockLocation { - CLockLocation(const char* pszName, const char* pszFile, int nLine) + CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn) { mutexName = pszName; sourceFile = pszFile; sourceLine = nLine; + fTry = fTryIn; } std::string ToString() const { - return mutexName + " " + sourceFile + ":" + itostr(sourceLine); + return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); } std::string MutexName() const { return mutexName; } + bool fTry; private: std::string mutexName; std::string sourceFile; @@ -53,29 +55,46 @@ struct CLockLocation { }; typedef std::vector > LockStack; +typedef std::map, LockStack> LockOrders; +typedef std::set > InvLockOrders; -static boost::mutex dd_mutex; -static std::map, LockStack> lockorders; -static boost::thread_specific_ptr lockstack; +struct LockData { + // Very ugly hack: as the global constructs and destructors run single + // threaded, we use this boolean to know whether LockData still exists, + // as DeleteLock can get called by global CCriticalSection destructors + // after LockData disappears. + bool available; + LockData() : available(true) {} + ~LockData() { available = false; } + LockOrders lockorders; + InvLockOrders invlockorders; + boost::mutex dd_mutex; +} static lockdata; + +boost::thread_specific_ptr lockstack; static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) { LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("Previous lock order was:\n"); for (const PAIRTYPE(void*, CLockLocation) & i : s2) { - if (i.first == mismatch.first) + if (i.first == mismatch.first) { LogPrintf(" (1)"); - if (i.first == mismatch.second) + } + if (i.first == mismatch.second) { LogPrintf(" (2)"); + } LogPrintf(" %s\n", i.second.ToString()); } LogPrintf("Current lock order is:\n"); for (const PAIRTYPE(void*, CLockLocation) & i : s1) { - if (i.first == mismatch.first) + if (i.first == mismatch.first) { LogPrintf(" (1)"); - if (i.first == mismatch.second) + } + if (i.first == mismatch.second) { LogPrintf(" (2)"); + } LogPrintf(" %s\n", i.second.ToString()); } } @@ -85,45 +104,34 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) if (lockstack.get() == NULL) lockstack.reset(new LockStack); - LogPrint("lock", "Locking: %s\n", locklocation.ToString()); - dd_mutex.lock(); + boost::unique_lock lock(lockdata.dd_mutex); (*lockstack).push_back(std::make_pair(c, locklocation)); - if (!fTry) { - for (const PAIRTYPE(void*, CLockLocation) & i : (*lockstack)) { - if (i.first == c) - break; - - std::pair p1 = std::make_pair(i.first, c); - if (lockorders.count(p1)) - continue; - lockorders[p1] = (*lockstack); - - std::pair p2 = std::make_pair(c, i.first); - if (lockorders.count(p2)) { - potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); - break; - } - } + for (const PAIRTYPE(void*, CLockLocation) & i : (*lockstack)) { + if (i.first == c) + break; + + std::pair p1 = std::make_pair(i.first, c); + if (lockdata.lockorders.count(p1)) + continue; + lockdata.lockorders[p1] = (*lockstack); + + std::pair p2 = std::make_pair(c, i.first); + lockdata.invlockorders.insert(p2); + if (lockdata.lockorders.count(p2)) + potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]); } - dd_mutex.unlock(); } static void pop_lock() { - if (fDebug) { - const CLockLocation& locklocation = (*lockstack).rbegin()->second; - LogPrint("lock", "Unlocked: %s\n", locklocation.ToString()); - } - dd_mutex.lock(); (*lockstack).pop_back(); - dd_mutex.unlock(); } void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); + push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry); } void LeaveCritical() @@ -148,4 +156,26 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, abort(); } +void DeleteLock(void* cs) +{ + if (!lockdata.available) { + // We're already shutting down. + return; + } + boost::unique_lock lock(lockdata.dd_mutex); + std::pair item = std::make_pair(cs, (void*)0); + LockOrders::iterator it = lockdata.lockorders.lower_bound(item); + while (it != lockdata.lockorders.end() && it->first.first == cs) { + std::pair invitem = std::make_pair(it->first.second, it->first.first); + lockdata.invlockorders.erase(invitem); + lockdata.lockorders.erase(it++); + } + InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item); + while (invit != lockdata.invlockorders.end() && invit->first == cs) { + std::pair invinvitem = std::make_pair(invit->second, invit->first); + lockdata.lockorders.erase(invinvitem); + lockdata.invlockorders.erase(invit++); + } +} + #endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h index e018ec4e23..c4b1c4ea00 100644 --- a/src/sync.h +++ b/src/sync.h @@ -14,16 +14,13 @@ #include -//////////////////////////////////////////////// -// // -// THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE // -// // -//////////////////////////////////////////////// +///////////////////////////////////////////////// +// // +// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE // +// // +///////////////////////////////////////////////// /* - - - CCriticalSection mutex; boost::recursive_mutex mutex; @@ -42,20 +39,18 @@ ENTER_CRITICAL_SECTION(mutex); // no RAII LEAVE_CRITICAL_SECTION(mutex); // no RAII mutex.unlock(); - - - */ - /////////////////////////////// // // // THE ACTUAL IMPLEMENTATION // // // /////////////////////////////// -// Template mixin that adds -Wthread-safety locking annotations to a -// subset of the mutex API. +/** + * Template mixin that adds -Wthread-safety locking + * annotations to a subset of the mutex API. + */ template class LOCKABLE AnnotatedMixin : public PARENT { @@ -76,37 +71,45 @@ class LOCKABLE AnnotatedMixin : public PARENT } }; -/** Wrapped boost mutex: supports recursive locking, but no waiting */ -// TODO: We should move away from using the recursive lock by default. -typedef AnnotatedMixin CCriticalSection; - -/** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; - -/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ -typedef boost::condition_variable CConditionVariable; - #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); +void DeleteLock(void* cs); #else -void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) -{ -} +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} +void static inline DeleteLock(void* cs) {} #endif #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +/** + * Wrapped boost mutex: supports recursive locking, but no waiting + * TODO: We should move away from using the recursive lock by default. + */ +class CCriticalSection : public AnnotatedMixin +{ +public: + ~CCriticalSection() { + DeleteLock((void*)this); + } +}; + +/** Wrapped boost mutex: supports waiting but not recursive locking */ +typedef AnnotatedMixin CWaitableCriticalSection; + +/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ +typedef boost::condition_variable CConditionVariable; + #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around boost::unique_lock */ +/** Wrapper around boost::unique_lock */ template -class CMutexLock +class SCOPED_LOCKABLE CMutexLock { private: boost::unique_lock lock; @@ -134,7 +137,7 @@ class CMutexLock } public: - CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) + CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -142,7 +145,7 @@ class CMutexLock Enter(pszName, pszFile, nLine); } - CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) + CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; @@ -153,7 +156,7 @@ class CMutexLock Enter(pszName, pszFile, nLine); } - ~CMutexLock() + ~CMutexLock() UNLOCK_FUNCTION() { if (lock.owns_lock()) LeaveCritical(); @@ -167,7 +170,10 @@ class CMutexLock typedef CMutexLock CCriticalBlock; -#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) +#define PASTE(x, y) x ## y +#define PASTE2(x, y) PASTE(x, y) + +#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__) #define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) From b26e4cfd065bf8b07fb7f1f2ab0cf12209d976d9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 19:09:26 -0500 Subject: [PATCH 0189/1888] [Wallet] use GetTime() for nStartupTime `nStartupTime` is initalized before the P2P network initialization takes place, making the use of `GetAdjustedTime()` cause a lock ordering segfault under certain situations. --- src/wallet/wallet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ab24b074be..df5ff887b5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -51,7 +51,7 @@ bool bSpendZeroConfChange = true; bool bdisableSystemnotifications = false; // Those bubbles can be annoying and slow down the UI when you get lots of trx bool fSendFreeTransactions = false; bool fPayAtLeastCustomFee = true; - +int64_t nStartupTime = GetTime(); //!< Client startup time for use with automint #include "uint256.h" @@ -135,7 +135,6 @@ void ECDHInfo::Decode(unsigned char* encodedMask, unsigned char* encodedAmount, * Override with -mintxfee */ CFeeRate CWallet::minTxFee = CFeeRate(10000); -int64_t nStartupTime = GetAdjustedTime(); /** @defgroup mapWallet * From 3d5c7c5489d4d57b61e12722a0d24a86445b8eaa Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 19:15:53 -0500 Subject: [PATCH 0190/1888] [P2P] Guard CInv::ToString against unknown types --- src/protocol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocol.cpp b/src/protocol.cpp index 323646d41a..8279fd5483 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -140,8 +140,10 @@ bool CInv::IsMasterNodeType() const{ const char* CInv::GetCommand() const { - if (!IsKnownType()) + if (!IsKnownType()) { LogPrint("net", "CInv::GetCommand() : type=%d unknown type", type); + return "UNKNOWN"; + } return ppszTypeName[type]; } From 5964b945bf5ec713e2f16334c7c0ba94b64fd40b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 20:51:57 -0500 Subject: [PATCH 0191/1888] Teach EnsureWalletIsUnlocked() to accept unlock for anon only Add an optional bool paramater to `EnsureWalletIsUnlocked()` that defaults to `false` (current bahavior). If passed `true`, then only require a partial unlock. --- src/rpc/server.h | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rpc/server.h b/src/rpc/server.h index 5ded236275..5ce3be3fad 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -176,7 +176,7 @@ extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); extern std::string HelpExampleRpc(std::string methodname, std::string args); -extern void EnsureWalletIsUnlocked(); +extern void EnsureWalletIsUnlocked(bool fAllowAnonOnly = false); extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp extern UniValue getpeerinfo(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index a78b51c09d..28d6dad80e 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -30,7 +30,7 @@ using namespace std; -void EnsureWalletIsUnlocked(); +void EnsureWalletIsUnlocked(bool fAllowAnonOnly); std::string static EncodeDumpTime(int64_t nTime) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3f3160b3c1..07bae40ead 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -38,9 +38,9 @@ std::string HelpRequiringPassphrase() return pwalletMain && pwalletMain->IsCrypted() ? "\nRequires wallet passphrase to be set with walletpassphrase call." : ""; } -void EnsureWalletIsUnlocked() +void EnsureWalletIsUnlocked(bool fAllowAnonOnly) { - if (pwalletMain->IsLocked() || pwalletMain->fWalletUnlockAnonymizeOnly) + if (pwalletMain->IsLocked() || (!fAllowAnonOnly && pwalletMain->fWalletUnlockAnonymizeOnly)) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with unlockwallet first."); } From beeca1d2a2b30bf844bbafc54d48bb55aec4f580 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 21:46:32 -0500 Subject: [PATCH 0192/1888] Remove TransactionRecord::Obfuscated / related items --- src/qt/transactionrecord.cpp | 18 +----------------- src/qt/transactiontablemodel.cpp | 15 --------------- src/qt/transactionview.cpp | 5 ----- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index ed7709c114..10d274fbc7 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -124,18 +124,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* sub.type = TransactionRecord::SendToSelf; sub.address = ""; - if (mapValue["DS"] == "1") { - sub.type = TransactionRecord::Obfuscated; - CTxDestination address; - if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { - // Sent to DAPS Address - sub.address = CBitcoinAddress(address).ToString(); - } else { - // Sent to IP, or other non-address transaction like OP_EVAL - sub.address = mapValue["to"]; - } - } else { - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { + for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; sub.idx = parts.size(); @@ -146,7 +135,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet* if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { // Sent to DAPS Address sub.address = CBitcoinAddress(address).ToString(); - } } //a sendtoself transaction has second output as change @@ -186,10 +174,6 @@ QList TransactionRecord::decomposeTransaction(const CWallet* sub.address = mapValue["to"]; } - if (mapValue["DS"] == "1") { - sub.type = TransactionRecord::Obfuscated; - } - CAmount nValue = wallet->getCTxOutValue(wtx, txout); /* Add fee to first output */ if (nTxFee > 0) { diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 89f1349628..311505b011 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -410,8 +410,6 @@ QString TransactionTableModel::formatTxType(const TransactionRecord* wtx) const return tr("Masternode Reward"); case TransactionRecord::RecvFromOther: return tr("Received from"); - case TransactionRecord::RecvWithObfuscation: - return tr("Received via Obfuscation"); case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: return tr("Sent to"); @@ -421,16 +419,6 @@ QString TransactionTableModel::formatTxType(const TransactionRecord* wtx) const return tr("Minted"); case TransactionRecord::Generated: return tr("Mined"); - case TransactionRecord::ObfuscationDenominate: - return tr("Obfuscation Denominate"); - case TransactionRecord::ObfuscationCollateralPayment: - return tr("Obfuscation Collateral Payment"); - case TransactionRecord::ObfuscationMakeCollaterals: - return tr("Obfuscation Make Collateral Inputs"); - case TransactionRecord::ObfuscationCreateDenominations: - return tr("Obfuscation Create Denominations"); - case TransactionRecord::Obfuscated: - return tr("Obfuscated"); default: return QString(); } @@ -473,13 +461,10 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord* wtx, b return QString::fromStdString(wtx->address) + watchAddress; case TransactionRecord::RecvWithAddress: case TransactionRecord::MNReward: - case TransactionRecord::RecvWithObfuscation: case TransactionRecord::SendToAddress: case TransactionRecord::Generated: case TransactionRecord::StakeMint: return lookupAddress(wtx->address, tooltip); - case TransactionRecord::Obfuscated: - return lookupAddress(wtx->address, tooltip) + watchAddress; case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address) + watchAddress; case TransactionRecord::SendToSelf: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 8f5ccc9c3d..d8c5ce718f 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -86,11 +86,6 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t typeWidget->addItem(tr("Most Common"), TransactionFilterProxy::COMMON_TYPES); typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther)); typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); - typeWidget->addItem(tr("Obfuscated"), TransactionFilterProxy::TYPE(TransactionRecord::Obfuscated)); - typeWidget->addItem(tr("Obfuscation Make Collateral Inputs"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationMakeCollaterals)); - typeWidget->addItem(tr("Obfuscation Create Denominations"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationCreateDenominations)); - typeWidget->addItem(tr("Obfuscation Denominate"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationDenominate)); - typeWidget->addItem(tr("Obfuscation Collateral Payment"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationCollateralPayment)); typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); typeWidget->addItem(tr("Minted"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint)); From e3c553a0bda9c2757a97d8736e0519f320e9306e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 21:47:31 -0500 Subject: [PATCH 0193/1888] Drop tab spacing to 20px from 25px --- src/qt/bitcoingui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a9fe5c2bd7..e679c1e3fd 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -631,7 +631,7 @@ void BitcoinGUI::createToolBars() } toolbar->setMovable(false); // remove unused icon in upper left corner overviewAction->setChecked(true); - toolbar->setStyleSheet("QToolBar{spacing:25px;}"); + toolbar->setStyleSheet("QToolBar{spacing:20px;}"); // Create NavBar QToolBar* bottomToolbar = new QToolBar(this); From 71c134e1904edd7676d6a78f8a83acb00b361dc7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:03:34 -0500 Subject: [PATCH 0194/1888] Miner: use std methods instead of boost for timing conditions --- src/rpc/mining.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 49a7948a50..6b5438d8af 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -508,7 +508,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; - boost::system_time checktxtime; + std::chrono::steady_clock::time_point checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { @@ -526,15 +526,16 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Release the wallet and main lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { - checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); + checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); boost::unique_lock lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { - if (!cvBlockChange.timed_wait(lock, checktxtime)) { + if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout) + { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; - checktxtime += boost::posix_time::seconds(10); + checktxtime += std::chrono::seconds(10); } } } From 569c361bfa714031265193ee09879cb2d4d8bd7a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:14:38 -0500 Subject: [PATCH 0195/1888] Ust std threading in sync.{h,cpp} Another removal of boost dependency as well as fixing up some `-Wthread-safety-analysis` issues. --- src/rpc/mining.cpp | 2 +- src/sync.cpp | 20 +++++++++------ src/sync.h | 63 ++++++++++++++++++++++------------------------ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 6b5438d8af..bdd95c0a35 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -528,7 +528,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - boost::unique_lock lock(csBestBlock); + WaitableLock lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout) { diff --git a/src/sync.cpp b/src/sync.cpp index 3eac5d831f..1033acaf2a 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -4,14 +4,18 @@ #include "sync.h" +#include + #include "util.h" #include "utilstrencodings.h" #include -#include #ifdef DEBUG_LOCKCONTENTION +#if !defined(HAVE_THREAD_LOCAL) +static_assert(false, "thread_local is not supported"); +#endif void PrintLockContention(const char* pszName, const char* pszFile, int nLine) { LogPrintf("LOCKCONTENTION: %s\n", pszName); @@ -47,8 +51,8 @@ struct CLockLocation { std::string MutexName() const { return mutexName; } - bool fTry; private: + bool fTry; std::string mutexName; std::string sourceFile; int sourceLine; @@ -69,10 +73,10 @@ struct LockData { LockOrders lockorders; InvLockOrders invlockorders; - boost::mutex dd_mutex; + std::mutex dd_mutex; } static lockdata; -boost::thread_specific_ptr lockstack; +static thread_local std::unique_ptr lockstack; static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) { @@ -101,12 +105,12 @@ static void potential_deadlock_detected(const std::pair& mismatch, static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) { - if (lockstack.get() == NULL) + if (!lockstack) lockstack.reset(new LockStack); - boost::unique_lock lock(lockdata.dd_mutex); + std::lock_guard lock(lockdata.dd_mutex); - (*lockstack).push_back(std::make_pair(c, locklocation)); + lockstack->push_back(std::make_pair(c, locklocation)); for (const PAIRTYPE(void*, CLockLocation) & i : (*lockstack)) { if (i.first == c) @@ -162,7 +166,7 @@ void DeleteLock(void* cs) // We're already shutting down. return; } - boost::unique_lock lock(lockdata.dd_mutex); + std::lock_guard lock(lockdata.dd_mutex); std::pair item = std::make_pair(cs, (void*)0); LockOrders::iterator it = lockdata.lockorders.lower_bound(item); while (it != lockdata.lockorders.end() && it->first.first == cs) { diff --git a/src/sync.h b/src/sync.h index c4b1c4ea00..6a52644ca8 100644 --- a/src/sync.h +++ b/src/sync.h @@ -8,10 +8,9 @@ #include "threadsafety.h" -#include -#include -#include -#include +#include +#include +#include ///////////////////////////////////////////////// @@ -22,17 +21,17 @@ /* CCriticalSection mutex; - boost::recursive_mutex mutex; + std::recursive_mutex mutex; LOCK(mutex); - boost::unique_lock criticalblock(mutex); + std::unique_lock criticalblock(mutex); LOCK2(mutex1, mutex2); - boost::unique_lock criticalblock1(mutex1); - boost::unique_lock criticalblock2(mutex2); + std::unique_lock criticalblock1(mutex1); + std::unique_lock criticalblock2(mutex2); TRY_LOCK(mutex, name); - boost::unique_lock name(mutex, boost::try_to_lock_t); + std::unique_lock name(mutex, std::try_to_lock_t); ENTER_CRITICAL_SECTION(mutex); // no RAII mutex.lock(); @@ -86,10 +85,10 @@ void static inline DeleteLock(void* cs) {} #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) /** - * Wrapped boost mutex: supports recursive locking, but no waiting + * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin +class CCriticalSection : public AnnotatedMixin { public: ~CCriticalSection() { @@ -97,22 +96,24 @@ class CCriticalSection : public AnnotatedMixin } }; -/** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; +/** Wrapped mutex: supports waiting but not recursive locking */ +typedef AnnotatedMixin CWaitableCriticalSection; -/** Just a typedef for boost::condition_variable, can be wrapped later if desired */ -typedef boost::condition_variable CConditionVariable; +/** Just a typedef for std::condition_variable, can be wrapped later if desired */ +typedef std::condition_variable CConditionVariable; + +/** Just a typedef for std::unique_lock, can be wrapped later if desired */ +typedef std::unique_lock WaitableLock; #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around boost::unique_lock */ -template -class SCOPED_LOCKABLE CMutexLock +/** Wrapper around std::unique_lock */ +class SCOPED_LOCKABLE CCriticalBlock { private: - boost::unique_lock lock; + std::unique_lock lock; void Enter(const char* pszName, const char* pszFile, int nLine) { @@ -137,7 +138,7 @@ class SCOPED_LOCKABLE CMutexLock } public: - CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock) + CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -145,18 +146,18 @@ class SCOPED_LOCKABLE CMutexLock Enter(pszName, pszFile, nLine); } - CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) + CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = boost::unique_lock(*pmutexIn, boost::defer_lock); + lock = std::unique_lock(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - ~CMutexLock() UNLOCK_FUNCTION() + ~CCriticalBlock() UNLOCK_FUNCTION() { if (lock.owns_lock()) LeaveCritical(); @@ -168,8 +169,6 @@ class SCOPED_LOCKABLE CMutexLock } }; -typedef CMutexLock CCriticalBlock; - #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) @@ -192,8 +191,8 @@ typedef CMutexLock CCriticalBlock; class CSemaphore { private: - boost::condition_variable condition; - boost::mutex mutex; + std::condition_variable condition; + std::mutex mutex; int value; public: @@ -201,16 +200,14 @@ class CSemaphore void wait() { - boost::unique_lock lock(mutex); - while (value < 1) { - condition.wait(lock); - } + std::unique_lock lock(mutex); + condition.wait(lock, [&]() { return value >= 1; }); value--; } bool try_wait() { - boost::unique_lock lock(mutex); + std::lock_guard lock(mutex); if (value < 1) return false; value--; @@ -220,7 +217,7 @@ class CSemaphore void post() { { - boost::unique_lock lock(mutex); + std::lock_guard lock(mutex); value++; } condition.notify_one(); From 758f9be40e00c4dd5b222f6b895a2110f0bc1368 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:22:18 -0500 Subject: [PATCH 0196/1888] Remove Boost dependency from sync.cpp use c++11 for loops instead of BOOST_FOREACH --- src/sync.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 1033acaf2a..32bf0363bf 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -11,7 +11,6 @@ #include - #ifdef DEBUG_LOCKCONTENTION #if !defined(HAVE_THREAD_LOCAL) static_assert(false, "thread_local is not supported"); @@ -82,7 +81,7 @@ static void potential_deadlock_detected(const std::pair& mismatch, { LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("Previous lock order was:\n"); - for (const PAIRTYPE(void*, CLockLocation) & i : s2) { + for (const std::pair& i : s2) { if (i.first == mismatch.first) { LogPrintf(" (1)"); } @@ -92,7 +91,7 @@ static void potential_deadlock_detected(const std::pair& mismatch, LogPrintf(" %s\n", i.second.ToString()); } LogPrintf("Current lock order is:\n"); - for (const PAIRTYPE(void*, CLockLocation) & i : s1) { + for (const std::pair& i : s1) { if (i.first == mismatch.first) { LogPrintf(" (1)"); } @@ -112,7 +111,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) lockstack->push_back(std::make_pair(c, locklocation)); - for (const PAIRTYPE(void*, CLockLocation) & i : (*lockstack)) { + for (const std::pair& i : (*lockstack)) { if (i.first == c) break; @@ -146,14 +145,14 @@ void LeaveCritical() std::string LocksHeld() { std::string result; - for (const PAIRTYPE(void*, CLockLocation) & i : *lockstack) + for (const std::pair& i : *lockstack) result += i.second.ToString() + std::string("\n"); return result; } void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) { - for (const PAIRTYPE(void*, CLockLocation) & i : *lockstack) + for (const std::pair& i : *lockstack) if (i.first == cs) return; fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str()); From 1bb23303481b55b233be12e9e91aa82c31b5b73f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:24:37 -0500 Subject: [PATCH 0197/1888] Initialize lockstack to prevent null pointer deref --- src/sync.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 32bf0363bf..4dd5a93226 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -75,7 +75,7 @@ struct LockData { std::mutex dd_mutex; } static lockdata; -static thread_local std::unique_ptr lockstack; +static thread_local LockStack g_lockstack; static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) { @@ -104,21 +104,18 @@ static void potential_deadlock_detected(const std::pair& mismatch, static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) { - if (!lockstack) - lockstack.reset(new LockStack); - std::lock_guard lock(lockdata.dd_mutex); - lockstack->push_back(std::make_pair(c, locklocation)); + g_lockstack.push_back(std::make_pair(c, locklocation)); - for (const std::pair& i : (*lockstack)) { + for (const std::pair& i : g_lockstack) { if (i.first == c) break; std::pair p1 = std::make_pair(i.first, c); if (lockdata.lockorders.count(p1)) continue; - lockdata.lockorders[p1] = (*lockstack); + lockdata.lockorders[p1] = g_lockstack; std::pair p2 = std::make_pair(c, i.first); lockdata.invlockorders.insert(p2); @@ -129,7 +126,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) static void pop_lock() { - (*lockstack).pop_back(); + g_lockstack.pop_back(); } void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) @@ -145,14 +142,14 @@ void LeaveCritical() std::string LocksHeld() { std::string result; - for (const std::pair& i : *lockstack) + for (const std::pair& i : g_lockstack) result += i.second.ToString() + std::string("\n"); return result; } void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) { - for (const std::pair& i : *lockstack) + for (const std::pair& i : g_lockstack) if (i.first == cs) return; fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str()); From 92739d4e1c6445354a9041325929959490c83427 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:26:20 -0500 Subject: [PATCH 0198/1888] Remove unused fTry from push_lock --- src/sync.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 4dd5a93226..d48150cc5c 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -102,7 +102,7 @@ static void potential_deadlock_detected(const std::pair& mismatch, } } -static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) +static void push_lock(void* c, const CLockLocation& locklocation) { std::lock_guard lock(lockdata.dd_mutex); @@ -131,7 +131,7 @@ static void pop_lock() void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry); + push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry)); } void LeaveCritical() From 5c8bffed1200a24f683276c34d06c6ca98f485c5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:28:17 -0500 Subject: [PATCH 0199/1888] Use c++11 nullptr instead of macros or void(0) in sync.cpp/h --- src/sync.cpp | 2 +- src/sync.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index d48150cc5c..596dc636b0 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -163,7 +163,7 @@ void DeleteLock(void* cs) return; } std::lock_guard lock(lockdata.dd_mutex); - std::pair item = std::make_pair(cs, (void*)0); + std::pair item = std::make_pair(cs, nullptr); LockOrders::iterator it = lockdata.lockorders.lower_bound(item); while (it != lockdata.lockorders.end() && it->first.first == cs) { std::pair invitem = std::make_pair(it->first.second, it->first.first); diff --git a/src/sync.h b/src/sync.h index 6a52644ca8..378a7f199f 100644 --- a/src/sync.h +++ b/src/sync.h @@ -264,7 +264,7 @@ class CSemaphoreGrant fHaveGrant = false; } - CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {} + CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {} CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { From af64309e3d2df221e754560d24188c41f94417c0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 9 Feb 2020 23:31:11 -0500 Subject: [PATCH 0200/1888] Finalize cleanup of sync.cpp/h - include memory system header for std pointers - remove unused MutexName - declare single-argument constructors as explicit --- src/sync.cpp | 3 +-- src/sync.h | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 596dc636b0..d088d51474 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -4,6 +4,7 @@ #include "sync.h" +#include #include #include "util.h" @@ -48,8 +49,6 @@ struct CLockLocation { return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); } - std::string MutexName() const { return mutexName; } - private: bool fTry; std::string mutexName; diff --git a/src/sync.h b/src/sync.h index 378a7f199f..ef003a8455 100644 --- a/src/sync.h +++ b/src/sync.h @@ -196,7 +196,7 @@ class CSemaphore int value; public: - CSemaphore(int init) : value(init) {} + explicit CSemaphore(int init) : value(init) {} void wait() { @@ -260,13 +260,12 @@ class CSemaphoreGrant grant.Release(); grant.sem = sem; grant.fHaveGrant = fHaveGrant; - sem = NULL; fHaveGrant = false; } CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {} - CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false) + explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { if (fTry) TryAcquire(); @@ -279,7 +278,7 @@ class CSemaphoreGrant Release(); } - operator bool() + operator bool() const { return fHaveGrant; } From 0e9c9bde9049421e0f35f81d1dc7f145654d1eba Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 10 Feb 2020 07:50:15 -0500 Subject: [PATCH 0201/1888] Add checkpoints for 270k/275k --- src/chainparams.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 75b24fb721..0fb5e70d5f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -119,11 +119,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (255000, uint256("a7e29e83aee66c7e2eb097ef8f729dcc44d5235a5533fb357e70fa14cf345bd6")) (260000, uint256("556f5deedff1c551551b6fda517fe939e0fb6810d35664fd55b5c5c2b6ec33c7")) (265000, uint256("84598b4790a1df395e5ef724c4a2784b27679ef07d9e864ff2fa1b91fcca0751")) + (270000, uint256("533f7d0f72700d23c3086fbf7f7f01e1b5e0b3c3d24a5f854187eb333610d266")) + (275000, uint256("7b1d412bc6bf0c994d46c830e6a52fd36e7dbfbde057f44d6c9e8655f50f8720")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1580714982, // * UNIX timestamp of last checkpoint block - 657750, // * total number of transactions between genesis and last checkpoint + 1581315652, // * UNIX timestamp of last checkpoint block + 681361, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From 5f9517816d2c4deff5b2d053c33ec311a547e52f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 10 Feb 2020 12:39:43 -0500 Subject: [PATCH 0202/1888] Ban older versions as well as Disconnect --- src/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 8c1bbb2069..da146b90b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5703,6 +5703,9 @@ void static ProcessGetData(CNode* pfrom) bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { + CNodeState* state = State(pfrom->GetId()); + if (state == NULL) + return false; RandAddSeedPerfmon(); if (fDebug) LogPrintf("received: %s (%u bytes) peer=%d, chainheight=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id, chainActive.Height()); @@ -5737,7 +5740,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (pfrom->strSubVer == "/DAPScoin:0.27.5.1/" || pfrom->strSubVer == "/DAPScoin:1.0.0/" || pfrom->strSubVer == "/DAPScoin:1.0.1/" || pfrom->strSubVer == "/DAPS:1.0.1.3/" || pfrom->strSubVer == "/DAPS:1.0.2/" || pfrom->strSubVer == "/DAPS:1.0.3.4/") { // disconnect from peers other than these sub versions - LogPrintf("partner %s using obsolete version %s; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); + LogPrintf("partner %s using obsolete version %s; banning and disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->strSubVer.c_str()); + state->fShouldBan = true; pfrom->fDisconnect = true; return false; } From 7b882270e3833fa212a1640c186dbc3e0ba74638 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 11 Feb 2020 19:04:26 -0500 Subject: [PATCH 0203/1888] [RPC] Add blocksizenotify command --- src/guiinterface.h | 3 +++ src/init.cpp | 13 +++++++++++++ src/main.cpp | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/src/guiinterface.h b/src/guiinterface.h index e538e61ed8..56f786c7b5 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -105,6 +105,9 @@ class CClientUIInterface /** New block has been accepted */ boost::signals2::signal NotifyBlockTip; + /** New block has been accepted and is over a certain size */ + boost::signals2::signal NotifyBlockSize; + /** Banlist did change. */ boost::signals2::signal BannedListChanged; }; diff --git a/src/init.cpp b/src/init.cpp index a40ba91db2..9fb93d6fd5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -364,6 +364,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); + strUsage += HelpMessageOpt("-blocksizenotify=", _("Execute command when the best block changes and its size is over (%s in cmd is replaced by block hash, %d with the block size)")); strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 500)); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "dapscoin.conf")); if (mode == HMM_BITCOIND) { @@ -590,6 +591,15 @@ static void BlockNotifyCallback(const uint256& hashNewTip) boost::thread t(runCommand, strCmd); // thread runs free } +static void BlockSizeNotifyCallback(int size, const uint256& hashNewTip) +{ + std::string strCmd = GetArg("-blocksizenotify", ""); + + boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); + boost::replace_all(strCmd, "%d", std::to_string(size)); + boost::thread t(runCommand, strCmd); // thread runs free +} + struct CImportingNow { CImportingNow() { @@ -1630,6 +1640,9 @@ bool AppInit2(bool isDaemon) if (mapArgs.count("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); + if (mapArgs.count("-blocksizenotify")) + uiInterface.NotifyBlockSize.connect(BlockSizeNotifyCallback); + // scan for better chains in the block chain database, that are not yet connected in the active best chain CValidationState state; if (!ActivateBestChain(state)) diff --git a/src/main.cpp b/src/main.cpp index d8fd8da3cf..dda7ed75e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3685,6 +3685,12 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe // Note: uiInterface, should switch main signals. uiInterface.NotifyBlockTip(hashNewTip); GetMainSignals().UpdatedBlockTip(pindexNewTip); + + unsigned size = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); + // If the size is over 1 MB notify external listeners, and it is within the last 5 minutes + if (size > MAX_BLOCK_SIZE_LEGACY && pblock->GetBlockTime() > GetAdjustedTime() - 300) { + uiInterface.NotifyBlockSize(static_cast(size), hashNewTip); + } } } while (pindexMostWork != chainActive.Tip()); CheckBlockIndex(); From 60f349ccf978b00b671ce0efbc53713a0c351f18 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 11 Feb 2020 19:37:24 -0500 Subject: [PATCH 0204/1888] [GUI] Open the app's window in the smallest, currently available, size. --- src/qt/bitcoingui.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b17bac5b61..ce49c807e9 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -121,7 +121,15 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai this->setStyleSheet(GUIUtil::loadStyleSheet()); this->setMinimumSize(BASE_WINDOW_WIDTH, BASE_WINDOW_MIN_HEIGHT); - GUIUtil::restoreWindowGeometry("nWindow", QSize(BASE_WINDOW_WIDTH, BASE_WINDOW_HEIGHT), this); + + // Adapt screen size + QRect rec = QApplication::desktop()->screenGeometry(); + int adaptedHeight = (rec.height() < BASE_WINDOW_HEIGHT) ? BASE_WINDOW_MIN_HEIGHT : BASE_WINDOW_HEIGHT; + GUIUtil::restoreWindowGeometry( + "nWindow", + QSize(BASE_WINDOW_WIDTH, adaptedHeight), + this + ); QString windowTitle = tr("DAPS Coin") + " "; fLiteMode = GetBoolArg("-litemode", false); From d36140fa0c16d7809cd5aa7dd308bee5d1e45ee8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 11 Feb 2020 20:42:09 -0500 Subject: [PATCH 0205/1888] [Refactor] Moved wallet balance computation from header to source file --- src/wallet/wallet.cpp | 295 ++++++++++++++++++++++++++++++++++++++++ src/wallet/wallet.h | 304 ++---------------------------------------- 2 files changed, 306 insertions(+), 293 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index df5ff887b5..4c277317c5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1453,6 +1453,301 @@ int CWalletTx::GetRequestCount() const return nRequests; } +CAmount CWalletTx::GetDebit(const isminefilter& filter) const +{ + if (vin.empty()) + return 0; + + CAmount debit = 0; + if (filter & ISMINE_SPENDABLE) { + if (fDebitCached) + debit += nDebitCached; + else { + nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); + fDebitCached = true; + debit += nDebitCached; + } + } + if (filter & ISMINE_WATCH_ONLY) { + if (fWatchDebitCached) + debit += nWatchDebitCached; + else { + nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY); + fWatchDebitCached = true; + debit += nWatchDebitCached; + } + } + return debit; +} + +CAmount CWalletTx::GetCredit(const isminefilter& filter) const +{ + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + CAmount credit = 0; + if (filter & ISMINE_SPENDABLE) { + // GetBalance can assume transactions in mapWallet won't change + if (fCreditCached) + credit += nCreditCached; + else { + nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); + fCreditCached = true; + credit += nCreditCached; + } + } + if (filter & ISMINE_WATCH_ONLY) { + if (fWatchCreditCached) + credit += nWatchCreditCached; + else { + nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); + fWatchCreditCached = true; + credit += nWatchCreditCached; + } + } + return credit; +} + +CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const +{ + LOCK(cs_main); + if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain()) { + if (fUseCache && fImmatureCreditCached) + return nImmatureCreditCached; + nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); + fImmatureCreditCached = true; + return nImmatureCreditCached; + } + return 0; +} + +CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + if (fUseCache && fAvailableCreditCached) { + if (nAvailableCreditCached) { + return nAvailableCreditCached; + } + } + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + //dont count if output is in mempool + COutPoint outpoint(hashTx, i); + if (pwallet->inSpendQueueOutpoints.count(outpoint) == 1) continue; + + if (!pwallet->IsSpent(hashTx, i)) { + const CTxOut& txout = vout[i]; + CAmount cre = pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + if (cre == 0 && fCreditCached) { + fCreditCached = false; + cre = pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + } + nCredit += cre; + } + } + + nAvailableCreditCached = nCredit; + fAvailableCreditCached = true; + return nCredit; +} + +CAmount CWalletTx::GetAnonymizableCredit(bool fUseCache) const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + if (fUseCache && fAnonymizableCreditCached) + return nAnonymizableCreditCached; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxIn vin = CTxIn(hashTx, i); + + if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; + if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) continue; // do not count MN-like outputs + } + + nAnonymizableCreditCached = nCredit; + fAnonymizableCreditCached = true; + return nCredit; +} + +CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + if (fUseCache && fAnonymizedCreditCached) + return nAnonymizedCreditCached; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxIn vin = CTxIn(hashTx, i); + if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; + } + + nAnonymizedCreditCached = nCredit; + fAnonymizedCreditCached = true; + return nCredit; +} + +// Return sum of unlocked coins +CAmount CWalletTx::GetUnlockedCredit() const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxOut& txout = vout[i]; + + if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; + if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) continue; // do not count MN-like outputs + + nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + } + + return nCredit; +} + +// Return sum of unlocked coins +CAmount CWalletTx::GetLockedCredit() const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxOut& txout = vout[i]; + + // Skip spent coins + if (pwallet->IsSpent(hashTx, i)) continue; + + // Add locked coins + if (pwallet->IsLockedCoin(hashTx, i)) { + nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + } + + // Add masternode collaterals which are handled likc locked coins + else if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) { + nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + } + + } + + return nCredit; +} + +CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + int nDepth = GetDepthInMainChain(false); + if (nDepth < 0) return 0; + + bool isUnconfirmed = !IsFinalTx(*this) || (!IsTrusted() && nDepth == 0); + if (unconfirmed != isUnconfirmed) return 0; + + if (fUseCache) { + if (unconfirmed && fDenomUnconfCreditCached) + return nDenomUnconfCreditCached; + else if (!unconfirmed && fDenomConfCreditCached) + return nDenomConfCreditCached; + } + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxOut& txout = vout[i]; + + if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(pwallet->getCTxOutValue(*this, txout))) continue; + + nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); + } + + if (unconfirmed) { + nDenomUnconfCreditCached = nCredit; + fDenomUnconfCreditCached = true; + } else { + nDenomConfCreditCached = nCredit; + fDenomConfCreditCached = true; + } + return nCredit; +} + +CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const +{ + LOCK(cs_main); + if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { + if (fUseCache && fImmatureWatchCreditCached) + return nImmatureWatchCreditCached; + nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); + fImmatureWatchCreditCached = true; + return nImmatureWatchCreditCached; + } + + return 0; +} + +CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const +{ + if (pwallet == 0) + return 0; + + // Must wait until coinbase is safely deep enough in the chain before valuing it + if (IsCoinBase() && GetBlocksToMaturity() > 0) + return 0; + + if (fUseCache && fAvailableWatchCreditCached) + return nAvailableWatchCreditCached; + + CAmount nCredit = 0; + for (unsigned int i = 0; i < vout.size(); i++) { + if (!pwallet->IsSpent(GetHash(), i)) { + const CTxOut& txout = vout[i]; + nCredit += pwallet->GetCredit(*this, txout, ISMINE_WATCH_ONLY); + } + } + + nAvailableWatchCreditCached = nCredit; + fAvailableWatchCreditCached = true; + return nCredit; +} + void CWalletTx::GetAmounts(list& listReceived, list& listSent, CAmount& nFee, diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5129333794..4262e95ada 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1095,300 +1095,18 @@ class CWalletTx : public CMerkleTx } //! filter decides which addresses will count towards the debit - CAmount GetDebit(const isminefilter& filter) const - { - if (vin.empty()) - return 0; - - CAmount debit = 0; - if (filter & ISMINE_SPENDABLE) { - if (fDebitCached) - debit += nDebitCached; - else { - nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); - fDebitCached = true; - debit += nDebitCached; - } - } - if (filter & ISMINE_WATCH_ONLY) { - if (fWatchDebitCached) - debit += nWatchDebitCached; - else { - nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY); - fWatchDebitCached = true; - debit += nWatchDebitCached; - } - } - return debit; - } - - CAmount GetCredit(const isminefilter& filter) const - { - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - CAmount credit = 0; - if (filter & ISMINE_SPENDABLE) { - // GetBalance can assume transactions in mapWallet won't change - if (fCreditCached) - credit += nCreditCached; - else { - nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); - fCreditCached = true; - credit += nCreditCached; - } - } - if (filter & ISMINE_WATCH_ONLY) { - if (fWatchCreditCached) - credit += nWatchCreditCached; - else { - nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); - fWatchCreditCached = true; - credit += nWatchCreditCached; - } - } - return credit; - } - - CAmount GetImmatureCredit(bool fUseCache = true) const - { - LOCK(cs_main); - if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain()) { - if (fUseCache && fImmatureCreditCached) - return nImmatureCreditCached; - nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); - fImmatureCreditCached = true; - return nImmatureCreditCached; - } - return 0; - } - - CAmount GetAvailableCredit(bool fUseCache = true) const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAvailableCreditCached) { - if (nAvailableCreditCached) { - return nAvailableCreditCached; - } - } - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - //dont count if output is in mempool - COutPoint outpoint(hashTx, i); - if (pwallet->inSpendQueueOutpoints.count(outpoint) == 1) continue; - - if (!pwallet->IsSpent(hashTx, i)) { - const CTxOut& txout = vout[i]; - CAmount cre = pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - if (cre == 0 && fCreditCached) { - fCreditCached = false; - cre = pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - nCredit += cre; - } - } - - nAvailableCreditCached = nCredit; - fAvailableCreditCached = true; - return nCredit; - } - - CAmount GetAnonymizableCredit(bool fUseCache = true) const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizableCreditCached) - return nAnonymizableCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; - if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) continue; // do not count MN-like outputs - } - - nAnonymizableCreditCached = nCredit; - fAnonymizableCreditCached = true; - return nCredit; - } - - CAmount GetAnonymizedCredit(bool fUseCache = true) const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizedCreditCached) - return nAnonymizedCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxIn vin = CTxIn(hashTx, i); - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; - } - - nAnonymizedCreditCached = nCredit; - fAnonymizedCreditCached = true; - return nCredit; - } - + CAmount GetUnlockedCredit() const; + CAmount GetDebit(const isminefilter& filter) const; + CAmount GetCredit(const isminefilter& filter) const; + CAmount GetImmatureCredit(bool fUseCache = true) const; + CAmount GetAvailableCredit(bool fUseCache = true) const; + CAmount GetAnonymizableCredit(bool fUseCache = true) const; + CAmount GetAnonymizedCredit(bool fUseCache = true) const; // Return sum of unlocked coins - CAmount GetUnlockedCredit() const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; - if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) continue; // do not count MN-like outputs - - nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - - return nCredit; - } - - // Return sum of unlocked coins - CAmount GetLockedCredit() const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - // Skip spent coins - if (pwallet->IsSpent(hashTx, i)) continue; - - // Add locked coins - if (pwallet->IsLockedCoin(hashTx, i)) { - nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - - // Add masternode collaterals which are handled likc locked coins - else if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) { - nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - - } - - return nCredit; - } - - CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - int nDepth = GetDepthInMainChain(false); - if (nDepth < 0) return 0; - - bool isUnconfirmed = !IsFinalTx(*this) || (!IsTrusted() && nDepth == 0); - if (unconfirmed != isUnconfirmed) return 0; - - if (fUseCache) { - if (unconfirmed && fDenomUnconfCreditCached) - return nDenomUnconfCreditCached; - else if (!unconfirmed && fDenomConfCreditCached) - return nDenomConfCreditCached; - } - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(pwallet->getCTxOutValue(*this, txout))) continue; - - nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - - if (unconfirmed) { - nDenomUnconfCreditCached = nCredit; - fDenomUnconfCreditCached = true; - } else { - nDenomConfCreditCached = nCredit; - fDenomConfCreditCached = true; - } - return nCredit; - } - - CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const - { - LOCK(cs_main); - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { - if (fUseCache && fImmatureWatchCreditCached) - return nImmatureWatchCreditCached; - nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); - fImmatureWatchCreditCached = true; - return nImmatureWatchCreditCached; - } - - return 0; - } - - CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const - { - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAvailableWatchCreditCached) - return nAvailableWatchCreditCached; - - CAmount nCredit = 0; - for (unsigned int i = 0; i < vout.size(); i++) { - if (!pwallet->IsSpent(GetHash(), i)) { - const CTxOut& txout = vout[i]; - nCredit += pwallet->GetCredit(*this, txout, ISMINE_WATCH_ONLY); - } - } - - nAvailableWatchCreditCached = nCredit; - fAvailableWatchCreditCached = true; - return nCredit; - } + CAmount GetLockedCredit() const; + CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const; + CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const; + CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetChange() const { From 8e47c14e3bb4db030cee5a9ed080491d4fdd993b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 11 Feb 2020 21:25:24 -0500 Subject: [PATCH 0206/1888] [Wallet] Add some LOCK to avoid crash We already have most of these, just a few that were missed --- src/wallet/wallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4c277317c5..8461567253 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2432,6 +2432,7 @@ bool less_then_denom(const COutput& out1, const COutput& out2) bool CWallet::SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) { + LOCK(cs_main); std::vector vCoins; AvailableCoins(vCoins, true, NULL, false, STAKABLE_COINS); CAmount nAmountSelected = 0; @@ -6221,6 +6222,7 @@ int CWallet::MaxTxSizePerTx() { bool CWallet::MultiSend() { + LOCK2(cs_main, cs_wallet); // Stop the old blocks from sending multisends if (chainActive.Tip()->nTime < (GetAdjustedTime() - 300) || IsLocked()) { return false; From c473a72a21237cac535035eb5af1aeb76e9ae294 Mon Sep 17 00:00:00 2001 From: JD Date: Wed, 12 Feb 2020 21:02:38 -0500 Subject: [PATCH 0207/1888] Bump version to v1.0.6.1 (#89) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 17074e2339..1a38355fd0 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 0) +define(_CLIENT_VERSION_BUILD, 1) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From 77b427fc990e3ee90bf2c350f1bb77352d236202 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 21:26:25 -0500 Subject: [PATCH 0208/1888] [Wallet] Add function CMerkleTx::IsInMainChainImmature --- src/wallet/wallet.cpp | 21 +++++++++++++++++++-- src/wallet/wallet.h | 13 +++---------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8461567253..2f942d23bb 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1512,7 +1512,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const { LOCK(cs_main); - if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain()) { + if (IsInMainChainImmature()) { if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); @@ -1712,7 +1712,7 @@ CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const { LOCK(cs_main); - if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { + if (IsInMainChainImmature()) { if (fUseCache && fImmatureWatchCreditCached) return nImmatureWatchCreditCached; nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); @@ -6409,6 +6409,12 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex*& pindexRet) const return chainActive.Height() - pindex->nHeight + 1; } +int CMerkleTx::GetDepthInMainChain(bool enableIX) const +{ + const CBlockIndex* pindexRet; + return GetDepthInMainChain(pindexRet, enableIX); +} + int CMerkleTx::GetDepthInMainChain(const CBlockIndex*& pindexRet, bool enableIX) const { AssertLockHeld(cs_main); @@ -6436,6 +6442,17 @@ int CMerkleTx::GetBlocksToMaturity() const return max(0, (Params().COINBASE_MATURITY() + 1) - GetDepthInMainChain()); } +bool CMerkleTx::IsInMainChain() const +{ + return GetDepthInMainChain(false) > 0; +} + +bool CMerkleTx::IsInMainChainImmature() const +{ + if (!IsCoinBase() && !IsCoinStake()) return false; + const int depth = GetDepthInMainChain(false); + return (depth > 0 && depth <= Params().COINBASE_MATURITY()); +} bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee, bool ignoreFees) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4262e95ada..29ee0687d3 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -905,16 +905,9 @@ class CMerkleTx : public CTransaction * >=1 : this many blocks deep in the main chain */ int GetDepthInMainChain(const CBlockIndex*& pindexRet, bool enableIX = true) const; - int GetDepthInMainChain(bool enableIX = true) const - { - const CBlockIndex* pindexRet; - return GetDepthInMainChain(pindexRet, enableIX); - } - bool IsInMainChain() const - { - const CBlockIndex* pindexRet; - return GetDepthInMainChainINTERNAL(pindexRet) > 0; - } + int GetDepthInMainChain(bool enableIX = true) const; + bool IsInMainChain() const; + bool IsInMainChainImmature() const; int GetBlocksToMaturity() const; bool AcceptToMemoryPool(bool fLimitFree = true, bool fRejectInsaneFee = true, bool ignoreFees = false); int GetTransactionLockSignatures() const; From 81b17df0cd23e80117156e23cd62bc5c1b63be04 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 22:30:12 -0500 Subject: [PATCH 0209/1888] RPC: Add waitforblock/waitfornewblock/waitforblockheight --- src/init.cpp | 40 ++++++++--- src/rpc/blockchain.cpp | 153 +++++++++++++++++++++++++++++++++++++++++ src/rpc/client.cpp | 6 ++ src/rpc/server.cpp | 3 + src/rpc/server.h | 4 ++ 5 files changed, 197 insertions(+), 9 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9fb93d6fd5..7671a84fa3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -335,8 +335,15 @@ bool static Bind(const CService& addr, unsigned int flags) return true; } +void OnRPCStarted() +{ + uiInterface.NotifyBlockTip.connect(RPCNotifyBlockChange); +} + void OnRPCStopped() { + uiInterface.NotifyBlockTip.disconnect(RPCNotifyBlockChange); + //RPCNotifyBlockChange(0); cvBlockChange.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } @@ -692,6 +699,7 @@ bool InitSanityCheck(void) bool AppInitServers() { + RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); RPCServer::OnPreCommand(&OnRPCPreCommand); if (!InitHTTPServer()) @@ -1407,16 +1415,30 @@ bool AppInit2(bool isDaemon) RecalculateDAPSSupply(1); } - uiInterface.InitMessage(_("Verifying blocks...")); - - // Flag sent to validation code to let it know it can skip certain checks - fVerifyingBlocks = true; + if (!fReindex) { + uiInterface.InitMessage(_("Verifying blocks...")); + + // Flag sent to validation code to let it know it can skip certain checks + fVerifyingBlocks = true; + + { + LOCK(cs_main); + CBlockIndex *tip = chainActive[chainActive.Height()]; + RPCNotifyBlockChange(tip->GetBlockHash()); + if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { + strLoadError = _("The block database contains a block which appears to be from the future. " + "This may be due to your computer's date and time being set incorrectly. " + "Only rebuild the block database if you are sure that your computer's date and time are correct"); + break; + } + } - //Must check at level 4 - if (!CVerifyDB().VerifyDB(pcoinsdbview, 4, GetArg("-checkblocks", 100))) { - strLoadError = _("Corrupted block database detected"); - fVerifyingBlocks = false; - break; + //Must check at level 4 + if (!CVerifyDB().VerifyDB(pcoinsdbview, 4, GetArg("-checkblocks", 100))) { + strLoadError = _("Corrupted block database detected"); + fVerifyingBlocks = false; + break; + } } } catch (std::exception& e) { if (fDebug) LogPrintf("%s\n", e.what()); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 68c18f71c2..cd17f3d9e7 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -17,10 +17,21 @@ #include #include +#include +#include #include "clientversion.h" using namespace std; +struct CUpdatedBlock +{ + uint256 hash; + int height; +}; +static std::mutex cs_blockchange; +static std::condition_variable cond_blockchange; +static CUpdatedBlock latestblock; + extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); extern void PoSBlockInfoToJSON(const uint256 hashBlock, int64_t nTime, int height, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); @@ -179,6 +190,148 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } +void RPCNotifyBlockChange(const uint256 hashBlock) +{ + CBlockIndex* pindex = nullptr; + pindex = mapBlockIndex.at(hashBlock); + if(pindex) { + std::lock_guard lock(cs_blockchange); + latestblock.hash = pindex->GetBlockHash(); + latestblock.height = pindex->nHeight; + } + cond_blockchange.notify_all(); +} + +UniValue waitfornewblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw std::runtime_error( + "waitfornewblock ( timeout )\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + + "\nArguments:\n" + "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("waitfornewblock", "1000") + + HelpExampleRpc("waitfornewblock", "1000") + ); + int timeout = 0; + if (params.size() > 0) + timeout = params[0].get_int(); + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + block = latestblock; + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + else + cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw std::runtime_error( + "waitforblock blockhash ( timeout )\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + + "\nArguments:\n" + "1. \"blockhash\" (required, string) Block hash to wait for.\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + ); + int timeout = 0; + + uint256 hash = uint256S(params[0].get_str()); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); }); + block = latestblock; + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblockheight(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw std::runtime_error( + "waitforblockheight height ( timeout )\n" + "\nWaits for (at least) block height and returns the height and hash\n" + "of the current tip.\n" + "\nReturns the current block on timeout or exit.\n" + + "\nArguments:\n" + "1. height (required, int) Block height to wait for (int)\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + + "\nResult:\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("waitforblockheight", "\"100\", 1000") + + HelpExampleRpc("waitforblockheight", "\"100\", 1000") + ); + int timeout = 0; + + int height = params[0].get_int(); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b57ad52ab4..ff3aae7fb4 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -55,6 +55,12 @@ static const CRPCConvertParam vRPCConvertParams[] = {"getbalances", 0}, {"getbalance", 2}, {"getblockhash", 0}, + { "waitforblockheight", 0 }, + { "waitforblockheight", 1 }, + { "waitforblock", 1 }, + { "waitforblock", 2 }, + { "waitfornewblock", 0 }, + { "waitfornewblock", 1 }, {"setmaxreorgdepth", 0}, {"resyncfrom", 0}, {"setdecoyconfirmation", 0}, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 0ad504b92b..796be6e335 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -341,6 +341,9 @@ static const CRPCCommand vRPCCommands[] = // {"hidden", "invalidateblock", &invalidateblock, true, true, false}, // {"hidden", "reconsiderblock", &reconsiderblock, true, true, false}, // {"hidden", "setmocktime", &setmocktime, true, false, false}, + { "hidden", "waitfornewblock", &waitfornewblock, true, true, false}, + { "hidden", "waitforblock", &waitforblock, true, true, false}, + { "hidden", "waitforblockheight", &waitforblockheight, true, true, false}, /* Dapscoin features */ {"dapscoin", "masternode", &masternode, true, true, false}, diff --git a/src/rpc/server.h b/src/rpc/server.h index 5ce3be3fad..90112ab976 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -281,6 +281,9 @@ extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); +extern UniValue waitfornewblock(const UniValue& params, bool fHelp); +extern UniValue waitforblock(const UniValue& params, bool fHelp); +extern UniValue waitforblockheight(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); @@ -343,5 +346,6 @@ bool StartRPC(); void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(const UniValue& vReq); +void RPCNotifyBlockChange(const uint256 nHeight); #endif // BITCOIN_RPCSERVER_H From ce9ccd0d1318e0fcc1f367fbdaf2c92ba53218a9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 22:37:23 -0500 Subject: [PATCH 0210/1888] [Signal] NotifyBlockTip signaling an immutable index pointer instead of a hash of the block that was later used to get the same index from the blocks map. --- src/guiinterface.h | 3 ++- src/init.cpp | 14 ++++++++++---- src/main.cpp | 1 + src/rpc/blockchain.cpp | 4 +--- src/rpc/server.h | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/guiinterface.h b/src/guiinterface.h index 56f786c7b5..fa15f76f0d 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -15,6 +15,7 @@ class CBasicKeyStore; class CWallet; class uint256; +class CBlockIndex; /** General change type (added, updated, removed). */ enum ChangeType { @@ -103,7 +104,7 @@ class CClientUIInterface boost::signals2::signal ShowProgress; /** New block has been accepted */ - boost::signals2::signal NotifyBlockTip; + boost::signals2::signal NotifyBlockTip; /** New block has been accepted and is over a certain size */ boost::signals2::signal NotifyBlockSize; diff --git a/src/init.cpp b/src/init.cpp index 7671a84fa3..4c7a98f912 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -590,12 +590,18 @@ std::string LicenseInfo() "\n"; } -static void BlockNotifyCallback(const uint256& hashNewTip) +static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex) { + if (initialSync || !pBlockIndex) + return; + std::string strCmd = GetArg("-blocknotify", ""); - boost::replace_all(strCmd, "%s", hashNewTip.GetHex()); - boost::thread t(runCommand, strCmd); // thread runs free + if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); + std::thread t(runCommand, strCmd); + t.detach(); // thread runs free + } } static void BlockSizeNotifyCallback(int size, const uint256& hashNewTip) @@ -1424,7 +1430,7 @@ bool AppInit2(bool isDaemon) { LOCK(cs_main); CBlockIndex *tip = chainActive[chainActive.Height()]; - RPCNotifyBlockChange(tip->GetBlockHash()); + RPCNotifyBlockChange(true, tip); if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { strLoadError = _("The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. " diff --git a/src/main.cpp b/src/main.cpp index e4a60450fe..520ba88875 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3684,6 +3684,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe // Notify external listeners about the new tip. // Note: uiInterface, should switch main signals. uiInterface.NotifyBlockTip(hashNewTip); + uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); GetMainSignals().UpdatedBlockTip(pindexNewTip); unsigned size = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index cd17f3d9e7..6f52ca0097 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -190,10 +190,8 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } -void RPCNotifyBlockChange(const uint256 hashBlock) +void RPCNotifyBlockChange(bool fInitialDownload, const CBlockIndex* pindex) { - CBlockIndex* pindex = nullptr; - pindex = mapBlockIndex.at(hashBlock); if(pindex) { std::lock_guard lock(cs_blockchange); latestblock.hash = pindex->GetBlockHash(); diff --git a/src/rpc/server.h b/src/rpc/server.h index 90112ab976..faadde7579 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -346,6 +346,6 @@ bool StartRPC(); void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(const UniValue& vReq); -void RPCNotifyBlockChange(const uint256 nHeight); +void RPCNotifyBlockChange(bool fInitialDownload, const CBlockIndex* pindex); #endif // BITCOIN_RPCSERVER_H From 717bbd3ecd6c730d30a42b239dd28ed75e2a1bb1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 14 Feb 2020 12:02:45 -0500 Subject: [PATCH 0211/1888] [Backport] Wait locking for genesis connection. --- src/init.cpp | 47 ++++++++++++++++++++++++++++++++++++++++------- src/main.cpp | 2 -- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9fb93d6fd5..979ef9310f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -600,6 +600,26 @@ static void BlockSizeNotifyCallback(int size, const uint256& hashNewTip) boost::thread t(runCommand, strCmd); // thread runs free } +//////////////////////////////////////////////////// + +static bool fHaveGenesis = false; +static std::mutex cs_GenesisWait; +static CConditionVariable condvar_GenesisWait; + +static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) +{ + if (pBlockIndex != nullptr) { + { + std::unique_lock lock_GenesisWait(cs_GenesisWait); + fHaveGenesis = true; + } + condvar_GenesisWait.notify_all(); + } +} + +//////////////////////////////////////////////////// + + struct CImportingNow { CImportingNow() { @@ -1637,6 +1657,17 @@ bool AppInit2(bool isDaemon) #endif // !ENABLE_WALLET // ********************************************************* Step 9: import blocks + if (!CheckDiskSpace()) + return false; + + // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. + // No locking, as this happens before any background thread is started. + if (chainActive.Tip() == nullptr) { + uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait); + } else { + fHaveGenesis = true; + } + if (mapArgs.count("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); @@ -1654,10 +1685,15 @@ bool AppInit2(bool isDaemon) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - if (chainActive.Tip() == NULL) { - LogPrintf("Waiting for genesis block to be imported...\n"); - while (!fRequestShutdown && chainActive.Tip() == NULL) - MilliSleep(10); + + // Wait for genesis block to be processed + LogPrintf("Waiting for genesis block to be imported...\n"); + { + std::unique_lock lockG(cs_GenesisWait); + while (!fHaveGenesis) { + condvar_GenesisWait.wait(lockG); + } + uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait); } // ********************************************************* Step 10: setup ObfuScation @@ -1809,9 +1845,6 @@ bool AppInit2(bool isDaemon) // ********************************************************* Step 11: start node - if (!CheckDiskSpace()) - return false; - if (!strErrors.str().empty()) return InitError(strErrors.str()); diff --git a/src/main.cpp b/src/main.cpp index e4a60450fe..632966b2a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5013,8 +5013,6 @@ bool InitBlockIndex() CBlockIndex* pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); - if (!ActivateBestChain(state, &block)) - return error("LoadBlockIndex() : genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesnt check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); } catch (std::runtime_error& e) { From 8a03dd909c2ad8dddcbf3f7e64178b48f56226d8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 22:46:22 -0500 Subject: [PATCH 0212/1888] [Model] Removing polling based chain height update. Previously we were updating the chain height polling every 1000ms, and trying to locking every single time cs_main from the main thread!. This commit removes the ugly, and not needed, critical section lock entirely using a signal based update. --- src/main.cpp | 55 +++++++++++++++++++++++++----------------- src/qt/clientmodel.cpp | 50 ++++++++++++++++++++------------------ src/qt/clientmodel.h | 4 +++ 3 files changed, 63 insertions(+), 46 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 520ba88875..311d3f2a1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3643,11 +3643,12 @@ ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, CBlo */ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChecked) { - CBlockIndex* pindexNewTip = NULL; - CBlockIndex* pindexMostWork = NULL; + CBlockIndex* pindexNewTip = nullptr; + CBlockIndex* pindexMostWork = nullptr; do { boost::this_thread::interruption_point(); + const CBlockIndex *pindexFork; bool fInitialDownload; while (true) { TRY_LOCK(cs_main, lockMain); @@ -3655,6 +3656,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe MilliSleep(50); continue; } + CBlockIndex *pindexOldTip = chainActive.Tip(); pindexMostWork = FindMostWorkChain(); // Whether we have anything to do at all. if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) @@ -3664,34 +3666,43 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe fAlreadyChecked)) return false; pindexNewTip = chainActive.Tip(); + pindexFork = chainActive.FindFork(pindexOldTip); fInitialDownload = IsInitialBlockDownload(); break; } - // When we reach this point, we switched to a new tip (stored in pindexNewTip). + // When we reach this point, we switched to a new tip (stored in pindexNewTip). // Notifications/callbacks that can run without cs_main - if (!fInitialDownload) { - uint256 hashNewTip = pindexNewTip->GetBlockHash(); - // Relay inventory, but don't relay old inventory during initial block download. - int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); - { - LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - if (chainActive.Height() > - (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); - } - // Notify external listeners about the new tip. - // Note: uiInterface, should switch main signals. - uiInterface.NotifyBlockTip(hashNewTip); + // Always notify the UI if a new block tip was connected + if (pindexFork != pindexNewTip) { + + // Notify the UI uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); - GetMainSignals().UpdatedBlockTip(pindexNewTip); - unsigned size = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); - // If the size is over 1 MB notify external listeners, and it is within the last 5 minutes - if (size > MAX_BLOCK_SIZE_LEGACY && pblock->GetBlockTime() > GetAdjustedTime() - 300) { - uiInterface.NotifyBlockSize(static_cast(size), hashNewTip); + // Notifications/callbacks that can run without cs_main + if (!fInitialDownload) { + uint256 hashNewTip = pindexNewTip->GetBlockHash(); + // Relay inventory, but don't relay old inventory during initial block download. + int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); + { + LOCK(cs_vNodes); + for (CNode *pnode : vNodes) + if (chainActive.Height() > + (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); + } + // Notify external listeners about the new tip. + GetMainSignals().UpdatedBlockTip(pindexNewTip); + + unsigned size = 0; + if (pblock) + size = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); + // If the size is over 1 MB notify external listeners, and it is within the last 5 minutes + if (size > MAX_BLOCK_SIZE_LEGACY && pblock->GetBlockTime() > GetAdjustedTime() - 300) { + uiInterface.NotifyBlockSize(static_cast(size), hashNewTip); + } } + } } while (pindexMostWork != chainActive.Tip()); CheckBlockIndex(); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index e7a310346b..88393358c9 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -29,6 +29,8 @@ #include static const int64_t nClientStartupTime = GetTime(); +// Last tip update notification +static int64_t nLastBlockTipUpdateNotification = 0; ClientModel::ClientModel(OptionsModel* optionsModel, QObject* parent) : QObject(parent), optionsModel(optionsModel), @@ -141,29 +143,6 @@ void ClientModel::updateTimer() // Get required lock upfront. This avoids the GUI from getting stuck on // periodical polls if the core is holding the locks for a longer time - // for example, during a wallet rescan. - TRY_LOCK(cs_main, lockMain); - if (!lockMain) - return; - // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change. - // Periodically check and update with a timer. - int newNumBlocks = getNumBlocks(); - - static int prevAttempt = -1; - static int prevAssets = -1; - - // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state - if (cachedNumBlocks != newNumBlocks || - cachedReindexing != fReindex || cachedImporting != fImporting || - masternodeSync.RequestedMasternodeAttempt != prevAttempt || masternodeSync.RequestedMasternodeAssets != prevAssets) { - cachedNumBlocks = newNumBlocks; - cachedReindexing = fReindex; - cachedImporting = fImporting; - prevAttempt = masternodeSync.RequestedMasternodeAttempt; - prevAssets = masternodeSync.RequestedMasternodeAssets; - - emit numBlocksChanged(newNumBlocks); - } - emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } @@ -276,6 +255,27 @@ void ClientModel::updateBanlist() banTableModel->refresh(); } +static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex) +{ + // lock free async UI updates in case we have a new block tip + // during initial sync, only update the UI if the last update + // was > 1000ms (MODEL_UPDATE_DELAY) ago + int64_t now = 0; + if (initialSync) + now = GetTimeMillis(); + + // if we are in-sync, update the UI regardless of last update time + if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) { + //pass a async signal to the UI thread + int newHeight = pIndex->nHeight; + clientmodel->setCacheNumBlocks(newHeight); + clientmodel->setCacheImporting(fImporting); + clientmodel->setCacheReindexing(fReindex); + Q_EMIT clientmodel->numBlocksChanged(newHeight); + nLastBlockTipUpdateNotification = now; + } +} + // Handlers for core signals static void ShowProgress(ClientModel* clientmodel, const std::string& title, int nProgress) { @@ -313,6 +313,7 @@ void ClientModel::subscribeToCoreSignals() uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); + uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); } void ClientModel::unsubscribeFromCoreSignals() @@ -320,6 +321,7 @@ void ClientModel::unsubscribeFromCoreSignals() // Disconnect signals from client uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); + uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 9f852f729c..a55e351702 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -81,6 +81,10 @@ class ClientModel : public QObject QString formatClientStartupTime() const; QString dataDir() const; + void setCacheNumBlocks(int blockNum) { cachedNumBlocks = blockNum; }; + void setCacheReindexing(bool reindex) { cachedReindexing = reindex; }; + void setCacheImporting(bool import) { cachedImporting = import; }; + private: OptionsModel* optionsModel; PeerTableModel* peerTableModel; From 6c28ad5324d932c9ba847c135829c1b385e707a3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 22:47:11 -0500 Subject: [PATCH 0213/1888] [Chain] Prevent FindFork from crashing when pindex is null (Only should happen on reindexing and initial sync). --- src/chain.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chain.cpp b/src/chain.cpp index d0314308ed..ac01768150 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -54,6 +54,9 @@ CBlockLocator CChain::GetLocator(const CBlockIndex* pindex) const const CBlockIndex* CChain::FindFork(const CBlockIndex* pindex) const { + if (pindex == nullptr) { + return nullptr; + } if (pindex->nHeight > Height()) pindex = pindex->GetAncestor(Height()); while (pindex && !Contains(pindex)) @@ -76,4 +79,4 @@ uint256 CBlockIndex::GetBlockTrust() const uint256 bnPoWTrust = ((~uint256(0) >> 20) / (bnTarget + 1)); return bnPoWTrust > 1 ? bnPoWTrust : 1; } -} \ No newline at end of file +} From 0b8b8f816fca467cf1c3414bf903fff12627afb8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 17:22:02 -0500 Subject: [PATCH 0214/1888] [Backport][Performance] Cache best block hash for miner thread usage + refactor. * Best block cached hash. * csBestBlock, cvBlockChange names updated to latest upstream naming convention. --- src/init.cpp | 2 +- src/main.cpp | 22 +++++++++++++++------- src/main.h | 8 ++++++-- src/miner.cpp | 4 ++-- src/rpc/mining.cpp | 6 +++--- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 369042f7a0..d8cfb4fb37 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -344,7 +344,7 @@ void OnRPCStopped() { uiInterface.NotifyBlockTip.disconnect(RPCNotifyBlockChange); //RPCNotifyBlockChange(0); - cvBlockChange.notify_all(); + g_best_block_cv.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } diff --git a/src/main.cpp b/src/main.cpp index c0efdbcd4d..9b045e734e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,8 +61,12 @@ map mapHashedBlocks; CChain chainActive; CBlockIndex* pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; -CWaitableCriticalSection csBestBlock; -CConditionVariable cvBlockChange; + +// Best block section +CWaitableCriticalSection g_best_block_mutex; +std::condition_variable g_best_block_cv; +uint256 g_best_block; + int nScriptCheckThreads = 0; bool fImporting = false; bool fReindex = false; @@ -3195,12 +3199,16 @@ void static UpdateTip(CBlockIndex* pindexNew) nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("UpdateTip: new best=%s height=%d version=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); + { + WaitableLock lock(g_best_block_mutex); + g_best_block = pindexNew->GetBlockHash(); + g_best_block_cv.notify_all(); + } - cvBlockChange.notify_all(); + LogPrintf("UpdateTip: new best=%s height=%d version=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; diff --git a/src/main.h b/src/main.h index c7dffa28c5..2c507f1d4c 100644 --- a/src/main.h +++ b/src/main.h @@ -140,8 +140,12 @@ extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; extern int64_t nTimeBestReceived; -extern CWaitableCriticalSection csBestBlock; -extern CConditionVariable cvBlockChange; + +// Best block section +extern CWaitableCriticalSection g_best_block_mutex; +extern std::condition_variable g_best_block_cv; +extern uint256 g_best_block; + extern bool fImporting; extern bool fReindex; extern int nScriptCheckThreads; diff --git a/src/miner.cpp b/src/miner.cpp index ffde93cd51..9148357b8b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -612,8 +612,8 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Found a solution { - LOCK(cs_main); - if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) + WaitableLock lock(g_best_block_mutex); + if (pblock->hashPrevBlock != g_best_block) return error("DAPScoinMiner : generated block is stale"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index bdd95c0a35..6c0f92c015 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -528,9 +528,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - WaitableLock lock(csBestBlock); - while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { - if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout) + WaitableLock lock(g_best_block_mutex); + while (g_best_block == hashWatchedChain && IsRPCRunning()) { + if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) From 17d5461c86306a93e4b5661dd795a33c07819754 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 21:11:19 -0500 Subject: [PATCH 0215/1888] [GUI] Do not update the GUI so often when reindex/import is being executed --- src/qt/walletmodel.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index f1c6f14992..502f9797ce 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -129,12 +129,26 @@ void WalletModel::updateStatus() emit encryptionStatusChanged(newEncryptionStatus); } +bool IsImportingOrReindexing() { + return fImporting || fReindex; +} + void WalletModel::pollBalanceChanged() { if (wallet->walletUnlockCountStatus == 1) { emit WalletUnlocked(); wallet->walletUnlockCountStatus++; } + + // Wait a little bit more when the wallet is reindexing and/or importing, no need to lock cs_main so often. + if (IsImportingOrReindexing()) { + static uint8_t waitLonger = 0; + waitLonger++; + if (waitLonger < 10) // 10 seconds + return; + waitLonger = 0; + } + // Get required locks upfront. This avoids the GUI from getting stuck on // periodical polls if the core is holding the locks for a longer time - // for example, during a wallet rescan. @@ -145,11 +159,12 @@ void WalletModel::pollBalanceChanged() if (!lockWallet) return; - if (fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || cachedTxLocks != nCompleteTXLocks) { + int chainHeight = chainActive.Height(); + if (fForceCheckBalanceChanged || chainHeight != cachedNumBlocks) { fForceCheckBalanceChanged = false; // Balance and number of transactions might have changed - cachedNumBlocks = chainActive.Height(); + cachedNumBlocks = chainHeight; checkBalanceChanged(); if (transactionTableModel) { From 2c487dfb1a786cb0b4b3b8703c6465356380ea8c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 13 Feb 2020 21:12:48 -0500 Subject: [PATCH 0216/1888] fReindex and fImporting moved to atomic bool. Both files are being accessed from different threads, including the UI thread. --- src/main.cpp | 6 +++--- src/main.h | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9b045e734e..5238cc2bf8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,8 +68,8 @@ std::condition_variable g_best_block_cv; uint256 g_best_block; int nScriptCheckThreads = 0; -bool fImporting = false; -bool fReindex = false; +std::atomic fImporting{false}; +std::atomic fReindex{false}; bool fTxIndex = true; bool fIsBareMultisigStd = true; bool fCheckBlockIndex = false; @@ -4877,7 +4877,7 @@ bool static LoadBlockIndexDB(string& strError) // Check whether we need to continue reindexing bool fReindexing = false; pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; + if(fReindexing) fReindex = true; // Check whether we have a transaction index pblocktree->ReadFlag("txindex", fTxIndex); diff --git a/src/main.h b/src/main.h index 2c507f1d4c..cfbbd72d14 100644 --- a/src/main.h +++ b/src/main.h @@ -146,8 +146,8 @@ extern CWaitableCriticalSection g_best_block_mutex; extern std::condition_variable g_best_block_cv; extern uint256 g_best_block; -extern bool fImporting; -extern bool fReindex; +extern std::atomic fImporting; +extern std::atomic fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; @@ -197,11 +197,11 @@ void DestroyContext(); bool VerifyDerivedAddress(const CTxOut& out, std::string stealth); bool ReVerifyPoSBlock(CBlockIndex* pindex); -/** +/** * Process an incoming block. This only returns after the best known valid * block is made active. Note that it does not, however, guarantee that the * specific block passed to it has been checked for validity! - * + * * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation. * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. * @param[in] pblock The block we want to process. @@ -337,7 +337,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF /** * Check transaction inputs, and make sure any * pay-to-script-hash transactions are evaluating IsStandard scripts - * + * * Why bother? To avoid denial-of-service attacks; an attacker * can submit a standard HASH... OP_EQUAL transaction, * which will get accepted into blocks. The redemption @@ -346,14 +346,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF * DUP CHECKSIG DROP ... repeated 100 times... OP_1 */ -/** +/** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending * @return True if all inputs (scriptSigs) use only standard transaction forms */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); -/** +/** * Count ECDSA signature operations the old-fashioned (pre-0.6) way * @return number of sigops this transaction's outputs will produce when spent * @see CTransaction::FetchInputs @@ -418,9 +418,9 @@ class CBlockUndo }; -/** +/** * Closure representing one script verification - * Note that this stores references to the spending transaction + * Note that this stores references to the spending transaction */ class CScriptCheck { From 4fea5d2ffbedd56f490284dc3b8d95403cb48864 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 19 Feb 2020 21:24:52 -0500 Subject: [PATCH 0217/1888] [Masterndoes] Masternodes sync, try locking cs_main when it looks for the tip, preventing possible multi-threading shared resource problem. Remove duplicated tip check. --- src/masternode-sync.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 963a30f897..f1d835bce7 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -45,14 +45,18 @@ bool CMasternodeSync::IsBlockchainSynced() if (fImporting || fReindex) return false; - TRY_LOCK(cs_main, lockMain); - if (!lockMain) return false; + int64_t blockTime = 0; + { + TRY_LOCK(cs_main, lockMain); + if (!lockMain) return false; - CBlockIndex* pindex = chainActive.Tip(); - if (pindex == NULL) return false; + CBlockIndex *pindex = chainActive.Tip(); + if (pindex == NULL) return false; + blockTime = pindex->nTime; + } - if (pindex->nTime + 60 * 60 < GetTime()) + if (blockTime + 60 * 60 < lastProcess) return false; fBlockchainSynced = true; @@ -315,9 +319,6 @@ void CMasternodeSync::Process() if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return; - CBlockIndex* pindexPrev = chainActive.Tip(); - if (pindexPrev == NULL) return; - int nMnCount = mnodeman.CountEnabled(); pnode->PushMessage("mnget", nMnCount); //sync payees RequestedMasternodeAttempt++; From a69683212acf40c0461582f4fb5e9dd0cd211f45 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 19 Feb 2020 21:42:35 -0500 Subject: [PATCH 0218/1888] [Masternodes] Reset mn sync process if it's sleep. --- src/masternode-sync.cpp | 13 ++++++------- src/masternode-sync.h | 3 +++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index f1d835bce7..7e9dd425cd 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -31,15 +31,14 @@ bool CMasternodeSync::IsSynced() bool CMasternodeSync::IsBlockchainSynced() { - static bool fBlockchainSynced = false; - static int64_t lastProcess = GetTime(); + int64_t now = GetTime(); // if the last call to this function was more than 60 minutes ago (client was in sleep mode) reset the sync process - if (GetTime() - lastProcess > 60 * 60) { + if (now > lastProcess + 60 * 60) { Reset(); fBlockchainSynced = false; } - lastProcess = GetTime(); + lastProcess = now; if (fBlockchainSynced) return true; @@ -49,10 +48,8 @@ bool CMasternodeSync::IsBlockchainSynced() { TRY_LOCK(cs_main, lockMain); if (!lockMain) return false; - CBlockIndex *pindex = chainActive.Tip(); - if (pindex == NULL) return false; - + if (pindex == nullptr) return false; blockTime = pindex->nTime; } @@ -66,6 +63,8 @@ bool CMasternodeSync::IsBlockchainSynced() void CMasternodeSync::Reset() { + fBlockchainSynced = false; + lastProcess = 0; lastMasternodeList = 0; lastMasternodeWinner = 0; lastBudgetItem = 0; diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 945d0084fc..7960a7657d 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -39,6 +39,9 @@ class CMasternodeSync int64_t lastFailure; int nCountFailures; + std::atomic lastProcess; + std::atomic fBlockchainSynced; + // sum of all counts int sumMasternodeList; int sumMasternodeWinner; From 505512324b80dd5f6228f1757b98a7c0989d1d13 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 22 Feb 2020 10:25:07 -0500 Subject: [PATCH 0219/1888] [Refactor] Move wallet functions out of header No functional changes --- src/wallet/wallet.cpp | 292 ++++++++++++++++++++++++++++++++++++++++ src/wallet/wallet.h | 301 +++++------------------------------------- 2 files changed, 323 insertions(+), 270 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2f942d23bb..6b356da76d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -6490,6 +6490,298 @@ bool CMerkleTx::IsTransactionLockTimedOut() const return false; } +CWallet::CWallet() +{ + SetNull(); +} + +CWallet::CWallet(std::string strWalletFileIn) +{ + SetNull(); + + strWalletFile = strWalletFileIn; + fFileBacked = true; +} + +CWallet::~CWallet() +{ + delete pwalletdbEncryption; +} + +void CWallet::SetNull() +{ + nWalletVersion = FEATURE_BASE; + nWalletMaxVersion = FEATURE_BASE; + fFileBacked = false; + nMasterKeyMaxID = 0; + pwalletdbEncryption = NULL; + nOrderPosNext = 0; + nNextResend = 0; + nLastResend = 0; + nTimeFirstKey = 0; + fWalletUnlockAnonymizeOnly = false; + walletStakingInProgress = false; + fBackupMints = false; + + // Stake Settings + nHashDrift = 45; + nStakeSplitThreshold = 100000; + nHashInterval = 22; + nStakeSetUpdateTime = 300; // 5 minutes + + //MultiSend + vMultiSend.clear(); + fMultiSendStake = false; + fMultiSendMasternodeReward = false; + fMultiSendNotify = false; + strMultiSendChangeAddress = ""; + nLastMultiSendHeight = 0; + vDisabledAddresses.clear(); + + //Auto Combine Dust + fCombineDust = true; + nAutoCombineThreshold = 540 * COIN; +} + +bool CWallet::isMultiSendEnabled() +{ + return fMultiSendMasternodeReward || fMultiSendStake; +} + +void CWallet::setMultiSendDisabled() +{ + fMultiSendMasternodeReward = false; + fMultiSendStake = false; +} + +bool CWallet::CanSupportFeature(enum WalletFeature wf) +{ + AssertLockHeld(cs_wallet); + return nWalletMaxVersion >= wf; +} + +bool CWallet::LoadMinVersion(int nVersion) +{ + AssertLockHeld(cs_wallet); + nWalletVersion = nVersion; + nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); + return true; +} + +isminetype CWallet::IsMine(const CTxOut& txout) const +{ + return ::IsMine(*this, txout.scriptPubKey); +} + +CAmount CWallet::GetCredit(const CTransaction& tx, const CTxOut& txout, const isminefilter& filter) const +{ + return ((IsMine(txout) & filter) ? getCTxOutValue(tx, txout) : 0); +} + +CAmount CWallet::GetChange(const CTransaction& tx, const CTxOut& txout) const +{ + return (IsChange(txout) ? getCTxOutValue(tx, txout) : 0); +} + +bool CWallet::IsMine(const CTransaction& tx) const +{ + for (const CTxOut& txout : tx.vout) + if (IsMine(txout)) + return true; + return false; +} + +bool CWallet::IsFromMe(const CTransaction& tx) const +{ + return (GetDebit(tx, ISMINE_ALL) > 0); +} + +CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const +{ + CAmount nDebit = 0; + for (const CTxIn& txin : tx.vin) { + nDebit += GetDebit(txin, filter); + } + return nDebit; +} + +CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const +{ + CAmount nCredit = 0; + for (const CTxOut& txout : tx.vout) { + nCredit += GetCredit(tx, txout, filter); + } + return nCredit; +} + +CAmount CWallet::GetChange(const CTransaction& tx) const +{ + CAmount nChange = 0; + for (const CTxOut& txout : tx.vout) { + nChange += GetChange(tx, txout); + } + return nChange; +} + +void CWallet::Inventory(const uint256& hash) +{ + { + LOCK(cs_wallet); + std::map::iterator mi = mapRequestCount.find(hash); + if (mi != mapRequestCount.end()) + (*mi).second++; + } +} + +unsigned int CWallet::GetKeyPoolSize() +{ + AssertLockHeld(cs_wallet); // setKeyPool + return setKeyPool.size(); +} + +int CWallet::GetVersion() +{ + LOCK(cs_wallet); + return nWalletVersion; +} + +CWalletTx::CWalletTx() +{ + Init(NULL); +} + +CWalletTx::CWalletTx(CWallet* pwalletIn) +{ + Init(pwalletIn); +} + +CWalletTx::CWalletTx(CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) +{ + Init(pwalletIn); +} + +CWalletTx::CWalletTx(CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) +{ + Init(pwalletIn); +} + +void CWalletTx::Init(CWallet* pwalletIn) +{ + pwallet = pwalletIn; + mapValue.clear(); + vOrderForm.clear(); + fTimeReceivedIsTxTime = false; + nTimeReceived = 0; + nTimeSmart = 0; + fFromMe = false; + strFromAccount.clear(); + fDebitCached = false; + fCreditCached = false; + fImmatureCreditCached = false; + fAvailableCreditCached = false; + fAnonymizableCreditCached = false; + fAnonymizedCreditCached = false; + fDenomUnconfCreditCached = false; + fDenomConfCreditCached = false; + fWatchDebitCached = false; + fWatchCreditCached = false; + fImmatureWatchCreditCached = false; + fAvailableWatchCreditCached = false; + fChangeCached = false; + nDebitCached = 0; + nCreditCached = 0; + nImmatureCreditCached = 0; + nAvailableCreditCached = 0; + nAnonymizableCreditCached = 0; + nAnonymizedCreditCached = 0; + nDenomUnconfCreditCached = 0; + nDenomConfCreditCached = 0; + nWatchDebitCached = 0; + nWatchCreditCached = 0; + nAvailableWatchCreditCached = 0; + nImmatureWatchCreditCached = 0; + nChangeCached = 0; + nOrderPos = -1; +} + +bool CWalletTx::IsTrusted() const +{ + // Quick answer in most cases + if (!IsFinalTx(*this)) + return false; + int nDepth = GetDepthInMainChain(); + if (nDepth >= 1) + return true; + if (nDepth < 0) + return false; + if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit + return false; + // Don't trust unconfirmed transactions from us unless they are in the mempool. + { + LOCK(mempool.cs); + if (!mempool.exists(GetHash())) { + return false; + } + } + // Trusted if all inputs are from us and are in the mempool: + for (const CTxIn& txin : vin) { + // Transactions not sent by us: not trusted + COutPoint prevout = pwallet->findMyOutPoint(txin); + const CWalletTx* parent = pwallet->GetWalletTx(prevout.hash); + if (parent == NULL) + return false; + const CTxOut& parentOut = parent->vout[prevout.n]; + if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE) + return false; + } + return true; +} + +void CWalletTx::MarkDirty() +{ + fCreditCached = false; + fAvailableCreditCached = false; + fAnonymizableCreditCached = false; + fAnonymizedCreditCached = false; + fDenomUnconfCreditCached = false; + fDenomConfCreditCached = false; + fWatchDebitCached = false; + fWatchCreditCached = false; + fAvailableWatchCreditCached = false; + fImmatureWatchCreditCached = false; + fDebitCached = false; + fChangeCached = false; +} + +void CWalletTx::BindWallet(CWallet* pwalletIn) +{ + pwallet = pwalletIn; + MarkDirty(); +} + +CAmount CWalletTx::GetChange() const +{ + if (fChangeCached) + return nChangeCached; + nChangeCached = pwallet->GetChange(*this); + fChangeCached = true; + return nChangeCached; +} + +bool CWalletTx::IsFromMe(const isminefilter& filter) const +{ + return (GetDebit(filter) > 0); +} + +int CWalletTx::GetBlockHeight() const +{ + if (hashBlock.IsNull()) { + return -1; //not in the chain + } else { + return mapBlockIndex[hashBlock]->nHeight; + } +} + bool CWallet::ReadAccountList(std::string& accountList) { return CWalletDB(strWalletFile).ReadStealthAccountList(accountList); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 29ee0687d3..632d60b1e9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -323,69 +323,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount nAutoCombineThreshold; bool CreateSweepingTransaction(CAmount target, CAmount threshold, uint32_t nTimeBefore); bool SendAll(std::string des); - CWallet() - { - SetNull(); - } - CWallet(std::string strWalletFileIn) - { - SetNull(); - - strWalletFile = strWalletFileIn; - fFileBacked = true; - } - - ~CWallet() - { - delete pwalletdbEncryption; - } - - void SetNull() - { - nWalletVersion = FEATURE_BASE; - nWalletMaxVersion = FEATURE_BASE; - fFileBacked = false; - nMasterKeyMaxID = 0; - pwalletdbEncryption = NULL; - nOrderPosNext = 0; - nNextResend = 0; - nLastResend = 0; - nTimeFirstKey = 0; - fWalletUnlockAnonymizeOnly = false; - walletStakingInProgress = false; - fBackupMints = false; - - // Stake Settings - nHashDrift = 45; - nStakeSplitThreshold = 100000; - nHashInterval = 22; - nStakeSetUpdateTime = 300; // 5 minutes - - //MultiSend - vMultiSend.clear(); - fMultiSendStake = false; - fMultiSendMasternodeReward = false; - fMultiSendNotify = false; - strMultiSendChangeAddress = ""; - nLastMultiSendHeight = 0; - vDisabledAddresses.clear(); - - //Auto Combine Dust - fCombineDust = true; - nAutoCombineThreshold = 540 * COIN; - } - - bool isMultiSendEnabled() - { - return fMultiSendMasternodeReward || fMultiSendStake; - } - - void setMultiSendDisabled() - { - fMultiSendMasternodeReward = false; - fMultiSendStake = false; - } + CWallet(); + CWallet(std::string strWalletFileIn); + ~CWallet(); + void SetNull(); + bool isMultiSendEnabled(); + void setMultiSendDisabled(); mutable std::map mapWallet; std::list laccentries; @@ -428,11 +372,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::vector getWalletTxs(); //! check whether we are allowed to upgrade (or already support) to the named feature - bool CanSupportFeature(enum WalletFeature wf) - { - AssertLockHeld(cs_wallet); - return nWalletMaxVersion >= wf; - } + bool CanSupportFeature(enum WalletFeature wf); bool generateKeyImage(const CPubKey& pub, CKeyImage& img) const; bool generateKeyImage(const CScript& scriptKey, CKeyImage& img) const; @@ -441,7 +381,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map > AvailableCoinsByAddress(bool fConfirmed = true, CAmount maxCoinValue = 0); bool SelectCoinsMinConf(bool needFee, CAmount& estimatedFee, int ringSize, int numOut, const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet); - /// Get 1000DASH output and keys which can be used for the Masternode + /// Get 1000000 DAPS output and keys which can be used for the Masternode bool GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet, CKey& keyRet, std::string strTxHash = "", std::string strOutputIndex = ""); /// Extract txin information and keys from output bool GetVinAndKeysFromOutput(COutput out, CTxIn& txinRet, CPubKey& pubKeyRet, CKey& keyRet); @@ -481,13 +421,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! Load metadata (used by LoadWallet) bool LoadKeyMetadata(const CPubKey& pubkey, const CKeyMetadata& metadata); - bool LoadMinVersion(int nVersion) - { - AssertLockHeld(cs_wallet); - nWalletVersion = nVersion; - nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); - return true; - } + bool LoadMinVersion(int nVersion); //! Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret); @@ -628,55 +562,16 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface isminetype IsMine(const CTxIn& txin) const; CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; - isminetype IsMine(const CTxOut& txout) const - { - return ::IsMine(*this, txout.scriptPubKey); - } - CAmount GetCredit(const CTransaction& tx, const CTxOut& txout, const isminefilter& filter) const - { - return ((IsMine(txout) & filter) ? getCTxOutValue(tx, txout) : 0); - } + isminetype IsMine(const CTxOut& txout) const; + CAmount GetCredit(const CTransaction& tx, const CTxOut& txout, const isminefilter& filter) const; bool IsChange(const CTxOut& txout) const; - CAmount GetChange(const CTransaction& tx, const CTxOut& txout) const - { - return (IsChange(txout) ? getCTxOutValue(tx, txout) : 0); - } - bool IsMine(const CTransaction& tx) const - { - for (const CTxOut& txout : tx.vout) - if (IsMine(txout)) - return true; - return false; - } + CAmount GetChange(const CTransaction& tx, const CTxOut& txout) const; + bool IsMine(const CTransaction& tx) const; /** should probably be renamed to IsRelevantToMe */ - bool IsFromMe(const CTransaction& tx) const - { - return (GetDebit(tx, ISMINE_ALL) > 0); - } - CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const - { - CAmount nDebit = 0; - for (const CTxIn& txin : tx.vin) { - nDebit += GetDebit(txin, filter); - } - return nDebit; - } - CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const - { - CAmount nCredit = 0; - for (const CTxOut& txout : tx.vout) { - nCredit += GetCredit(tx, txout, filter); - } - return nCredit; - } - CAmount GetChange(const CTransaction& tx) const - { - CAmount nChange = 0; - for (const CTxOut& txout : tx.vout) { - nChange += GetChange(tx, txout); - } - return nChange; - } + bool IsFromMe(const CTransaction& tx) const; + CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetChange(const CTransaction& tx) const; void SetBestChain(const CBlockLocator& loc); DBErrors LoadWallet(bool& fFirstRunRet); @@ -688,21 +583,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool UpdatedTransaction(const uint256& hashTx); - void Inventory(const uint256& hash) - { - { - LOCK(cs_wallet); - std::map::iterator mi = mapRequestCount.find(hash); - if (mi != mapRequestCount.end()) - (*mi).second++; - } - } + void Inventory(const uint256& hash); - unsigned int GetKeyPoolSize() - { - AssertLockHeld(cs_wallet); // setKeyPool - return setKeyPool.size(); - } + unsigned int GetKeyPoolSize(); //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false); @@ -711,11 +594,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool SetMaxVersion(int nVersion); //! get the current wallet format (the oldest client version guaranteed to understand this wallet) - int GetVersion() - { - LOCK(cs_wallet); - return nWalletVersion; - } + int GetVersion(); //! Get wallet transactions that conflict with given transaction (spend same outputs) std::set GetConflicts(const uint256& txid) const; @@ -964,64 +843,11 @@ class CWalletTx : public CMerkleTx mutable CAmount nChangeCached; - CWalletTx() - { - Init(NULL); - } - - CWalletTx(CWallet* pwalletIn) - { - Init(pwalletIn); - } - - CWalletTx(CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) - { - Init(pwalletIn); - } - - CWalletTx(CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) - { - Init(pwalletIn); - } - - void Init(CWallet* pwalletIn) - { - pwallet = pwalletIn; - mapValue.clear(); - vOrderForm.clear(); - fTimeReceivedIsTxTime = false; - nTimeReceived = 0; - nTimeSmart = 0; - fFromMe = false; - strFromAccount.clear(); - fDebitCached = false; - fCreditCached = false; - fImmatureCreditCached = false; - fAvailableCreditCached = false; - fAnonymizableCreditCached = false; - fAnonymizedCreditCached = false; - fDenomUnconfCreditCached = false; - fDenomConfCreditCached = false; - fWatchDebitCached = false; - fWatchCreditCached = false; - fImmatureWatchCreditCached = false; - fAvailableWatchCreditCached = false; - fChangeCached = false; - nDebitCached = 0; - nCreditCached = 0; - nImmatureCreditCached = 0; - nAvailableCreditCached = 0; - nAnonymizableCreditCached = 0; - nAnonymizedCreditCached = 0; - nDenomUnconfCreditCached = 0; - nDenomConfCreditCached = 0; - nWatchDebitCached = 0; - nWatchCreditCached = 0; - nAvailableWatchCreditCached = 0; - nImmatureWatchCreditCached = 0; - nChangeCached = 0; - nOrderPos = -1; - } + CWalletTx(); + CWalletTx(CWallet* pwalletIn); + CWalletTx(CWallet* pwalletIn, const CMerkleTx& txIn); + CWalletTx(CWallet* pwalletIn, const CTransaction& txIn); + void Init(CWallet* pwalletIn); ADD_SERIALIZE_METHODS; @@ -1065,27 +891,9 @@ class CWalletTx : public CMerkleTx } //! make sure balances are recalculated - void MarkDirty() - { - fCreditCached = false; - fAvailableCreditCached = false; - fAnonymizableCreditCached = false; - fAnonymizedCreditCached = false; - fDenomUnconfCreditCached = false; - fDenomConfCreditCached = false; - fWatchDebitCached = false; - fWatchCreditCached = false; - fAvailableWatchCreditCached = false; - fImmatureWatchCreditCached = false; - fDebitCached = false; - fChangeCached = false; - } + void MarkDirty(); - void BindWallet(CWallet* pwalletIn) - { - pwallet = pwalletIn; - MarkDirty(); - } + void BindWallet(CWallet* pwalletIn); //! filter decides which addresses will count towards the debit CAmount GetUnlockedCredit() const; @@ -1101,14 +909,7 @@ class CWalletTx : public CMerkleTx CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const; - CAmount GetChange() const - { - if (fChangeCached) - return nChangeCached; - nChangeCached = pwallet->GetChange(*this); - fChangeCached = true; - return nChangeCached; - } + CAmount GetChange() const; void GetAmounts(std::list& listReceived, std::list& listSent, @@ -1118,53 +919,13 @@ class CWalletTx : public CMerkleTx void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived, CAmount& nSent, CAmount& nFee, const isminefilter& filter) const; - bool IsFromMe(const isminefilter& filter) const - { - return (GetDebit(filter) > 0); - } + bool IsFromMe(const isminefilter& filter) const; bool InMempool() const; - bool IsTrusted() const - { - // Quick answer in most cases - if (!IsFinalTx(*this)) - return false; - int nDepth = GetDepthInMainChain(); - if (nDepth >= 1) - return true; - if (nDepth < 0) - return false; - if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit - return false; - // Don't trust unconfirmed transactions from us unless they are in the mempool. - { - LOCK(mempool.cs); - if (!mempool.exists(GetHash())) { - return false; - } - } - // Trusted if all inputs are from us and are in the mempool: - for (const CTxIn& txin : vin) { - // Transactions not sent by us: not trusted - COutPoint prevout = pwallet->findMyOutPoint(txin); - const CWalletTx* parent = pwallet->GetWalletTx(prevout.hash); - if (parent == NULL) - return false; - const CTxOut& parentOut = parent->vout[prevout.n]; - if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE) - return false; - } - return true; - } + bool IsTrusted() const; - int GetBlockHeight() const { - if (hashBlock.IsNull()) { - return -1; //not in the chain - } else { - return mapBlockIndex[hashBlock]->nHeight; - } - } + int GetBlockHeight() const; bool WriteToDisk(); From 5303cbf25dfcdae275482ad8dea574de5d3f4c27 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 23 Feb 2020 15:07:14 -0500 Subject: [PATCH 0220/1888] [GUI] Make "For anonymization and staking only" checked by default --- src/qt/addresstablemodel.cpp | 3 +- src/qt/askpassphrasedialog.cpp | 46 +++++++++++++++++++----------- src/qt/askpassphrasedialog.h | 19 ++++++++++-- src/qt/bip38tooldialog.cpp | 5 ++-- src/qt/bitcoingui.cpp | 2 +- src/qt/masternodelist.cpp | 7 +++-- src/qt/multisigdialog.cpp | 2 +- src/qt/optionspage.cpp | 4 +-- src/qt/sendcoinsdialog.cpp | 2 +- src/qt/signverifymessagedialog.cpp | 3 +- src/qt/walletframe.cpp | 14 +++++++-- src/qt/walletframe.h | 5 +++- src/qt/walletmodel.cpp | 4 +-- src/qt/walletmodel.h | 5 ++-- src/qt/walletview.cpp | 14 ++++----- src/qt/walletview.h | 3 +- 16 files changed, 92 insertions(+), 46 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index c0b82da50e..473c38020f 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -12,6 +12,7 @@ #include "base58.h" #include "wallet/wallet.h" +#include "askpassphrasedialog.h" #include #include @@ -351,7 +352,7 @@ QString AddressTableModel::addRow(const QString& type, const QString& label, con // Generate a new address to associate with given label CPubKey newKey; if (!wallet->GetKeyFromPool(newKey)) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); if (!ctx.isValid()) { // Unlock wallet failed or was cancelled editStatus = WALLET_UNLOCK_FAILURE; diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index bd42c51d4b..8876172ba7 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -17,10 +17,11 @@ #include #include -AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), +AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model, Context context) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::AskPassphraseDialog), mode(mode), model(model), + context(context), fCapsLock(false) { ui->setupUi(this); @@ -41,24 +42,24 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel this->model = model; switch (mode) { - case Encrypt: // Ask passphrase x2 + case Mode::Encrypt: // Ask passphrase x2 ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
    Please use a passphrase of ten or more random characters, or eight or more words.")); ui->passLabel1->hide(); ui->passEdit1->hide(); setWindowTitle(tr("Encrypt Wallet")); break; - case UnlockAnonymize: ui->anonymizationCheckBox->setChecked(false); ui->anonymizationCheckBox->hide(); - case Unlock: // Ask passphrase ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); + case Mode::UnlockAnonymize: + case Mode::Unlock: // Ask passphrase ui->passLabel2->hide(); ui->passEdit2->hide(); ui->passLabel3->hide(); ui->passEdit3->hide(); setWindowTitle(tr("Unlock Wallet")); break; - case Decrypt: // Ask passphrase + case Mode::Decrypt: // Ask passphrase ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet.")); ui->passLabel2->hide(); ui->passEdit2->hide(); @@ -66,13 +67,24 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel ui->passEdit3->hide(); setWindowTitle(tr("Decrypt Wallet")); break; - case ChangePass: // Ask old passphrase + new passphrase x2 + case Mode::ChangePass: // Ask old passphrase + new passphrase x2 setWindowTitle(tr("Change Passphrase")); ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet.")); break; } - ui->anonymizationCheckBox->setChecked(model->isAnonymizeOnlyUnlocked()); + // Set checkbox "For anonymization, automint, and staking only" depending on from where we were called + if (context == Context::Unlock_Menu || context == Context::BIP_38) { + ui->anonymizationCheckBox->setChecked(true); + } + else { + ui->anonymizationCheckBox->setChecked(false); + } + + // It doesn't make sense to show the checkbox for sending DAPS because you wouldn't check it anyway. + if (context == Context::Send) { + ui->anonymizationCheckBox->hide(); + } textChanged(); connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); @@ -104,7 +116,7 @@ void AskPassphraseDialog::accept() newpass2.assign(ui->passEdit3->text().toStdString().c_str()); switch (mode) { - case Encrypt: { + case Mode::Encrypt: { if (newpass1.empty() || newpass2.empty()) { // Cannot encrypt with empty passphrase break; @@ -149,8 +161,8 @@ void AskPassphraseDialog::accept() QDialog::reject(); // Cancelled } } break; - case UnlockAnonymize: - case Unlock: + case Mode::UnlockAnonymize: + case Mode::Unlock: if (!model->setWalletLocked(false, oldpass, ui->anonymizationCheckBox->isChecked())) { QMessageBox msgBox; msgBox.setWindowTitle("Wallet Unlock Failed"); @@ -162,7 +174,7 @@ void AskPassphraseDialog::accept() QDialog::accept(); // Success } break; - case Decrypt: + case Mode::Decrypt: if (!model->setWalletEncrypted(false, oldpass)) { QMessageBox msgBox; msgBox.setWindowTitle("Wallet Decryption Failed"); @@ -174,7 +186,7 @@ void AskPassphraseDialog::accept() QDialog::accept(); // Success } break; - case ChangePass: + case Mode::ChangePass: if (newpass1 == newpass2) { if (model->changePassphrase(oldpass, newpass1)) { QMessageBox msgBox; @@ -209,15 +221,15 @@ void AskPassphraseDialog::textChanged() // Validate input, set Ok button to enabled when acceptable bool acceptable = false; switch (mode) { - case Encrypt: // New passphrase x2 + case Mode::Encrypt: // New passphrase x2 acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); break; - case UnlockAnonymize: // Old passphrase x1 - case Unlock: // Old passphrase x1 - case Decrypt: + case Mode::UnlockAnonymize: // Old passphrase x1 + case Mode::Unlock: // Old passphrase x1 + case Mode::Decrypt: acceptable = !ui->passEdit1->text().isEmpty(); break; - case ChangePass: // Old passphrase x1, new passphrase x2 + case Mode::ChangePass: // Old passphrase x1, new passphrase x2 acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); break; } diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 655ba32912..213b873806 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -21,7 +21,7 @@ class AskPassphraseDialog : public QDialog Q_OBJECT public: - enum Mode { + enum class Mode { Encrypt, /**< Ask passphrase twice and encrypt */ UnlockAnonymize, /**< Ask passphrase and unlock only for anonymization */ Unlock, /**< Ask passphrase and unlock */ @@ -29,7 +29,21 @@ class AskPassphraseDialog : public QDialog Decrypt /**< Ask passphrase and decrypt wallet */ }; - explicit AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model); + // Context from where / for what the passphrase dialog was called to set the status of the checkbox + // Partly redundant to Mode above, but offers more flexibility for future enhancements + enum class Context { + Unlock_Menu, /** Unlock wallet from menu */ + Unlock_Full, /** Wallet needs to be fully unlocked */ + Encrypt, /** Encrypt unencrypted wallet */ + ToggleLock, /** Toggle wallet lock state */ + ChangePass, /** Change passphrase */ + Send, /** Send DAPS */ + BIP_38, /** BIP38 menu */ + Multi_Sig, /** Multi-Signature dialog */ + Sign_Message /** Sign/verify message dialog */ + }; + + explicit AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model, Context context); ~AskPassphraseDialog(); void accept(); @@ -38,6 +52,7 @@ class AskPassphraseDialog : public QDialog Ui::AskPassphraseDialog* ui; Mode mode; WalletModel* model; + Context context; bool fCapsLock; private slots: diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index dbc3ecf38f..ffe58854f9 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -16,6 +16,7 @@ #include "bip38.h" #include "init.h" #include "wallet/wallet.h" +#include "askpassphrasedialog.h" #include #include @@ -136,7 +137,7 @@ void Bip38ToolDialog::on_encryptKeyButton_ENC_clicked() return; } - WalletModel::UnlockContext ctx(model->requestUnlock(true)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::BIP_38, true)); if (!ctx.isValid()) { ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_ENC->setText(tr("Wallet unlock was cancelled.")); @@ -193,7 +194,7 @@ void Bip38ToolDialog::on_decryptKeyButton_DEC_clicked() void Bip38ToolDialog::on_importAddressButton_DEC_clicked() { - WalletModel::UnlockContext ctx(model->requestUnlock(true)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::BIP_38, true)); if (!ctx.isValid()) { ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_DEC->setText(tr("Wallet unlock was cancelled.")); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bec4f11535..1db23f0e14 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -501,7 +501,7 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet())); connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase())); - connect(unlockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(unlockWallet())); + connect(unlockWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(unlockWallet(bool))); connect(lockWalletAction, SIGNAL(triggered()), walletFrame, SLOT(lockWallet())); connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses())); connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index cafb36db71..fab357805a 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -11,6 +11,7 @@ #include "sync.h" #include "wallet/wallet.h" #include "walletmodel.h" +#include "askpassphrasedialog.h" #include #include @@ -247,7 +248,7 @@ void MasternodeList::on_startButton_clicked() WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full)); if (!ctx.isValid()) return; // Unlock wallet was cancelled @@ -271,7 +272,7 @@ void MasternodeList::on_startAllButton_clicked() WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full)); if (!ctx.isValid()) return; // Unlock wallet was cancelled @@ -302,7 +303,7 @@ void MasternodeList::on_startMissingButton_clicked() WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock()); + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full)); if (!ctx.isValid()) return; // Unlock wallet was cancelled diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index 70ffd2bb29..eff5aaafb6 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -595,7 +595,7 @@ bool MultisigDialog::signMultisigTx(CMutableTransaction& tx, string& errorOut, Q } }else{ if (model->getEncryptionStatus() == model->Locked) { - if (!model->requestUnlock(true).isValid()) { + if (!model->requestUnlock(AskPassphraseDialog::Context::Multi_Sig, true).isValid()) { // Unlock wallet was cancelled throw runtime_error("Error: Your wallet is locked. Please enter the wallet passphrase first."); } diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index c6c3a91c46..93b4109a85 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -817,7 +817,7 @@ void OptionsPage::on_month() { void OptionsPage::onShowMnemonic() { int status = model->getEncryptionStatus(); if (status == WalletModel::Locked || status == WalletModel::UnlockedForAnonymizationOnly) { - WalletModel::UnlockContext ctx(model->requestUnlock(false)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); if (!ctx.isValid()) { QMessageBox msgBox; msgBox.setWindowTitle("Mnemonic Recovery Phrase"); @@ -837,7 +837,7 @@ void OptionsPage::onShowMnemonic() { reply = QMessageBox::question(this, "Are You Sure?", "Are you sure you would like to view your Mnemonic Phrase?\nYou will be required to enter your passphrase. Failed or canceled attempts will be logged.", QMessageBox::Yes|QMessageBox::No); if (reply == QMessageBox::Yes) { model->setWalletLocked(true); - WalletModel::UnlockContext ctx(model->requestUnlock(false)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); if (!ctx.isValid()) { QMessageBox msgBox; msgBox.setWindowTitle("Mnemonic Recovery Phrase"); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 23b9cad9f3..a4af6871d7 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -173,7 +173,7 @@ void SendCoinsDialog::on_sendButton_clicked(){ // will call relock WalletModel::EncryptionStatus encStatus = model->getEncryptionStatus(); if (encStatus == model->Locked || encStatus == model->UnlockedForAnonymizationOnly) { - WalletModel::UnlockContext ctx(model->requestUnlock(true)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::Send, true)); if (!ctx.isValid()) { // Unlock wallet was cancelled return; diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 6b74d17649..6df3e90621 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -15,6 +15,7 @@ #include "base58.h" #include "init.h" #include "wallet/wallet.h" +#include "askpassphrasedialog.h" #include #include @@ -117,7 +118,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() return; } - WalletModel::UnlockContext ctx(model->requestUnlock(true)); + WalletModel::UnlockContext ctx(model->requestUnlock(AskPassphraseDialog::Context::Sign_Message, true)); if (!ctx.isValid()) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled.")); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 75d13a390c..4dc1ad480d 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -183,11 +183,21 @@ void WalletFrame::changePassphrase() walletView->changePassphrase(); } -void WalletFrame::unlockWallet() +void WalletFrame::unlockWallet(bool setContext) +{ + if (setContext) { + unlockWallet(AskPassphraseDialog::Context::Unlock_Full); + } + else { + unlockWallet(AskPassphraseDialog::Context::Unlock_Menu); + } +} + +void WalletFrame::unlockWallet(AskPassphraseDialog::Context context) { WalletView* walletView = currentWalletView(); if (walletView) - walletView->unlockWallet(); + walletView->unlockWallet(context); } void WalletFrame::lockWallet() diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index a66137e40f..6bd812fd90 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_QT_WALLETFRAME_H #define BITCOIN_QT_WALLETFRAME_H +#include "askpassphrasedialog.h" + #include #include @@ -68,7 +70,8 @@ public slots: /** Change encrypted wallet passphrase */ void changePassphrase(); /** Ask for passphrase to unlock wallet temporarily */ - void unlockWallet(); + void unlockWallet(AskPassphraseDialog::Context context); + void unlockWallet(bool setContext); /** Lock wallet */ void lockWallet(); /** Toggle Wallet Lock State */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 502f9797ce..1b5db91c8a 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -534,7 +534,7 @@ void WalletModel::unsubscribeFromCoreSignals() } // WalletModel::UnlockContext implementation -WalletModel::UnlockContext WalletModel::requestUnlock(bool relock) +WalletModel::UnlockContext WalletModel::requestUnlock(AskPassphraseDialog::Context context, bool relock) { bool was_locked = getEncryptionStatus() == Locked; @@ -546,7 +546,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock(bool relock) if (was_locked) { // Request UI to unlock wallet - emit requireUnlock(); + emit requireUnlock(context); } // If wallet is still locked, unlock was failed or cancelled, mark context as invalid bool valid = getEncryptionStatus() != Locked; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 0d44f88875..4e8ffc34fe 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_QT_WALLETMODEL_H #define BITCOIN_QT_WALLETMODEL_H +#include "askpassphrasedialog.h" #include "paymentrequestplus.h" #include "walletmodeltransaction.h" @@ -202,7 +203,7 @@ class WalletModel : public QObject void CopyFrom(const UnlockContext& rhs); }; - UnlockContext requestUnlock(bool relock = false); + UnlockContext requestUnlock(AskPassphraseDialog::Context context, bool relock = false); CWallet* getCWallet(); @@ -262,7 +263,7 @@ class WalletModel : public QObject // Signal emitted when wallet needs to be unlocked // It is valid behaviour for listeners to keep the wallet locked after this signal; // this means that the unlocking failed or was cancelled. - void requireUnlock(); + void requireUnlock(AskPassphraseDialog::Context context); // Fired when a message should be reported to the user void message(const QString& title, const QString& message, unsigned int style); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 6a90e1ad2f..3fe33f89b4 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -5,7 +5,6 @@ #include "walletview.h" #include "addressbookpage.h" -#include "askpassphrasedialog.h" #include "bip38tooldialog.h" #include "bitcoingui.h" #include "blockexplorer.h" @@ -159,7 +158,7 @@ void WalletView::setWalletModel(WalletModel* walletModel) this, SLOT(processNewTransaction(QModelIndex, int, int))); // Ask for passphrase if needed - connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + connect(walletModel, SIGNAL(requireUnlock(AskPassphraseDialog::Context)), this, SLOT(unlockWallet(AskPassphraseDialog::Context))); // Show progress dialog connect(walletModel, SIGNAL(showProgress(QString, int)), this, SLOT(showProgress(QString, int))); @@ -256,7 +255,8 @@ void WalletView::encryptWallet(bool status) { if (!walletModel) return; - AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt : AskPassphraseDialog::Decrypt, this, walletModel); + AskPassphraseDialog dlg(status ? AskPassphraseDialog::Mode::Encrypt : AskPassphraseDialog::Mode::Decrypt, this, + walletModel, AskPassphraseDialog::Context::Encrypt); dlg.exec(); updateEncryptionStatus(); @@ -282,18 +282,18 @@ void WalletView::backupWallet() void WalletView::changePassphrase() { - AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this, walletModel); + AskPassphraseDialog dlg(AskPassphraseDialog::Mode::ChangePass, this, walletModel, AskPassphraseDialog::Context::ChangePass); dlg.exec(); } -void WalletView::unlockWallet() +void WalletView::unlockWallet(AskPassphraseDialog::Context context) { if (!walletModel) return; // Unlock wallet when requested by wallet model if (walletModel->getEncryptionStatus() == WalletModel::Locked || walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly) { - AskPassphraseDialog dlg(AskPassphraseDialog::UnlockAnonymize, this, walletModel); + AskPassphraseDialog dlg(AskPassphraseDialog::Mode::UnlockAnonymize, this, walletModel, context); dlg.exec(); } } @@ -315,7 +315,7 @@ void WalletView::toggleLockWallet() // Unlock the wallet when requested if (encStatus == walletModel->Locked) { - AskPassphraseDialog dlg(AskPassphraseDialog::UnlockAnonymize, this, walletModel); + AskPassphraseDialog dlg(AskPassphraseDialog::Mode::UnlockAnonymize, this, walletModel, AskPassphraseDialog::Context::ToggleLock); dlg.exec(); } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index c8990ed942..bbc5f192de 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_WALLETVIEW_H #include "amount.h" +#include "askpassphrasedialog.h" #include "masternodelist.h" #include @@ -106,7 +107,7 @@ public slots: /** Change encrypted wallet passphrase */ void changePassphrase(); /** Ask for passphrase to unlock wallet temporarily */ - void unlockWallet(); + void unlockWallet(AskPassphraseDialog::Context context); /** Lock wallet */ void lockWallet(); /** Toggle wallet lock state */ From e9f5d1dc5870ca3fb57f6b9099bfa97691156f47 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 23 Feb 2020 15:08:31 -0500 Subject: [PATCH 0221/1888] Remove UnlockDialog --- contrib/dapscoin-qt.pro | 2 - src/Makefile.qt.include | 4 -- src/qt/dapscoin.cpp | 8 +-- src/qt/forms/unlockdialog.ui | 131 ----------------------------------- src/qt/overviewpage.cpp | 26 +++---- src/qt/overviewpage.h | 1 - src/qt/unlockdialog.cpp | 50 ------------- src/qt/unlockdialog.h | 32 --------- 8 files changed, 10 insertions(+), 244 deletions(-) delete mode 100644 src/qt/forms/unlockdialog.ui delete mode 100644 src/qt/unlockdialog.cpp delete mode 100644 src/qt/unlockdialog.h diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index a318b3944a..c811111b8d 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -235,7 +235,6 @@ HEADERS += src/activemasternode.h \ src/qt/transactiontablemodel.h \ src/qt/transactionview.h \ src/qt/txentry.h \ - src/qt/unlockdialog.h \ src/qt/utilitydialog.h \ src/qt/walletframe.h \ src/qt/walletmodel.h \ @@ -559,7 +558,6 @@ SOURCES += src/activemasternode.cpp \ src/qt/transactiontablemodel.cpp \ src/qt/transactionview.cpp \ src/qt/txentry.cpp \ - src/qt/unlockdialog.cpp \ src/qt/utilitydialog.cpp \ src/qt/walletframe.cpp \ src/qt/walletmodel.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3e3bed670a..143a600c40 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -68,7 +68,6 @@ QT_FORMS_UI = \ qt/forms/togglebutton.ui \ qt/forms/transactiondescdialog.ui \ qt/forms/txentry.ui \ - qt/forms/unlockdialog.ui \ qt/forms/lockdialog.ui \ qt/forms/importorcreate.ui \ qt/forms/entermnemonics.ui @@ -132,7 +131,6 @@ QT_MOC_CPP = \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp \ - qt/moc_unlockdialog.cpp \ qt/moc_lockdialog.cpp \ qt/moc_importorcreate.cpp \ qt/moc_entermnemonics.cpp @@ -224,7 +222,6 @@ BITCOIN_QT_H = \ qt/walletmodeltransaction.h \ qt/walletview.h \ qt/winshutdownmonitor.h \ - qt/unlockdialog.h \ qt/lockdialog.h \ qt/importorcreate.h \ qt/entermnemonics.h @@ -368,7 +365,6 @@ BITCOIN_QT_CPP += \ qt/walletmodel.cpp \ qt/walletmodeltransaction.cpp \ qt/walletview.cpp \ - qt/unlockdialog.cpp \ qt/lockdialog.cpp \ qt/importorcreate.cpp \ qt/entermnemonics.cpp diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 851293ed59..49f01802bf 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -41,7 +41,6 @@ #endif #include "encryptdialog.h" -#include "unlockdialog.h" #include "entermnemonics.h" #include @@ -500,11 +499,8 @@ void BitcoinApplication::initializeResult(int retval) QTimer::singleShot(100, paymentServer, SLOT(uiReady())); if (pwalletMain) { if (walletModel->getEncryptionStatus() == WalletModel::Locked) { - UnlockDialog unlockdlg; - unlockdlg.setWindowTitle("Unlock Keychain Wallet"); - unlockdlg.setModel(walletModel); - unlockdlg.setStyleSheet(GUIUtil::loadStyleSheet()); - if (unlockdlg.exec() == QDialog::Accepted) { + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); + if (ctx.isValid()) { walletUnlocked = true; if (fLiteMode) { pwalletMain->WriteStakingStatus(false); diff --git a/src/qt/forms/unlockdialog.ui b/src/qt/forms/unlockdialog.ui deleted file mode 100644 index 28df5ebc38..0000000000 --- a/src/qt/forms/unlockdialog.ui +++ /dev/null @@ -1,131 +0,0 @@ - - - UnlockDialog - - - - 0 - 0 - 488 - 186 - - - - - 0 - 0 - - - - Transaction Details - - - - 30 - - - - - - - Enter your passphrase: - - - Qt::AlignCenter - - - - - - - (Wallet may appear not responding as it rescans for all transactions) - - - - - - - - - 30 - - - 20 - - - 10 - - - 20 - - - 10 - - - - - - 0 - 0 - - - - - 0 - 40 - - - - - 0 - 0 - - - - false - - - Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData - - - QLineEdit::Password - - - - - - - - - - - - 50 - - - 100 - - - 100 - - - - - Unlock - - - - - - - Cancel - - - - - - - - - - diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 956bfc8163..a0965253e4 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -7,7 +7,6 @@ #include "overviewpage.h" #include "ui_overviewpage.h" -#include "unlockdialog.h" #include "lockdialog.h" #include "bitcoinunits.h" #include "clientmodel.h" @@ -525,12 +524,14 @@ void OverviewPage::refreshRecentTransactions() { void OverviewPage::on_lockUnlock() { if (walletModel->getEncryptionStatus() == WalletModel::Locked || walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly) { - UnlockDialog unlockdlg; - unlockdlg.setWindowTitle("Unlock Keychain Wallet"); - unlockdlg.setModel(walletModel); - unlockdlg.setStyleSheet(GUIUtil::loadStyleSheet()); - connect(&unlockdlg, SIGNAL(finished (int)), this, SLOT(unlockDialogIsFinished(int))); - unlockdlg.exec(); + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); + if (ctx.isValid()) { + ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/unlock) 0 0 0 0 stretch stretch; width: 30px;"); + ui->labelBalance_2->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getBalance(), false, BitcoinUnits::separatorAlways)); + ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getSpendableBalance(), false, BitcoinUnits::separatorAlways)); + ui->labelUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getUnconfirmedBalance(), false, BitcoinUnits::separatorAlways)); + pwalletMain->stakingMode = StakingMode::STAKING_WITH_CONSOLIDATION; + } } else { LockDialog lockdlg; @@ -542,17 +543,6 @@ void OverviewPage::on_lockUnlock() { } } - -void OverviewPage::unlockDialogIsFinished(int result) { - if(result == QDialog::Accepted){ - ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/unlock) 0 0 0 0 stretch stretch; width: 30px;"); - ui->labelBalance_2->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getBalance(), false, BitcoinUnits::separatorAlways)); - ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getSpendableBalance(), false, BitcoinUnits::separatorAlways)); - ui->labelUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, walletModel->getUnconfirmedBalance(), false, BitcoinUnits::separatorAlways)); - pwalletMain->stakingMode = StakingMode::STAKING_WITH_CONSOLIDATION; - } -} - void OverviewPage::lockDialogIsFinished(int result) { if(result == QDialog::Accepted){ ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/lock) 0 0 0 0 stretch stretch; width: 20px;"); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index e5c8a3651b..905200eac2 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -96,7 +96,6 @@ private slots: void updateAlerts(const QString& warnings); void updateWatchOnlyLabels(bool showWatchOnly); void on_lockUnlock(); - void unlockDialogIsFinished(int result); void lockDialogIsFinished(int result); void updateLockStatus(int status); }; diff --git a/src/qt/unlockdialog.cpp b/src/qt/unlockdialog.cpp deleted file mode 100644 index e267295a59..0000000000 --- a/src/qt/unlockdialog.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "unlockdialog.h" -#include "ui_unlockdialog.h" - -#include "guiconstants.h" -#include "allocators.h" -#include "walletmodel.h" - -#include -#include - -UnlockDialog::UnlockDialog(QWidget *parent) : - QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), - model(0), - ui(new Ui::UnlockDialog) -{ - ui->setupUi(this); - - ui->txtpassphrase->setMaxLength(MAX_PASSPHRASE_SIZE); - - connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_unlock())); - connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); - -} - -UnlockDialog::~UnlockDialog() -{ - delete ui; -} - -void UnlockDialog::on_unlock() -{ - if (!model) - reject(); - - SecureString pass; - pass.reserve(MAX_PASSPHRASE_SIZE); - pass.assign(ui->txtpassphrase->text().toStdString().c_str()); - - if (!model->setWalletLocked(false, pass)) { - QMessageBox::critical(this, tr("Wallet unlock failed"), - tr("The passphrase entered for the wallet decryption was incorrect.")); - } else { - accept(); - } -} - -void UnlockDialog::setModel(WalletModel* model) -{ - this->model = model; -} \ No newline at end of file diff --git a/src/qt/unlockdialog.h b/src/qt/unlockdialog.h deleted file mode 100644 index cd4be2a910..0000000000 --- a/src/qt/unlockdialog.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef UNLOCKDIALOG_H -#define UNLOCKDIALOG_H - -#include -#include - -class WalletModel; - -namespace Ui { -class UnlockDialog; -} - -class UnlockDialog : public QDialog -{ - Q_OBJECT - -public: - explicit UnlockDialog(QWidget *parent = 0); - ~UnlockDialog(); - - void setModel(WalletModel* model); - -private slots: - void on_unlock(); - -private: - Ui::UnlockDialog *ui; - WalletModel* model; - QSettings settings; -}; - -#endif // UNLOCKDIALOG_H From 485699c03a1d2070b467f3c0d01036ae770e40e5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 23 Feb 2020 16:01:32 -0500 Subject: [PATCH 0222/1888] Update unlock texts --- src/qt/askpassphrasedialog.cpp | 3 ++- src/qt/forms/askpassphrasedialog.ui | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 8876172ba7..b78632c111 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -50,9 +50,10 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel break; ui->anonymizationCheckBox->setChecked(false); ui->anonymizationCheckBox->hide(); - ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); case Mode::UnlockAnonymize: case Mode::Unlock: // Ask passphrase + ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.

    (Wallet may appear not responding as it rescans for all transactions)

    ")); + ui->warningLabel->setAlignment(Qt::AlignHCenter); ui->passLabel2->hide(); ui->passEdit2->hide(); ui->passLabel3->hide(); diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui index ad07731c5e..65aad9069a 100644 --- a/src/qt/forms/askpassphrasedialog.ui +++ b/src/qt/forms/askpassphrasedialog.ui @@ -113,14 +113,14 @@ true + + false + Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - For anonymization and staking only - - - false + For staking only
    From 4b0439a852aa76a22c50a3f76c3cdb3fe95f29e0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 23 Feb 2020 18:23:13 -0500 Subject: [PATCH 0223/1888] Remove LockDialog --- contrib/dapscoin-qt.pro | 2 - src/Makefile.qt.include | 4 -- src/qt/forms/lockdialog.ui | 85 ------------------------------------ src/qt/locale/dapscoin_en.ts | 63 -------------------------- src/qt/lockdialog.cpp | 33 -------------- src/qt/lockdialog.h | 32 -------------- src/qt/overviewpage.cpp | 27 +++++------- src/qt/overviewpage.h | 1 - 8 files changed, 10 insertions(+), 237 deletions(-) delete mode 100644 src/qt/forms/lockdialog.ui delete mode 100644 src/qt/lockdialog.cpp delete mode 100644 src/qt/lockdialog.h diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index c811111b8d..466e233aaf 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -197,7 +197,6 @@ HEADERS += src/activemasternode.h \ src/qt/historypage.h \ src/qt/importorcreate.h \ src/qt/intro.h \ - src/qt/lockdialog.h \ src/qt/macdockiconhandler.h \ src/qt/macnotificationhandler.h \ src/qt/masternodelist.h \ @@ -522,7 +521,6 @@ SOURCES += src/activemasternode.cpp \ src/qt/historypage.cpp \ src/qt/importorcreate.cpp \ src/qt/intro.cpp \ - src/qt/lockdialog.cpp \ src/qt/masternodelist.cpp \ src/qt/multisenddialog.cpp \ src/qt/multisigdialog.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 143a600c40..127dcbcb86 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -68,7 +68,6 @@ QT_FORMS_UI = \ qt/forms/togglebutton.ui \ qt/forms/transactiondescdialog.ui \ qt/forms/txentry.ui \ - qt/forms/lockdialog.ui \ qt/forms/importorcreate.ui \ qt/forms/entermnemonics.ui @@ -131,7 +130,6 @@ QT_MOC_CPP = \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp \ - qt/moc_lockdialog.cpp \ qt/moc_importorcreate.cpp \ qt/moc_entermnemonics.cpp @@ -222,7 +220,6 @@ BITCOIN_QT_H = \ qt/walletmodeltransaction.h \ qt/walletview.h \ qt/winshutdownmonitor.h \ - qt/lockdialog.h \ qt/importorcreate.h \ qt/entermnemonics.h @@ -365,7 +362,6 @@ BITCOIN_QT_CPP += \ qt/walletmodel.cpp \ qt/walletmodeltransaction.cpp \ qt/walletview.cpp \ - qt/lockdialog.cpp \ qt/importorcreate.cpp \ qt/entermnemonics.cpp diff --git a/src/qt/forms/lockdialog.ui b/src/qt/forms/lockdialog.ui deleted file mode 100644 index d59048024b..0000000000 --- a/src/qt/forms/lockdialog.ui +++ /dev/null @@ -1,85 +0,0 @@ - - - LockDialog - - - - 0 - 0 - 488 - 164 - - - - - 0 - 0 - - - - Transaction Details - - - - 30 - - - - - 20 - - - 20 - - - - - 3 - - - Would you like to lock your keychain wallet now? - -(Staking will also be stopped) - - - Qt::AlignCenter - - - true - - - - - - - - - 50 - - - 100 - - - 100 - - - - - Lock - - - - - - - Cancel - - - - - - - - - - diff --git a/src/qt/locale/dapscoin_en.ts b/src/qt/locale/dapscoin_en.ts index f990c5ed33..4ee3b00ae8 100644 --- a/src/qt/locale/dapscoin_en.ts +++ b/src/qt/locale/dapscoin_en.ts @@ -1896,31 +1896,6 @@ lowercase letters, numbers, symbols) (of %1 GB needed) - - LockDialog - - - Transaction Details - - - - - Would you like to lock your keychain wallet now? - -(Staking will also be stopped) - - - - - Lock - - - - - Cancel - - - MasternodeList @@ -5326,44 +5301,6 @@ Please try again. Unit to show amounts in. Click to select another unit. - - UnlockDialog - - - Transaction Details - - - - - Enter your passphrase: - - - - - (Wallet may appear not responding as it rescans for all transactions) - - - - - Unlock - - - - - Cancel - - - - - Wallet unlock failed - Wallet unlock failed - - - - The passphrase entered for the wallet decryption was incorrect. - The passphrase entered for the wallet decryption was incorrect. - - WalletFrame diff --git a/src/qt/lockdialog.cpp b/src/qt/lockdialog.cpp deleted file mode 100644 index 0b1189b90a..0000000000 --- a/src/qt/lockdialog.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "lockdialog.h" -#include "ui_lockdialog.h" -#include "walletmodel.h" - -#include - -LockDialog::LockDialog(QWidget *parent) : - QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), - model(0), - ui(new Ui::LockDialog) -{ - ui->setupUi(this); - - connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(on_lock())); - connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); - -} - -LockDialog::~LockDialog() -{ - delete ui; -} - -void LockDialog::on_lock() -{ - if (model->setWalletLocked(true)) - accept(); -} - -void LockDialog::setModel(WalletModel* model) -{ - this->model = model; -} \ No newline at end of file diff --git a/src/qt/lockdialog.h b/src/qt/lockdialog.h deleted file mode 100644 index 05302d270f..0000000000 --- a/src/qt/lockdialog.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef LOCKDIALOG_H -#define LOCKDIALOG_H - -#include -#include - -class WalletModel; - -namespace Ui { -class LockDialog; -} - -class LockDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LockDialog(QWidget *parent = 0); - ~LockDialog(); - - void setModel(WalletModel* model); - -private slots: - void on_lock(); - -private: - Ui::LockDialog *ui; - WalletModel* model; - QSettings settings; -}; - -#endif // LOCKDIALOG_H diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index a0965253e4..ee070139dd 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -7,7 +7,6 @@ #include "overviewpage.h" #include "ui_overviewpage.h" -#include "lockdialog.h" #include "bitcoinunits.h" #include "clientmodel.h" #include "guiconstants.h" @@ -534,22 +533,16 @@ void OverviewPage::on_lockUnlock() { } } else { - LockDialog lockdlg; - lockdlg.setWindowTitle("Lock Keychain Wallet"); - lockdlg.setModel(walletModel); - lockdlg.setStyleSheet(GUIUtil::loadStyleSheet()); - connect(&lockdlg, SIGNAL(finished (int)), this, SLOT(lockDialogIsFinished(int))); - lockdlg.exec(); - } -} - -void OverviewPage::lockDialogIsFinished(int result) { - if(result == QDialog::Accepted){ - ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/lock) 0 0 0 0 stretch stretch; width: 20px;"); - ui->labelBalance_2->setText("Locked; Hidden"); - ui->labelBalance->setText("Locked; Hidden"); - ui->labelUnconfirmed->setText("Locked; Hidden"); - pwalletMain->stakingMode = StakingMode::STOPPED; + QMessageBox::StandardButton msgReply; + msgReply = QMessageBox::question(this, "Lock Keychain Wallet", "Would you like to lock your keychain wallet now?\n\n(Staking will also be stopped)", QMessageBox::Yes|QMessageBox::No); + if (msgReply == QMessageBox::Yes) { + walletModel->setWalletLocked(true); + ui->btnLockUnlock->setStyleSheet("border-image: url(:/images/lock) 0 0 0 0 stretch stretch; width: 20px;"); + ui->labelBalance_2->setText("Locked; Hidden"); + ui->labelBalance->setText("Locked; Hidden"); + ui->labelUnconfirmed->setText("Locked; Hidden"); + pwalletMain->stakingMode = StakingMode::STOPPED; + } } } diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 905200eac2..032c4ddc6a 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -96,7 +96,6 @@ private slots: void updateAlerts(const QString& warnings); void updateWatchOnlyLabels(bool showWatchOnly); void on_lockUnlock(); - void lockDialogIsFinished(int result); void updateLockStatus(int status); }; From fdb9ebbfd25d738951c3f468dc1544744d3d690f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 21:00:21 -0500 Subject: [PATCH 0224/1888] Bump version to v1.0.6.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1a38355fd0..95921e7bb9 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From f95b280899800bd32c6a889ba18511c9b5305f0b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 22:49:13 -0500 Subject: [PATCH 0225/1888] Remove unused functions in wallet.cpp these functions were used back when obfuscation existed and are no longer called anywhere in the source tree. --- src/wallet/wallet.cpp | 287 ------------------------------------------ src/wallet/wallet.h | 12 -- 2 files changed, 299 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6b356da76d..cee7793b06 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2065,119 +2065,6 @@ CAmount CWallet::GetLockedCoins() const } -CAmount CWallet::GetAnonymizableBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizableCredit(); - } - } - - return nTotal; -} - -CAmount CWallet::GetAnonymizedBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizedCredit(); - } - } - - return nTotal; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -double CWallet::GetAverageAnonymizedRounds() -{ - if (fLiteMode) return 0; - - double fTotal = 0; - double fCount = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - int rounds = GetInputObfuscationRounds(vin); - fTotal += (float)rounds; - fCount += 1; - } - } - } - - if (fCount == 0) return 0; - - return fTotal / fCount; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -CAmount CWallet::GetNormalizedAnonymizedBalance() -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - if (pcoin->GetDepthInMainChain() < 0) continue; - } - } - } - - return nTotal; -} - -CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - nTotal += pcoin->GetDenominatedCredit(unconfirmed); - } - } - - return nTotal; -} - CAmount CWallet::GetUnconfirmedBalance() const { CAmount nTotal = 0; @@ -3023,49 +2910,6 @@ bool CWallet::IsMasternodeController() return masternodeConfig.getEntries().size() > 0; } -bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) -{ - CCoinControl* coinControl = NULL; - - setCoinsRet.clear(); - nValueRet = 0; - - std::vector vCoins; - AvailableCoins(vCoins, true, coinControl, false, nObfuscationRoundsMin < 0 ? ONLY_NONDENOMINATED_NOT1000000IFMN : ONLY_DENOMINATED); - - set > setCoinsRet2; - - //order the array so largest nondenom are first, then denominations, then very small inputs. - sort(vCoins.rbegin(), vCoins.rend(), CompareByPriority()); - - for (const COutput& out : vCoins) { - //do not allow inputs less than 1 CENT - CAmount outValue = getCTxOutValue(*out.tx, out.tx->vout[out.i]); - if (outValue < CENT) continue; - //do not allow collaterals to be selected - - if (IsCollateralAmount(getCTxOutValue(*out.tx, out.tx->vout[out.i]))) continue; - if (fMasterNode && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == 1000000 * COIN) continue; //masternode input - - if (nValueRet + outValue <= nValueMax) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += outValue; - setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); - } - } - - // if it's more than min, we're good to return - if (nValueRet >= nValueMin) return true; - - return false; -} bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) { @@ -3092,33 +2936,6 @@ bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nV return false; } -int CWallet::CountInputsWithAmount(CAmount nInputAmount) -{ - CAmount nTotal = 0; - { - LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - if (pcoin->IsTrusted()) { - int nDepth = pcoin->GetDepthInMainChain(false); - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - COutput out = COutput(pcoin, i, nDepth, true); - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - if (getCOutPutValue(out) != nInputAmount) continue; - if (!IsDenominatedAmount(getCTxOutValue(*pcoin, pcoin->vout[i]))) continue; - if (IsSpent(out.tx->GetHash(), i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - nTotal++; - } - } - } - } - - return nTotal; -} - bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) { std::vector vCoins; @@ -3136,61 +2953,6 @@ bool CWallet::IsCollateralAmount(CAmount nInputAmount) const return nInputAmount != 0 && nInputAmount % OBFUSCATION_COLLATERAL == 0 && nInputAmount < OBFUSCATION_COLLATERAL * 5 && nInputAmount > OBFUSCATION_COLLATERAL; } -bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) -{ - /* - To doublespend a collateral transaction, it will require a fee higher than this. So there's - still a significant cost. - */ - CAmount nFeeRet = 1 * COIN; - - txCollateral.vin.clear(); - txCollateral.vout.clear(); - - CReserveKey reservekey(this); - CAmount nValueIn2 = 0; - std::vector vCoinsCollateral; - - if (!SelectCoinsCollateral(vCoinsCollateral, nValueIn2)) { - strReason = "Error: Obfuscation requires a collateral transaction and could not locate an acceptable input!"; - return false; - } - - // make our change address - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey); - reservekey.KeepKey(); - - for (CTxIn v : vCoinsCollateral) - txCollateral.vin.push_back(v); - - if (nValueIn2 - OBFUSCATION_COLLATERAL - nFeeRet > 0) { - //pay collateral charge in fees - CTxOut vout3 = CTxOut(nValueIn2 - OBFUSCATION_COLLATERAL, scriptChange); - CPubKey sharedSec; - CKey view; - myViewPrivateKey(view); - EncodeTxOutAmount(vout3, vout3.nValue, 0); - txCollateral.vout.push_back(vout3); - } - - int vinNumber = 0; - for (CTxIn v : txCollateral.vin) { - if (!SignSignature(*this, v.prevPubKey, txCollateral, vinNumber, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { - for (CTxIn v : vCoinsCollateral) - UnlockCoin(v.prevout); - - strReason = "CObfuscationPool::Sign - Unable to sign collateral transaction! \n"; - return false; - } - vinNumber++; - } - - return true; -} - bool CWallet::GetBudgetSystemCollateralTX(CTransaction& tx, uint256 hash, bool useIX) { CWalletTx wtx; @@ -3224,23 +2986,6 @@ bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useI return true; } - -bool CWallet::ConvertList(std::vector vCoins, std::vector& vecAmounts) -{ - for (CTxIn i : vCoins) { - COutPoint prevout = findMyOutPoint(i); - if (mapWallet.count(prevout.hash)) { - CWalletTx& wtx = mapWallet[prevout.hash]; - if (prevout.n < wtx.vout.size()) { - vecAmounts.push_back(getCTxOutValue(wtx, wtx.vout[prevout.n])); - } - } else { - LogPrintf("ConvertList -- Couldn't find transaction\n"); - } - } - return true; -} - bool CWallet::CreateCommitment(const CAmount val, CKey& blind, std::vector& commitment) { blind.MakeNewKey(true); @@ -4792,24 +4537,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge return nFeeNeeded; } -CAmount CWallet::GetTotalValue(std::vector vCoins) -{ - CAmount nTotalValue = 0; - CWalletTx wtx; - for (CTxIn i : vCoins) { - COutPoint prevout = findMyOutPoint(i); - if (mapWallet.count(prevout.hash)) { - CWalletTx& wtx = mapWallet[prevout.hash]; - if (prevout.n < wtx.vout.size()) { - nTotalValue += wtx.vout[prevout.n].nValue; - } - } else { - LogPrintf("GetTotalValue -- Couldn't find transaction\n"); - } - } - return nTotalValue; -} - string CWallet::PrepareObfuscationDenominate(int minRounds, int maxRounds) { if (IsLocked()) @@ -5656,20 +5383,6 @@ bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, c return true; } -bool CWallet::GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const -{ - std::map::const_iterator i = mapAddressBook.find(dest); - if (i != mapAddressBook.end()) { - CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); - if (j != i->second.destdata.end()) { - if (value) - *value = j->second; - return true; - } - } - return false; -} - bool CWallet::SendAll(std::string des) { if (this->IsLocked()) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 632d60b1e9..21009365b7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -263,13 +263,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool MintableCoins(); StakingStatusError StakingCoinStatus(CAmount& minFee, CAmount& maxFee); bool SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) ; - bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) ; bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax); bool SelectCoinsDarkDenominated(CAmount nTargetValue, std::vector& setCoinsRet, CAmount& nValueRet) ; bool HasCollateralInputs(bool fOnlyConfirmed = true); bool IsCollateralAmount(CAmount nInputAmount) const; bool IsMasternodeController(); - int CountInputsWithAmount(CAmount nInputAmount); bool checkPassPhraseRule(const char *pass); COutPoint findMyOutPoint(const CTxIn& txin) const; bool SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet); @@ -393,7 +391,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void UnlockCoin(COutPoint& output); void UnlockAllCoins(); void ListLockedCoins(std::vector& vOutpts); - CAmount GetTotalValue(std::vector vCoins); // keystore implementation // Generate a new key @@ -436,8 +433,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool EraseDestData(const CTxDestination& dest, const std::string& key); //! Adds a destination data tuple to the store, without saving it to disk bool LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value); - //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const; //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnly(const CScript& dest); @@ -479,11 +474,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetUnlockedCoins() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; - CAmount GetAnonymizableBalance() const; - CAmount GetAnonymizedBalance() const; - double GetAverageAnonymizedRounds(); - CAmount GetNormalizedAnonymizedBalance(); - CAmount GetDenominatedBalance(bool unconfirmed = false) const; CAmount GetWatchOnlyBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; @@ -524,8 +514,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); std::string PrepareObfuscationDenominate(int minRounds, int maxRounds); int GenerateObfuscationOutputs(int nTotalValue, std::vector& vout); - bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); - bool ConvertList(std::vector vCoins, std::vector& vecAmounts); bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); bool MultiSend(); void AutoCombineDust(); From 54b3fc999b081b0ed623a0c41fd6a40adabefdc8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 23:42:57 -0500 Subject: [PATCH 0226/1888] Remove more useless obfuscation code --- src/init.cpp | 4 - src/main.cpp | 1 - src/obfuscation.cpp | 1269 -------------------------------------- src/obfuscation.h | 137 ---- src/qt/optionsdialog.cpp | 1 - src/wallet/wallet.cpp | 482 --------------- src/wallet/wallet.h | 14 - 7 files changed, 1908 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index d8cfb4fb37..dc615431c1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1857,10 +1857,6 @@ bool AppInit2(bool isDaemon) obfuScationDenominations.push_back((10 * COIN) + 10000); obfuScationDenominations.push_back((1 * COIN) + 1000); obfuScationDenominations.push_back((.1 * COIN) + 100); - /* Disabled till we need them - obfuScationDenominations.push_back( (.01 * COIN)+10 ); - obfuScationDenominations.push_back( (.001 * COIN)+1 ); - */ obfuScationPool.InitCollateralAddress(); diff --git a/src/main.cpp b/src/main.cpp index 5238cc2bf8..9d091809c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6459,7 +6459,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } else { //probably one the extensions - obfuScationPool.ProcessMessageObfuscation(pfrom, strCommand, vRecv); mnodeman.ProcessMessage(pfrom, strCommand, vRecv); budget.ProcessMessage(pfrom, strCommand, vRecv); masternodePayments.ProcessMessageMasternodePayments(pfrom, strCommand, vRecv); diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 2c6831dd89..6e9df699c7 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -38,349 +38,12 @@ map mapObfuscationBroadcastTxes; // Keep track of the active Masternode CActiveMasternode activeMasternode; -/* *** BEGIN OBFUSCATION MAGIC - DAPS ********** - Copyright (c) 2014-2015, Dash Developers - eduffield - evan@dashpay.io - udjinm6 - udjinm6@dashpay.io -*/ - -void CObfuscationPool::ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) -{ - if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality - if (!masternodeSync.IsBlockchainSynced()) return; - - if (strCommand == "dsa") { //Obfuscation Accept Into Pool - - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - errorID = ERR_VERSION; - LogPrintf("dsa -- incompatible version! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - errorID = ERR_NOT_A_MN; - LogPrintf("dsa -- not a Masternode! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - int nDenom; - CTransaction txCollateral; - vRecv >> nDenom >> txCollateral; - - CMasternode* pmn = mnodeman.Find(activeMasternode.vin); - if (pmn == NULL) { - errorID = ERR_MN_LIST; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (sessionUsers == 0) { - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrintf("dsa -- last dsq too recent, must wait. %s \n", pfrom->addr.ToString()); - errorID = ERR_RECENT; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - if (!IsCompatibleWithSession(nDenom, txCollateral, errorID)) { - LogPrintf("dsa -- not compatible with existing transactions! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } else { - LogPrintf("dsa -- is compatible, please submit! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - return; - } - - } else if (strCommand == "dsq") { //Obfuscation Queue - TRY_LOCK(cs_obfuscation, lockRecv); - if (!lockRecv) return; - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - CObfuscationQueue dsq; - vRecv >> dsq; - - CService addr; - if (!dsq.GetAddress(addr)) return; - if (!dsq.CheckSignature()) return; - - if (dsq.IsExpired()) return; - - CMasternode* pmn = mnodeman.Find(dsq.vin); - if (pmn == NULL) return; - - // if the queue is ready, submit if we can - if (dsq.ready) { - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)addr) { - LogPrintf("dsq - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), addr.ToString()); - return; - } - - if (state == POOL_STATUS_QUEUE) { - LogPrint("obfuscation", "Obfuscation queue is ready - %s\n", addr.ToString()); - PrepareObfuscationDenominate(); - } - } else { - for (CObfuscationQueue q : vecObfuscationQueue) { - if (q.vin == dsq.vin) return; - } - - LogPrint("obfuscation", "dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size() / 5, mnodeman.nDsqCount); - //don't allow a few nodes to dominate the queuing process - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrint("obfuscation", "dsq -- Masternode sending too many dsq messages. %s \n", pmn->addr.ToString()); - return; - } - mnodeman.nDsqCount++; - pmn->nLastDsq = mnodeman.nDsqCount; - pmn->allowFreeTx = true; - - LogPrint("obfuscation", "dsq - new Obfuscation queue object - %s\n", addr.ToString()); - vecObfuscationQueue.push_back(dsq); - dsq.Relay(); - dsq.time = GetTime(); - } - - } else if (strCommand == "dsi") { //ObfuScation vIn - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - LogPrintf("dsi -- incompatible version! \n"); - errorID = ERR_VERSION; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - LogPrintf("dsi -- not a Masternode! \n"); - errorID = ERR_NOT_A_MN; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - std::vector in; - CAmount nAmount; - CTransaction txCollateral; - std::vector out; - vRecv >> in >> nAmount >> txCollateral >> out; - - //do we have enough users in the current session? - if (!IsSessionReady()) { - LogPrintf("dsi -- session not complete! \n"); - errorID = ERR_SESSION; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //do we have the same denominations as the current session? - if (!IsCompatibleWithEntries(out)) { - LogPrintf("dsi -- not compatible with existing transactions! \n"); - errorID = ERR_EXISTING_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //check it like a transaction - { - CAmount nValueIn = 0; - CAmount nValueOut = 0; - bool missingTx = false; - - CValidationState state; - CMutableTransaction tx; - - for (const CTxOut &o : out) { - nValueOut += o.nValue; - tx.vout.push_back(o); - - if (o.scriptPubKey.size() != 25) { - LogPrintf("dsi - non-standard pubkey detected! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_NON_STANDARD_PUBKEY; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("dsi - invalid script! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_INVALID_SCRIPT; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - for (const CTxIn &i : in) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } - - if (nValueIn > OBFUSCATION_POOL_MAX) { - LogPrintf("dsi -- more than Obfuscation pool max! %s\n", tx.ToString()); - errorID = ERR_MAXIMUM; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (!missingTx) { - if (nValueIn - nValueOut > nValueIn * .01) { - LogPrintf("dsi -- fees are too high! %s\n", tx.ToString()); - errorID = ERR_FEES; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } else { - LogPrintf("dsi -- missing input tx! %s\n", tx.ToString()); - errorID = ERR_MISSING_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - { - LOCK(cs_main); - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! \n"); - errorID = ERR_INVALID_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - } - - if (AddEntry(in, nAmount, txCollateral, out, errorID)) { - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - Check(); - - RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); - } else { - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - } - - } else if (strCommand == "dssu") { //Obfuscation status update - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - return; - } - - int sessionIDMessage; - int state; - int entriesCount; - int accepted; - int errorID; - vRecv >> sessionIDMessage >> state >> entriesCount >> accepted >> errorID; - - LogPrint("obfuscation", "dssu - state: %i entriesCount: %i accepted: %i error: %s \n", state, entriesCount, accepted, GetMessageByID(errorID)); - - if ((accepted != 1 && accepted != 0) && sessionID != sessionIDMessage) { - LogPrintf("dssu - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - StatusUpdate(state, entriesCount, accepted, errorID, sessionIDMessage); - - } else if (strCommand == "dss") { //Obfuscation Sign Final Tx - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - vector sigs; - vRecv >> sigs; - - bool success = false; - int count = 0; - - for (const CTxIn &item : sigs) { - if (AddScriptSig(item)) success = true; - LogPrint("obfuscation", " -- sigs count %d %d\n", (int)sigs.size(), count); - count++; - } - - if (success) { - obfuScationPool.Check(); - RelayStatus(obfuScationPool.sessionID, obfuScationPool.GetState(), obfuScationPool.GetEntriesCount(), MASTERNODE_RESET); - } - } else if (strCommand == "dsf") { //Obfuscation Final tx - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - return; - } - - int sessionIDMessage; - CTransaction txNew; - vRecv >> sessionIDMessage >> txNew; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsf - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - //check to see if input is spent already? (and probably not confirmed) - SignFinalTransaction(txNew, pfrom); - - } else if (strCommand == "dsc") { //Obfuscation Complete - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - return; - } - - int sessionIDMessage; - bool error; - int errorID; - vRecv >> sessionIDMessage >> error >> errorID; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsc - message doesn't match current Obfuscation session %d %d\n", obfuScationPool.sessionID, sessionIDMessage); - return; - } - - obfuScationPool.CompletedTransaction(error, errorID); - } -} - int randomizeList(int i) { return secp256k1_rand32() % i; } void CObfuscationPool::Reset() { cachedLastSuccess = 0; lastNewBlock = 0; - txCollateral = CMutableTransaction(); vecMasternodesUsed.clear(); UnlockCoins(); SetNull(); @@ -396,7 +59,6 @@ void CObfuscationPool::SetNull() entriesCount = 0; lastEntryAccepted = 0; countEntriesAccepted = 0; - sessionFoundMasternode = false; // Both sides state = POOL_STATUS_IDLE; @@ -906,196 +568,6 @@ void CObfuscationPool::CheckForCompleteQueue() } } -// check to see if the signature is valid -bool CObfuscationPool::SignatureValid(const CScript& newSig, const CTxIn& newVin) -{ - CMutableTransaction txNew; - txNew.vin.clear(); - txNew.vout.clear(); - - int found = -1; - CScript sigPubKey = CScript(); - unsigned int i = 0; - - for (CObfuScationEntry& e : entries) { - for (const CTxOut& out : e.vout) - txNew.vout.push_back(out); - - for (const CTxDSIn& s : e.sev) { - txNew.vin.push_back(s); - - if (s == newVin) { - found = i; - sigPubKey = s.prevPubKey; - } - i++; - } - } - - if (found >= 0) { //might have to do this one input at a time? - int n = found; - txNew.vin[n].scriptSig = newSig; - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0, 24)); - if (!VerifyScript(txNew.vin[n].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, n))) { - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Error signing input %u\n", n); - return false; - } - } - - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Successfully validated input\n"); - return true; -} - -// check to make sure the collateral provided by the client is valid -bool CObfuscationPool::IsCollateralValid(const CTransaction& txCollateral) -{ - if (txCollateral.vout.size() < 1) return false; - if (txCollateral.nLockTime != 0) return false; - - int64_t nValueIn = 0; - int64_t nValueOut = 0; - bool missingTx = false; - - for (const CTxOut &o : txCollateral.vout) { - nValueOut += o.nValue; - - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("CObfuscationPool::IsCollateralValid - Invalid Script %s\n", txCollateral.ToString()); - return false; - } - } - - for (const CTxIn &i : txCollateral.vin) { - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } - - if (missingTx) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString()); - return false; - } - - //collateral transactions are required to pay out OBFUSCATION_COLLATERAL as a fee to the miners - if (nValueIn - nValueOut < OBFUSCATION_COLLATERAL) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - did not include enough fees in transaction %d\n%s\n", nValueOut - nValueIn, txCollateral.ToString()); - return false; - } - - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid %s\n", txCollateral.ToString()); - - { - LOCK(cs_main); - CValidationState state; - if (!AcceptableInputs(mempool, state, txCollateral, true, NULL)) { - if (fDebug) LogPrintf("CObfuscationPool::IsCollateralValid - didn't pass IsAcceptable\n"); - return false; - } - } - - return true; -} - - -// -// Add a clients transaction to the pool -// -bool CObfuscationPool::AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID) -{ - if (!fMasterNode) return false; - - for (CTxIn in : newInput) { - if (in.prevout.IsNull() || nAmount < 0) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - input not valid!\n"); - errorID = ERR_INVALID_INPUT; - sessionUsers--; - return false; - } - } - - if (!IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - sessionUsers--; - return false; - } - - if ((int)entries.size() >= GetMaxPoolTransactions()) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - entries is full!\n"); - errorID = ERR_ENTRIES_FULL; - sessionUsers--; - return false; - } - - for (CTxIn in : newInput) { - LogPrint("obfuscation", "looking for vin -- %s\n", in.ToString()); - for (const CObfuScationEntry& v : entries) { - for (const CTxDSIn& s : v.sev) { - if ((CTxIn)s == in) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - found in vin\n"); - errorID = ERR_ALREADY_HAVE; - sessionUsers--; - return false; - } - } - } - } - - CObfuScationEntry v; - v.Add(newInput, nAmount, txCollateral, newOutput); - entries.push_back(v); - - LogPrint("obfuscation", "CObfuscationPool::AddEntry -- adding %s\n", newInput[0].ToString()); - errorID = MSG_ENTRIES_ADDED; - - return true; -} - -bool CObfuscationPool::AddScriptSig(const CTxIn& newVin) -{ - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- new sig %s\n", newVin.scriptSig.ToString().substr(0, 24)); - - - for (const CObfuScationEntry& v : entries) { - for (const CTxDSIn& s : v.sev) { - if (s.scriptSig == newVin.scriptSig) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - already exists\n"); - return false; - } - } - } - - if (!SignatureValid(newVin.scriptSig, newVin)) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - Invalid Sig\n"); - return false; - } - - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- sig %s\n", newVin.ToString()); - - for (CTxIn& vin : finalTransaction.vin) { - if (newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence) { - vin.scriptSig = newVin.scriptSig; - vin.prevPubKey = newVin.prevPubKey; - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding to finalTransaction %s\n", newVin.scriptSig.ToString().substr(0, 24)); - } - } - for (unsigned int i = 0; i < entries.size(); i++) { - if (entries[i].AddSig(newVin)) { - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding %s\n", newVin.scriptSig.ToString().substr(0, 24)); - return true; - } - } - - LogPrintf("CObfuscationPool::AddScriptSig -- Couldn't set sig!\n"); - return false; -} - // Check to make sure everything is signed bool CObfuscationPool::SignaturesComplete() { @@ -1107,220 +579,6 @@ bool CObfuscationPool::SignaturesComplete() return true; } -// -// Execute a Obfuscation denomination via a Masternode. -// This is only ran from clients -// -void CObfuscationPool::SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount) -{ - if (fMasterNode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Obfuscation from a Masternode is not supported currently.\n"); - return; - } - - // lock the funds we're going to use - for (CTxIn in : txCollateral.vin) - lockedCoins.push_back(in); - - for (CTxIn in : vin) - lockedCoins.push_back(in); - - // we should already be connected to a Masternode - if (!sessionFoundMasternode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - No Masternode has been selected yet.\n"); - UnlockCoins(); - SetNull(); - return; - } - - if (!CheckDiskSpace()) { - UnlockCoins(); - SetNull(); - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Not enough disk space, disabling Obfuscation.\n"); - return; - } - - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Added transaction to pool.\n"); - - ClearLastMessage(); - - //check it against the memory pool to make sure it's valid - { - CAmount nValueOut = 0; - - CValidationState state; - CMutableTransaction tx; - - for (const CTxOut& o : vout) { - nValueOut += o.nValue; - tx.vout.push_back(o); - } - - for (const CTxIn& i : vin) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - } - - LogPrintf("Submitting tx %s\n", tx.ToString()); - - while (true) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) { - MilliSleep(50); - continue; - } - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! %s \n", tx.ToString()); - UnlockCoins(); - SetNull(); - return; - } - break; - } - } - - // store our entry for later use - CObfuScationEntry e; - e.Add(vin, amount, txCollateral, vout); - entries.push_back(e); - - RelayIn(entries[0].sev, entries[0].amount, txCollateral, entries[0].vout); - Check(); -} - -// Incoming message from Masternode updating the progress of Obfuscation -// newAccepted: -1 mean's it'n not a "transaction accepted/not accepted" message, just a standard update -// 0 means transaction was not accepted -// 1 means transaction was accepted - -bool CObfuscationPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID) -{ - if (fMasterNode) return false; - if (state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; - - UpdateState(newState); - entriesCount = newEntriesCount; - - if (errorID != MSG_NOERR) strAutoDenomResult = _("Masternode:") + " " + GetMessageByID(errorID); - - if (newAccepted != -1) { - lastEntryAccepted = newAccepted; - countEntriesAccepted += newAccepted; - if (newAccepted == 0) { - UpdateState(POOL_STATUS_ERROR); - lastMessage = GetMessageByID(errorID); - } - - if (newAccepted == 1 && newSessionID != 0) { - sessionID = newSessionID; - LogPrintf("CObfuscationPool::StatusUpdate - set sessionID to %d\n", sessionID); - sessionFoundMasternode = true; - } - } - - if (newState == POOL_STATUS_ACCEPTING_ENTRIES) { - if (newAccepted == 1) { - LogPrintf("CObfuscationPool::StatusUpdate - entry accepted! \n"); - sessionFoundMasternode = true; - //wait for other users. Masternode will report when ready - UpdateState(POOL_STATUS_QUEUE); - } else if (newAccepted == 0 && sessionID == 0 && !sessionFoundMasternode) { - LogPrintf("CObfuscationPool::StatusUpdate - entry not accepted by Masternode \n"); - UnlockCoins(); - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - DoAutomaticDenominating(); //try another Masternode - } - if (sessionFoundMasternode) return true; - } - - return true; -} - -// -// After we receive the finalized transaction from the Masternode, we must -// check it to make sure it's what we want, then sign it if we agree. -// If we refuse to sign, it's possible we'll be charged collateral -// -bool CObfuscationPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node) -{ - if (fMasterNode) return false; - - finalTransaction = finalTransactionNew; - LogPrintf("CObfuscationPool::SignFinalTransaction %s", finalTransaction.ToString()); - - vector sigs; - - //make sure my inputs/outputs are present, otherwise refuse to sign - for (const CObfuScationEntry &e : entries) { - for (const CTxDSIn &s : e.sev) { - /* Sign my transaction and all outputs */ - int mine = -1; - CScript prevPubKey = CScript(); - CTxIn vin = CTxIn(); - - for (unsigned int i = 0; i < finalTransaction.vin.size(); i++) { - if (finalTransaction.vin[i] == s) { - mine = i; - prevPubKey = s.prevPubKey; - vin = s; - } - } - - if (mine >= 0) { //might have to do this one input at a time? - int foundOutputs = 0; - CAmount nValue1 = 0; - CAmount nValue2 = 0; - - for (unsigned int i = 0; i < finalTransaction.vout.size(); i++) { - for (const CTxOut& o : e.vout) { - if (finalTransaction.vout[i] == o) { - foundOutputs++; - nValue1 += finalTransaction.vout[i].nValue; - } - } - } - - for (const CTxOut &o : e.vout) - nValue2 += o.nValue; - - int targetOuputs = e.vout.size(); - if (foundOutputs < targetOuputs || nValue1 != nValue2) { - // in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's - // better then signing if the transaction doesn't look like what we wanted. - LogPrintf("CObfuscationPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs); - UnlockCoins(); - SetNull(); - - return false; - } - - const CKeyStore& keystore = *pwalletMain; - - LogPrint("obfuscation", "CObfuscationPool::Sign - Signing my input %i\n", mine); - if (!SignSignature(keystore, prevPubKey, finalTransaction, mine, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig - LogPrint("obfuscation", "CObfuscationPool::Sign - Unable to sign my own transaction! \n"); - // not sure what to do here, it will timeout...? - } - - sigs.push_back(finalTransaction.vin[mine]); - LogPrint("obfuscation", " -- dss %d %d %s\n", mine, (int)sigs.size(), finalTransaction.vin[mine].scriptSig.ToString()); - } - } - - LogPrint("obfuscation", "CObfuscationPool::Sign - txNew:\n%s", finalTransaction.ToString()); - } - - // push all of our signatures to the Masternode - if (sigs.size() > 0 && node != NULL) - node->PushMessage("dss", sigs); - - - return true; -} - void CObfuscationPool::NewBlock() { LogPrint("obfuscation", "CObfuscationPool::NewBlock \n"); @@ -1332,490 +590,6 @@ void CObfuscationPool::NewBlock() obfuScationPool.CheckTimeout(); } -// Obfuscation transaction was completed (failed or successful) -void CObfuscationPool::CompletedTransaction(bool error, int errorID) -{ - if (fMasterNode) return; - - if (error) { - LogPrintf("CompletedTransaction -- error \n"); - UpdateState(POOL_STATUS_ERROR); - - Check(); - UnlockCoins(); - SetNull(); - } else { - LogPrintf("CompletedTransaction -- success \n"); - UpdateState(POOL_STATUS_SUCCESS); - - UnlockCoins(); - SetNull(); - - // To avoid race conditions, we'll only let DS run once per block - cachedLastSuccess = chainActive.Tip()->nHeight; - } - lastMessage = GetMessageByID(errorID); -} - -void CObfuscationPool::ClearLastMessage() -{ - lastMessage = ""; -} - -// -// Passively run Obfuscation in the background to anonymize funds based on the given configuration. -// -// This does NOT run by default for daemons, only for QT. -// -bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) -{ - return false; // Disabled until Obfuscation is completely removed -} - - -bool CObfuscationPool::PrepareObfuscationDenominate() -{ - std::string strError = ""; - - // We failed? That's strange but let's just make final attempt and try to mix everything - strError = pwalletMain->PrepareObfuscationDenominate(0, 0); - LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for all rounds. Return '%s'\n", strError); - if (strError == "") return true; - - // Should never actually get here but just in case - strAutoDenomResult = strError; - LogPrintf("DoAutomaticDenominating : Error running denominate, %s\n", strError); - return false; -} - -bool CObfuscationPool::SendRandomPaymentToSelf() -{ - int64_t nBalance = pwalletMain->GetBalance(); - int64_t nPayment = (nBalance * 0.35) + (secp256k1_rand32() % nBalance); - - if (nPayment > nBalance) nPayment = nBalance - (0.1 * COIN); - - // make our change address - CReserveKey reservekey(pwalletMain); - - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey); - - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - - // ****** Add fees ************ / - vecSend.push_back(make_pair(scriptChange, nPayment)); - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRet, strFail, coinControl, ONLY_DENOMINATED); - if (!success) { - LogPrintf("SendRandomPaymentToSelf: Error - %s\n", strFail); - return false; - } - - pwalletMain->CommitTransaction(wtx, reservekey); - - LogPrintf("SendRandomPaymentToSelf Success: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -// Split up large inputs or create fee sized inputs -bool CObfuscationPool::MakeCollateralAmounts() -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - CCoinControl coinControl; - coinControl.fAllowOtherInputs = false; - coinControl.fAllowWatchOnly = false; - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey); - - vecSend.push_back(make_pair(scriptCollateral, OBFUSCATION_COLLATERAL * 4)); - - // try to use non-denominated and not mn-like funds - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, &coinControl, ONLY_NONDENOMINATED_NOT1000000IFMN); - if (!success) { - // if we failed (most likeky not enough funds), try to use all coins instead - - // MN-like funds should not be touched in any case and we can't mix denominated without collaterals anyway - CCoinControl* coinControlNull = NULL; - LogPrintf("MakeCollateralAmounts: ONLY_NONDENOMINATED_NOT10000IFMN Error - %s\n", strFail); - success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, coinControlNull, ONLY_NOT1000000IFMN); - if (!success) { - LogPrintf("MakeCollateralAmounts: ONLY_NOT10000IFMN Error - %s\n", strFail); - reservekeyCollateral.ReturnKey(); - return false; - } - } - - reservekeyCollateral.KeepKey(); - - LogPrintf("MakeCollateralAmounts: tx %s\n", wtx.GetHash().GetHex()); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (!pwalletMain->CommitTransaction(wtx, reservekeyChange)) { - LogPrintf("MakeCollateralAmounts: CommitTransaction failed!\n"); - return false; - } - - cachedLastSuccess = chainActive.Tip()->nHeight; - - return true; -} - -// Create denominations -bool CObfuscationPool::CreateDenominated(CAmount nTotalValue) -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - vector > vecSend; - CAmount nValueLeft = nTotalValue; - - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - // make our denom addresses - CReserveKey reservekeyDenom(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey); - - // ****** Add collateral outputs ************ / - if (!pwalletMain->HasCollateralInputs()) { - vecSend.push_back(make_pair(scriptCollateral, OBFUSCATION_COLLATERAL * 4)); - nValueLeft -= OBFUSCATION_COLLATERAL * 4; - } - - // ****** Add denoms ************ / - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= OBFUSCATION_COLLATERAL && nOutputs <= 10) { - CScript scriptDenom; - CPubKey vchPubKey; - //use a unique change address - assert(reservekeyDenom.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptDenom = GetScriptForDestination(vchPubKey); - // TODO: do not keep reservekeyDenom here - reservekeyDenom.KeepKey(); - - vecSend.push_back(make_pair(scriptDenom, v)); - - //increment outputs and subtract denomination amount - nOutputs++; - nValueLeft -= v; - LogPrintf("CreateDenominated1 %d\n", nValueLeft); - } - - if (nValueLeft == 0) break; - } - LogPrintf("CreateDenominated2 %d\n", nValueLeft); - - // if we have anything left over, it will be automatically send back as change - there is no need to send it manually - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, strFail, coinControl, ONLY_NONDENOMINATED_NOT1000000IFMN); - if (!success) { - LogPrintf("CreateDenominated: Error - %s\n", strFail); - // TODO: return reservekeyDenom here - reservekeyCollateral.ReturnKey(); - return false; - } - - // TODO: keep reservekeyDenom here - reservekeyCollateral.KeepKey(); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (pwalletMain->CommitTransaction(wtx, reservekeyChange)) - cachedLastSuccess = chainActive.Tip()->nHeight; - else - LogPrintf("CreateDenominated: CommitTransaction failed!\n"); - - LogPrintf("CreateDenominated: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -bool CObfuscationPool::IsCompatibleWithEntries(std::vector& vout) -{ - if (GetDenominations(vout) == 0) return false; - - for (const CObfuScationEntry &v : entries) { - LogPrintf(" IsCompatibleWithEntries %d %d\n", GetDenominations(vout), GetDenominations(v.vout)); - if (GetDenominations(vout) != GetDenominations(v.vout)) return false; - } - - return true; -} - -bool CObfuscationPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, int& errorID) -{ - if (nDenom == 0) return false; - - LogPrintf("CObfuscationPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers); - - if (!unitTest && !IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::IsCompatibleWithSession - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - return false; - } - - if (sessionUsers < 0) sessionUsers = 0; - - if (sessionUsers == 0) { - sessionID = 1 + (secp256k1_rand32() % 999999); - sessionDenom = nDenom; - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - - if (!unitTest) { - //broadcast that I'm accepting entries, only if it's the first entry through - CObfuscationQueue dsq; - dsq.nDenom = nDenom; - dsq.vin = activeMasternode.vin; - dsq.time = GetTime(); - dsq.Sign(); - dsq.Relay(); - } - - UpdateState(POOL_STATUS_QUEUE); - vecSessionCollateral.push_back(txCollateral); - return true; - } - - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()) { - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE)) errorID = ERR_MODE; - if (sessionUsers >= GetMaxPoolTransactions()) errorID = ERR_QUEUE_FULL; - LogPrintf("CObfuscationPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions()); - return false; - } - - if (nDenom != sessionDenom) { - errorID = ERR_DENOM; - return false; - } - - LogPrintf("CObfuScationPool::IsCompatibleWithSession - compatible\n"); - - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - vecSessionCollateral.push_back(txCollateral); - - return true; -} - -//create a nice string to show the denominations -void CObfuscationPool::GetDenominationsToString(int nDenom, std::string& strDenom) -{ - // Function returns as follows: - // - // bit 0 - 100DAPS+1 ( bit on if present ) - // bit 1 - 10DAPS+1 - // bit 2 - 1DAPS+1 - // bit 3 - .1DAPS+1 - // bit 3 - non-denom - - - strDenom = ""; - - if (nDenom & (1 << 0)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "100"; - } - - if (nDenom & (1 << 1)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "10"; - } - - if (nDenom & (1 << 2)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "1"; - } - - if (nDenom & (1 << 3)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "0.1"; - } -} - -int CObfuscationPool::GetDenominations(const std::vector& vout) -{ - std::vector vout2; - - for (CTxDSOut out : vout) - vout2.push_back(out); - - return GetDenominations(vout2); -} - -// return a bitshifted integer representing the denominations in this list -int CObfuscationPool::GetDenominations(const std::vector& vout, bool fSingleRandomDenom) -{ - std::vector > denomUsed; - - // make a list of denominations, with zero uses - for (int64_t d : obfuScationDenominations) - denomUsed.push_back(make_pair(d, 0)); - - // look for denominations and update uses to 1 - for (CTxOut out : vout) { - bool found = false; - for (PAIRTYPE(int64_t, int) & s : denomUsed) { - if (out.nValue == s.first) { - s.second = 1; - found = true; - } - } - if (!found) return 0; - } - - int denom = 0; - int c = 0; - // if the denomination is used, shift the bit on. - // then move to the next - for (PAIRTYPE(int64_t, int) & s : denomUsed) { - int bit = (fSingleRandomDenom ? secp256k1_rand32() % 2 : 1) * s.second; - denom |= bit << c++; - if (fSingleRandomDenom && bit) break; // use just one random denomination - } - - // Function returns as follows: - // - // bit 0 - 100DAPS+1 ( bit on if present ) - // bit 1 - 10DAPS+1 - // bit 2 - 1DAPS+1 - // bit 3 - .1DAPS+1 - - return denom; -} - - -int CObfuscationPool::GetDenominationsByAmounts(std::vector& vecAmount) -{ - CScript e = CScript(); - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, vecAmount) { - CTxOut o(v, e); - vout1.push_back(o); - } - - return GetDenominations(vout1, true); -} - -int CObfuscationPool::GetDenominationsByAmount(CAmount nAmount, int nDenomTarget) -{ - CScript e = CScript(); - CAmount nValueLeft = nAmount; - - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - if (nDenomTarget != 0) { - bool fAccepted = false; - if ((nDenomTarget & (1 << 0)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 1)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 2)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 3)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - } - - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= 0 && nOutputs <= 10) { - CTxOut o(v, e); - vout1.push_back(o); - nValueLeft -= v; - nOutputs++; - } - LogPrintf("GetDenominationsByAmount --- %d nOutputs %d\n", v, nOutputs); - } - - return GetDenominations(vout1); -} - -std::string CObfuscationPool::GetMessageByID(int messageID) -{ - switch (messageID) { - case ERR_ALREADY_HAVE: - return _("Already have that input."); - case ERR_DENOM: - return _("No matching denominations found for mixing."); - case ERR_ENTRIES_FULL: - return _("Entries are full."); - case ERR_EXISTING_TX: - return _("Not compatible with existing transactions."); - case ERR_FEES: - return _("Transaction fees are too high."); - case ERR_INVALID_COLLATERAL: - return _("Collateral not valid."); - case ERR_INVALID_INPUT: - return _("Input is not valid."); - case ERR_INVALID_SCRIPT: - return _("Invalid script detected."); - case ERR_INVALID_TX: - return _("Transaction not valid."); - case ERR_MAXIMUM: - return _("Value more than Obfuscation pool maximum allows."); - case ERR_MN_LIST: - return _("Not in the Masternode list."); - case ERR_MODE: - return _("Incompatible mode."); - case ERR_NON_STANDARD_PUBKEY: - return _("Non-standard public key detected."); - case ERR_NOT_A_MN: - return _("This is not a Masternode."); - case ERR_QUEUE_FULL: - return _("Masternode queue is full."); - case ERR_RECENT: - return _("Last Obfuscation was too recent."); - case ERR_SESSION: - return _("Session not complete!"); - case ERR_MISSING_TX: - return _("Missing input transaction information."); - case ERR_VERSION: - return _("Incompatible version."); - case MSG_SUCCESS: - return _("Transaction created successfully."); - case MSG_ENTRIES_ADDED: - return _("Your entries added successfully."); - case MSG_NOERR: - default: - return ""; - } -} - bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) { CScript payee2; @@ -1943,25 +717,6 @@ bool CObfuscationQueue::Relay() return true; } -bool CObfuscationQueue::CheckSignature() -{ - CMasternode* pmn = mnodeman.Find(vin); - - if (pmn != NULL) { - HEX_DATA_STREAM_PROTOCOL(pmn->protocolVersion) << vin.ToString() << nDenom << time << ready; - std::string strMessage = HEX_STR(ser); - std::string errorMessage = ""; - if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - return error("CObfuscationQueue::CheckSignature() - Got bad Masternode address signature %s \n", vin.ToString().c_str()); - } - - return true; - } - - return false; -} - - void CObfuscationPool::RelayFinalTransaction(const int sessionID, const CTransaction& txNew) { LOCK(cs_vNodes); @@ -1970,26 +725,6 @@ void CObfuscationPool::RelayFinalTransaction(const int sessionID, const CTransac } } -void CObfuscationPool::RelayIn(const std::vector& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& vout) -{ - if (!pSubmittedToMasternode) return; - - std::vector vin2; - std::vector vout2; - - for (CTxDSIn in : vin) - vin2.push_back(in); - - for (CTxDSOut out : vout) - vout2.push_back(out); - - CNode* pnode = FindNode(pSubmittedToMasternode->addr); - if (pnode != NULL) { - LogPrintf("RelayIn - found master, relaying message - %s \n", pnode->addr.ToString()); - pnode->PushMessage("dsi", vin2, nAmount, txCollateral, vout2); - } -} - void CObfuscationPool::RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID) { LOCK(cs_vNodes); @@ -2037,10 +772,6 @@ void ThreadCheckObfuScationPool() obfuScationPool.CheckTimeout(); obfuScationPool.CheckForCompleteQueue(); - - if (obfuScationPool.GetState() == POOL_STATUS_IDLE && c % 15 == 0) { - obfuScationPool.DoAutomaticDenominating(); - } } } } diff --git a/src/obfuscation.h b/src/obfuscation.h index 56268accd5..d75097c1e0 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -81,14 +81,11 @@ class CTxDSIn : public CTxIn class CTxDSOut : public CTxOut { public: - int nSentTimes; //times we've sent this anonymously - CTxDSOut(const CTxOut& out) { nValue = out.nValue; nRounds = out.nRounds; scriptPubKey = out.scriptPubKey; - nSentTimes = 0; } }; @@ -101,7 +98,6 @@ class CObfuScationEntry std::vector vout; CAmount amount; CTransaction collateral; - CTransaction txSupporting; int64_t addedTime; // time in UTC milliseconds CObfuScationEntry() @@ -132,24 +128,6 @@ class CObfuScationEntry return true; } - bool AddSig(const CTxIn& vin) - { - for (CTxDSIn& s : sev) { - if (s.prevout == vin.prevout && s.nSequence == vin.nSequence) { - if (s.fHasSig) { - return false; - } - s.scriptSig = vin.scriptSig; - s.prevPubKey = vin.prevPubKey; - s.fHasSig = true; - - return true; - } - } - - return false; - } - bool IsExpired() { return (GetTime() - addedTime) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds @@ -190,27 +168,6 @@ class CObfuscationQueue READWRITE(vchSig); } - bool GetAddress(CService& addr) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - addr = pmn->addr; - return true; - } - return false; - } - - /// Get the protocol version - bool GetProtocolVersion(int& protocolVersion) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - protocolVersion = pmn->protocolVersion; - return true; - } - return false; - } - /** Sign this Obfuscation transaction * \return true if all conditions are met: * 1) we have an active Masternode, @@ -228,8 +185,6 @@ class CObfuscationQueue return (GetTime() - time) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds } - /// Check if we have a valid Masternode address - bool CheckSignature(); }; /** Helper class to store Obfuscation transaction (tx) information. @@ -265,7 +220,6 @@ class CObfuScationSigner class CObfuscationPool { private: - mutable CCriticalSection cs_obfuscation; std::vector entries; // Masternode/clients entries CMutableTransaction finalTransaction; // the finalized transaction ready for signing @@ -280,18 +234,15 @@ class CObfuscationPool std::vector lockedCoins; std::string lastMessage; - bool unitTest; int sessionID; int sessionUsers; //N Users have said they'll join - bool sessionFoundMasternode; //If we've found a compatible Masternode std::vector vecSessionCollateral; int cachedLastSuccess; int minBlockSpacing; //required blocks between mixes - CMutableTransaction txCollateral; int64_t lastNewBlock; @@ -329,7 +280,6 @@ class CObfuscationPool CMasternode* pSubmittedToMasternode; int sessionDenom; //Users must submit an denom matching this - int cachedNumBlocks; //used for the overview screen CObfuscationPool() { @@ -337,42 +287,17 @@ class CObfuscationPool to behave themselves. If they don't it takes their money. */ cachedLastSuccess = 0; - cachedNumBlocks = std::numeric_limits::max(); - unitTest = false; - txCollateral = CMutableTransaction(); minBlockSpacing = 0; lastNewBlock = 0; SetNull(); } - /** Process a Obfuscation message using the Obfuscation protocol - * \param pfrom - * \param strCommand lower case command string; valid values are: - * Command | Description - * -------- | ----------------- - * dsa | Obfuscation Acceptable - * dsc | Obfuscation Complete - * dsf | Obfuscation Final tx - * dsi | Obfuscation vIn - * dsq | Obfuscation Queue - * dss | Obfuscation Signal Final Tx - * dssu | Obfuscation status update - * dssub | Obfuscation Subscribe To - * \param vRecv - */ - void ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); - void InitCollateralAddress() { SetCollateralAddress(Params().ObfuscationPoolDummyAddress()); } - void SetMinBlockSpacing(int minBlockSpacingIn) - { - minBlockSpacing = minBlockSpacingIn; - } - bool SetCollateralAddress(std::string strAddress); void Reset(); void SetNull(); @@ -396,12 +321,6 @@ class CObfuscationPool return entries.size(); } - /// Get the time the last entry was accepted (time in UTC milliseconds) - int GetLastEntryAccepted() const - { - return lastEntryAccepted; - } - /// Get the count of the accepted entries int GetCountEntriesAccepted() const { @@ -430,22 +349,6 @@ class CObfuscationPool return Params().PoolMaxTransactions(); } - /// Do we have enough users to take entries? - bool IsSessionReady() - { - return sessionUsers >= GetMaxPoolTransactions(); - } - - /// Are these outputs compatible with other client in the pool? - bool IsCompatibleWithEntries(std::vector& vout); - - /// Is this amount compatible with other client in the pool? - bool IsCompatibleWithSession(CAmount nAmount, CTransaction txCollateral, int& errorID); - - /// Passively run Obfuscation in the background according to the configuration in settings (only for QT) - bool DoAutomaticDenominating(bool fDryRun = false); - bool PrepareObfuscationDenominate(); - /// Check for process in Obfuscation void Check(); void CheckFinalTransaction(); @@ -455,57 +358,17 @@ class CObfuscationPool void ChargeRandomFees(); void CheckTimeout(); void CheckForCompleteQueue(); - /// Check to make sure a signature matches an input in the pool - bool SignatureValid(const CScript& newSig, const CTxIn& newVin); - /// If the collateral is valid given by a client - bool IsCollateralValid(const CTransaction& txCollateral); - /// Add a clients entry to the pool - bool AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID); - /// Add signature to a vin - bool AddScriptSig(const CTxIn& newVin); /// Check that all inputs are signed. (Are all inputs signed?) bool SignaturesComplete(); - /// As a client, send a transaction to a Masternode to start the denomination process - void SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount); - /// Get Masternode updates about the progress of Obfuscation - bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID = 0); - /// As a client, check and sign the final transaction - bool SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node); - - /// Get the last valid block hash for a given modulus - bool GetLastValidBlockHash(uint256& hash, int mod = 1, int nBlockHeight = 0); /// Process a new block void NewBlock(); - void CompletedTransaction(bool error, int errorID); - void ClearLastMessage(); - /// Used for liquidity providers - bool SendRandomPaymentToSelf(); - - /// Split up large inputs or make fee sized inputs - bool MakeCollateralAmounts(); - bool CreateDenominated(CAmount nTotalValue); - - /// Get the denominations for a list of outputs (returns a bitshifted integer) - int GetDenominations(const std::vector& vout, bool fSingleRandomDenom = false); - int GetDenominations(const std::vector& vout); - - void GetDenominationsToString(int nDenom, std::string& strDenom); - - /// Get the denominations for a specific amount of dapscoin. - int GetDenominationsByAmount(CAmount nAmount, int nDenomTarget = 0); // is not used anymore? - int GetDenominationsByAmounts(std::vector& vecAmount); - - std::string GetMessageByID(int messageID); // // Relay Obfuscation Messages // void RelayFinalTransaction(const int sessionID, const CTransaction& txNew); - void RelaySignaturesAnon(std::vector& vin); - void RelayInAnon(std::vector& vin, std::vector& vout); - void RelayIn(const std::vector& vin, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& vout); void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID = MSG_NOERR); void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID); }; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 8fd5f24e9a..ca272eff8c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -232,7 +232,6 @@ void OptionsDialog::on_resetButton_clicked() void OptionsDialog::on_okButton_clicked() { mapper->submit(); - obfuScationPool.cachedNumBlocks = std::numeric_limits::max(); if (pwalletMain) pwalletMain->MarkDirty(); accept(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cee7793b06..40276bcf68 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1270,93 +1270,6 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const return 0; } -// Recursively determine the rounds of a given input (How deep is the Obfuscation chain for a given input) -int CWallet::GetRealInputObfuscationRounds(CTxIn in, int rounds) const -{ - static std::map mDenomWtxes; - - if (rounds >= 16) return 15; // 16 rounds max - - uint256 hash = in.prevout.hash; - unsigned int nout = in.prevout.n; - - const CWalletTx* wtx = GetWalletTx(hash); - if (wtx != NULL) { - std::map::const_iterator mdwi = mDenomWtxes.find(hash); - // not known yet, let's add it - if (mdwi == mDenomWtxes.end()) { - LogPrint("obfuscation", "GetInputObfuscationRounds INSERTING %s\n", hash.ToString()); - mDenomWtxes[hash] = CMutableTransaction(*wtx); - } - // found and it's not an initial value, just return it - else if (mDenomWtxes[hash].vout[nout].nRounds != -10) { - return mDenomWtxes[hash].vout[nout].nRounds; - } - - - // bounds check - if (nout >= wtx->vout.size()) { - // should never actually hit this - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, -4); - return -4; - } - - if (pwalletMain->IsCollateralAmount(pwalletMain->getCTxOutValue(*wtx, wtx->vout[nout]))) { - mDenomWtxes[hash].vout[nout].nRounds = -3; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - //make sure the final output is non-denominate - if (!IsDenominatedAmount(pwalletMain->getCTxOutValue(*wtx, wtx->vout[nout]))) //NOT DENOM - { - mDenomWtxes[hash].vout[nout].nRounds = -2; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - bool fAllDenoms = true; - for (CTxOut out : wtx->vout) { - fAllDenoms = fAllDenoms && IsDenominatedAmount(pwalletMain->getCTxOutValue(*wtx, out)); - } - // this one is denominated but there is another non-denominated output found in the same tx - if (!fAllDenoms) { - mDenomWtxes[hash].vout[nout].nRounds = 0; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - int nShortest = -10; // an initial value, should be no way to get this by calculations - bool fDenomFound = false; - // only denoms here so let's look up - for (CTxIn in2 : wtx->vin) { - if (IsMine(in2)) { - int n = GetRealInputObfuscationRounds(in2, rounds + 1); - // denom found, find the shortest chain or initially assign nShortest with the first found value - if (n >= 0 && (n < nShortest || nShortest == -10)) { - nShortest = n; - fDenomFound = true; - } - } - } - mDenomWtxes[hash].vout[nout].nRounds = fDenomFound ? (nShortest >= 15 ? 16 : nShortest + 1) // good, we a +1 to the shortest one but only 16 rounds max allowed - : - 0; // too bad, we are the fist one in that chain - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - return rounds - 1; -} - -// respect current settings -int CWallet::GetInputObfuscationRounds(CTxIn in) const -{ - LOCK(cs_wallet); - int realObfuscationRounds = GetRealInputObfuscationRounds(in, 0); - return realObfuscationRounds > 0 ? 0 : realObfuscationRounds; -} - bool CWallet::IsDenominated(const CTxIn& txin) const { { @@ -1371,21 +1284,6 @@ bool CWallet::IsDenominated(const CTxIn& txin) const return false; } -bool CWallet::IsDenominated(const CTransaction& tx) const -{ - /* - Return false if ANY inputs are non-denom - */ - bool ret = true; - for (const CTxIn& txin : tx.vin) { - if (!IsDenominated(txin)) { - ret = false; - } - } - return ret; -} - - bool CWallet::IsDenominatedAmount(CAmount nInputAmount) const { for (CAmount d : obfuScationDenominations) @@ -1560,56 +1458,6 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const return nCredit; } -CAmount CWalletTx::GetAnonymizableCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizableCreditCached) - return nAnonymizableCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; - if (fMasterNode && pwallet->getCTxOutValue(*this, vout[i]) == 1000000 * COIN) continue; // do not count MN-like outputs - } - - nAnonymizableCreditCached = nCredit; - fAnonymizableCreditCached = true; - return nCredit; -} - -CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizedCreditCached) - return nAnonymizedCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxIn vin = CTxIn(hashTx, i); - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; - } - - nAnonymizedCreditCached = nCredit; - fAnonymizedCreditCached = true; - return nCredit; -} - // Return sum of unlocked coins CAmount CWalletTx::GetUnlockedCredit() const { @@ -1667,48 +1515,6 @@ CAmount CWalletTx::GetLockedCredit() const return nCredit; } -CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - int nDepth = GetDepthInMainChain(false); - if (nDepth < 0) return 0; - - bool isUnconfirmed = !IsFinalTx(*this) || (!IsTrusted() && nDepth == 0); - if (unconfirmed != isUnconfirmed) return 0; - - if (fUseCache) { - if (unconfirmed && fDenomUnconfCreditCached) - return nDenomUnconfCreditCached; - else if (!unconfirmed && fDenomConfCreditCached) - return nDenomConfCreditCached; - } - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(pwallet->getCTxOutValue(*this, txout))) continue; - - nCredit += pwallet->GetCredit(*this, txout, ISMINE_SPENDABLE); - } - - if (unconfirmed) { - nDenomUnconfCreditCached = nCredit; - fDenomUnconfCreditCached = true; - } else { - nDenomConfCreditCached = nCredit; - fDenomConfCreditCached = true; - } - return nCredit; -} - CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const { LOCK(cs_main); @@ -2765,13 +2571,6 @@ bool CWallet::SelectCoins(bool needFee, CAmount& estimatedFee, int ringSize, int if (!out.fSpendable) continue; - if (coin_type == ONLY_DENOMINATED) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = GetInputObfuscationRounds(vin); - // make sure it's actually anonymized - if (rounds < 0) continue; - } - nValueRet += getCOutPutValue(out); setCoinsRet.insert(make_pair(out.tx, out.i)); } @@ -2783,118 +2582,6 @@ bool CWallet::SelectCoins(bool needFee, CAmount& estimatedFee, int ringSize, int (bSpendZeroConfChange && SelectCoinsMinConf(needFee, estimatedFee, ringSize, numOut, nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); } -struct CompareByPriority { - bool operator()(const COutput& t1, - const COutput& t2) const - { - return t1.Priority() > t2.Priority(); - } -}; - -bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) -{ - vCoinsRet.clear(); - nValueRet = 0; - - vCoinsRet2.clear(); - std::vector vCoins; - AvailableCoins(vCoins, true, NULL, false, ONLY_DENOMINATED); - - std::random_shuffle(vCoins.rbegin(), vCoins.rend()); - - //keep track of each denomination that we have - bool fFound10000 = false; - bool fFound1000 = false; - bool fFound100 = false; - bool fFound10 = false; - bool fFound1 = false; - bool fFoundDot1 = false; - - //Check to see if any of the denomination are off, in that case mark them as fulfilled - if (!(nDenom & (1 << 0))) fFound10000 = true; - if (!(nDenom & (1 << 1))) fFound1000 = true; - if (!(nDenom & (1 << 2))) fFound100 = true; - if (!(nDenom & (1 << 3))) fFound10 = true; - if (!(nDenom & (1 << 4))) fFound1 = true; - if (!(nDenom & (1 << 5))) fFoundDot1 = true; - - for (const COutput& out : vCoins) { - // masternode-like input should not be selected by AvailableCoins now anyway - if (nValueRet + getCTxOutValue(*out.tx, out.tx->vout[out.i]) <= nValueMax) { - bool fAccepted = false; - - // Function returns as follows: - // - // bit 0 - 10000 DAPS+1 ( bit on if present ) - // bit 1 - 1000 DAPS+1 - // bit 2 - 100 DAPS+1 - // bit 3 - 10 DAPS+1 - // bit 4 - 1 DAPS+1 - // bit 5 - .1 DAPS+1 - - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - CAmount outValue = getCTxOutValue(*out.tx, out.tx->vout[out.i]); - if (fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1) { //if fulfilled - //we can return this for submission - if (nValueRet >= nValueMin) { - //random reduce the max amount we'll submit for anonymity - nValueMax -= (secp256k1_rand32() % (nValueMax / 5)); - //on average use 50% of the inputs or less - int r = (secp256k1_rand32() % (int)vCoins.size()); - if ((int)vCoinsRet.size() > r) return true; - } - //Denomination criterion has been met, we can take any matching denominations - if ((nDenom & (1 << 0)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 1)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 2)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenom & (1 << 3)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenom & (1 << 4)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenom & (1 << 5)) && getCTxOutValue(*out.tx, out.tx->vout[out.i]) == ((.1 * COIN) + 100)) { - fAccepted = true; - } - } else { - //Criterion has not been satisfied, we will only take 1 of each until it is. - if ((nDenom & (1 << 0)) && outValue == ((10000 * COIN) + 10000000)) { - fAccepted = true; - fFound10000 = true; - } else if ((nDenom & (1 << 1)) && outValue == ((1000 * COIN) + 1000000)) { - fAccepted = true; - fFound1000 = true; - } else if ((nDenom & (1 << 2)) && outValue == ((100 * COIN) + 100000)) { - fAccepted = true; - fFound100 = true; - } else if ((nDenom & (1 << 3)) && outValue == ((10 * COIN) + 10000)) { - fAccepted = true; - fFound10 = true; - } else if ((nDenom & (1 << 4)) && outValue == ((1 * COIN) + 1000)) { - fAccepted = true; - fFound1 = true; - } else if ((nDenom & (1 << 5)) && outValue == ((.1 * COIN) + 100)) { - fAccepted = true; - fFoundDot1 = true; - } - } - if (!fAccepted) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += outValue; - vCoinsRet.push_back(vin); - vCoinsRet2.push_back(out); - } - } - - return (nValueRet >= nValueMin && fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1); -} - bool CWallet::IsCollateralized(const COutPoint& outpoint) { for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { @@ -2910,44 +2597,6 @@ bool CWallet::IsMasternodeController() return masternodeConfig.getEntries().size() > 0; } - -bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) -{ - std::vector vCoins; - - AvailableCoins(vCoins); - - set > setCoinsRet2; - - for (const COutput& out : vCoins) { - // collateral inputs will always be a multiple of DARSEND_COLLATERAL, up to five - CAmount outValue = getCTxOutValue(*out.tx, out.tx->vout[out.i]); - if (IsCollateralAmount(outValue)) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += outValue; - setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); - return true; - } - } - - return false; -} - -bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) -{ - std::vector vCoins; - AvailableCoins(vCoins, fOnlyConfirmed); - - int nFound = 0; - for (const COutput& out : vCoins) - if (IsCollateralAmount(getCOutPutValue(out))) nFound++; - - return nFound > 0; -} - bool CWallet::IsCollateralAmount(CAmount nInputAmount) const { return nInputAmount != 0 && nInputAmount % OBFUSCATION_COLLATERAL == 0 && nInputAmount < OBFUSCATION_COLLATERAL * 5 && nInputAmount > OBFUSCATION_COLLATERAL; @@ -4537,137 +4186,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge return nFeeNeeded; } -string CWallet::PrepareObfuscationDenominate(int minRounds, int maxRounds) -{ - if (IsLocked()) - return _("Error: Wallet locked, unable to create transaction!"); - - if (obfuScationPool.GetState() != POOL_STATUS_ERROR && obfuScationPool.GetState() != POOL_STATUS_SUCCESS) - if (obfuScationPool.GetEntriesCount() > 0) - return _("Error: You already have pending entries in the Obfuscation pool"); - - // ** find the coins we'll use - std::vector vCoins; - std::vector vCoinsResult; - std::vector vCoins2; - CAmount nValueIn = 0; - CReserveKey reservekey(this); - - /* - Select the coins we'll use - - if minRounds >= 0 it means only denominated inputs are going in and coming out - */ - if (minRounds >= 0) { - if (!SelectCoinsByDenominations(obfuScationPool.sessionDenom, 0.1 * COIN, OBFUSCATION_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds)) - return _("Error: Can't select current denominated inputs"); - } - - LogPrintf("PrepareObfuscationDenominate - preparing obfuscation denominate . Got: %d \n", nValueIn); - - { - LOCK(cs_wallet); - for (CTxIn v : vCoins) - LockCoin(v.prevout); - } - - CAmount nValueLeft = nValueIn; - std::vector vOut; - - /* - TODO: Front load with needed denominations (e.g. .1, 1 ) - */ - - // Make outputs by looping through denominations: try to add every needed denomination, repeat up to 5-10 times. - // This way we can be pretty sure that it should have at least one of each needed denomination. - // NOTE: No need to randomize order of inputs because they were - // initially shuffled in CWallet::SelectCoinsByDenominations already. - int nStep = 0; - int nStepsMax = 5 + GetRandInt(5); - while (nStep < nStepsMax) { - for (CAmount v : obfuScationDenominations) { - // only use the ones that are approved - bool fAccepted = false; - if ((obfuScationPool.sessionDenom & (1 << 0)) && v == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 1)) && v == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 2)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 3)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 4)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 5)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - - // try to add it - if (nValueLeft - v >= 0) { - // Note: this relies on a fact that both vectors MUST have same size - std::vector::iterator it = vCoins.begin(); - std::vector::iterator it2 = vCoins2.begin(); - while (it2 != vCoins2.end()) { - // we have matching inputs - if ((*it2).tx->vout[(*it2).i].nValue == v) { - // add new input in resulting vector - vCoinsResult.push_back(*it); - // remove corresponting items from initial vectors - vCoins.erase(it); - vCoins2.erase(it2); - - CScript scriptChange; - CPubKey vchPubKey; - // use a unique change address - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey); - reservekey.KeepKey(); - - // add new output - CTxOut o(v, scriptChange); - vOut.push_back(o); - - // subtract denomination amount - nValueLeft -= v; - - break; - } - ++it; - ++it2; - } - } - } - - nStep++; - - if (nValueLeft == 0) break; - } - - { - // unlock unused coins - LOCK(cs_wallet); - for (CTxIn v : vCoins) - UnlockCoin(v.prevout); - } - - if (obfuScationPool.GetDenominations(vOut) != obfuScationPool.sessionDenom) { - // unlock used coins on failure - LOCK(cs_wallet); - for (CTxIn v : vCoinsResult) - UnlockCoin(v.prevout); - return "Error: can't make current denominated outputs"; - } - - // randomize the output order - std::random_shuffle(vOut.begin(), vOut.end()); - - // We also do not care about full amount as long as we have right denominations, just pass what we found - obfuScationPool.SendObfuscationDenominate(vCoinsResult, vOut, nValueIn - nValueLeft); - - return ""; -} - void CWallet::ScanWalletKeyImages() { if (IsLocked()) return; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 21009365b7..c14fccf471 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -263,14 +263,10 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool MintableCoins(); StakingStatusError StakingCoinStatus(CAmount& minFee, CAmount& maxFee); bool SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) ; - bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax); - bool SelectCoinsDarkDenominated(CAmount nTargetValue, std::vector& setCoinsRet, CAmount& nValueRet) ; - bool HasCollateralInputs(bool fOnlyConfirmed = true); bool IsCollateralAmount(CAmount nInputAmount) const; bool IsMasternodeController(); bool checkPassPhraseRule(const char *pass); COutPoint findMyOutPoint(const CTxIn& txin) const; - bool SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet); static int ComputeTxSize(size_t numIn, size_t numOut, size_t ringSize); void resetPendingOutPoints(); bool estimateStakingConsolidationFees(CAmount& min, CAmount& max); @@ -512,7 +508,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface AvailableCoinsType coin_type = ALL_COINS, bool useIX = false, CAmount nFeePay = 0); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand = "tx"); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); - std::string PrepareObfuscationDenominate(int minRounds, int maxRounds); int GenerateObfuscationOutputs(int nTotalValue, std::vector& vout); bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); bool MultiSend(); @@ -538,13 +533,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool GetBudgetSystemCollateralTX(CTransaction& tx, uint256 hash, bool useIX); bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX); - // get the Obfuscation chain depth for a given input - int GetRealInputObfuscationRounds(CTxIn in, int rounds) const; - // respect current settings - int GetInputObfuscationRounds(CTxIn in) const; - bool IsDenominated(const CTxIn& txin) const; - bool IsDenominated(const CTransaction& tx) const; bool IsDenominatedAmount(CAmount nInputAmount) const; @@ -889,11 +878,8 @@ class CWalletTx : public CMerkleTx CAmount GetCredit(const isminefilter& filter) const; CAmount GetImmatureCredit(bool fUseCache = true) const; CAmount GetAvailableCredit(bool fUseCache = true) const; - CAmount GetAnonymizableCredit(bool fUseCache = true) const; - CAmount GetAnonymizedCredit(bool fUseCache = true) const; // Return sum of unlocked coins CAmount GetLockedCredit() const; - CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const; CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const; From bba9d549920fb82a68a75ac522361a314aae6402 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 23:56:39 -0500 Subject: [PATCH 0227/1888] Remove more useless obfuscation code --- src/obfuscation.cpp | 66 --------------------------------------------- src/obfuscation.h | 2 -- 2 files changed, 68 deletions(-) diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 6e9df699c7..8b37c7ece1 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -108,72 +108,6 @@ void CObfuscationPool::UnlockCoins() lockedCoins.clear(); } -std::string CObfuscationPool::GetStatus() -{ - static int showingObfuScationMessage = 0; - showingObfuScationMessage += 10; - std::string suffix = ""; - - if (chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing || !masternodeSync.IsBlockchainSynced()) { - return strAutoDenomResult; - } - switch (state) { - case POOL_STATUS_IDLE: - return _("Obfuscation is idle."); - case POOL_STATUS_ACCEPTING_ENTRIES: - if (entriesCount == 0) { - showingObfuScationMessage = 0; - return strAutoDenomResult; - } else if (lastEntryAccepted == 1) { - if (showingObfuScationMessage % 10 > 8) { - lastEntryAccepted = 0; - showingObfuScationMessage = 0; - } - return _("Obfuscation request complete:") + " " + _("Your transaction was accepted into the pool!"); - } else { - std::string suffix = ""; - if (showingObfuScationMessage % 70 <= 40) - return strprintf(_("Submitted following entries to masternode: %u / %d"), entriesCount, GetMaxPoolTransactions()); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting for more entries ( %u / %d ) %s"), entriesCount, GetMaxPoolTransactions(), suffix); - } - case POOL_STATUS_SIGNING: - if (showingObfuScationMessage % 70 <= 40) - return _("Found enough users, signing ..."); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Found enough users, signing ( waiting %s )"), suffix); - case POOL_STATUS_TRANSMISSION: - return _("Transmitting final transaction."); - case POOL_STATUS_FINALIZE_TRANSACTION: - return _("Finalizing transaction."); - case POOL_STATUS_ERROR: - return _("Obfuscation request incomplete:") + " " + lastMessage + " " + _("Will retry..."); - case POOL_STATUS_SUCCESS: - return _("Obfuscation request complete:") + " " + lastMessage; - case POOL_STATUS_QUEUE: - if (showingObfuScationMessage % 70 <= 30) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 50) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting in queue %s"), suffix); - ; - default: - return strprintf(_("Unknown state: id = %u"), state); - } -} - // // Check the Obfuscation progress and send client updates if a Masternode // diff --git a/src/obfuscation.h b/src/obfuscation.h index d75097c1e0..c3582c7ecc 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -314,8 +314,6 @@ class CObfuscationPool return state; } - std::string GetStatus(); - int GetEntriesCount() const { return entries.size(); From 6b692895746506885843b11049a240bef9d57808 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 16:50:06 -0500 Subject: [PATCH 0228/1888] [Trivial] Move class below the global function declaration --- src/sync.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sync.h b/src/sync.h index cf37715aad..d73aaa6637 100644 --- a/src/sync.h +++ b/src/sync.h @@ -46,6 +46,20 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII // // /////////////////////////////// +#ifdef DEBUG_LOCKORDER +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +void LeaveCritical(); +std::string LocksHeld(); +void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); +void DeleteLock(void* cs); +#else +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +void static inline LeaveCritical() {} +void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} +void static inline DeleteLock(void* cs) {} +#endif +#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) + /** * Template mixin that adds -Wthread-safety locking * annotations to a subset of the mutex API. @@ -70,20 +84,6 @@ class LOCKABLE AnnotatedMixin : public PARENT } }; -#ifdef DEBUG_LOCKORDER -void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); -void LeaveCritical(); -std::string LocksHeld(); -void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); -void DeleteLock(void* cs); -#else -void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} -void static inline LeaveCritical() {} -void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} -void static inline DeleteLock(void* cs) {} -#endif -#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) - /** * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. From 16c61a95a232190c89fb273a7edaa40838f27ac6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 16:54:16 -0500 Subject: [PATCH 0229/1888] threadnames.h/cpp files created. --- src/Makefile.am | 2 ++ src/util/threadnames.cpp | 66 ++++++++++++++++++++++++++++++++++++++++ src/util/threadnames.h | 26 ++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 src/util/threadnames.cpp create mode 100644 src/util/threadnames.h diff --git a/src/Makefile.am b/src/Makefile.am index 947a7d63e9..c4870bd3db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -176,6 +176,7 @@ BITCOIN_CORE_H = \ uint256.h \ undo.h \ util.h \ + util/threadnames.h \ utilstrencodings.h \ utilmoneystr.h \ utiltime.h \ @@ -370,6 +371,7 @@ libbitcoin_util_a_SOURCES = \ uint256.cpp \ util.cpp \ utilstrencodings.cpp \ + util/threadnames.cpp \ utilmoneystr.cpp \ utiltime.cpp \ $(BITCOIN_CORE_H) diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp new file mode 100644 index 0000000000..f69e72dc81 --- /dev/null +++ b/src/util/threadnames.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2018-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) +#include +#include +#endif + +#include + +#ifdef HAVE_SYS_PRCTL_H +#include // For prctl, PR_SET_NAME, PR_GET_NAME +#endif + +//! Set the thread's name at the process level. Does not affect the +//! internal name. +static void SetThreadName(const char* name) +{ +#if defined(PR_SET_NAME) + // Only the first 15 characters are used (16 - NUL terminator) + ::prctl(PR_SET_NAME, name, 0, 0, 0); +#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) + pthread_set_name_np(pthread_self(), name); +#elif defined(MAC_OSX) + pthread_setname_np(name); +#else + // Prevent warnings for unused parameters... + (void)name; +#endif +} + +// If we have thread_local, just keep thread ID and name in a thread_local +// global. +#if defined(HAVE_THREAD_LOCAL) + +static thread_local std::string g_thread_name; +const std::string& util::ThreadGetInternalName() { return g_thread_name; } +//! Set the in-memory internal name for this thread. Does not affect the process +//! name. +static void SetInternalName(std::string name) { g_thread_name = std::move(name); } + +// Without thread_local available, don't handle internal name at all. +#else + +static const std::string empty_string; +const std::string& util::ThreadGetInternalName() { return empty_string; } +static void SetInternalName(std::string name) { } +#endif + +void util::ThreadRename(std::string&& name) +{ + SetThreadName(("b-" + name).c_str()); + SetInternalName(std::move(name)); +} + +void util::ThreadSetInternalName(std::string&& name) +{ + SetInternalName(std::move(name)); +} diff --git a/src/util/threadnames.h b/src/util/threadnames.h new file mode 100644 index 0000000000..64b2689cf1 --- /dev/null +++ b/src/util/threadnames.h @@ -0,0 +1,26 @@ +// Copyright (c) 2018-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_THREADNAMES_H +#define BITCOIN_UTIL_THREADNAMES_H + +#include + +namespace util { +//! Rename a thread both in terms of an internal (in-memory) name as well +//! as its system thread name. +//! @note Do not call this for the main thread, as this will interfere with +//! UNIX utilities such as top and killall. Use ThreadSetInternalName instead. +void ThreadRename(std::string&&); + +//! Set the internal (in-memory) name of the current thread only. +void ThreadSetInternalName(std::string&&); + +//! Get the thread's internal (in-memory) name; used e.g. for identification in +//! logging. +const std::string& ThreadGetInternalName(); + +} // namespace util + +#endif // BITCOIN_UTIL_THREADNAMES_H From c84fb90ab8397ddb7de230367b2fa660ad3cb315 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 17:01:50 -0500 Subject: [PATCH 0230/1888] [Refactor] RenameThread moved to the new util::ThreadRename. --- src/httpserver.cpp | 4 ++-- src/init.cpp | 5 +++-- src/main.cpp | 2 +- src/miner.cpp | 2 +- src/obfuscation.cpp | 2 +- src/util.cpp | 24 ------------------------ src/util.h | 4 ++-- src/wallet/walletdb.cpp | 2 +- 8 files changed, 11 insertions(+), 34 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 83038db010..6c3fb2a955 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -306,7 +306,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*) /** Event dispatcher thread */ static bool ThreadHTTP(struct event_base* base, struct evhttp* http) { - RenameThread("bitcoin-http"); + util::ThreadRename("bitcoin-http"); LogPrint("http", "Entering http event loop\n"); event_base_dispatch(base); // Event loop will be interrupted by InterruptHTTPServer() @@ -356,7 +356,7 @@ static bool HTTPBindAddresses(struct evhttp* http) /** Simple wrapper to set thread name and run work queue */ static void HTTPWorkQueueRun(WorkQueue* queue) { - RenameThread("bitcoin-httpworker"); + util::ThreadRename("bitcoin-httpworker"); queue->Run(); } diff --git a/src/init.cpp b/src/init.cpp index dc615431c1..af4d5b370e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -35,6 +35,7 @@ #include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" +#include "util/threadnames.h" #include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/db.h" @@ -188,7 +189,7 @@ void PrepareShutdown() /// for example if the data directory was found to be locked. /// Be sure that anything that writes files or flushes caches only does this if the respective /// module was initialized. - RenameThread("dapscoin-shutoff"); + util::ThreadRename("dapscoin-shutoff"); mempool.AddTransactionsUpdated(1); StopHTTPRPC(); StopREST(); @@ -649,7 +650,7 @@ struct CImportingNow { void ThreadImport(std::vector vImportFiles) { - RenameThread("dapscoin-loadblk"); + util::ThreadRename("dapscoin-loadblk"); // -reindex if (fReindex) { diff --git a/src/main.cpp b/src/main.cpp index 9d091809c4..1af2ce559e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2774,7 +2774,7 @@ static CCheckQueue scriptcheckqueue(128); void ThreadScriptCheck() { - RenameThread("dapscoin-scriptch"); + util::ThreadRename("dapscoin-scriptch"); scriptcheckqueue.Thread(); } diff --git a/src/miner.cpp b/src/miner.cpp index 9148357b8b..aba5fbaa2a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -650,7 +650,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) nDefaultMinerSleep = GetArg("-minersleep", 30000); LogPrintf("DAPScoinMiner started with %sms sleep time\n", nDefaultMinerSleep); SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("dapscoin-miner"); + util::ThreadRename("dapscoin-miner"); fGenerateDapscoins = true; // Each thread has its own key and counter CReserveKey reservekey(pwallet); diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 8b37c7ece1..f20a1a0c25 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -679,7 +679,7 @@ void ThreadCheckObfuScationPool() if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality // Make this thread recognisable as the wallet flushing thread - RenameThread("dapscoin-obfuscation"); + util::ThreadRename("dapscoin-obfuscation"); LogPrintf("Masternodes thread started\n"); unsigned int c = 0; diff --git a/src/util.cpp b/src/util.cpp index 4104bb371f..08f90c26eb 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -769,30 +769,6 @@ void runCommand(std::string strCommand) LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); } -void RenameThread(const char* name) -{ -#if defined(PR_SET_NAME) - // Only the first 15 characters are used (16 - NUL terminator) - ::prctl(PR_SET_NAME, name, 0, 0, 0); -#elif 0 && (defined(__FreeBSD__) || defined(__OpenBSD__)) - // TODO: This is currently disabled because it needs to be verified to work - // on FreeBSD or OpenBSD first. When verified the '0 &&' part can be - // removed. - pthread_set_name_np(pthread_self(), name); - -#elif defined(MAC_OSX) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) - -// pthread_setname_np is XCode 10.6-and-later -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 - pthread_setname_np(name); -#endif - -#else - // Prevent warnings for unused parameters... - (void)name; -#endif -} - void SetupEnvironment() { // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale diff --git a/src/util.h b/src/util.h index a5e28bd932..5c99abc9a2 100644 --- a/src/util.h +++ b/src/util.h @@ -20,6 +20,7 @@ #include "compat.h" #include "tinyformat.h" #include "utiltime.h" +#include "util/threadnames.h" #include #include @@ -212,7 +213,6 @@ std::string HelpMessageGroup(const std::string& message); std::string HelpMessageOpt(const std::string& option, const std::string& message); void SetThreadPriority(int nPriority); -void RenameThread(const char* name); /** @@ -222,7 +222,7 @@ template void TraceThread(const char* name, Callable func) { std::string s = strprintf("dapscoin-%s", name); - RenameThread(s.c_str()); + util::ThreadRename(s.c_str()); try { LogPrintf("%s thread start\n", name); func(); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7cc433116e..ee54872cfe 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -995,7 +995,7 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector& vWtx) void ThreadFlushWalletDB(const string& strFile) { // Make this thread recognisable as the wallet flushing thread - RenameThread("dapscoin-wallet"); + util::ThreadRename("dapscoin-wallet"); static bool fOneThread; if (fOneThread) From 5dd6b64ec4b51f402eccb6a8973065f9670b95f8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 17:03:47 -0500 Subject: [PATCH 0231/1888] Thread name added to the lock location struct. --- src/sync.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index d088d51474..891e5c9a6f 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -9,6 +9,7 @@ #include "util.h" #include "utilstrencodings.h" +#include "util/threadnames.h" #include @@ -36,23 +37,30 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine) // struct CLockLocation { - CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn) - { - mutexName = pszName; - sourceFile = pszFile; - sourceLine = nLine; - fTry = fTryIn; - } + CLockLocation( + const char* pszName, + const char* pszFile, + int nLine, + bool fTryIn, + const std::string& thread_name) + : fTry(fTryIn), + mutexName(pszName), + sourceFile(pszFile), + m_thread_name(thread_name), + sourceLine(nLine) {} std::string ToString() const { - return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); + return strprintf( + "%s %s:%s%s (in thread %s)", + mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name); } private: bool fTry; std::string mutexName; std::string sourceFile; + const std::string& m_thread_name; int sourceLine; }; @@ -130,7 +138,7 @@ static void pop_lock() void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry)); + push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName())); } void LeaveCritical() From 4c983bdee34d489ff7fefdae1575bc6316bbb880 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 17 Feb 2020 17:08:32 -0500 Subject: [PATCH 0232/1888] Refactor: Sync, GetLockData + few inlines with upstream's formatting. --- src/sync.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sync.cpp b/src/sync.cpp index 891e5c9a6f..c045dc0660 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -80,7 +80,11 @@ struct LockData { LockOrders lockorders; InvLockOrders invlockorders; std::mutex dd_mutex; -} static lockdata; +}; +LockData& GetLockData() { + static LockData lockdata; + return lockdata; +} static thread_local LockStack g_lockstack; @@ -88,22 +92,22 @@ static void potential_deadlock_detected(const std::pair& mismatch, { LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("Previous lock order was:\n"); - for (const std::pair& i : s2) { + for (const std::pair & i : s2) { if (i.first == mismatch.first) { - LogPrintf(" (1)"); + LogPrintf(" (1)"); /* Continued */ } if (i.first == mismatch.second) { - LogPrintf(" (2)"); + LogPrintf(" (2)"); /* Continued */ } LogPrintf(" %s\n", i.second.ToString()); } LogPrintf("Current lock order is:\n"); - for (const std::pair& i : s1) { + for (const std::pair & i : s1) { if (i.first == mismatch.first) { - LogPrintf(" (1)"); + LogPrintf(" (1)"); /* Continued */ } if (i.first == mismatch.second) { - LogPrintf(" (2)"); + LogPrintf(" (2)"); /* Continued */ } LogPrintf(" %s\n", i.second.ToString()); } @@ -111,6 +115,7 @@ static void potential_deadlock_detected(const std::pair& mismatch, static void push_lock(void* c, const CLockLocation& locklocation) { + LockData& lockdata = GetLockData(); std::lock_guard lock(lockdata.dd_mutex); g_lockstack.push_back(std::make_pair(c, locklocation)); @@ -122,7 +127,7 @@ static void push_lock(void* c, const CLockLocation& locklocation) std::pair p1 = std::make_pair(i.first, c); if (lockdata.lockorders.count(p1)) continue; - lockdata.lockorders[p1] = g_lockstack; + lockdata.lockorders.emplace(p1, g_lockstack); std::pair p2 = std::make_pair(c, i.first); lockdata.invlockorders.insert(p2); @@ -165,6 +170,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void DeleteLock(void* cs) { + LockData& lockdata = GetLockData(); if (!lockdata.available) { // We're already shutting down. return; From 6ac14e0c727f873ce9071565859eb881af8e1a2d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 18 Feb 2020 17:14:25 -0500 Subject: [PATCH 0233/1888] Sync.h: Upstream updates 1) Refactor: * Call sync.h primitives "locks" and "mutexes" instead of "blocks" and "waitable critical sections" to match current coding conventions and c++11 standard names. 2) Make LOCK, LOCK2, TRY_LOCK work with Mutex 3) WAIT_LOCK added. --- src/main.cpp | 2 +- src/main.h | 2 +- src/sync.h | 67 ++++++++++++++++++++++++++-------------------------- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1af2ce559e..b3476854b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,7 +63,7 @@ CBlockIndex* pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; // Best block section -CWaitableCriticalSection g_best_block_mutex; +Mutex g_best_block_mutex; std::condition_variable g_best_block_cv; uint256 g_best_block; diff --git a/src/main.h b/src/main.h index cfbbd72d14..443cb994df 100644 --- a/src/main.h +++ b/src/main.h @@ -142,7 +142,7 @@ extern const std::string strMessageMagic; extern int64_t nTimeBestReceived; // Best block section -extern CWaitableCriticalSection g_best_block_mutex; +extern Mutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; extern uint256 g_best_block; diff --git a/src/sync.h b/src/sync.h index d73aaa6637..8933ca15be 100644 --- a/src/sync.h +++ b/src/sync.h @@ -61,13 +61,17 @@ void static inline DeleteLock(void* cs) {} #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) /** - * Template mixin that adds -Wthread-safety locking - * annotations to a subset of the mutex API. + * Template mixin that adds -Wthread-safety locking annotations and lock order + * checking to a subset of the mutex API. */ template class LOCKABLE AnnotatedMixin : public PARENT { public: + ~AnnotatedMixin() { + DeleteLock((void*)this); + } + void lock() EXCLUSIVE_LOCK_FUNCTION() { PARENT::lock(); @@ -82,25 +86,17 @@ class LOCKABLE AnnotatedMixin : public PARENT { return PARENT::try_lock(); } + using UniqueLock = std::unique_lock; }; /** * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin -{ -public: - ~CCriticalSection() { - DeleteLock((void*)this); - } -}; +typedef AnnotatedMixin CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; - -/** Just a typedef for std::condition_variable, can be wrapped later if desired */ -typedef std::condition_variable CConditionVariable; +typedef AnnotatedMixin Mutex; /** Just a typedef for std::unique_lock, can be wrapped later if desired */ typedef std::unique_lock WaitableLock; @@ -109,20 +105,19 @@ typedef std::unique_lock WaitableLock; void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif -/** Wrapper around std::unique_lock */ -class SCOPED_LOCKABLE CCriticalBlock +/** Wrapper around std::unique_lock style lock for Mutex. */ +template +class SCOPED_LOCKABLE UniqueLock : public Base { private: - std::unique_lock lock; - void Enter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex())); #ifdef DEBUG_LOCKCONTENTION - if (!lock.try_lock()) { + if (!Base::try_lock()) { PrintLockContention(pszName, pszFile, nLine); #endif - lock.lock(); + Base::lock(); #ifdef DEBUG_LOCKCONTENTION } #endif @@ -130,15 +125,15 @@ class SCOPED_LOCKABLE CCriticalBlock bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); - lock.try_lock(); - if (!lock.owns_lock()) + EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true); + Base::try_lock(); + if (!Base::owns_lock()) LeaveCritical(); - return lock.owns_lock(); + return Base::owns_lock(); } public: - CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock) + UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); @@ -146,35 +141,41 @@ class SCOPED_LOCKABLE CCriticalBlock Enter(pszName, pszFile, nLine); } - CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) + UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = std::unique_lock(*pmutexIn, std::defer_lock); + *static_cast(this) = Base(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - ~CCriticalBlock() UNLOCK_FUNCTION() + ~UniqueLock() UNLOCK_FUNCTION() { - if (lock.owns_lock()) + if (Base::owns_lock()) LeaveCritical(); } operator bool() { - return lock.owns_lock(); + return Base::owns_lock(); } }; +template +using DebugLock = UniqueLock::type>::type>; + #define PASTE(x, y) x ## y #define PASTE2(x, y) PASTE(x, y) -#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) -#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__) -#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) +#define LOCK(cs) DebugLock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1, cs2) \ + DebugLock criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ + DebugLock criticalblock2(cs2, #cs2, __FILE__, __LINE__); +#define TRY_LOCK(cs, name) DebugLock name(cs, #cs, __FILE__, __LINE__, true) +#define WAIT_LOCK(cs, name) DebugLock name(cs, #cs, __FILE__, __LINE__) #define ENTER_CRITICAL_SECTION(cs) \ { \ From c8a7d42237bcc235bf9bc048900011e94f987cf7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 18 Feb 2020 17:15:43 -0500 Subject: [PATCH 0234/1888] condvar_GenesisWait moved to std::condition_variable. --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index af4d5b370e..e5a959ada4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -618,7 +618,7 @@ static void BlockSizeNotifyCallback(int size, const uint256& hashNewTip) static bool fHaveGenesis = false; static std::mutex cs_GenesisWait; -static CConditionVariable condvar_GenesisWait; +static std::condition_variable condvar_GenesisWait; static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) { From 7d9df80fa735c81f958ae25b6158d7f7ae5634d9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 16 Feb 2020 12:50:22 -0500 Subject: [PATCH 0235/1888] Add OK Button to Send TX Dialog --- src/qt/sendcoinsdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a4af6871d7..01802845d0 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -324,6 +324,7 @@ void SendCoinsDialog::sendTx() { QString txhash = resultTx.GetHash().GetHex().c_str(); QMessageBox msgBox; QPushButton *copyButton = msgBox.addButton(tr("Copy"), QMessageBox::ActionRole); + QPushButton *okButton = msgBox.addButton(tr("OK"), QMessageBox::ActionRole); copyButton->setStyleSheet("background:transparent;"); copyButton->setIcon(QIcon(":/icons/editcopy")); msgBox.setWindowTitle("Transaction Initialized"); From 4b4e74218e3d20f261763c5653f5c1aee083bb9c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 23 Feb 2020 22:10:45 -0500 Subject: [PATCH 0236/1888] [GUI] Change colors for tx labels --- src/qt/guiconstants.h | 7 ++++++- src/qt/overviewpage.cpp | 8 ++------ src/qt/transactiontablemodel.cpp | 18 ++++++++++++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index d1bf9bb056..5298c6c3c0 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -34,7 +34,12 @@ static const bool DEFAULT_SPLASHSCREEN = true; #define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192) /* Transaction list -- TX status decoration - default color */ #define COLOR_BLACK QColor(51, 51, 51) - +/* Transaction list -- TX status decoration - conflicted */ +#define COLOR_CONFLICTED QColor(255, 0, 0) +/* Transaction list -- TX status decoration - orphan (Light Gray #D3D3D3) */ +#define COLOR_ORPHAN QColor(211, 211, 211) +/* Transaction list -- TX status decoration - stake (BlueViolet #8A2BE2) */ +#define COLOR_STAKE QColor(138,43,226) /* Tooltips longer than this (in characters) are converted into rich text, so that they can be word-wrapped. */ diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index ee070139dd..dc23b1ce2d 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -75,13 +75,9 @@ class TxViewDelegate : public QAbstractItemDelegate iconWatchonly.paint(painter, watchonlyRect); } - if (amount < 0) { + if (amount < 0) foreground = COLOR_NEGATIVE; - } else if (!confirmed) { - foreground = COLOR_UNCONFIRMED; - } else { - foreground = COLOR_BLACK; - } + painter->setPen(foreground); QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways); if (!confirmed) { diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 311505b011..05a77a4cde 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -477,8 +477,6 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord* wtx, b QVariant TransactionTableModel::addressColor(const TransactionRecord* wtx) const { switch (wtx->type) { - case TransactionRecord::SendToSelf: - return COLOR_BAREADDRESS; // Show addresses without label in a less visible color case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: @@ -488,6 +486,7 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord* wtx) const if (label.isEmpty()) return COLOR_BAREADDRESS; } + case TransactionRecord::SendToSelf: default: // To avoid overriding above conditional formats a default text color for this QTableView is not defined in stylesheet, // so we must always return a color here @@ -619,8 +618,19 @@ QVariant TransactionTableModel::data(const QModelIndex& index, int role) const case Qt::TextAlignmentRole: return column_alignments[index.column()]; case Qt::ForegroundRole: - // Non-confirmed (but not immature) as transactions are grey - if (!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature) { + // Minted + if (rec->type == TransactionRecord::Generated || rec->type == TransactionRecord::StakeMint || rec->type == TransactionRecord::MNReward) { + if (rec->status.status == TransactionStatus::Conflicted || rec->status.status == TransactionStatus::NotAccepted) + return COLOR_ORPHAN; + else + return COLOR_STAKE; + } + // Conflicted tx + if (rec->status.status == TransactionStatus::Conflicted || rec->status.status == TransactionStatus::NotAccepted) { + return COLOR_CONFLICTED; + } + // Unconfimed or immature + if ((rec->status.status == TransactionStatus::Unconfirmed) || (rec->status.status == TransactionStatus::Immature)) { return COLOR_UNCONFIRMED; } if (index.column() == Amount && (rec->credit + rec->debit) < 0) { From acab750314d3cda1d0d2aaaa611e0e94177210d5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 19:57:05 -0500 Subject: [PATCH 0237/1888] Add IsLocked() return to AvailableCoins --- src/wallet/wallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 40276bcf68..1918715db9 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1945,6 +1945,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const */ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl* coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseIX) { + if (IsLocked()) return; vCoins.clear(); { @@ -1961,6 +1962,7 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const bool CWallet::AvailableCoins(const uint256 wtxid, const CWalletTx* pcoin, vector& vCoins, int cannotSpend, bool fOnlyConfirmed, const CCoinControl* coinControl, bool fIncludeZeroValue, AvailableCoinsType nCoinType, bool fUseIX) { + if (IsLocked()) return false; cannotSpend = 0; { if (!CheckFinalTx(*pcoin)) From 030764328b37c5d97019aba418a0349b6be16355 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 24 Feb 2020 20:26:36 -0500 Subject: [PATCH 0238/1888] [GUI][Model] Do not re request passphrase when the wallet is unlocked. Add lockForStakingOnly function - not used yet --- src/qt/walletmodel.cpp | 11 +++++++++++ src/qt/walletmodel.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 1b5db91c8a..393a8f0292 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -431,6 +431,17 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString& passPhrase, b } } +bool WalletModel::lockForStakingOnly(const SecureString& passPhrase) +{ + if (!wallet->IsLocked()) { + wallet->fWalletUnlockAnonymizeOnly = true; + return true; + } else { + setWalletLocked(false, passPhrase, true); + } + return false; +} + bool WalletModel::isAnonymizeOnlyUnlocked() { return wallet->fWalletUnlockAnonymizeOnly; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 4e8ffc34fe..68e1baafbc 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -173,6 +173,11 @@ class WalletModel : public QObject bool setWalletEncrypted(bool encrypted, const SecureString& passphrase); // Passphrase only needed when unlocking bool setWalletLocked(bool locked, const SecureString& passPhrase = SecureString(), bool anonymizeOnly = false); + + // Method used to "lock" the wallet only for staking purposes. Just a flag that should prevent possible movements in the wallet. + // Passphrase only needed when unlocking. + bool lockForStakingOnly(const SecureString& passPhrase = SecureString()); + bool changePassphrase(const SecureString& oldPass, const SecureString& newPass); // Is wallet unlocked for anonymization only? bool isAnonymizeOnlyUnlocked(); From f8822cc1dc2a10d846205c0e59668dfb77af208b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 25 Feb 2020 11:00:19 -0500 Subject: [PATCH 0239/1888] Fix for empty Transaction Creation Error msgbox Currently just a generic response if no err returned --- src/qt/sendcoinsdialog.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 01802845d0..36c7858936 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -309,9 +309,13 @@ void SendCoinsDialog::sendTx() { return; } } else { + QString msg = err.what(); + if (msg == "") { + msg = "Unable to create transaction. Please try again later."; + } QMessageBox msgBox; msgBox.setWindowTitle("Transaction Creation Error"); - msgBox.setText(QString(err.what())); + msgBox.setText(msg); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.setIcon(QMessageBox::Critical); msgBox.exec(); From 900dae0da5e4dd1b2a2fd0a181d0b989666ce933 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 25 Feb 2020 17:34:40 -0500 Subject: [PATCH 0240/1888] [Trivial] Fix to display missing clock5.png tx image --- src/qt/transactiontablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 05a77a4cde..8c2e34cadb 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -534,7 +534,7 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord* wtx) return QIcon(":/icons/transaction_conflicted"); case TransactionStatus::Immature: { int total = wtx->status.depth + wtx->status.matures_in; - int part = (wtx->status.depth * 4 / total) + 1; + int part = (wtx->status.depth * 5 / total) + 1; return QIcon(QString(":/icons/transaction_%1").arg(part)); } case TransactionStatus::MaturesWarning: From 35fe0ef628e83732c4ddf8006472039ee6765da7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 11:16:11 -0500 Subject: [PATCH 0241/1888] Update checkpoints to 300k --- src/chainparams.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0fb5e70d5f..cccb137734 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -121,11 +121,16 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (265000, uint256("84598b4790a1df395e5ef724c4a2784b27679ef07d9e864ff2fa1b91fcca0751")) (270000, uint256("533f7d0f72700d23c3086fbf7f7f01e1b5e0b3c3d24a5f854187eb333610d266")) (275000, uint256("7b1d412bc6bf0c994d46c830e6a52fd36e7dbfbde057f44d6c9e8655f50f8720")) + (280000, uint256("4ddc6eafeb7bcdb14d2836dfe5b5b9d053400a1fb91eae9534e6d7b55e22629a")) + (285000, uint256("b3b578a10bcc8d9f9251ce6694689c9df8d5956a5b5c536054c75cb39096a1be")) + (290000, uint256("49c13c93d22f4de36dd8cab41ef8fb879e657198d8b16dd97c4225d199126169")) + (295000, uint256("e6742077e1d536bdbd4d4e1f440371be5045b604b21bbe5ab9cf5bed30747e46")) + (300000, uint256("28fe81715aa6450890103e65fbfa3e9d0b4bac3baf86a480ce0c630e82a32e62")) ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1581315652, // * UNIX timestamp of last checkpoint block - 681361, // * total number of transactions between genesis and last checkpoint + 1582819136,, // * UNIX timestamp of last checkpoint block + 741138, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint }; From dbb6fe9ee57bfad62a053a3daaa81e0f5b2607a8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 12:53:09 -0500 Subject: [PATCH 0242/1888] Fix extra comma in chainparams --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index cccb137734..eb53fa83ab 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -129,7 +129,7 @@ static Checkpoints::MapCheckpoints mapCheckpoints = ; static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1582819136,, // * UNIX timestamp of last checkpoint block + 1582819136, // * UNIX timestamp of last checkpoint block 741138, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint From 88a9c51e2101b2d75aaf24e4f0f14c478aa2c648 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 14:09:52 -0500 Subject: [PATCH 0243/1888] [Cleanup] Remove stale UNITTEST network This network is un-necessary as our unit test suite can simply be run with MainNet's parameters, which is basically what we already do. --- src/chainparams.cpp | 50 -------------------------------- src/chainparams.h | 22 -------------- src/chainparamsbase.cpp | 17 ----------- src/chainparamsbase.h | 1 - src/test/base58_tests.cpp | 4 +-- src/test/test_dapscoin.cpp | 2 +- src/test/wallet_tests.cpp | 2 +- src/wallet/test/wallet_tests.cpp | 2 +- 8 files changed, 5 insertions(+), 95 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index eb53fa83ab..148a7b092f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -489,56 +489,8 @@ class CRegTestParams : public CTestNetParams }; static CRegTestParams regTestParams; -/** - * Unit test - */ -class CUnitTestParams : public CMainParams, public CModifiableParams -{ -public: - CUnitTestParams() - { - networkID = CBaseChainParams::UNITTEST; - strNetworkID = "unittest"; - nDefaultPort = 51478; - vFixedSeeds.clear(); //! Unit test mode doesn't have any fixed seeds. - vSeeds.clear(); //! Unit test mode doesn't have any DNS seeds. - - fRequireRPCPassword = false; - fMiningRequiresPeers = false; - fDefaultConsistencyChecks = true; - fAllowMinDifficultyBlocks = false; - fMineBlocksOnDemand = true; - - nExtCoinType = 0x80000166; - } - - const Checkpoints::CCheckpointData& Checkpoints() const - { - // UnitTest share the same checkpoints as MAIN - return data; - } - - //! Published setters to allow changing values in unit test cases - virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval = anSubsidyHalvingInterval; } - virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority = anEnforceBlockUpgradeMajority; } - virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority = anRejectBlockOutdatedMajority; } - virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority = anToCheckBlockUpgradeMajority; } - virtual void setDefaultConsistencyChecks(bool afDefaultConsistencyChecks) { fDefaultConsistencyChecks = afDefaultConsistencyChecks; } - virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks = afAllowMinDifficultyBlocks; } - virtual void setSkipProofOfWorkCheck(bool afSkipProofOfWorkCheck) { fSkipProofOfWorkCheck = afSkipProofOfWorkCheck; } -}; -static CUnitTestParams unitTestParams; - - static CChainParams* pCurrentParams = 0; -CModifiableParams* ModifiableParams() -{ - assert(pCurrentParams); - assert(pCurrentParams == &unitTestParams); - return (CModifiableParams*)&unitTestParams; -} - const CChainParams& Params() { assert(pCurrentParams); @@ -554,8 +506,6 @@ CChainParams& Params(CBaseChainParams::Network network) return testNetParams; case CBaseChainParams::REGTEST: return regTestParams; - case CBaseChainParams::UNITTEST: - return unitTestParams; default: assert(false && "Unimplemented network"); return mainParams; diff --git a/src/chainparams.h b/src/chainparams.h index cd9ea30a2c..c419fde041 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -167,26 +167,6 @@ class CChainParams } }; -/** - * Modifiable parameters interface is used by test cases to adapt the parameters in order - * to test specific features more easily. Test cases should always restore the previous - * values after finalization. - */ - -class CModifiableParams -{ -public: - //! Published setters to allow changing values in unit test cases - virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) = 0; - virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) = 0; - virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) = 0; - virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) = 0; - virtual void setDefaultConsistencyChecks(bool aDefaultConsistencyChecks) = 0; - virtual void setAllowMinDifficultyBlocks(bool aAllowMinDifficultyBlocks) = 0; - virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck) = 0; -}; - - /** * Return the currently selected parameters. This won't change after app startup * outside of the unit tests. @@ -196,8 +176,6 @@ const CChainParams& Params(); /** Return parameters for the given network. */ CChainParams& Params(CBaseChainParams::Network network); -/** Get modifiable network parameters (UNITTEST only) */ -CModifiableParams* ModifiableParams(); /** Sets the params returned by Params() to those for the given network. */ void SelectParams(CBaseChainParams::Network network); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 1dac73353f..9bbc76da98 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -56,20 +56,6 @@ class CBaseRegTestParams : public CBaseTestNetParams }; static CBaseRegTestParams regTestParams; -/* - * Unit test - */ -class CBaseUnitTestParams : public CBaseMainParams -{ -public: - CBaseUnitTestParams() - { - networkID = CBaseChainParams::UNITTEST; - strDataDir = "unittest"; - } -}; -static CBaseUnitTestParams unitTestParams; - static CBaseChainParams* pCurrentBaseParams = 0; const CBaseChainParams& BaseParams() @@ -90,9 +76,6 @@ void SelectBaseParams(CBaseChainParams::Network network) case CBaseChainParams::REGTEST: pCurrentBaseParams = ®TestParams; break; - case CBaseChainParams::UNITTEST: - pCurrentBaseParams = &unitTestParams; - break; default: assert(false && "Unimplemented network"); return; diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 95953bc830..53f0611ca7 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -19,7 +19,6 @@ class CBaseChainParams MAIN, TESTNET, REGTEST, - UNITTEST, MAX_NETWORK_TYPES }; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index c9ce2f47d7..9400182f61 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -125,6 +125,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) std::vector result; CBitcoinSecret secret; CBitcoinAddress addr; + SelectParams(CBaseChainParams::MAIN); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; @@ -174,7 +175,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); } } - SelectParams(CBaseChainParams::UNITTEST); } // Goal: check that generated keys match test vectors @@ -241,7 +241,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) CTxDestination nodest = CNoDestination(); BOOST_CHECK(!dummyAddr.Set(nodest)); - SelectParams(CBaseChainParams::UNITTEST); + SelectParams(CBaseChainParams::MAIN); } // Goal: check that base58 parsing code is robust against a variety of corrupted data diff --git a/src/test/test_dapscoin.cpp b/src/test/test_dapscoin.cpp index 4d3f809bef..3b37897488 100644 --- a/src/test/test_dapscoin.cpp +++ b/src/test/test_dapscoin.cpp @@ -33,7 +33,7 @@ struct TestingSetup { SetupEnvironment(); fPrintToDebugLog = true; // don't want to write to debug.log file fCheckBlockIndex = false; - SelectParams(CBaseChainParams::UNITTEST); + SelectParams(CBaseChainParams::MAIN); noui_connect(); #ifdef ENABLE_WALLET bitdb.MakeMock(); diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index 9bfc92742d..5f1aaa2a4d 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -388,6 +388,6 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("%llu/%llu/%llu/%llu\n", pwalletMain->GetSpendableBalance(), pwalletMain->GetBalance(), pwalletMain->GetUnlockedCoins(), pwalletMain->GetLockedCoins()); // check stealth sending on not enough balance wallet - SelectParams(CBaseChainParams::UNITTEST); + SelectParams(CBaseChainParams::MAIN); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index cac4e6fd02..772944806e 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -388,6 +388,6 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("%llu/%llu/%llu/%llu\n", pwalletMain->GetSpendableBalance(), pwalletMain->GetBalance(), pwalletMain->GetUnlockedCoins(), pwalletMain->GetLockedCoins()); // check stealth sending on not enough balance wallet - SelectParams(CBaseChainParams::UNITTEST); + SelectParams(CBaseChainParams::MAIN); } BOOST_AUTO_TEST_SUITE_END() From 778e33e297d9c4eb41fb1c18d5bdd8350dba861e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 25 Feb 2020 12:03:01 -0500 Subject: [PATCH 0244/1888] Sync.h: AssertLockNotHeld backported. --- src/main.cpp | 11 ++++++++++- src/rpc/rawtransaction.cpp | 2 +- src/sync.cpp | 10 ++++++++++ src/sync.h | 3 +++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b3476854b5..c54fc3b27a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3651,6 +3651,12 @@ ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, CBlo */ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChecked) { + // Note that while we're often called here from ProcessNewBlock, this is + // far from a guarantee. Things in the P2P/RPC will often end up calling + // us in the middle of ProcessNewBlock - do not assume pblock is set + // sanely for performance or correctness! + AssertLockNotHeld(cs_main); + CBlockIndex* pindexNewTip = nullptr; CBlockIndex* pindexMostWork = nullptr; do { @@ -4507,6 +4513,8 @@ void CBlockIndex::BuildSkip() bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDiskBlockPos* dbp) { + AssertLockNotHeld(cs_main); + // Preliminary checks int64_t nStartTime = GetTimeMillis(); bool checked = CheckBlock(*pblock, state); @@ -5440,8 +5448,9 @@ bool static AlreadyHave(const CInv& inv) void static ProcessGetData(CNode* pfrom) { - std::deque::iterator it = pfrom->vRecvGetData.begin(); + AssertLockNotHeld(cs_main); + std::deque::iterator it = pfrom->vRecvGetData.begin(); vector vNotFound; LOCK(cs_main); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 76a5980f64..d05e45c514 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -873,7 +873,6 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + "\nAs a json rpc call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")); - LOCK(cs_main); RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)); // parse hex string from parameter @@ -886,6 +885,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) if (params.size() > 1) fOverrideFees = params[1].get_bool(); + AssertLockNotHeld(cs_main); CCoinsViewCache& view = *pcoinsTip; const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); diff --git a/src/sync.cpp b/src/sync.cpp index c045dc0660..f201848400 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -168,6 +168,16 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, abort(); } +void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) +{ + for (const std::pair& i : g_lockstack) { + if (i.first == cs) { + tfm::format(std::cerr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld()); + abort(); + } + } +} + void DeleteLock(void* cs) { LockData& lockdata = GetLockData(); diff --git a/src/sync.h b/src/sync.h index 8933ca15be..6ae6463bcf 100644 --- a/src/sync.h +++ b/src/sync.h @@ -51,14 +51,17 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs void LeaveCritical(); std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); +void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); void DeleteLock(void* cs); #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} +void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} void static inline DeleteLock(void* cs) {} #endif #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) /** * Template mixin that adds -Wthread-safety locking annotations and lock order From a02c9428f5fc84432a637e2e0801e1c6af451445 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 25 Feb 2020 12:06:32 -0500 Subject: [PATCH 0245/1888] move-only: PASTE macros to util/macros.h --- src/Makefile.am | 1 + src/sync.h | 4 +--- src/util/macros.h | 11 +++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/util/macros.h diff --git a/src/Makefile.am b/src/Makefile.am index c4870bd3db..877345db37 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -176,6 +176,7 @@ BITCOIN_CORE_H = \ uint256.h \ undo.h \ util.h \ + util/macros.h \ util/threadnames.h \ utilstrencodings.h \ utilmoneystr.h \ diff --git a/src/sync.h b/src/sync.h index 6ae6463bcf..cb5534d356 100644 --- a/src/sync.h +++ b/src/sync.h @@ -7,6 +7,7 @@ #define BITCOIN_SYNC_H #include "threadsafety.h" +#include "util/macros.h" #include #include @@ -170,9 +171,6 @@ class SCOPED_LOCKABLE UniqueLock : public Base template using DebugLock = UniqueLock::type>::type>; -#define PASTE(x, y) x ## y -#define PASTE2(x, y) PASTE(x, y) - #define LOCK(cs) DebugLock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) \ DebugLock criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ diff --git a/src/util/macros.h b/src/util/macros.h new file mode 100644 index 0000000000..49accac254 --- /dev/null +++ b/src/util/macros.h @@ -0,0 +1,11 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_MACROS_H +#define BITCOIN_UTIL_MACROS_H + +#define PASTE(x, y) x ## y +#define PASTE2(x, y) PASTE(x, y) + +#endif // BITCOIN_UTIL_MACROS_H \ No newline at end of file From 0c8f60702cf9efa4bde0ba907ab5c4f6727a116e Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 25 Feb 2020 13:35:13 -0500 Subject: [PATCH 0246/1888] sync: Add RecursiveMutex type alias --- src/sync.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sync.h b/src/sync.h index cb5534d356..a8fac886ca 100644 --- a/src/sync.h +++ b/src/sync.h @@ -21,7 +21,7 @@ ///////////////////////////////////////////////// /* -CCriticalSection mutex; +RecursiveMutex mutex; std::recursive_mutex mutex; LOCK(mutex); @@ -97,6 +97,7 @@ class LOCKABLE AnnotatedMixin : public PARENT * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ +using RecursiveMutex = AnnotatedMixin; typedef AnnotatedMixin CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ From fbb31c6188a4597d50e3b109f0420ca90101c7b0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 08:35:59 -0500 Subject: [PATCH 0247/1888] Add debug_lockorder code (without unit test) --- src/sync.cpp | 7 +++++++ src/sync.h | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/sync.cpp b/src/sync.cpp index f201848400..a0c027afd6 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -111,6 +111,11 @@ static void potential_deadlock_detected(const std::pair& mismatch, } LogPrintf(" %s\n", i.second.ToString()); } + if (g_debug_lockorder_abort) { + tfm::format(std::cerr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__); + abort(); + } + throw std::logic_error("potential deadlock detected"); } static void push_lock(void* c, const CLockLocation& locklocation) @@ -201,4 +206,6 @@ void DeleteLock(void* cs) } } +bool g_debug_lockorder_abort = true; + #endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h index a8fac886ca..79a406560f 100644 --- a/src/sync.h +++ b/src/sync.h @@ -54,6 +54,13 @@ std::string LocksHeld(); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs); void DeleteLock(void* cs); + +/** + * Call abort() if a potential lock order deadlock bug is detected, instead of + * just logging information and throwing a logic_error. Defaults to true, and + * set to false in DEBUG_LOCKORDER unit tests. + */ +extern bool g_debug_lockorder_abort; #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} From 299d3f610b462a731ea56cb90a69c35f8706c520 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 19:07:15 -0500 Subject: [PATCH 0248/1888] [Qt] Replace deprecated Qt methods `qSort`, `qStableSort`, `qLowerBound`, and `qUpperBound` have been marked as deprecated since Qt 5.2. Also, `QSslSocket::setDefaultCaCertificates()` and `QSslSocket::systemCaCertificates()` member functions are obsolete as of Qt 5.12. This PR replaces the former with their `std::` equivalents, and the latter with `QSslConfiguration` equivalents. Changes maintain backwards compatibility with Qt 5.5.1 --- src/qt/addresstablemodel.cpp | 10 ++++++---- src/qt/bantablemodel.cpp | 4 +++- src/qt/paymentserver.cpp | 6 +++--- src/qt/peertablemodel.cpp | 4 +++- src/qt/recentrequeststablemodel.cpp | 4 +++- src/qt/transactiontablemodel.cpp | 6 ++++-- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 473c38020f..6537599d00 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -14,6 +14,8 @@ #include "wallet/wallet.h" #include "askpassphrasedialog.h" +#include + #include #include @@ -92,18 +94,18 @@ class AddressTablePriv QString::fromStdString(address.ToString()))); } } - // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order + // std::lower_bound() and std::upper_bound() require our cachedAddressTable list to be sorted in asc order // Even though the map is already sorted this re-sorting step is needed because the originating map // is sorted by binary address, not by base58() address. - qSort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); + std::sort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); } void updateEntry(const QString& address, const QString& label, bool isMine, const QString& purpose, int status) { // Find address / label in model - QList::iterator lower = qLowerBound( + QList::iterator lower = std::lower_bound( cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); - QList::iterator upper = qUpperBound( + QList::iterator upper = std::upper_bound( cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); int lowerIndex = (lower - cachedAddressTable.begin()); int upperIndex = (upper - cachedAddressTable.begin()); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 9958f01179..4c4846dfb8 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -13,6 +13,8 @@ #include "sync.h" #include "utiltime.h" +#include + #include #include @@ -64,7 +66,7 @@ class BanTablePriv if (sortColumn >= 0) // sort cachedBanlist (use stable sort to prevent rows jumping around unneceesarily) - qStableSort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder)); + std::stable_sort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder)); } int size() const diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 3372c26e3d..2463a33cd5 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -38,8 +38,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -131,9 +131,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) if (certFile != "-system-") { certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: - QSslSocket::setDefaultCaCertificates(certList); + QSslConfiguration::defaultConfiguration().setCaCertificates(certList); } else - certList = QSslSocket::systemCaCertificates(); + certList = QSslConfiguration::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 2c71796098..30c45164db 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -11,6 +11,8 @@ #include "net.h" #include "sync.h" +#include + #include #include #include @@ -81,7 +83,7 @@ class PeerTablePriv if (sortColumn >= 0) // sort cacheNodeStats (use stable sort to prevent rows jumping around unneceesarily) - qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); + std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); // build index map mapNodeRows.clear(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index a3f1337da9..cc899973d0 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -10,6 +10,8 @@ #include "optionsmodel.h" #include "streams.h" +#include + RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* parent) : walletModel(parent) { Q_UNUSED(wallet); @@ -196,7 +198,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry& recipient) void RecentRequestsTableModel::sort(int column, Qt::SortOrder order) { - qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); + std::sort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 8c2e34cadb..9fcdfc7032 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -18,6 +18,8 @@ #include "util.h" #include "wallet/wallet.h" +#include + #include #include #include @@ -167,9 +169,9 @@ class TransactionTablePriv qDebug() << "TransactionTablePriv::updateWallet : " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); // Find bounds of this transaction in model - QList::iterator lower = qLowerBound( + QList::iterator lower = std::lower_bound( cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); - QList::iterator upper = qUpperBound( + QList::iterator upper = std::upper_bound( cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); int lowerIndex = (lower - cachedWallet.begin()); int upperIndex = (upper - cachedWallet.begin()); From 3b20bf3d0c8df92c3989439066942dc103070637 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 19:48:40 -0500 Subject: [PATCH 0249/1888] net: require lookup functions to specify all arguments To make it clear where DNS resolves are happening --- src/net.cpp | 4 ++-- src/netbase.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 6f2863d22d..ffa1f353f7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1219,7 +1219,7 @@ void ThreadDNSAddressSeed() { } else { vector vIPs; vector vAdd; - if (LookupHost(seed.host.c_str(), vIPs)) { + if (LookupHost(seed.host.c_str(), vIPs, 0, true)) { for (CNetAddr & ip : vIPs) { int nOneDay = 24 * 3600; @@ -1627,7 +1627,7 @@ void static Discover(boost::thread_group &threadGroup) { char pszHostName[256] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { vector vaddr; - if (LookupHost(pszHostName, vaddr)) { + if (LookupHost(pszHostName, vaddr, 0, true)) { for (const CNetAddr& addr : vaddr) { if (AddLocal(addr, LOCAL_IF)) LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString()); diff --git a/src/netbase.h b/src/netbase.h index dd4b83b9e2..389d3a1cde 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -206,9 +206,9 @@ bool GetProxy(enum Network net, proxyType& proxyInfoOut); bool IsProxy(const CNetAddr& addr); bool SetNameProxy(const proxyType &addrProxy); bool HaveNameProxy(); -bool LookupHost(const char* pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); -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 LookupHost(const char* pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup); +bool Lookup(const char* pszName, CService& addr, int portDefault, bool fAllowLookup); +bool Lookup(const char* pszName, std::vector& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions); bool LookupNumeric(const char* pszName, CService& addr, int portDefault = 0); bool ConnectSocket(const CService& addr, SOCKET& hSocketRet, int nTimeout, bool* outProxyConnectionFailed = 0); bool ConnectSocketByName(CService& addr, SOCKET& hSocketRet, const char* pszDest, int portDefault, int nTimeout, bool* outProxyConnectionFailed = 0); From 70ecb33b0d27bcab644543855c7ebe2f8a0a9e55 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 19:49:52 -0500 Subject: [PATCH 0250/1888] net: manually resolve dns seed sources Note: Some seeds aren't actually returning an IP for their name entries, so they're being added to addrman with a source of [::]. This commit shouldn't change that behavior, for better or worse. --- src/net.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/net.cpp b/src/net.cpp index ffa1f353f7..b5e36d8a86 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1230,7 +1230,15 @@ void ThreadDNSAddressSeed() { found++; } } - addrman.Add(vAdd, CNetAddr(seed.name, true)); + // TODO: The seed name resolve may fail, yielding an IP of [::], which results in + // addrman assigning the same source to results from different seeds. + // This should switch to a hard-coded stable dummy IP for each seed name, so that the + // resolve is not required at all. + if (!vIPs.empty()) { + CService seedSource; + Lookup(seed.name.c_str(), seedSource, 0, true); + addrman.Add(vAdd, seedSource); + } } } From 7ee4490f172a4de38bae934051ddf22d8efae721 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 19:56:44 -0500 Subject: [PATCH 0251/1888] net: resolve outside of storage structures Rather than allowing CNetAddr/CService/CSubNet to launch DNS queries, require that addresses are already resolved. This greatly simplifies async resolve logic, and makes it harder to accidentally leak --- src/init.cpp | 7 ++++--- src/netbase.cpp | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index e5a959ada4..1cd6cf64c7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1341,10 +1341,11 @@ bool AppInit2(bool isDaemon) if (mapArgs.count("-externalip")) { for (string strAddr : mapMultiArgs["-externalip"]) { - CService addrLocal(strAddr, GetListenPort(), fNameLookup); - if (!addrLocal.IsValid()) + CService addrLocal; + if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) + AddLocal(addrLocal,LOCAL_MANUAL); + else return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); - AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); } } diff --git a/src/netbase.cpp b/src/netbase.cpp index b34eea880b..68d9073ff1 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -623,10 +623,12 @@ bool ConnectSocketByName(CService& addr, SOCKET& hSocketRet, const char* pszDest proxyType nameProxy; GetNameProxy(nameProxy); - CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port); - if (addrResolved.IsValid()) { - addr = addrResolved; - return ConnectSocket(addr, hSocketRet, nTimeout); + CService addrResolved; + if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy())) { + if (addrResolved.IsValid()) { + addr = addrResolved; + return ConnectSocket(addr, hSocketRet, nTimeout); + } } addr = CService("0.0.0.0:0"); From 6da014a2a6fc370a5c99a701a2bac267fcad77c3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 20:05:25 -0500 Subject: [PATCH 0252/1888] net: disable resolving from storage structures CNetAddr/CService/CSubnet can no longer resolve DNS. --- src/masternodeman.cpp | 2 +- src/netbase.cpp | 29 +++++++++++++++-------------- src/netbase.h | 14 +++++++------- src/rpc/masternode.cpp | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index deb68a0d2d..4ebfa7228b 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -393,7 +393,7 @@ void CMasternodeMan::CountNetworks(int protocolVersion, int& ipv4, int& ipv6, in std::string strHost; int port; SplitHostPort(mn.addr.ToString(), port, strHost); - CNetAddr node = CNetAddr(strHost, false); + CNetAddr node = CNetAddr(strHost); int nNetwork = node.GetNetwork(); switch (nNetwork) { case 1 : diff --git a/src/netbase.cpp b/src/netbase.cpp index 68d9073ff1..4beb1f108e 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -694,19 +694,19 @@ CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); } -CNetAddr::CNetAddr(const char* pszIp, bool fAllowLookup) +CNetAddr::CNetAddr(const char* pszIp) { Init(); std::vector vIP; - if (LookupHost(pszIp, vIP, 1, fAllowLookup)) + if (LookupHost(pszIp, vIP, 1, false)) *this = vIP[0]; } -CNetAddr::CNetAddr(const std::string& strIp, bool fAllowLookup) +CNetAddr::CNetAddr(const std::string& strIp) { Init(); std::vector vIP; - if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) + if (LookupHost(strIp.c_str(), vIP, 1, false)) *this = vIP[0]; } @@ -1136,35 +1136,35 @@ bool CService::SetSockAddr(const struct sockaddr* paddr) } } -CService::CService(const char* pszIpPort, bool fAllowLookup) +CService::CService(const char* pszIpPort) { Init(); CService ip; - if (Lookup(pszIpPort, ip, 0, fAllowLookup)) + if (Lookup(pszIpPort, ip, 0, false)) *this = ip; } -CService::CService(const char* pszIpPort, int portDefault, bool fAllowLookup) +CService::CService(const char* pszIpPort, int portDefault) { Init(); CService ip; - if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) + if (Lookup(pszIpPort, ip, portDefault, false)) *this = ip; } -CService::CService(const std::string& strIpPort, bool fAllowLookup) +CService::CService(const std::string& strIpPort) { Init(); CService ip; - if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) + if (Lookup(strIpPort.c_str(), ip, 0, false)) *this = ip; } -CService::CService(const std::string& strIpPort, int portDefault, bool fAllowLookup) +CService::CService(const std::string& strIpPort, int portDefault) { Init(); CService ip; - if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) + if (Lookup(strIpPort.c_str(), ip, portDefault, false)) *this = ip; } @@ -1256,7 +1256,7 @@ CSubNet::CSubNet() : valid(false) memset(netmask, 0, sizeof(netmask)); } -CSubNet::CSubNet(const std::string& strSubnet, bool fAllowLookup) +CSubNet::CSubNet(const std::string& strSubnet) { size_t slash = strSubnet.find_last_of('/'); std::vector vIP; @@ -1266,7 +1266,8 @@ CSubNet::CSubNet(const std::string& strSubnet, bool fAllowLookup) memset(netmask, 255, sizeof(netmask)); std::string strAddress = strSubnet.substr(0, slash); - if (LookupHost(strAddress.c_str(), vIP, 1, fAllowLookup)) { + if (LookupHost(strAddress.c_str(), vIP, 1, false)) + { network = vIP[0]; if (slash != strSubnet.npos) { std::string strNetmask = strSubnet.substr(slash + 1); diff --git a/src/netbase.h b/src/netbase.h index 389d3a1cde..9755fd8526 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -47,8 +47,8 @@ class CNetAddr 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); + explicit CNetAddr(const char* pszIp); + explicit CNetAddr(const std::string& strIp); void Init(); void SetIP(const CNetAddr& ip); @@ -118,7 +118,7 @@ class CSubNet public: CSubNet(); - explicit CSubNet(const std::string& strSubnet, bool fAllowLookup = false); + explicit CSubNet(const std::string& strSubnet); //constructor for single ip subnet (/32 or /128) explicit CSubNet(const CNetAddr &addr); @@ -153,10 +153,10 @@ class CService : public CNetAddr 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); + explicit CService(const char* pszIpPort, int portDefault); + explicit CService(const char* pszIpPort); + explicit CService(const std::string& strIpPort, int portDefault); + explicit CService(const std::string& strIpPort); void Init(); void SetPort(unsigned short portIn); unsigned short GetPort() const; diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 3b01e1cba3..5ce0887d24 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -247,7 +247,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) std::string strHost; int port; SplitHostPort(mn->addr.ToString(), port, strHost); - CNetAddr node = CNetAddr(strHost, false); + CNetAddr node = CNetAddr(strHost); std::string strNetwork = GetNetworkName(node.GetNetwork()); obj.push_back(Pair("rank", (strStatus == "ENABLED" ? s.first : 0))); From 8a8a44e83dbfb5e4b65394964de17d908932ba9c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 18:06:45 -0500 Subject: [PATCH 0253/1888] doc: Add comment to cs_main and mempool::cs --- src/main.cpp | 13 ++++++++++++- src/main.h | 2 +- src/txmempool.h | 29 ++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c54fc3b27a..03b5510560 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,7 +53,18 @@ using namespace std; * Global state */ -CCriticalSection cs_main; + +/** + * Mutex to guard access to validation specific variables, such as reading + * or changing the chainstate. + * + * This may also need to be locked when updating the transaction pool, e.g. on + * AcceptToMemoryPool. See CTxMemPool::cs comment for details. + * + * The transaction pool has a separate lock to allow reading from it and the + * chainstate at the same time. + */ +RecursiveMutex cs_main; BlockMap mapBlockIndex; map mapProofOfStake; diff --git a/src/main.h b/src/main.h index 443cb994df..7d508b6f6b 100644 --- a/src/main.h +++ b/src/main.h @@ -132,7 +132,7 @@ struct BlockHasher { }; extern CScript COINBASE_FLAGS; -extern CCriticalSection cs_main; +extern RecursiveMutex cs_main; extern CTxMemPool mempool; typedef boost::unordered_map BlockMap; extern BlockMap mapBlockIndex; diff --git a/src/txmempool.h b/src/txmempool.h index 365139aaa5..c71fe193b6 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -104,7 +104,34 @@ class CTxMemPool uint64_t totalTxSize; //! sum of all mempool tx' byte sizes public: - mutable CCriticalSection cs; + /** + * This mutex needs to be locked when accessing `mapTx` or other members + * that are guarded by it. + * + * @par Consistency guarantees + * + * By design, it is guaranteed that: + * + * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool + * that is consistent with current chain tip (`::ChainActive()` and + * `CoinsTip()`) and is fully populated. Fully populated means that if the + * current active chain is missing transactions that were present in a + * previously active chain, all the missing transactions will have been + * re-added to the mempool and should be present if they meet size and + * consistency constraints. + * + * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool + * consistent with some chain that was active since `cs_main` was last + * locked, and that is fully populated as described above. It is ok for + * code that only needs to query or remove transactions from the mempool + * to lock just `mempool.cs` without `cs_main`. + * + * To provide these guarantees, it is necessary to lock both `cs_main` and + * `mempool.cs` whenever adding transactions to the mempool and whenever + * changing the chain tip. It's necessary to keep both mutexes locked until + * the mempool is consistent with the new chain tip and fully populated. + */ + mutable RecursiveMutex cs; std::map mapTx; std::map mapNextTx; std::map > mapDeltas; From c25e17c4e96e3b8ad34a16e1f3d9ebeb3defb10f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 18:39:23 -0500 Subject: [PATCH 0254/1888] [Refactor] Complete move from CCriticalSection to identical Recursive Mutex (both are AnnotatedMixin). --- src/activemasternode.h | 2 +- src/addrman.h | 2 +- src/alert.cpp | 2 +- src/alert.h | 2 +- src/init.cpp | 2 +- src/keystore.h | 2 +- src/main.cpp | 8 ++++---- src/masternode-budget.cpp | 2 +- src/masternode-budget.h | 8 ++++---- src/masternode-payments.cpp | 6 +++--- src/masternode-payments.h | 6 +++--- src/masternode.h | 2 +- src/masternodeman.h | 4 ++-- src/miner.cpp | 2 +- src/net.cpp | 22 +++++++++++----------- src/net.h | 26 +++++++++++++------------- src/netbase.cpp | 2 +- src/qt/masternodelist.cpp | 2 +- src/qt/masternodelist.h | 2 +- src/rpc/server.cpp | 2 +- src/sync.cpp | 2 +- src/test/util_tests.cpp | 4 ++-- src/timedata.cpp | 2 +- src/util.cpp | 8 ++++---- src/wallet/db.h | 2 +- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.h | 2 +- 27 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/activemasternode.h b/src/activemasternode.h index f2ab25976a..a325f1551d 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -26,7 +26,7 @@ class CActiveMasternode { private: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; /// Ping Masternode bool SendMasternodePing(std::string& errorMessage); diff --git a/src/addrman.h b/src/addrman.h index a10af3672f..3769090dc8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -170,7 +170,7 @@ class CAddrMan { private: //! critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; //! secret key to randomize bucket select with uint256 nKey; diff --git a/src/alert.cpp b/src/alert.cpp index 8024a640fb..ab26b8a19f 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -24,7 +24,7 @@ using namespace std; map mapAlerts; -CCriticalSection cs_mapAlerts; +RecursiveMutex cs_mapAlerts; void CUnsignedAlert::SetNull() { diff --git a/src/alert.h b/src/alert.h index 2341420b79..65d97fe5d3 100644 --- a/src/alert.h +++ b/src/alert.h @@ -19,7 +19,7 @@ class CNode; class uint256; extern std::map mapAlerts; -extern CCriticalSection cs_mapAlerts; +extern RecursiveMutex cs_mapAlerts; /** Alerts are for notifying old versions if they become too obsolete and * need to upgrade. The message is displayed in the status bar. diff --git a/src/init.cpp b/src/init.cpp index 1cd6cf64c7..f1f29c1e36 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -180,7 +180,7 @@ void PrepareShutdown() fRequestShutdown = true; // Needed when we shutdown the wallet fRestartRequested = true; // Needed when we restart the wallet LogPrintf("%s: In progress...\n", __func__); - static CCriticalSection cs_Shutdown; + static RecursiveMutex cs_Shutdown; TRY_LOCK(cs_Shutdown, lockShutdown); if (!lockShutdown) return; diff --git a/src/keystore.h b/src/keystore.h index 7a443eed57..38cd8aedf3 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -21,7 +21,7 @@ class CScriptID; class CKeyStore { protected: - mutable CCriticalSection cs_KeyStore; + mutable RecursiveMutex cs_KeyStore; public: virtual ~CKeyStore() {} diff --git a/src/main.cpp b/src/main.cpp index 03b5510560..8ce34359c3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -160,7 +160,7 @@ int nSyncStarted = 0; /** All pairs A->B, where A (or one if its ancestors) misses transactions, but B has transactions. */ multimap mapBlocksUnlinked; -CCriticalSection cs_LastBlockFile; +RecursiveMutex cs_LastBlockFile; std::vector vinfoBlockFile; int nLastBlockFile = 0; @@ -168,7 +168,7 @@ int nLastBlockFile = 0; * Every received block is assigned a unique and increasing identifier, so we * know which one to give priority in case of a fork. */ -CCriticalSection cs_nBlockSequenceId; +RecursiveMutex cs_nBlockSequenceId; /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ uint32_t nBlockSequenceId = 1; @@ -1760,7 +1760,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize - 300)) { - static CCriticalSection csFreeLimiter; + static RecursiveMutex csFreeLimiter; static double dFreeCount; static int64_t nLastTime; int64_t nNow = GetTime(); @@ -1964,7 +1964,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize)) { - static CCriticalSection csFreeLimiter; + static RecursiveMutex csFreeLimiter; static double dFreeCount; static int64_t nLastTime; int64_t nNow = GetTime(); diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index fa6b234c6b..ba68dfcfce 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -17,7 +17,7 @@ #include CBudgetManager budget; -CCriticalSection cs_budget; +RecursiveMutex cs_budget; std::map askedForSourceProposalOrBudget; std::vector vecImmatureBudgetProposals; diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 4a458a6984..6d3f1857f2 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -18,7 +18,7 @@ using namespace std; -extern CCriticalSection cs_budget; +extern RecursiveMutex cs_budget; class CBudgetManager; class CFinalizedBudgetBroadcast; @@ -179,7 +179,7 @@ class CBudgetManager public: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; // keep track of the scanning errors I've seen map mapProposals; @@ -308,7 +308,7 @@ class CFinalizedBudget { private: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; bool fAutoChecked; //If it matches what we see, we'll auto vote for it (masternode only) public: @@ -453,7 +453,7 @@ class CBudgetProposal { private: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; CAmount nAlloted; public: diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 7e2615b5e4..0e574e346d 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -18,9 +18,9 @@ /** Object for who's going to get paid on which blocks */ CMasternodePayments masternodePayments; -CCriticalSection cs_vecPayments; -CCriticalSection cs_mapMasternodeBlocks; -CCriticalSection cs_mapMasternodePayeeVotes; +RecursiveMutex cs_vecPayments; +RecursiveMutex cs_mapMasternodeBlocks; +RecursiveMutex cs_mapMasternodePayeeVotes; // // CMasternodePaymentDB diff --git a/src/masternode-payments.h b/src/masternode-payments.h index fb868e3a81..dbe00ef24d 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -13,9 +13,9 @@ using namespace std; -extern CCriticalSection cs_vecPayments; -extern CCriticalSection cs_mapMasternodeBlocks; -extern CCriticalSection cs_mapMasternodePayeeVotes; +extern RecursiveMutex cs_vecPayments; +extern RecursiveMutex cs_mapMasternodeBlocks; +extern RecursiveMutex cs_mapMasternodePayeeVotes; class CMasternodePayments; class CMasternodePaymentWinner; diff --git a/src/masternode.h b/src/masternode.h index ef76f1b401..5013bca067 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -109,7 +109,7 @@ class CMasternode { private: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; int64_t lastTimeChecked; public: diff --git a/src/masternodeman.h b/src/masternodeman.h index 6659e1ab48..8cd347546c 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -53,10 +53,10 @@ class CMasternodeMan { private: // critical section to protect the inner data structures - mutable CCriticalSection cs; + mutable RecursiveMutex cs; // critical section to protect the inner data structures specifically on messaging - mutable CCriticalSection cs_process_message; + mutable RecursiveMutex cs_process_message; // map to hold all MNs std::vector vMasternodes; diff --git a/src/miner.cpp b/src/miner.cpp index aba5fbaa2a..33f5b46231 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -791,7 +791,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) } else nHashCounter += nHashesDone; if (GetTimeMillis() - nHPSTimerStart > 4000) { - static CCriticalSection cs; + static RecursiveMutex cs; { LOCK(cs); if (GetTimeMillis() - nHPSTimerStart > 4000) { diff --git a/src/net.cpp b/src/net.cpp index b5e36d8a86..cb0fcdd61a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -77,7 +77,7 @@ namespace { bool fDiscover = true; bool fListen = true; uint64_t nLocalServices = NODE_NETWORK; -CCriticalSection cs_mapLocalHost; +RecursiveMutex cs_mapLocalHost; map mapLocalHost; //static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; @@ -90,23 +90,23 @@ bool fAddressesInitialized = false; std::string strSubVersion; vector vNodes; -CCriticalSection cs_vNodes; +RecursiveMutex cs_vNodes; map mapRelay; deque > vRelayExpiration; -CCriticalSection cs_mapRelay; +RecursiveMutex cs_mapRelay; limitedmap mapAlreadyAskedFor(MAX_INV_SZ); static deque vOneShots; -CCriticalSection cs_vOneShots; +RecursiveMutex cs_vOneShots; set setservAddNodeAddresses; -CCriticalSection cs_setservAddNodeAddresses; +RecursiveMutex cs_setservAddNodeAddresses; vector vAddedNodes; -CCriticalSection cs_vAddedNodes; +RecursiveMutex cs_vAddedNodes; NodeId nLastNodeId = 0; -CCriticalSection cs_nLastNodeId; +RecursiveMutex cs_nLastNodeId; static CSemaphore *semOutbound = NULL; boost::condition_variable messageHandlerCondition; @@ -325,8 +325,8 @@ void AddressCurrentlyConnected(const CService &addr) { uint64_t CNode::nTotalBytesRecv = 0; uint64_t CNode::nTotalBytesSent = 0; -CCriticalSection CNode::cs_totalBytesRecv; -CCriticalSection CNode::cs_totalBytesSent; +RecursiveMutex CNode::cs_totalBytesRecv; +RecursiveMutex CNode::cs_totalBytesSent; CNode *FindNode(const CNetAddr &ip) { LOCK(cs_vNodes); @@ -471,7 +471,7 @@ void CNode::PushVersion() { banmap_t CNode::setBanned; -CCriticalSection CNode::cs_setBanned; +RecursiveMutex CNode::cs_setBanned; bool CNode::setBannedIsDirty; void CNode::ClearBanned() { @@ -613,7 +613,7 @@ void CNode::SetBannedSetDirty(bool dirty) { } std::vector CNode::vWhitelistedRange; -CCriticalSection CNode::cs_vWhitelistedRange; +RecursiveMutex CNode::cs_vWhitelistedRange; bool CNode::IsWhitelistedRange(const CNetAddr &addr) { LOCK(cs_vWhitelistedRange); diff --git a/src/net.h b/src/net.h index 68475d84c4..0b1f7149e4 100644 --- a/src/net.h +++ b/src/net.h @@ -132,17 +132,17 @@ extern CAddrMan addrman; extern int nMaxConnections; extern std::vector vNodes; -extern CCriticalSection cs_vNodes; +extern RecursiveMutex cs_vNodes; extern std::map mapRelay; extern std::deque > vRelayExpiration; -extern CCriticalSection cs_mapRelay; +extern RecursiveMutex cs_mapRelay; extern limitedmap mapAlreadyAskedFor; extern std::vector vAddedNodes; -extern CCriticalSection cs_vAddedNodes; +extern RecursiveMutex cs_vAddedNodes; extern NodeId nLastNodeId; -extern CCriticalSection cs_nLastNodeId; +extern RecursiveMutex cs_nLastNodeId; /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; @@ -152,7 +152,7 @@ struct LocalServiceInfo { int nPort; }; -extern CCriticalSection cs_mapLocalHost; +extern RecursiveMutex cs_mapLocalHost; extern std::map mapLocalHost; class CNodeStats @@ -291,11 +291,11 @@ class CNode size_t nSendOffset; // offset inside the first vSendMsg already sent uint64_t nSendBytes; std::deque vSendMsg; - CCriticalSection cs_vSend; + RecursiveMutex cs_vSend; std::deque vRecvGetData; std::deque vRecvMsg; - CCriticalSection cs_vRecvMsg; + RecursiveMutex cs_vRecvMsg; uint64_t nRecvBytes; int nRecvVersion; @@ -331,7 +331,7 @@ class CNode // For such cases node should be released manually (preferably right after corresponding code). bool fObfuScationMaster; CSemaphoreGrant grantOutbound; - CCriticalSection cs_filter; + RecursiveMutex cs_filter; CBloomFilter* pfilter; int nRefCount; NodeId id; @@ -340,7 +340,7 @@ class CNode // Denial-of-service detection/prevention // Key is IP address, value is banned-until-time static banmap_t setBanned; - static CCriticalSection cs_setBanned; + static RecursiveMutex cs_setBanned; static bool setBannedIsDirty; std::vector vecRequestsFulfilled; //keep track of what client has asked for @@ -348,7 +348,7 @@ class CNode // Whitelisted ranges. Any node connecting from these is automatically // whitelisted (as well as those connecting to whitelisted binds). static std::vector vWhitelistedRange; - static CCriticalSection cs_vWhitelistedRange; + static RecursiveMutex cs_vWhitelistedRange; // Basic fuzz-testing void Fuzz(int nChance); // modifies ssSend @@ -366,7 +366,7 @@ class CNode // inventory based relay mruset setInventoryKnown; std::vector vInventoryToSend; - CCriticalSection cs_inventory; + RecursiveMutex cs_inventory; std::multimap mapAskFor; std::vector vBlockRequested; @@ -385,8 +385,8 @@ class CNode private: // Network usage totals - static CCriticalSection cs_totalBytesRecv; - static CCriticalSection cs_totalBytesSent; + static RecursiveMutex cs_totalBytesRecv; + static RecursiveMutex cs_totalBytesSent; static uint64_t nTotalBytesRecv; static uint64_t nTotalBytesSent; diff --git a/src/netbase.cpp b/src/netbase.cpp index 4beb1f108e..8289fe88d4 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -40,7 +40,7 @@ using namespace std; // Settings static proxyType proxyInfo[NET_MAX]; static proxyType nameProxy; -static CCriticalSection cs_proxyInfos; +static RecursiveMutex cs_proxyInfos; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = false; diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index fab357805a..b69e749a31 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -17,7 +17,7 @@ #include #include -CCriticalSection cs_masternodes; +RecursiveMutex cs_masternodes; MasternodeList::MasternodeList(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), ui(new Ui::MasternodeList), diff --git a/src/qt/masternodelist.h b/src/qt/masternodelist.h index 5b3712af7f..e0451dc686 100644 --- a/src/qt/masternodelist.h +++ b/src/qt/masternodelist.h @@ -63,7 +63,7 @@ public Q_SLOTS: Ui::MasternodeList* ui; ClientModel* clientModel; WalletModel* walletModel; - CCriticalSection cs_mnlistupdate; + RecursiveMutex cs_mnlistupdate; QString strCurrentFilter; virtual void resizeEvent(QResizeEvent* event); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 796be6e335..69ab3006e0 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -38,7 +38,7 @@ using namespace std; static bool fRPCRunning = false; static bool fRPCInWarmup = true; static std::string rpcWarmupStatus("RPC server started"); -static CCriticalSection cs_rpcWarmup; +static RecursiveMutex cs_rpcWarmup; /* Timer-creating functions */ static RPCTimerInterface* timerInterface = NULL; diff --git a/src/sync.cpp b/src/sync.cpp index a0c027afd6..e3ee15f54a 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -71,7 +71,7 @@ typedef std::set > InvLockOrders; struct LockData { // Very ugly hack: as the global constructs and destructors run single // threaded, we use this boolean to know whether LockData still exists, - // as DeleteLock can get called by global CCriticalSection destructors + // as DeleteLock can get called by global RecursiveMutex destructors // after LockData disappears. bool available; LockData() : available(true) {} diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index e2bf3af8f2..cb5861f368 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -23,7 +23,7 @@ BOOST_AUTO_TEST_SUITE(util_tests) BOOST_AUTO_TEST_CASE(util_criticalsection) { - CCriticalSection cs; + RecursiveMutex cs; do { LOCK(cs); @@ -426,4 +426,4 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion) BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/")); } BOOST_AUTO_TEST_SUITE_END() -#endif \ No newline at end of file +#endif diff --git a/src/timedata.cpp b/src/timedata.cpp index 813b119d5b..54ffa565cc 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -12,7 +12,7 @@ using namespace std; -static CCriticalSection cs_nTimeOffset; +static RecursiveMutex cs_nTimeOffset; static int64_t nTimeOffset = 0; /** diff --git a/src/util.cpp b/src/util.cpp index 08f90c26eb..e7dd24d149 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -136,7 +136,7 @@ bool fLogIPs = false; volatile bool fReopenDebugLog = false; /** Init OpenSSL library multithreading support */ -static CCriticalSection** ppmutexOpenSSL; +static RecursiveMutex** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS { if (mode & CRYPTO_LOCK) { @@ -153,9 +153,9 @@ class CInit CInit() { // Init OpenSSL library multithreading support - ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*)); + ppmutexOpenSSL = (RecursiveMutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(RecursiveMutex*)); for (int i = 0; i < CRYPTO_num_locks(); i++) - ppmutexOpenSSL[i] = new CCriticalSection(); + ppmutexOpenSSL[i] = new RecursiveMutex(); CRYPTO_set_locking_callback(locking_callback); // OpenSSL can optionally load a config file which lists optional loadable modules and engines. @@ -471,7 +471,7 @@ boost::filesystem::path GetDefaultDataDir() static boost::filesystem::path pathCached; static boost::filesystem::path pathCachedNetSpecific; -static CCriticalSection csPathCached; +static RecursiveMutex csPathCached; const boost::filesystem::path& GetDataDir(bool fNetSpecific) { diff --git a/src/wallet/db.h b/src/wallet/db.h index d380c2a307..b2454fc755 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -42,7 +42,7 @@ class CDBEnv void EnvShutdown(); public: - mutable CCriticalSection cs_db; + mutable RecursiveMutex cs_db; DbEnv dbenv; std::map mapFileUseCount; std::map mapDb; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 07bae40ead..74f87d3f70 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -31,7 +31,7 @@ using namespace boost; using namespace boost::assign; int64_t nWalletUnlockTime; -static CCriticalSection cs_nWalletUnlockTime; +static RecursiveMutex cs_nWalletUnlockTime; std::string HelpRequiringPassphrase() { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c14fccf471..19ab5cb798 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -282,7 +282,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * fFileBacked (immutable after instantiation) * strWalletFile (immutable after instantiation) */ - mutable CCriticalSection cs_wallet; + mutable RecursiveMutex cs_wallet; bool fFileBacked; bool fWalletUnlockAnonymizeOnly; From 175c6aca0da9122851847f227ba7ed05f78abed9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 18:40:46 -0500 Subject: [PATCH 0255/1888] Using WAIT_LOCK macro instead of WaitableLock. --- src/main.cpp | 2 +- src/miner.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/sync.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8ce34359c3..faa7be4c28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3211,7 +3211,7 @@ void static UpdateTip(CBlockIndex* pindexNew) mempool.AddTransactionsUpdated(1); { - WaitableLock lock(g_best_block_mutex); + LOCK(g_best_block_mutex); g_best_block = pindexNew->GetBlockHash(); g_best_block_cv.notify_all(); } diff --git a/src/miner.cpp b/src/miner.cpp index 33f5b46231..9a3dd58ebf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -612,7 +612,7 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Found a solution { - WaitableLock lock(g_best_block_mutex); + WAIT_LOCK(g_best_block_mutex, lock); if (pblock->hashPrevBlock != g_best_block) return error("DAPScoinMiner : generated block is stale"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 6c0f92c015..27039e0396 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -528,7 +528,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); - WaitableLock lock(g_best_block_mutex); + WAIT_LOCK(g_best_block_mutex, lock); while (g_best_block == hashWatchedChain && IsRPCRunning()) { if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { diff --git a/src/sync.h b/src/sync.h index 79a406560f..ca36736c8c 100644 --- a/src/sync.h +++ b/src/sync.h @@ -97,6 +97,7 @@ class LOCKABLE AnnotatedMixin : public PARENT { return PARENT::try_lock(); } + using UniqueLock = std::unique_lock; }; @@ -105,7 +106,6 @@ class LOCKABLE AnnotatedMixin : public PARENT * TODO: We should move away from using the recursive lock by default. */ using RecursiveMutex = AnnotatedMixin; -typedef AnnotatedMixin CCriticalSection; /** Wrapped mutex: supports waiting but not recursive locking */ typedef AnnotatedMixin Mutex; From d1990d307f60eadee028b95fd21949212d4e1b71 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 12:04:24 -0500 Subject: [PATCH 0256/1888] banlist: update set dirty to be more fine grained --- src/net.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index cb0fcdd61a..36bae17aba 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1258,7 +1258,9 @@ void DumpAddresses() { void DumpData() { DumpAddresses(); - DumpBanlist(); + + if (CNode::BannedSetIsDirty()) + DumpBanlist(); } void static ProcessOneShot() { @@ -2241,6 +2243,7 @@ bool CBanDB::Read(banmap_t &banSet) { } void DumpBanlist() { + int64_t nStart = GetTimeMillis(); CNode::SweepBanned(); //clean unused entires (if bantime has expired) if (!CNode::BannedSetIsDirty()) @@ -2250,9 +2253,8 @@ void DumpBanlist() { CBanDB bandb; banmap_t banmap; CNode::GetBanned(banmap); - if (bandb.Write(banmap)) { + if (bandb.Write(banmap)) CNode::SetBannedSetDirty(false); - } LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); From ee421ead7664d2c161346ba94c816f9f9aa27b31 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 12:05:57 -0500 Subject: [PATCH 0257/1888] banlist: better handling of banlist in StartNode() - only start working on/with banlist data, if reading in the banlist from disk didn't fail - as CNode::setBannedIsDirty is false (default) when reading fails, we don't need to explicitly set it to false to prevent writing banlist.dat in that case either --- src/net.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 36bae17aba..fe864b8507 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1683,18 +1683,19 @@ void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { //try to read stored banlist CBanDB bandb; banmap_t banmap; - if (!bandb.Read(banmap)) + if (bandb.Read(banmap)) { + CNode::SetBanned(banmap); // thread save setter + CNode::SetBannedSetDirty(false); // no need to write down, just read data + CNode::SweepBanned(); // sweep out unused entries + + LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", + banmap.size(), GetTimeMillis() - nStart); + } else LogPrintf("Invalid or missing banlist.dat; recreating\n"); - CNode::SetBanned(banmap); //thread save setter - CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data - CNode::SweepBanned(); //sweap out unused entries - // Initialize random numbers. Even when rand() is only usable for trivial use-cases most nodes should have a different // seed after all the file-IO done at this point. Should be good enough even when nodes are started via scripts. srand(time(NULL)); - LogPrintf("Loaded %i addresses from peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; if (semOutbound == NULL) { From 4cdf845c43037568d3209dc6c7c5f96e126bc94c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 12:07:42 -0500 Subject: [PATCH 0258/1888] banlist: add more banlist infos to log / add GUI signal - to match the peers.dat handling also supply a debug.log entry for how many entries were loaded from banlist.dat and how long it took - add a GUI init message for loading the banlist (same as with peers.dat) - move the same message for peers.dat upwards in the code, to be able to reuse the timing variable nStart and also just log, if our read from peers.dat didn't fai --- src/net.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index fe864b8507..215cc40c71 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -39,7 +39,7 @@ #include #include -// Dump addresses to peers.dat every 15 minutes (900s) +// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) @@ -1672,15 +1672,19 @@ void static Discover(boost::thread_group &threadGroup) { void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { uiInterface.InitMessage(_("Loading addresses...")); - // Load addresses for peers.dat + // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); { CAddrDB adb; - if (!adb.Read(addrman)) + if (adb.Read(addrman)) + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); + else LogPrintf("Invalid or missing peers.dat; recreating\n"); } - //try to read stored banlist + uiInterface.InitMessage(_("Loading banlist...")); + // Load addresses from banlist.dat + nStart = GetTimeMillis(); CBanDB bandb; banmap_t banmap; if (bandb.Read(banmap)) { From 9efee7f3355ebfa16960fa4fab2caf305bffbd3b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 29 Feb 2020 12:10:46 -0500 Subject: [PATCH 0259/1888] banlist (bugfix): allow CNode::SweepBanned() to run on interval - allows CNode::SweepBanned() to run, even if !CNode::BannedSetIsDirty(), because if nBanUntil is over we want the ban to be disabled for these nodes --- src/net.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 215cc40c71..6290a2e3a4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1258,9 +1258,7 @@ void DumpAddresses() { void DumpData() { DumpAddresses(); - - if (CNode::BannedSetIsDirty()) - DumpBanlist(); + DumpBanlist(); } void static ProcessOneShot() { @@ -2248,7 +2246,6 @@ bool CBanDB::Read(banmap_t &banSet) { } void DumpBanlist() { - int64_t nStart = GetTimeMillis(); CNode::SweepBanned(); //clean unused entires (if bantime has expired) if (!CNode::BannedSetIsDirty()) From fa31edb32e0a8350e26da1b4eed5490a1e60e856 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 7 Mar 2020 10:33:24 -0500 Subject: [PATCH 0260/1888] Update alert notification and GUI backports https://github.com/bitcoin/bitcoin/commit/92066344fdc3eb3071cb6fc0ce6a41d79c2dda53 --- src/alert.cpp | 6 +++--- src/guiinterface.h | 2 +- src/main.cpp | 24 ++++++++++++++++++++++-- src/qt/clientmodel.cpp | 26 +++++++------------------- src/qt/clientmodel.h | 2 +- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/alert.cpp b/src/alert.cpp index ab26b8a19f..2bd2b5b298 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -200,11 +200,11 @@ bool CAlert::ProcessAlert(bool fThread) const CAlert& alert = (*mi).second; if (Cancels(alert)) { LogPrint("alert", "cancelling alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + uiInterface.NotifyAlertChanged(); mapAlerts.erase(mi++); } else if (!alert.IsInEffect()) { LogPrint("alert", "expiring alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + uiInterface.NotifyAlertChanged(); mapAlerts.erase(mi++); } else mi++; @@ -223,7 +223,7 @@ bool CAlert::ProcessAlert(bool fThread) mapAlerts.insert(make_pair(GetHash(), *this)); // Notify UI and -alertnotify if it applies to me if (AppliesToMe()) { - uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); + uiInterface.NotifyAlertChanged(); Notify(strStatusBar, fThread); } } diff --git a/src/guiinterface.h b/src/guiinterface.h index fa15f76f0d..8a7f80b1f9 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -95,7 +95,7 @@ class CClientUIInterface * New, updated or cancelled alert. * @note called with lock cs_mapAlerts held. */ - boost::signals2::signal NotifyAlertChanged; + boost::signals2::signal NotifyAlertChanged; /** A wallet has been loaded. */ boost::signals2::signal LoadWallet; diff --git a/src/main.cpp b/src/main.cpp index faa7be4c28..40cce0af69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2335,6 +2335,26 @@ bool fLargeWorkForkFound = false; bool fLargeWorkInvalidChainFound = false; CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; +static void AlertNotify(const std::string& strMessage, bool fThread) +{ + uiInterface.NotifyAlertChanged(); + std::string strCmd = GetArg("-alertnotify", ""); + if (strCmd.empty()) return; + + // Alert text should be plain ascii coming from a trusted source, but to + // be safe we first strip anything not in safeChars, then add single quotes around + // the whole string before passing it to the shell: + std::string singleQuote("'"); + std::string safeStatus = SanitizeString(strMessage); + safeStatus = singleQuote+safeStatus+singleQuote; + boost::replace_all(strCmd, "%s", safeStatus); + + if (fThread) + boost::thread t(runCommand, strCmd); // thread runs free + else + runCommand(strCmd); +} + bool VerifyZeroBlindCommitment(const CTxOut& out) { if (out.nValue == 0) return true; @@ -2385,7 +2405,7 @@ void CheckForkWarningConditions() if (pindexBestForkBase->phashBlock) { std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + pindexBestForkBase->phashBlock->ToString() + std::string("'"); - CAlert::Notify(warning, true); + AlertNotify(warning, true); } } if (pindexBestForkTip && pindexBestForkBase) { @@ -3236,7 +3256,7 @@ void static UpdateTip(CBlockIndex* pindexNew) if (nUpgraded > 100 / 2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); - CAlert::Notify(strMiscWarning, true); + AlertNotify(strMiscWarning, true); fWarned = true; } } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 88393358c9..be154b261f 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -168,18 +168,8 @@ void ClientModel::updateNumConnections(int numConnections) emit numConnectionsChanged(numConnections); } -void ClientModel::updateAlert(const QString& hash, int status) -{ - // Show error message notification for new alert - if (status == CT_NEW) { - uint256 hash_256; - hash_256.SetHex(hash.toStdString()); - CAlert alert = CAlert::getAlertByHash(hash_256); - if (!alert.IsNull()) { - emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR); - } - } - +void ClientModel::updateAlert() +{ emit alertsChanged(getStatusBarWarnings()); } @@ -292,12 +282,10 @@ static void NotifyNumConnectionsChanged(ClientModel* clientmodel, int newNumConn Q_ARG(int, newNumConnections)); } -static void NotifyAlertChanged(ClientModel* clientmodel, const uint256& hash, ChangeType status) +static void NotifyAlertChanged(ClientModel* clientmodel) { - qDebug() << "NotifyAlertChanged : " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); - QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); + qDebug() << "NotifyAlertChanged"; + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection); } static void BannedListChanged(ClientModel *clientmodel) @@ -311,7 +299,7 @@ void ClientModel::subscribeToCoreSignals() // Connect signals to client uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); } @@ -321,7 +309,7 @@ void ClientModel::unsubscribeFromCoreSignals() // Disconnect signals from client uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); - uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); + uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index a55e351702..e409586b07 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -120,7 +120,7 @@ public slots: void updateTimer(); void updateMnTimer(); void updateNumConnections(int numConnections); - void updateAlert(const QString& hash, int status); + void updateAlert(); void updateBanlist(); }; From 058da9ffb2db5f7f80e989e0724c6ebd6ae09203 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 7 Mar 2020 10:36:33 -0500 Subject: [PATCH 0261/1888] Remove `-alerts` option Backports https://github.com/bitcoin/bitcoin/commit/01fdfeffc4515ea43748230139a3bcee2eec3865 Also remove alert command --- src/init.cpp | 3 --- src/main.cpp | 33 --------------------------------- src/main.h | 3 --- 3 files changed, 39 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f1f29c1e36..4c583fba5b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -370,7 +370,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-?", _("This help message")); strUsage += HelpMessageOpt("-version", _("Print version and exit")); strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); - strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS)); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-blocksizenotify=", _("Execute command when the best block changes and its size is over (%s in cmd is replaced by block hash, %d with the block size)")); strUsage += HelpMessageOpt("-checkblocks=", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 500)); @@ -1012,8 +1011,6 @@ bool AppInit2(bool isDaemon) fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true) != 0; nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); - fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); - if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices |= NODE_BLOOM; diff --git a/src/main.cpp b/src/main.cpp index 40cce0af69..a3c63f085b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -86,7 +86,6 @@ bool fIsBareMultisigStd = true; bool fCheckBlockIndex = false; bool fVerifyingBlocks = false; unsigned int nCoinCacheSize = 5000; -bool fAlerts = DEFAULT_ALERTS; /* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; @@ -5806,13 +5805,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - // Relay alerts - { - LOCK(cs_mapAlerts); - for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) - item.second.RelayTo(pfrom); - } - pfrom->fSuccessfullyConnected = true; string remoteAddr; @@ -6405,31 +6397,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (bPingFinished) { pfrom->nPingNonceSent = 0; } - } else if (fAlerts && strCommand == "alert") { - CAlert alert; - vRecv >> alert; - - uint256 alertHash = alert.GetHash(); - if (pfrom->setKnown.count(alertHash) == 0) { - if (alert.ProcessAlert()) { - // Relay - pfrom->setKnown.insert(alertHash); - { - LOCK(cs_vNodes); - for (CNode* pnode : vNodes) - alert.RelayTo(pnode); - } - } else { - // Small DoS penalty so peers that send us lots of - // duplicate/expired/invalid-signature/whatever alerts - // eventually get banned. - // This isn't a Misbehaving(100) (immediate ban) because the - // peer might be an older or different implementation with - // a different signature key, etc. - LOCK(cs_main); - Misbehaving(pfrom->GetId(), 10); - } - } } else if (!(nLocalServices & NODE_BLOOM) && (strCommand == "filterload" || strCommand == "filteradd" || diff --git a/src/main.h b/src/main.h index 7d508b6f6b..6ef0b88748 100644 --- a/src/main.h +++ b/src/main.h @@ -64,8 +64,6 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; /** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; -/** Default for accepting alerts from the P2P network. */ -static const bool DEFAULT_ALERTS = true; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** The maximum allowed number of signature check operations in a block (network rule) */ @@ -154,7 +152,6 @@ extern bool fIsBareMultisigStd; extern bool fCheckBlockIndex; extern unsigned int nCoinCacheSize; extern CFeeRate minRelayTxFee; -extern bool fAlerts; extern int64_t nMaxTipAge; extern bool fVerifyingBlocks; extern bool fGenerateDapscoins; From 06a296196f439e9bbd1bcb1a7545cf3dae01b1d1 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 7 Mar 2020 10:45:19 -0500 Subject: [PATCH 0262/1888] Remove p2p alert handling Backports https://github.com/bitcoin/bitcoin/commit/bbb9d1d1231099122a5b0ad5dd86f3f93ce22724 --- contrib/dapscoin-qt.pro | 2 - src/Makefile.am | 2 - src/Makefile.test.include | 2 +- src/alert.cpp | 252 ----------------------------------- src/alert.h | 115 ---------------- src/main.cpp | 21 --- src/qt/clientmodel.cpp | 1 - src/test/alert_tests.cpp | 179 +------------------------ src/test/data/alertTests.raw | Bin 1279 -> 0 bytes 9 files changed, 6 insertions(+), 568 deletions(-) delete mode 100644 src/alert.cpp delete mode 100644 src/alert.h delete mode 100644 src/test/data/alertTests.raw diff --git a/contrib/dapscoin-qt.pro b/contrib/dapscoin-qt.pro index 466e233aaf..bd2a11cdb1 100644 --- a/contrib/dapscoin-qt.pro +++ b/contrib/dapscoin-qt.pro @@ -57,7 +57,6 @@ INCLUDEPATH += . \ # Input HEADERS += src/activemasternode.h \ src/addrman.h \ - src/alert.h \ src/allocators.h \ src/amount.h \ src/arith_uint256.h \ @@ -381,7 +380,6 @@ FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/transactiondescdialog.ui \ SOURCES += src/activemasternode.cpp \ src/addrman.cpp \ - src/alert.cpp \ src/allocators.cpp \ src/amount.cpp \ src/arith_uint256.cpp \ diff --git a/src/Makefile.am b/src/Makefile.am index 877345db37..82f538abf3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,7 +94,6 @@ endif BITCOIN_CORE_H = \ activemasternode.h \ addrman.h \ - alert.h \ allocators.h \ amount.h \ base58.h \ @@ -202,7 +201,6 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) libbitcoin_server_a_SOURCES = \ addrman.cpp \ - alert.cpp \ bloom.cpp \ chain.cpp \ checkpoints.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 876a594be5..4eef22e19f 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -29,7 +29,7 @@ JSON_TEST_FILES = \ test/data/tx_valid.json \ test/data/sighash.json -RAW_TEST_FILES = test/data/alertTests.raw +RAW_TEST_FILES = GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) diff --git a/src/alert.cpp b/src/alert.cpp deleted file mode 100644 index 2bd2b5b298..0000000000 --- a/src/alert.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "alert.h" - -#include "chainparams.h" -#include "clientversion.h" -#include "net.h" -#include "pubkey.h" -#include "timedata.h" -#include "guiinterface.h" -#include "util.h" - -#include -#include -#include - -#include -#include -#include - -using namespace std; - -map mapAlerts; -RecursiveMutex cs_mapAlerts; - -void CUnsignedAlert::SetNull() -{ - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strReserved.clear(); -} - -std::string CUnsignedAlert::ToString() const -{ - std::string strSetCancel; - for (auto& n: setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - for (std::string str : setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %d\n" - " nExpiration = %d\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel, - nMinVer, - nMaxVer, - strSetSubVer, - nPriority, - strComment, - strStatusBar); -} - -void CAlert::SetNull() -{ - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); -} - -bool CAlert::IsNull() const -{ - return (nExpiration == 0); -} - -uint256 CAlert::GetHash() const -{ - return Hash(this->vchMsg.begin(), this->vchMsg.end()); -} - -bool CAlert::IsInEffect() const -{ - return (GetAdjustedTime() < nExpiration); -} - -bool CAlert::Cancels(const CAlert& alert) const -{ - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); -} - -bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const -{ - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); -} - -bool CAlert::AppliesToMe() const -{ - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); -} - -bool CAlert::RelayTo(CNode* pnode) const -{ - if (!IsInEffect()) - return false; - // don't relay to nodes which haven't sent their version message - if (pnode->nVersion == 0) - return false; - // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) { - if (AppliesTo(pnode->nVersion, pnode->strSubVer) || - AppliesToMe() || - GetAdjustedTime() < nRelayUntil) { - pnode->PushMessage("alert", *this); - return true; - } - } - return false; -} - -bool CAlert::CheckSignature() const -{ - CPubKey key(Params().AlertKey()); - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CAlert::CheckSignature() : verify signature failed"); - - // Now unserialize the data - CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); - sMsg >> *(CUnsignedAlert*)this; - return true; -} - -CAlert CAlert::getAlertByHash(const uint256& hash) -{ - CAlert retval; - { - LOCK(cs_mapAlerts); - map::iterator mi = mapAlerts.find(hash); - if (mi != mapAlerts.end()) - retval = mi->second; - } - return retval; -} - -bool CAlert::ProcessAlert(bool fThread) -{ - if (!CheckSignature()) - return false; - if (!IsInEffect()) - return false; - - // alert.nID=max is reserved for if the alert key is - // compromised. It must have a pre-defined message, - // must never expire, must apply to all versions, - // and must cancel all previous - // alerts or it will be ignored (so an attacker can't - // send an "everything is OK, don't panic" version that - // cannot be overridden): - int maxInt = std::numeric_limits::max(); - if (nID == maxInt) { - if (!( - nExpiration == maxInt && - nCancel == (maxInt - 1) && - nMinVer == 0 && - nMaxVer == maxInt && - setSubVer.empty() && - nPriority == maxInt && - strStatusBar == "URGENT: Alert key compromised, upgrade required")) - return false; - } - - { - LOCK(cs_mapAlerts); - // Cancel previous alerts - for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { - const CAlert& alert = (*mi).second; - if (Cancels(alert)) { - LogPrint("alert", "cancelling alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged(); - mapAlerts.erase(mi++); - } else if (!alert.IsInEffect()) { - LogPrint("alert", "expiring alert %d\n", alert.nID); - uiInterface.NotifyAlertChanged(); - mapAlerts.erase(mi++); - } else - mi++; - } - - // Check if this alert has been cancelled - for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { - const CAlert& alert = item.second; - if (alert.Cancels(*this)) { - LogPrint("alert", "alert already cancelled by %d\n", alert.nID); - return false; - } - } - - // Add to mapAlerts - mapAlerts.insert(make_pair(GetHash(), *this)); - // Notify UI and -alertnotify if it applies to me - if (AppliesToMe()) { - uiInterface.NotifyAlertChanged(); - Notify(strStatusBar, fThread); - } - } - - LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); - return true; -} - -void CAlert::Notify(const std::string& strMessage, bool fThread) -{ - std::string strCmd = GetArg("-alertnotify", ""); - if (strCmd.empty()) return; - - // Alert text should be plain ascii coming from a trusted source, but to - // be safe we first strip anything not in safeChars, then add single quotes around - // the whole string before passing it to the shell: - std::string singleQuote("'"); - std::string safeStatus = SanitizeString(strMessage); - safeStatus = singleQuote + safeStatus + singleQuote; - boost::replace_all(strCmd, "%s", safeStatus); - - if (fThread) - boost::thread t(runCommand, strCmd); // thread runs free - else - runCommand(strCmd); -} diff --git a/src/alert.h b/src/alert.h deleted file mode 100644 index 65d97fe5d3..0000000000 --- a/src/alert.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 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_ALERT_H -#define BITCOIN_ALERT_H - -#include "serialize.h" -#include "sync.h" - -#include -#include -#include -#include - -class CAlert; -class CNode; -class uint256; - -extern std::map mapAlerts; -extern RecursiveMutex cs_mapAlerts; - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes - int64_t nExpiration; - int nID; - int nCancel; - std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strReserved; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) - { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(LIMITED_STRING(strComment, 65536)); - READWRITE(LIMITED_STRING(strStatusBar, 256)); - READWRITE(LIMITED_STRING(strReserved, 256)); - } - - void SetNull(); - - std::string ToString() const; -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector vchMsg; - std::vector vchSig; - - CAlert() - { - SetNull(); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) - { - READWRITE(vchMsg); - READWRITE(vchSig); - } - - void SetNull(); - bool IsNull() const; - uint256 GetHash() const; - bool IsInEffect() const; - bool Cancels(const CAlert& alert) const; - bool AppliesTo(int nVersion, std::string strSubVerIn) const; - bool AppliesToMe() const; - bool RelayTo(CNode* pnode) const; - bool CheckSignature() const; - bool ProcessAlert(bool fThread = true); // fThread means run -alertnotify in a free-running thread - static void Notify(const std::string& strMessage, bool fThread); - - /* - * Get copy of (active) alert object by hash. Returns a null alert if it is not found. - */ - static CAlert getAlertByHash(const uint256& hash); -}; - -#endif // BITCOIN_ALERT_H diff --git a/src/main.cpp b/src/main.cpp index a3c63f085b..4272845f58 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,6 @@ #include "main.h" #include "addrman.h" -#include "alert.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -5353,14 +5352,9 @@ void static CheckBlockIndex() assert(nNodes == forward.size()); } -////////////////////////////////////////////////////////////////////////////// -// -// CAlert -// string GetWarnings(string strFor) { - int nPriority = 0; string strStatusBar; string strRPC; @@ -5373,32 +5367,17 @@ string GetWarnings(string strFor) // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { - nPriority = 1000; strStatusBar = strMiscWarning; } if (fLargeWorkForkFound) { - nPriority = 2000; strStatusBar = strRPC = _( "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); } else if (fLargeWorkInvalidChainFound) { - nPriority = 2000; strStatusBar = strRPC = _( "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } - // Alerts - { - LOCK(cs_mapAlerts); - for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { - const CAlert& alert = item.second; - if (alert.AppliesToMe() && alert.nPriority > nPriority) { - nPriority = alert.nPriority; - strStatusBar = alert.strStatusBar; - } - } - } - if (strFor == "statusbar") return strStatusBar; else if (strFor == "rpc") diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index be154b261f..4bdec7dfa9 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -11,7 +11,6 @@ #include "guiutil.h" #include "peertablemodel.h" -#include "alert.h" #include "chainparams.h" #include "checkpoints.h" #include "clientversion.h" diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index b2e3045b47..c43881be20 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -6,187 +6,18 @@ // Unit tests for alert system // -#include "alert.h" -#include "clientversion.h" -#include "data/alertTests.raw.h" - -#include "serialize.h" -#include "streams.h" +#include "chainparams.h" #include "util.h" -#include "utilstrencodings.h" -#include +#include "test/test_bitcoin.h" -#include #include -#if 0 -// -// alertTests contains 7 alerts, generated with this code: -// (SignAndSave code not shown, alert signing key is secret) -// -{ - CAlert alert; - alert.nRelayUntil = 60; - alert.nExpiration = 24 * 60 * 60; - alert.nID = 1; - alert.nCancel = 0; // cancels previous messages up to this ID number - alert.nMinVer = 0; // These versions are protocol versions - alert.nMaxVer = 999001; - alert.nPriority = 1; - alert.strComment = "Alert comment"; - alert.strStatusBar = "Alert 1"; - - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0"; - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.insert(std::string("/Satoshi:0.2.0/")); - alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0"; - SignAndSave(alert, "test/alertTests"); - - alert.setSubVer.clear(); - ++alert.nID; - alert.nCancel = 1; - alert.nPriority = 100; - alert.strStatusBar = "Alert 2, cancels 1"; - SignAndSave(alert, "test/alertTests"); - - alert.nExpiration += 60; - ++alert.nID; - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.nMinVer = 11; - alert.nMaxVer = 22; - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.strStatusBar = "Alert 2 for Satoshi 0.1.0"; - alert.setSubVer.insert(std::string("/Satoshi:0.1.0/")); - SignAndSave(alert, "test/alertTests"); - - ++alert.nID; - alert.nMinVer = 0; - alert.nMaxVer = 999999; - alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; - alert.setSubVer.clear(); - SignAndSave(alert, "test/alertTests"); -} -#endif - -struct ReadAlerts -{ - ReadAlerts() - { - std::vector vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests)); - CDataStream stream(vch, SER_DISK, CLIENT_VERSION); - try { - while (!stream.eof()) - { - CAlert alert; - stream >> alert; - alerts.push_back(alert); - } - } - catch (std::exception) { } - } - ~ReadAlerts() { } - - static std::vector read_lines(boost::filesystem::path filepath) - { - std::vector result; - - std::ifstream f(filepath.string().c_str()); - std::string line; - while (std::getline(f,line)) - result.push_back(line); - - return result; - } - - std::vector alerts; -}; - -#ifdef DISABLE_PASSED_TEST -BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) - +BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup) -BOOST_AUTO_TEST_CASE(AlertApplies) +BOOST_AUTO_TEST_CASE(PartitionAlert) { - SetMockTime(11); - - for (const CAlert& alert : alerts) - { - BOOST_CHECK(alert.CheckSignature()); - } - - BOOST_CHECK(alerts.size() >= 3); - - // Matches: - BOOST_CHECK(alerts[0].AppliesTo(1, "")); - BOOST_CHECK(alerts[0].AppliesTo(999001, "")); - BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/")); - - BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/")); - - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/")); - BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/")); - - // Don't match: - BOOST_CHECK(!alerts[0].AppliesTo(-1, "")); - BOOST_CHECK(!alerts[0].AppliesTo(999002, "")); - - BOOST_CHECK(!alerts[1].AppliesTo(1, "")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/")); - - BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/")); - - SetMockTime(0); -} - - -BOOST_AUTO_TEST_CASE(AlertNotify) -{ - SetMockTime(11); - - boost::filesystem::path temp = GetTempPath() / "alertnotify.txt"; - boost::filesystem::remove(temp); - - mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - - for (CAlert alert : alerts) - alert.ProcessAlert(false); - - std::vector r = read_lines(temp); - BOOST_CHECK_EQUAL(r.size(), 4u); - -// Windows built-in echo semantics are different than posixy shells. Quotes and -// whitespace are printed literally. - -#ifndef WIN32 - BOOST_CHECK_EQUAL(r[0], "Alert 1"); - BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed -#else - BOOST_CHECK_EQUAL(r[0], "'Alert 1' "); - BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' "); -#endif - boost::filesystem::remove(temp); - - SetMockTime(0); + // !TODO: implement this } BOOST_AUTO_TEST_SUITE_END() -#endif diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw deleted file mode 100644 index 01f50680b95aa307a1a013b643ded4ae0bc47162..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1279 zcmZ={WME*h0b&qn2n6vM7$78=$-oe4#}5(Vb<9aEDp5$z&&^HED`AK53>n-FT$vOZ zT6;>jOMiNBjj`hU_HgHQ?~0yVcV6r{KVN{qoVTd1?j)0f{?x_?$@^IxUUY29f16*- z{-FM@nZvZ(TZ|lvBLA-{pO8$HOBng}gA+^gi!(B<4D<~34D>;|P+cYob(un1evtxH zu>x2zgPVa1lY-RE%g6XV)mGXqWBmT=!_|Y)_kR4}7A7R>c0E!g1h&KK=J$_^x?-%R>l_4VpRoijgP z&DbIlds%@=!Hs|Q$%9_UR_lD=jto@ZWi)^P&3X0fwJdjAvK+dmdHF6@N3p;h#SLVL z0Wkw{0R?f?PV@b-k5Wyi>i4_%Bo<$lHv6ySF0|S7Vr$;KnH3w}K4Ve{5mx)@H;>VG zV)PxY7R{(M)t&dXdm1tqJ%LW&jLQ5abT(~;1uVuU5DK-_v|qEX;l z`;Ea8OG>`yYWv(O?P7~*yl?IK{6}Bi%Enc$ObUtn4ofyOb8$Z~I;nGod;9)Xj~<*9 zKa_r_FRL*-b5> Date: Sat, 7 Mar 2020 10:47:11 -0500 Subject: [PATCH 0263/1888] Remove alert keys Backports https://github.com/bitcoin/bitcoin/commit/1b77471bd62b31b6682c5e40d2d8bf88db3034c7 --- src/chainparams.cpp | 2 -- src/chainparams.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 148a7b092f..1530c6cd84 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -167,7 +167,6 @@ class CMainParams : public CChainParams pchMessageStart[1] = 0xb7; pchMessageStart[2] = 0x79; pchMessageStart[3] = 0x84; - vAlertPubKey = ParseHex("049def8e22e7f78b624dc62007c66c06066d032310b3507642306b143326a8295e03576ffab7469c552e1a68655598d78d501eb10cc27408bfd7876dbadb08b0ee"); nDefaultPort = 53572; bnProofOfWorkLimit = ~uint256(0) >> 1; // DAPScoin starting difficulty is 1 / 2^12 nSubsidyHalvingInterval = 210000; @@ -314,7 +313,6 @@ class CTestNetParams : public CMainParams pchMessageStart[1] = 0xb8; pchMessageStart[2] = 0x7a; pchMessageStart[3] = 0x85; - vAlertPubKey = ParseHex("04b6c4c72f1ef439a603ab52aa2ca7c73c59c5cfb0ebdae305f7fd2928bb90b41293dc746753f59fea3a6fb2cc546bbebf4387a368bdf1a3755d4545fe28ba449e"); nDefaultPort = 53574; nEnforceBlockUpgradeMajority = 51; nRejectBlockOutdatedMajority = 75; diff --git a/src/chainparams.h b/src/chainparams.h index c419fde041..befe3e5a9a 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -46,7 +46,6 @@ class CChainParams const uint256& HashGenesisBlock() const { return hashGenesisBlock; } const MessageStartChars& MessageStart() const { return pchMessageStart; } - const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } @@ -116,7 +115,6 @@ class CChainParams uint256 hashGenesisBlock; MessageStartChars pchMessageStart; //! Raw pub key bytes for the broadcast alert signing key. - std::vector vAlertPubKey; int nDefaultPort; int nExtCoinType; uint256 bnProofOfWorkLimit; From eabec4c5253cb24dc068797b7d75b62faef9754f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 7 Mar 2020 10:49:20 -0500 Subject: [PATCH 0264/1888] [Trivial] Fix NotifyAlertChanged comment (cs_mapAlerts not required) --- src/guiinterface.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/guiinterface.h b/src/guiinterface.h index 8a7f80b1f9..6277ab6125 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -91,10 +91,7 @@ class CClientUIInterface /** Number of network connections changed. */ boost::signals2::signal NotifyNumConnectionsChanged; - /** - * New, updated or cancelled alert. - * @note called with lock cs_mapAlerts held. - */ + /** New, updated or cancelled alert. */ boost::signals2::signal NotifyAlertChanged; /** A wallet has been loaded. */ From 8c6b414bc4c7616238b20570500f934603e0f636 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 4 Mar 2020 22:02:01 -0500 Subject: [PATCH 0265/1888] [Refactor] move nReserveBalance from main to wallet --- src/init.cpp | 2 ++ src/main.cpp | 1 - src/main.h | 2 +- src/wallet/wallet.cpp | 3 ++- src/wallet/wallet.h | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4c583fba5b..b99fc7b85f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -885,12 +885,14 @@ bool AppInit2(bool isDaemon) LogPrintf("AppInit2 : parameter interaction: -enableswifttx=false -> setting -nSwiftTXDepth=0\n"); } +#ifdef ENABLE_WALLET if (mapArgs.count("-reservebalance")) { if (!ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) { InitError(_("Invalid amount for -reservebalance=")); return false; } } +#endif // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); diff --git a/src/main.cpp b/src/main.cpp index 4272845f58..28200bcec9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,7 +90,6 @@ unsigned int nCoinCacheSize = 5000; int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; unsigned int nStakeMinAge = 60 * 60; -int64_t nReserveBalance = 0; const int MIN_RING_SIZE = 11; const int MAX_RING_SIZE = 15; diff --git a/src/main.h b/src/main.h index 6ef0b88748..36cc499e3d 100644 --- a/src/main.h +++ b/src/main.h @@ -163,7 +163,7 @@ extern unsigned int nStakeMinAge; extern int64_t nLastCoinStakeSearchInterval; //extern int64_t nConsolidationTime; extern int64_t nLastCoinStakeSearchTime; -extern int64_t nReserveBalance; + extern const int MIN_RING_SIZE; extern const int MAX_RING_SIZE; extern const int MAX_TX_INPUTS; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1918715db9..493b3a88e4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -51,7 +51,8 @@ bool bSpendZeroConfChange = true; bool bdisableSystemnotifications = false; // Those bubbles can be annoying and slow down the UI when you get lots of trx bool fSendFreeTransactions = false; bool fPayAtLeastCustomFee = true; -int64_t nStartupTime = GetTime(); //!< Client startup time for use with automint +int64_t nStartupTime = GetTime(); +int64_t nReserveBalance = 0; #include "uint256.h" diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 19ab5cb798..8eebbf0e0d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -55,6 +55,7 @@ extern bool bSpendZeroConfChange; extern bool bdisableSystemnotifications; extern bool fSendFreeTransactions; extern bool fPayAtLeastCustomFee; +extern int64_t nReserveBalance; //! -paytxfee default static const CAmount DEFAULT_TRANSACTION_FEE = 0.1 * COIN;// From 5d814b08dcc991d2455f7246f999cd32269046ac Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 13 Mar 2020 18:30:40 -0400 Subject: [PATCH 0266/1888] Refactor parameter interaction, call it before AppInit2() --- src/dapscoind.cpp | 2 ++ src/init.cpp | 59 ++++++++++++++++++++++++++--------------------- src/init.h | 2 ++ 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 256311ebad..112d943a26 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -148,6 +148,8 @@ bool AppInit(int argc, char* argv[]) } #endif SoftSetBoolArg("-server", true); + + InitParameterInteraction(); fRet = AppInit2(true); } catch (std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); diff --git a/src/init.cpp b/src/init.cpp index b99fc7b85f..60cc30f389 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -809,34 +809,22 @@ bool AppInitBasicSetup() return true; } -/** Initialize daps. - * @pre Parameters should be parsed and config file should be read. - */ -bool AppInit2(bool isDaemon) +// Parameter interaction based on rules +void InitParameterInteraction() { - // ********************************************************* Step 1: setup - if (!AppInitBasicSetup()) - return false; - - // ********************************************************* Step 2: parameter interactions - // Set this early so that parameter interactions go to console - fPrintToConsole = GetBoolArg("-printtoconsole", false); - fLogTimestamps = GetBoolArg("-logtimestamps", true); - fLogIPs = GetBoolArg("-logips", false); - if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified if (SoftSetBoolArg("-listen", true)) - LogPrintf("AppInit2 : parameter interaction: -bind or -whitebind set -> setting -listen=1\n"); + LogPrintf("%s : parameter interaction: -bind or -whitebind set -> setting -listen=1\n", __func__); } if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default if (SoftSetBoolArg("-dnsseed", false)) - LogPrintf("AppInit2 : parameter interaction: -connect set -> setting -dnsseed=0\n"); + LogPrintf("%s : parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); if (SoftSetBoolArg("-listen", false)) - LogPrintf("AppInit2 : parameter interaction: -connect set -> setting -listen=0\n"); + LogPrintf("%s : parameter interaction: -connect set -> setting -listen=0\n", __func__); } if (mapArgs.count("-proxy")) { @@ -849,41 +837,60 @@ bool AppInit2(bool isDaemon) LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); // to protect privacy, do not discover addresses by default if (SoftSetBoolArg("-discover", false)) - LogPrintf("AppInit2 : parameter interaction: -proxy set -> setting -discover=0\n"); + LogPrintf("%s : parameter interaction: -proxy set -> setting -discover=0\n", __func__); } if (!GetBoolArg("-listen", true)) { // do not map ports or try to retrieve public IP when not listening (pointless) if (SoftSetBoolArg("-upnp", false)) - LogPrintf("AppInit2 : parameter interaction: -listen=0 -> setting -upnp=0\n"); + LogPrintf("%s : parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); if (SoftSetBoolArg("-discover", false)) - LogPrintf("AppInit2 : parameter interaction: -listen=0 -> setting -discover=0\n"); + LogPrintf("%s : parameter interaction: -listen=0 -> setting -discover=0\n", __func__); if (SoftSetBoolArg("-listenonion", false)) - LogPrintf("AppInit2 : parameter interaction: -listen=0 -> setting -listenonion=0\n"); + LogPrintf("%s : parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } if (mapArgs.count("-externalip")) { // if an explicit public IP is specified, do not try to find others if (SoftSetBoolArg("-discover", false)) - LogPrintf("AppInit2 : parameter interaction: -externalip set -> setting -discover=0\n"); + LogPrintf("%s : parameter interaction: -externalip set -> setting -discover=0\n", __func__); } if (GetBoolArg("-salvagewallet", false)) { // Rewrite just private keys: rescan to find transactions if (SoftSetBoolArg("-rescan", true)) - LogPrintf("AppInit2 : parameter interaction: -salvagewallet=1 -> setting -rescan=1\n"); + LogPrintf("%s : parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__); } // -zapwallettx implies a rescan if (GetBoolArg("-zapwallettxes", false)) { if (SoftSetBoolArg("-rescan", true)) - LogPrintf("AppInit2 : parameter interaction: -zapwallettxes= -> setting -rescan=1\n"); + LogPrintf("%s : parameter interaction: -zapwallettxes= -> setting -rescan=1\n", __func__); } if (!GetBoolArg("-enableswifttx", fEnableSwiftTX)) { if (SoftSetArg("-swifttxdepth", "0")) - LogPrintf("AppInit2 : parameter interaction: -enableswifttx=false -> setting -nSwiftTXDepth=0\n"); + LogPrintf("%s : parameter interaction: -enableswifttx=false -> setting -nSwiftTXDepth=0\n", __func__); } +} + +/** Initialize daps. + * @pre Parameters should be parsed and config file should be read. + */ +bool AppInit2(bool isDaemon) +{ + // ********************************************************* Step 1: setup + if (!AppInitBasicSetup()) + return false; + + // ********************************************************* Step 2: parameter interactions + // Set this early so that parameter interactions go to console + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fLogTimestamps = GetBoolArg("-logtimestamps", true); + fLogIPs = GetBoolArg("-logips", false); + + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("DAPS version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); #ifdef ENABLE_WALLET if (mapArgs.count("-reservebalance")) { @@ -947,7 +954,7 @@ bool AppInit2(bool isDaemon) if (fDisableWallet) { #endif if (SoftSetBoolArg("-staking", false)) - LogPrintf("AppInit2 : parameter interaction: wallet functionality not enabled -> setting -staking=0\n"); + LogPrintf("%s : parameter interaction: wallet functionality not enabled -> setting -staking=0\n"); #ifdef ENABLE_WALLET } #endif diff --git a/src/init.h b/src/init.h index 168b1fa7cf..441aca4d9a 100644 --- a/src/init.h +++ b/src/init.h @@ -24,6 +24,8 @@ bool ShutdownRequested(); void Interrupt(); void Shutdown(); void PrepareShutdown(); +//!Parameter interaction: change current parameters depending on various rules +void InitParameterInteraction(); bool AppInit2(bool isDaemon); /** Initialize DAPS: Basic context setup. From e3e13c101989dd6421cc6ee6486da1dfb3811262 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 13 Mar 2020 18:39:09 -0400 Subject: [PATCH 0267/1888] [QT] Call inits parameter interaction before we create the options model --- src/qt/dapscoin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index 49f01802bf..a529f4e622 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -206,6 +206,8 @@ class BitcoinApplication : public QApplication /// Create payment server void createPaymentServer(); #endif + /// parameter interaction/setup based on rules + void parameterSetup(); /// Create options model void createOptionsModel(); /// Create main window @@ -416,6 +418,11 @@ void BitcoinApplication::startThread() coreThread->start(); } +void BitcoinApplication::parameterSetup() +{ + InitParameterInteraction(); +} + void BitcoinApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; @@ -697,6 +704,8 @@ int main(int argc, char* argv[]) #endif // Install qDebug() message handler to route to debug.log qInstallMessageHandler(DebugMessageHandler); + // Allow parameter interaction before we create the options model + app.parameterSetup(); // Load GUI settings from QSettings app.createOptionsModel(); From a5659fd002204d813f587ab7f4b25e8c0ef59a5c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 13 Mar 2020 19:06:27 -0400 Subject: [PATCH 0268/1888] Initialize logging before we do parameter interaction --- src/dapscoind.cpp | 2 ++ src/init.cpp | 33 +++++++++++++++++---------------- src/init.h | 2 ++ src/qt/dapscoin.cpp | 1 + 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 112d943a26..4bade08cbb 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -149,6 +149,8 @@ bool AppInit(int argc, char* argv[]) #endif SoftSetBoolArg("-server", true); + // Set this early so that parameter interactions go to console + InitLogging(); InitParameterInteraction(); fRet = AppInit2(true); } catch (std::exception& e) { diff --git a/src/init.cpp b/src/init.cpp index 60cc30f389..bc7fd69102 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -874,6 +874,16 @@ void InitParameterInteraction() } } +void InitLogging() +{ + fPrintToConsole = GetBoolArg("-printtoconsole", false); + fLogTimestamps = GetBoolArg("-logtimestamps", true); + fLogIPs = GetBoolArg("-logips", false); + + LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + LogPrintf("DAPS version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); +} + /** Initialize daps. * @pre Parameters should be parsed and config file should be read. */ @@ -884,14 +894,6 @@ bool AppInit2(bool isDaemon) return false; // ********************************************************* Step 2: parameter interactions - // Set this early so that parameter interactions go to console - fPrintToConsole = GetBoolArg("-printtoconsole", false); - fLogTimestamps = GetBoolArg("-logtimestamps", true); - fLogIPs = GetBoolArg("-logips", false); - - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("DAPS version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); - #ifdef ENABLE_WALLET if (mapArgs.count("-reservebalance")) { if (!ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) { @@ -1053,8 +1055,7 @@ bool AppInit2(bool isDaemon) #endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); - LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - LogPrintf("DAPS version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); + LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); #ifdef ENABLE_WALLET LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); @@ -1164,7 +1165,7 @@ bool AppInit2(bool isDaemon) // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state filesystem::path blocksDir = GetDataDir() / "blocks"; filesystem::path chainstateDir = GetDataDir() / "chainstate"; - + // We delete in 4 individual steps in case one of the folder is missing already try { if (filesystem::exists(blocksDir)){ @@ -1498,7 +1499,7 @@ bool AppInit2(bool isDaemon) filesystem::path blocksDir = GetDataDir() / "blocks"; filesystem::path chainstateDir = GetDataDir() / "chainstate"; - + // We delete in 4 individual steps in case one of the folder is missing already try { if (filesystem::exists(blocksDir)){ @@ -1510,13 +1511,13 @@ bool AppInit2(bool isDaemon) boost::filesystem::remove_all(chainstateDir); LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); } - + boost::filesystem::create_directories(blocksDir); boost::filesystem::create_directories(chainstateDir); } catch (boost::filesystem::filesystem_error& error) { LogPrintf("Failed to delete blockchain folders %s\n", error.what()); } - + } else { LogPrintf("Aborted block database rebuild. Exiting.\n"); return false; @@ -1611,7 +1612,7 @@ bool AppInit2(bool isDaemon) if (!isDaemon) { uiInterface.ShowRecoveryDialog(); } - + if (!pwalletMain->IsHDEnabled()) { // generate a new master key pwalletMain->GenerateNewHDChain(); @@ -1915,7 +1916,7 @@ bool AppInit2(bool isDaemon) // Run a thread to flush wallet periodically threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); - + storedStakingStatus = pwalletMain->ReadStakingStatus(); if (GetBoolArg("-staking", false) || storedStakingStatus) { fGenerateDapscoins = true; diff --git a/src/init.h b/src/init.h index 441aca4d9a..370a05f013 100644 --- a/src/init.h +++ b/src/init.h @@ -24,6 +24,8 @@ bool ShutdownRequested(); void Interrupt(); void Shutdown(); void PrepareShutdown(); +//!Initialize the logging infrastructure +void InitLogging(); //!Parameter interaction: change current parameters depending on various rules void InitParameterInteraction(); bool AppInit2(bool isDaemon); diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index a529f4e622..f23ad325b8 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -420,6 +420,7 @@ void BitcoinApplication::startThread() void BitcoinApplication::parameterSetup() { + InitLogging(); InitParameterInteraction(); } From 0dd9b2d45a071f29222af90d6e8d18009cfb06db Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Mar 2020 00:00:13 -0400 Subject: [PATCH 0269/1888] [Cleanup] Remove multiple calls to chainActive in main functions from https://github.com/PIVX-Project/PIVX/pull/1322/commits/80753f9bf591367960f8a71d788633dde1c3a3ac --- src/checkpoints.cpp | 2 +- src/checkpoints.h | 2 +- src/main.cpp | 66 +++++++++++++++++++++++++-------------------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 3654968a67..0509adbf34 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -42,7 +42,7 @@ bool CheckBlock(int nHeight, const uint256& hash, bool fMatchesCheckpoint) } //! Guess how far we are in the verification process at the given block index -double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks) +double GuessVerificationProgress(const CBlockIndex* pindex, bool fSigchecks) { if (pindex == NULL) return 0.0; diff --git a/src/checkpoints.h b/src/checkpoints.h index 2fdb2c9783..11cc2f93bf 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -35,7 +35,7 @@ int GetTotalBlocksEstimate(); //! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(); -double GuessVerificationProgress(CBlockIndex* pindex, bool fSigchecks = true); +double GuessVerificationProgress(const CBlockIndex* pindex, bool fSigchecks = true); extern bool fEnabled; diff --git a/src/main.cpp b/src/main.cpp index 28200bcec9..39ddcb6afc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1832,6 +1832,8 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact if (pfMissingInputs) *pfMissingInputs = false; + const int chainHeight = chainActive.Height(); + if (!CheckTransaction(tx, false, true, state)) return error("AcceptableInputs: : CheckTransaction failed"); @@ -1898,7 +1900,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // check for invalid/fraudulent inputs - if (!ValidOutPoint(txin.prevout, chainActive.Height())) { + if (!ValidOutPoint(txin.prevout, chainHeight)) { return state.Invalid( error("%s : tried to spend invalid input %s in tx %s", __func__, txin.prevout.ToString(), tx.GetHash().GetHex()), @@ -1935,9 +1937,9 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact CAmount nValueOut = tx.GetValueOut(); CAmount nFees = tx.nTxFee; - double dPriority = GetPriority(tx, chainActive.Height()); + double dPriority = GetPriority(tx, chainHeight); - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainHeight); unsigned int nSize = entry.GetTxSize(); // Don't accept it if it can't get into a block @@ -1953,7 +1955,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // Require that free transactions have sufficient priority to be mined in the next block. //TODO: @campv need to recompute the fee /*if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && - !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + !AllowFree(view.GetPriority(tx, chainHeight + 1))) { return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); }*/ @@ -2316,12 +2318,13 @@ int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCou bool IsInitialBlockDownload() { LOCK(cs_main); - if (fImporting || fReindex || fVerifyingBlocks || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) + const int chainHeight = chainActive.Height(); + if (fImporting || fReindex || fVerifyingBlocks || chainHeight < Checkpoints::GetTotalBlocksEstimate()) return true; static bool lockIBDState = false; if (lockIBDState) return false; - bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || + bool state = (chainHeight < pindexBestHeader->nHeight - 24 * 6 || pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; @@ -2487,10 +2490,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew) LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble()) / log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime())); + + const CBlockIndex* pChainTip = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; LogPrintf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime())); + pChainTip->GetBlockHash().GetHex(), pChainTip->nHeight, log(pChainTip->nChainWork.getdouble()) / log(2.0), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pChainTip->GetBlockTime())); CheckForkWarningConditions(); } @@ -2808,7 +2812,8 @@ void ThreadScriptCheck() bool RecalculateDAPSSupply(int nHeightStart) { - if (nHeightStart > chainActive.Height()) + const int chainHeight = chainActive.Height(); + if (nHeightStart > chainHeight) return false; CBlockIndex* pindex = chainActive[nHeightStart]; @@ -2818,7 +2823,7 @@ bool RecalculateDAPSSupply(int nHeightStart) while (true) { if (pindex->nHeight % 1000 == 0) { LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); - int percent = std::max(1, std::min(99, (int)((double)((pindex->nHeight - nHeightStart) * 100) / (chainActive.Height() - nHeightStart)))); + int percent = std::max(1, std::min(99, (int)((double)((pindex->nHeight - nHeightStart) * 100) / (chainHeight - nHeightStart)))); uiInterface.ShowProgress(_("Recalculating DAPS supply..."), percent); } CBlock block; @@ -2874,7 +2879,7 @@ bool RecalculateDAPSSupply(int nHeightStart) assert(pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))); - if (pindex->nHeight < chainActive.Height()) + if (pindex->nHeight < chainHeight) pindex = chainActive.Next(pindex); else break; @@ -3233,10 +3238,11 @@ void static UpdateTip(CBlockIndex* pindexNew) g_best_block_cv.notify_all(); } + const CBlockIndex* pChainTip = chainActive.Tip(); LogPrintf("UpdateTip: new best=%s height=%d version=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion, log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); + pChainTip->GetBlockHash().GetHex(), pChainTip->nHeight, pChainTip->nVersion, log(pChainTip->nChainWork.getdouble()) / log(2.0), (unsigned long)pChainTip->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pChainTip->GetBlockTime()), + Checkpoints::GuessVerificationProgress(pChainTip), (unsigned int)pcoinsTip->GetCacheSize()); // Check the version of the last 100 blocks to see if we need to upgrade: static bool fWarned = false; @@ -4254,13 +4260,13 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta assert(pindexPrev); - int nHeight = pindexPrev->nHeight + 1; + const int nHeight = pindexPrev->nHeight + 1; + const int chainHeight = chainActive.Height(); //If this is a reorg, check that it is not too deep int nMaxReorgDepth = GetArg("-maxreorg", Params().MaxReorganizationDepth()); - if (chainActive.Height() - nHeight >= nMaxReorgDepth) - return state.DoS(1, - error("%s: forked chain older than max reorganization depth (height %d)", __func__, nHeight)); + if (chainHeight - nHeight >= nMaxReorgDepth) + return state.DoS(1, error("%s: forked chain older than max reorganization depth (height %d)", __func__, chainHeight - nHeight)); // Check timestamp against prev if (!block.IsPoABlockByVersion() && block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) { @@ -4930,10 +4936,11 @@ bool static LoadBlockIndexDB(string& strError) PruneBlockIndexCandidates(); + const CBlockIndex* pChainTip = chainActive.Tip(); LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s progress=%f\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip())); + pChainTip->GetBlockHash().GetHex(), pChainTip->nHeight, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pChainTip->GetBlockTime()), + Checkpoints::GuessVerificationProgress(pChainTip)); return true; } @@ -4954,11 +4961,12 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) return true; + const int chainHeight = chainActive.Height(); // Verify blocks in the best chain if (nCheckDepth <= 0) nCheckDepth = 1000000000; // suffices until the year 19000 - if (nCheckDepth > chainActive.Height()) - nCheckDepth = chainActive.Height(); + if (nCheckDepth > chainHeight) + nCheckDepth = chainHeight; nCheckLevel = std::max(0, std::min(4, nCheckLevel)); LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CCoinsViewCache coins(coinsview); @@ -4968,8 +4976,8 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth CValidationState state; for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); - if (pindex->nHeight < chainActive.Height() - nCheckDepth) + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainHeight - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); + if (pindex->nHeight < chainHeight - nCheckDepth) break; CBlock block; // check level 0: read from disk @@ -5003,14 +5011,14 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth return true; } if (pindexFailure) - return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); + return error("VerifyDB() : *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainHeight - pindexFailure->nHeight + 1, nGoodTransactions); // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { CBlockIndex* pindex = pindexState; while (pindex != chainActive.Tip()) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainHeight - pindex->nHeight)) / (double)nCheckDepth * 50)))); pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex)) @@ -5020,7 +5028,7 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth } } - LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); + LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainHeight - pindexState->nHeight, nGoodTransactions); return true; } From c66186a67ce6c73349d8fd239230c6ebf0478d6f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 16 Mar 2020 00:19:00 -0400 Subject: [PATCH 0270/1888] Combine common error strings so translations can be shared and reused --- src/init.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index bc7fd69102..ea1f0aaefc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -874,6 +874,16 @@ void InitParameterInteraction() } } +static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) +{ + return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); +} + +static std::string AmountErrMsg(const char * const optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); +} + void InitLogging() { fPrintToConsole = GetBoolArg("-printtoconsole", false); @@ -976,7 +986,7 @@ bool AppInit2(bool isDaemon) if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) ::minRelayTxFee = CFeeRate(n); else - return InitError(strprintf(_("Invalid amount for -minrelaytxfee=: '%s'"), mapArgs["-minrelaytxfee"])); + return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"])); } #ifdef ENABLE_WALLET @@ -985,12 +995,12 @@ bool AppInit2(bool isDaemon) if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) CWallet::minTxFee = CFeeRate(n); else - return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), mapArgs["-mintxfee"])); + return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); } if (mapArgs.count("-paytxfee")) { CAmount nFeePerK = 0; if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), mapArgs["-paytxfee"])); + return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); if (nFeePerK > nHighTransactionFeeWarning) InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); payTxFee = CFeeRate(nFeePerK, 1000); @@ -1002,7 +1012,7 @@ bool AppInit2(bool isDaemon) if (mapArgs.count("-maxtxfee")) { CAmount nMaxFee = 0; if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s'"), mapArgs["-maxtxfee"])); + return InitError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"])); if (nMaxFee > nHighTransactionMaxFeeWarning) InitWarning(_("Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction.")); maxTxFee = nMaxFee; @@ -1325,13 +1335,13 @@ bool AppInit2(bool isDaemon) for (std::string strBind : mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) - return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); + return InitError(ResolveErrMsg("bind", strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } for (std::string strBind : mapMultiArgs["-whitebind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) - return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); + return InitError(ResolveErrMsg("whitebind", strBind)); if (addrBind.GetPort() == 0) return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); @@ -1352,7 +1362,7 @@ bool AppInit2(bool isDaemon) if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) AddLocal(addrLocal,LOCAL_MANUAL); else - return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); + return InitError(ResolveErrMsg("externalip", strAddr)); } } From 6436b5d54463985cfed7b0552106eab3f52e952d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Mar 2020 08:26:11 -0400 Subject: [PATCH 0271/1888] [Model] Save cache BlockIndex tip in the model In order to call - getNumBlocks - getLastBlockDate - getLastBlockHash - getVerificationProgress without locking the main UI thread. --- src/qt/clientmodel.cpp | 28 ++++++++++------------------ src/qt/clientmodel.h | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 4bdec7dfa9..43f906cc47 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -18,6 +18,7 @@ #include "masternode-sync.h" #include "masternodeman.h" #include "net.h" +#include "netbase.h" #include "guiinterface.h" #include "util.h" @@ -35,7 +36,7 @@ ClientModel::ClientModel(OptionsModel* optionsModel, QObject* parent) : QObject( optionsModel(optionsModel), peerTableModel(0), banTableModel(0), - cachedNumBlocks(0), + cacheTip(nullptr), cachedMasternodeCountString(""), cachedReindexing(0), cachedImporting(0), numBlocksAtStartup(-1), pollTimer(0) @@ -84,8 +85,7 @@ QString ClientModel::getMasternodeCountString() const int ClientModel::getNumBlocks() const { - LOCK(cs_main); - return chainActive.Height(); + return cacheTip == nullptr ? 0 : cacheTip->nHeight; } int ClientModel::getNumBlocksAtStartup() @@ -106,20 +106,14 @@ quint64 ClientModel::getTotalBytesSent() const QDateTime ClientModel::getLastBlockDate() const { - LOCK(cs_main); - if (chainActive.Tip()) - return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime()); - else - return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network + const int nTime = (cacheTip == nullptr ? Params().GenesisBlock().GetBlockTime() : cacheTip->GetBlockTime()); + return QDateTime::fromTime_t(nTime); } QString ClientModel::getLastBlockHash() const { - LOCK(cs_main); - if (chainActive.Tip()) - return QString::fromStdString(chainActive.Tip()->GetBlockHash().ToString()); - else - return QString::fromStdString(Params().GenesisBlock().GetHash().ToString()); // Genesis block's hash of current network + const uint256& nHash = (cacheTip == nullptr ? Params().GenesisBlock().GetHash() : cacheTip->GetBlockHash()); + return QString::fromStdString(nHash.GetHex()); } int ClientModel::getChainHeight() const @@ -133,8 +127,7 @@ int ClientModel::getChainHeight() const double ClientModel::getVerificationProgress() const { - LOCK(cs_main); - return Checkpoints::GuessVerificationProgress(chainActive.Tip()); + return Checkpoints::GuessVerificationProgress(cacheTip); } void ClientModel::updateTimer() @@ -256,11 +249,10 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB // if we are in-sync, update the UI regardless of last update time if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread - int newHeight = pIndex->nHeight; - clientmodel->setCacheNumBlocks(newHeight); + clientmodel->setCacheTip(pIndex); clientmodel->setCacheImporting(fImporting); clientmodel->setCacheReindexing(fReindex); - Q_EMIT clientmodel->numBlocksChanged(newHeight); + Q_EMIT clientmodel->numBlocksChanged(pIndex->nHeight); nLastBlockTipUpdateNotification = now; } } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index e409586b07..dfa0a23176 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -9,6 +9,7 @@ #define BITCOIN_QT_CLIENTMODEL_H #include "uint256.h" +#include "chain.h" #include #include @@ -54,18 +55,18 @@ class ClientModel : public QObject //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; - QString getMasternodeCountString() const; - int getNumBlocks() const; int getNumBlocksAtStartup(); + QString getMasternodeCountString() const; - quint64 getTotalBytesRecv() const; - quint64 getTotalBytesSent() const; - - double getVerificationProgress() const; + // from cached block index + int getNumBlocks() const; QDateTime getLastBlockDate() const; + QString getLastBlockHash() const; int getChainHeight() const; + double getVerificationProgress() const; - QString getLastBlockHash() const; + quint64 getTotalBytesRecv() const; + quint64 getTotalBytesSent() const; //! Return true if core is doing initial block download bool inInitialBlockDownload() const; @@ -81,7 +82,7 @@ class ClientModel : public QObject QString formatClientStartupTime() const; QString dataDir() const; - void setCacheNumBlocks(int blockNum) { cachedNumBlocks = blockNum; }; + void setCacheTip(const CBlockIndex* const tip) { cacheTip = tip; }; void setCacheReindexing(bool reindex) { cachedReindexing = reindex; }; void setCacheImporting(bool import) { cachedImporting = import; }; @@ -90,7 +91,7 @@ class ClientModel : public QObject PeerTableModel* peerTableModel; BanTableModel *banTableModel; - int cachedNumBlocks; + const CBlockIndex* cacheTip; QString cachedMasternodeCountString; bool cachedReindexing; bool cachedImporting; From 900f2c655677b48c7a4e96c7c01c29012326b1c0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 15 Mar 2020 11:02:13 -0400 Subject: [PATCH 0272/1888] Fix de-serialization bug where AddrMan is corrupted after exception * CAddrDB modified so that when de-serialization code throws an exception Addrman is reset to a clean state * CAddrDB modified to make unit tests possible * Regression test created to ensure bug is fixed * StartNode modifed to clear adrman if CAddrDB::Read returns an error code. --- src/Makefile.test.include | 1 + src/net.cpp | 11 ++- src/net.h | 1 + src/test/net_tests.cpp | 138 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/test/net_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 4eef22e19f..8acad71485 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -51,6 +51,7 @@ BITCOIN_TESTS =\ test/mempool_tests.cpp \ test/mruset_tests.cpp \ test/multisig_tests.cpp \ + test/net_tests.cpp \ test/netbase_tests.cpp \ test/pmt_tests.cpp \ test/reverselock_tests.cpp \ diff --git a/src/net.cpp b/src/net.cpp index 6290a2e3a4..8c9d25d13c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1676,8 +1676,10 @@ void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { CAddrDB adb; if (adb.Read(addrman)) LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); - else + else { + addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it LogPrintf("Invalid or missing peers.dat; recreating\n"); + } } uiInterface.InitMessage(_("Loading banlist...")); @@ -1983,6 +1985,11 @@ bool CAddrDB::Read(CAddrMan &addr) { if (hashIn != hashTmp) return error("%s : Checksum mismatch, data corrupted", __func__); + return Read(addr, ssPeers); +} + +bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) +{ unsigned char pchMsgTmp[4]; try { // de-serialize file header (network specific magic number) and .. @@ -1995,6 +2002,8 @@ bool CAddrDB::Read(CAddrMan &addr) { // de-serialize address data into one CAddrMan object ssPeers >> addr; } catch (std::exception &e) { + // de-serialization has failed, ensure addrman is left in a clean state + addr.Clear(); return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } diff --git a/src/net.h b/src/net.h index 0b1f7149e4..f490d7e05c 100644 --- a/src/net.h +++ b/src/net.h @@ -751,6 +751,7 @@ class CAddrDB CAddrDB(); bool Write(const CAddrMan& addr); bool Read(CAddrMan& addr); + bool Read(CAddrMan& addr, CDataStream& ssPeers); }; /** Access to the banlist database (banlist.dat) */ diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp new file mode 100644 index 0000000000..3af0fa9f0b --- /dev/null +++ b/src/test/net_tests.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 2012-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "addrman.h" +#include "chainparams.h" +#include "hash.h" +#include "net.h" +#include "serialize.h" +#include "streams.h" + +#include "test/test_dapscoin.h" + +#include + +#include + +class CAddrManSerializationMock : public CAddrMan +{ +public: + virtual void Serialize(CDataStream& s, int nType, int nVersionDummy) const = 0; +}; + +class CAddrManUncorrupted : public CAddrManSerializationMock +{ +public: + void Serialize(CDataStream& s, int nType, int nVersionDummy) const + { + CAddrMan::Serialize(s, nType, nVersionDummy); + } +}; + +class CAddrManCorrupted : public CAddrManSerializationMock +{ +public: + void Serialize(CDataStream& s, int nType, int nVersionDummy) const + { + // Produces corrupt output that claims addrman has 20 addrs when it only has one addr. + unsigned char nVersion = 1; + s << nVersion; + s << ((unsigned char)32); + s << nKey; + s << 10; // nNew + s << 10; // nTried + + int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); + s << nUBuckets; + + CAddress addr = CAddress(CService("252.1.1.1", 7777)); + CAddrInfo info = CAddrInfo(addr, CNetAddr("252.2.2.2")); + s << info; + } +}; + +CDataStream AddrmanToStream(CAddrManSerializationMock& addrman) +{ + CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION); + ssPeersIn << FLATDATA(Params().MessageStart()); + ssPeersIn << addrman; + std::string str = ssPeersIn.str(); + std::vector vchData(str.begin(), str.end()); + return CDataStream(vchData, SER_DISK, CLIENT_VERSION); +} + +BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(caddrdb_read) +{ + CAddrManUncorrupted addrmanUncorrupted; + + CService addr1 = CService("250.7.1.1", 8333); + CService addr2 = CService("250.7.2.2", 9999); + CService addr3 = CService("250.7.3.3", 9999); + + // Add three addresses to new table. + addrmanUncorrupted.Add(CAddress(addr1), CService("252.5.1.1", 8333)); + addrmanUncorrupted.Add(CAddress(addr2), CService("252.5.1.1", 8333)); + addrmanUncorrupted.Add(CAddress(addr3), CService("252.5.1.1", 8333)); + + // Test that the de-serialization does not throw an exception. + CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted); + bool exceptionThrown = false; + CAddrMan addrman1; + + BOOST_CHECK(addrman1.size() == 0); + try { + unsigned char pchMsgTmp[4]; + ssPeers1 >> FLATDATA(pchMsgTmp); + ssPeers1 >> addrman1; + } catch (const std::exception& e) { + exceptionThrown = true; + } + + BOOST_CHECK(addrman1.size() == 3); + BOOST_CHECK(exceptionThrown == false); + + // Test that CAddrDB::Read creates an addrman with the correct number of addrs. + CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted); + + CAddrMan addrman2; + CAddrDB adb; + BOOST_CHECK(addrman2.size() == 0); + adb.Read(addrman2, ssPeers2); + BOOST_CHECK(addrman2.size() == 3); +} + + +BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) +{ + CAddrManCorrupted addrmanCorrupted; + + // Test that the de-serialization of corrupted addrman throws an exception. + CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted); + bool exceptionThrown = false; + CAddrMan addrman1; + BOOST_CHECK(addrman1.size() == 0); + try { + unsigned char pchMsgTmp[4]; + ssPeers1 >> FLATDATA(pchMsgTmp); + ssPeers1 >> addrman1; + } catch (const std::exception& e) { + exceptionThrown = true; + } + // Even through de-serialization failed addrman is not left in a clean state. + BOOST_CHECK(addrman1.size() == 1); + BOOST_CHECK(exceptionThrown); + + // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails. + CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted); + + CAddrMan addrman2; + CAddrDB adb; + BOOST_CHECK(addrman2.size() == 0); + adb.Read(addrman2, ssPeers2); + BOOST_CHECK(addrman2.size() == 0); +} + +BOOST_AUTO_TEST_SUITE_END() From 8ad4e255ee9dcbc09f3e7069d6065d23ffdad09b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sun, 15 Mar 2020 11:03:27 -0400 Subject: [PATCH 0273/1888] peers.dat, banlist.dat recreated when missing --- src/net.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/net.cpp b/src/net.cpp index 8c9d25d13c..5a46a06b18 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1679,6 +1679,7 @@ void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { else { addrman.Clear(); // Addrman can be in an inconsistent state after failure, reset it LogPrintf("Invalid or missing peers.dat; recreating\n"); + DumpAddresses(); } } @@ -1694,8 +1695,11 @@ void StartNode(boost::thread_group &threadGroup, CScheduler &scheduler) { LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); - } else + } else { LogPrintf("Invalid or missing banlist.dat; recreating\n"); + CNode::SetBannedSetDirty(true); // force write + DumpBanlist(); + } // Initialize random numbers. Even when rand() is only usable for trivial use-cases most nodes should have a different // seed after all the file-IO done at this point. Should be good enough even when nodes are started via scripts. srand(time(NULL)); From f32310848ea5198a5a24de1cad8c3811a45bc1ab Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 22:34:48 -0500 Subject: [PATCH 0274/1888] Bump version to v1.0.6.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 95921e7bb9..fb7896227f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 2) +define(_CLIENT_VERSION_BUILD, 3) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From 37b8cbe6c564d8317c0aced23d570fba7dc2b7d2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Mar 2020 14:08:34 -0400 Subject: [PATCH 0275/1888] Add "Loading Blocks" status text --- src/qt/bitcoingui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 1db23f0e14..0d76a6b691 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1159,8 +1159,9 @@ void BitcoinGUI::setNumBlocks(int count) tooltip += QString("
    "); tooltip += tr("Transactions after this will not yet be visible."); } - - if (IsInitialBlockDownload()) { + if (count == 0) { + blockCount->setText(tr("Loading Blocks...")); + } else if (IsInitialBlockDownload()) { blockCount->setText(tr("Syncing Blocks...")); } else { blockCount->setText(tr("%n Blocks", "", count)); From 85ef56a8a23226fb5ef6a800de246cb5053bc100 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 17 Mar 2020 18:30:24 -0400 Subject: [PATCH 0276/1888] Add "(loading)" to sync circle on Overview page --- src/qt/forms/overviewpage.ui | 2 +- src/qt/overviewpage.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 529ad8c053..8ad333f802 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -156,7 +156,7 @@ - (syncing) + (loading) Qt::AlignHCenter|Qt::AlignTop diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index dc23b1ce2d..3c12b3542f 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -327,8 +327,14 @@ void OverviewPage::showBlockSync(bool fShow) isSyncingBlocks = fShow; - ui->labelBlockCurrent->setText(QString::number(clientModel->getNumBlocks())); - if (isSyncingBlocks){ + int count = clientModel->getNumBlocks(); + ui->labelBlockCurrent->setText(QString::number(count)); + + if (count == 0 & isSyncingBlocks){ + ui->labelBlockStatus->setText("(loading)"); + ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); + ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); + } else if (isSyncingBlocks){ ui->labelBlockStatus->setText("(syncing)"); ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); From 42c55fa2851805f21ac56b3f81868a6101b053c2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Mar 2020 08:41:08 -0400 Subject: [PATCH 0277/1888] Make "Data Directory" and "Last block hash" details selectable --- src/qt/forms/rpcconsole.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index 91acfeab51..ab8cde90cb 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -32,6 +32,9 @@ N/A + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + @@ -390,6 +393,9 @@ N/A + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse +
    From e03da0f139076cf869a31b258766bf7ebde3c8b6 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 5 Mar 2020 22:36:57 -0500 Subject: [PATCH 0278/1888] [RPC][Bug] Fix masternodecurrent: return next winner, not rank-1 mn --- src/rpc/masternode.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 5ce0887d24..82ed4b4930 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -341,23 +341,24 @@ UniValue masternodecurrent (const UniValue& params, bool fHelp) if (fHelp || (params.size() != 0)) throw runtime_error( "masternodecurrent\n" - "\nGet current masternode winner\n" + "\nGet current masternode winner (scheduled to be paid next).\n" "\nResult:\n" "{\n" " \"protocol\": xxxx, (numeric) Protocol version\n" " \"txhash\": \"xxxx\", (string) Collateral transaction hash\n" " \"pubkey\": \"xxxx\", (string) MN Public key\n" - " \"lastseen\": xxx, (numeric) Time since epoch of last seen\n" - " \"activeseconds\": xxx, (numeric) Seconds MN has been active\n" + " \"lastseen\": xxx, (numeric) Time since epoch of last seen\n" + " \"activeseconds\": xxx, (numeric) Seconds MN has been active\n" "}\n" "\nExamples:\n" + HelpExampleCli("masternodecurrent", "") + HelpExampleRpc("masternodecurrent", "")); - CMasternode* winner = mnodeman.GetCurrentMasterNode(1); + const int nHeight = WITH_LOCK(cs_main, return chainActive.Height() + 1); + int nCount = 0; + CMasternode* winner = mnodeman.GetNextMasternodeInQueueForPayment(nHeight, true, nCount); if (winner) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("protocol", (int64_t)winner->protocolVersion)); obj.push_back(Pair("txhash", winner->vin.prevout.hash.ToString())); obj.push_back(Pair("pubkey", CBitcoinAddress(winner->pubKeyCollateralAddress.GetID()).ToString())); From dc196f05785dd48f68d523600abcba9175a3823d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 18 Mar 2020 17:40:44 -0400 Subject: [PATCH 0279/1888] Fix passphrase issue https://github.com/DAPSCoin/DAPSCoin/commit/6b911fdc90e40384c198125a515a30076ac7dcc9 This commit caused an issue with passphrases in the daemon. Revert it for now. --- src/crypter.h | 3 +-- src/init.cpp | 12 +++++------- src/wallet/wallet.cpp | 16 ++++++++++++---- src/wallet/wallet.h | 4 ++++ src/wallet/walletdb.cpp | 19 ++++++++++--------- src/wallet/walletdb.h | 2 ++ 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/crypter.h b/src/crypter.h index 412ab4f75f..dee3dddac4 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -121,6 +121,7 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con class CCryptoKeyStore : public CBasicKeyStore { private: + CryptedKeyMap mapCryptedKeys; CHDChain cryptedHDChain; CKeyingMaterial vMasterKey; @@ -145,8 +146,6 @@ class CCryptoKeyStore : public CBasicKeyStore bool Unlock(const CKeyingMaterial& vMasterKeyIn); - CryptedKeyMap mapCryptedKeys; - public: CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) { diff --git a/src/init.cpp b/src/init.cpp index ea1f0aaefc..3ee6420769 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1630,18 +1630,16 @@ bool AppInit2(bool isDaemon) } CPubKey newDefaultKey; - // Top up the keypool - if (!pwalletMain->TopUpKeyPool()) { - // Error generating keys - InitError(_("Unable to generate initial key") += "\n"); - LogPrintf("%s %s\n", __func__ , "Unable to generate initial key"); - return false; + if (pwalletMain->GetKeyFromPool(newDefaultKey)) { + pwalletMain->SetDefaultKey(newDefaultKey); + if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) + strErrors << _("Cannot write default address") << "\n"; } pwalletMain->SetBestChain(chainActive.GetLocator()); } - LogPrintf("Init errors: %s\n", strErrors.str()); + LogPrintf("%s", strErrors.str()); LogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nWalletStartTime); RegisterValidationInterface(pwalletMain); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 493b3a88e4..31b62ea9fd 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4204,7 +4204,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) return DB_LOAD_OK; - + fFirstRunRet = false; DBErrors nLoadWalletRet = CWalletDB(strWalletFile, "cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { @@ -4216,11 +4216,9 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } } - // This wallet is in its first run if all of these are empty - fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapMasterKeys.empty() && setWatchOnly.empty() && mapScripts.empty(); - if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; + fFirstRunRet = !vchDefaultKey.IsValid(); uiInterface.LoadWallet(this); ScanWalletKeyImages(); @@ -4294,6 +4292,16 @@ bool CWallet::DelAddressBook(const CTxDestination& address) return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } +bool CWallet::SetDefaultKey(const CPubKey& vchPubKey) +{ + if (fFileBacked) { + if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) + return false; + } + vchDefaultKey = vchPubKey; + return true; +} + /** * Mark old keypool keys as used, * and generate all new keys diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 8eebbf0e0d..05923482f0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -340,6 +340,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map addrToTxHashMap; std::vector txPrivKeys; //only for temporary storing tx private keys for user transactions, dont care staking transactions + CPubKey vchDefaultKey; + std::set setLockedCoins; bool walletStakingInProgress; std::map mapHdPubKeys; //nTimeFirstKey)) pwallet->nTimeFirstKey = keyMeta.nCreateTime; } else if (strType == "defaultkey") { - // We don't want or need the default key, but if there is one set, - // we want to make sure that it is valid so that we can detect corruption - CPubKey vchPubKey; - ssValue >> vchPubKey; - if (!vchPubKey.IsValid()) { - strErr = "Error reading wallet database: Default Key corrupt"; - return false; - } + ssValue >> pwallet->vchDefaultKey; } else if (strType == "pool") { int64_t nIndex; ssKey >> nIndex; @@ -820,6 +819,7 @@ static bool IsKeyType(string strType) DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { + pwallet->vchDefaultKey = CPubKey(); CWalletScanState wss; bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; @@ -857,7 +857,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: - if (IsKeyType(strType) || strType == "defaultkey") + if (IsKeyType(strType)) result = DB_CORRUPT; else { // Leave other errors alone, if we try to fix them we might make things worse. @@ -918,6 +918,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vector& vWtx) { + pwallet->vchDefaultKey = CPubKey(); bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 4f195ed2f0..ee22ced4ca 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -146,6 +146,8 @@ class CWalletDB : public CDB bool EraseMSDisabledAddresses(std::vector vDisabledAddresses); bool WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold); + bool WriteDefaultKey(const CPubKey& vchPubKey); + bool ReadPool(int64_t nPool, CKeyPool& keypool); bool WritePool(int64_t nPool, const CKeyPool& keypool); bool ErasePool(int64_t nPool); From 0a869c8ffe16af8599a9e473896b2edc84d326c9 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 3 Mar 2020 20:10:01 -0500 Subject: [PATCH 0280/1888] [Net] Max block locator entries size. Backport coming from upstream@e254ff5d53b79bee29203b965fca572f218bff54 --- src/main.cpp | 12 ++++++++++++ src/net.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 39ddcb6afc..8c53438223 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5964,6 +5964,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 hashStop; vRecv >> locator >> hashStop; + if (locator.vHave.size() > MAX_LOCATOR_SZ) { + LogPrint("net", "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + LOCK(cs_main); // Find the last block the caller has in the main chain @@ -5995,6 +6001,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 hashStop; vRecv >> locator >> hashStop; + if (locator.vHave.size() > MAX_LOCATOR_SZ) { + LogPrint("net", "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + LOCK(cs_main); if (IsInitialBlockDownload()) diff --git a/src/net.h b/src/net.h index f490d7e05c..c61d959004 100644 --- a/src/net.h +++ b/src/net.h @@ -47,6 +47,8 @@ static const int PING_INTERVAL = 2 * 60; static const int TIMEOUT_INTERVAL = 20 * 60; /** The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; +/** The maximum number of entries in a locator */ +static const unsigned int MAX_LOCATOR_SZ = 101; /** The maximum number of new addresses to accumulate before announcing. */ static const unsigned int MAX_ADDR_TO_SEND = 1000; /** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */ From d631b5436d11b059798cd8b77619a45a53fdf1b3 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 19 Mar 2020 13:54:08 -0400 Subject: [PATCH 0281/1888] [Qt] Define QT_NO_KEYWORDS QT_NO_KEYWORDS prevents Qt from defining the `foreach`, `signals`, `slots` and `emit` macros. This avoids overlap between Qt macros and boost, and enforces the standard. --- src/Makefile.qt.include | 2 +- src/qt/2faconfirmdialog.h | 2 +- src/qt/2fadialog.h | 2 +- src/qt/2faqrdialog.h | 2 +- src/qt/addressbookpage.cpp | 2 +- src/qt/addressbookpage.h | 6 ++-- src/qt/addresstablemodel.cpp | 2 +- src/qt/addresstablemodel.h | 2 +- src/qt/askpassphrasedialog.h | 2 +- src/qt/bip38tooldialog.h | 2 +- src/qt/bitcoinamountfield.cpp | 4 +-- src/qt/bitcoinamountfield.h | 4 +-- src/qt/bitcoingui.cpp | 10 +++--- src/qt/bitcoingui.h | 8 ++--- src/qt/clientmodel.cpp | 8 ++--- src/qt/clientmodel.h | 4 +-- src/qt/coincontroldialog.cpp | 2 +- src/qt/coincontroldialog.h | 2 +- src/qt/dapscoin.cpp | 28 ++++++++-------- src/qt/editaddressdialog.h | 2 +- src/qt/encryptdialog.h | 2 +- src/qt/entermnemonics.h | 2 +- src/qt/guiutil.cpp | 2 +- src/qt/guiutil.h | 2 +- src/qt/historypage.h | 4 +-- src/qt/importorcreate.h | 2 +- src/qt/include/qgoogleauth/base32.h | 4 +-- src/qt/include/qgoogleauth/hmac.h | 4 +-- src/qt/intro.cpp | 10 +++--- src/qt/intro.h | 6 ++-- src/qt/macdockiconhandler.h | 2 +- src/qt/macdockiconhandler.mm | 2 +- src/qt/multisenddialog.h | 2 +- src/qt/multisigdialog.h | 4 +-- src/qt/notificator.h | 2 +- src/qt/openuridialog.h | 4 +-- src/qt/optionsdialog.cpp | 4 +-- src/qt/optionsdialog.h | 4 +-- src/qt/optionsmodel.cpp | 8 ++--- src/qt/optionsmodel.h | 2 +- src/qt/optionspage.cpp | 24 ++++++------- src/qt/optionspage.h | 4 +-- src/qt/overviewpage.cpp | 2 +- src/qt/overviewpage.h | 6 ++-- src/qt/paymentserver.cpp | 52 ++++++++++++++--------------- src/qt/paymentserver.h | 6 ++-- src/qt/peertablemodel.cpp | 4 +-- src/qt/peertablemodel.h | 2 +- src/qt/qvalidatedlineedit.h | 4 +-- src/qt/qvaluecombobox.cpp | 2 +- src/qt/qvaluecombobox.h | 4 +-- src/qt/receivecoinsdialog.h | 4 +-- src/qt/receiverequestdialog.h | 4 +-- src/qt/recentrequeststablemodel.cpp | 4 +-- src/qt/recentrequeststablemodel.h | 2 +- src/qt/revealtxdialog.h | 2 +- src/qt/rpcconsole.cpp | 26 +++++++-------- src/qt/rpcconsole.h | 6 ++-- src/qt/sendcoinsdialog.h | 6 ++-- src/qt/sendcoinsentry.cpp | 2 +- src/qt/sendcoinsentry.h | 6 ++-- src/qt/signverifymessagedialog.h | 2 +- src/qt/splashscreen.h | 2 +- src/qt/test/paymentservertests.h | 4 +-- src/qt/test/uritests.h | 2 +- src/qt/togglebutton.cpp | 2 +- src/qt/togglebutton.h | 6 ++-- src/qt/trafficgraphwidget.cpp | 4 +-- src/qt/trafficgraphwidget.h | 2 +- src/qt/transactiondesc.cpp | 4 +-- src/qt/transactiontablemodel.cpp | 14 ++++---- src/qt/transactiontablemodel.h | 2 +- src/qt/transactionview.cpp | 10 +++--- src/qt/transactionview.h | 6 ++-- src/qt/txentry.h | 6 ++-- src/qt/utilitydialog.h | 2 +- src/qt/walletframe.h | 2 +- src/qt/walletmodel.cpp | 18 +++++----- src/qt/walletmodel.h | 6 ++-- src/qt/walletmodeltransaction.cpp | 2 +- src/qt/walletview.cpp | 10 +++--- src/qt/walletview.h | 6 ++-- 82 files changed, 226 insertions(+), 226 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 127dcbcb86..a38823a7ee 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -395,7 +395,7 @@ RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png) BITCOIN_RC = qt/res/dapscoin-qt-res.rc BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ - -I$(builddir)/qt/forms + -I$(builddir)/qt/forms -DQT_NO_KEYWORDS qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) diff --git a/src/qt/2faconfirmdialog.h b/src/qt/2faconfirmdialog.h index 6b70547b75..4679a01520 100644 --- a/src/qt/2faconfirmdialog.h +++ b/src/qt/2faconfirmdialog.h @@ -16,7 +16,7 @@ class TwoFAConfirmDialog : public QDialog explicit TwoFAConfirmDialog(QWidget *parent = 0); ~TwoFAConfirmDialog(); -private slots: +private Q_SLOTS: void on_acceptCode(); void codeChanged(const QString & txt); diff --git a/src/qt/2fadialog.h b/src/qt/2fadialog.h index a5d466a282..5b06fd258b 100644 --- a/src/qt/2fadialog.h +++ b/src/qt/2fadialog.h @@ -16,7 +16,7 @@ class TwoFADialog : public QDialog explicit TwoFADialog(QWidget *parent = 0); ~TwoFADialog(); -private slots: +private Q_SLOTS: void on_acceptCode(); void codeChanged(const QString & txt); diff --git a/src/qt/2faqrdialog.h b/src/qt/2faqrdialog.h index 39b6e2bdf1..366e290cd2 100644 --- a/src/qt/2faqrdialog.h +++ b/src/qt/2faqrdialog.h @@ -23,7 +23,7 @@ class TwoFAQRDialog : public QDialog private: void update(); -private slots: +private Q_SLOTS: void on_btnCopyURI_clicked(); diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 248084d76d..ed50c06f08 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -243,7 +243,7 @@ void AddressBookPage::done(int retval) // Figure out which address was selected, and return it QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - foreach (QModelIndex index, indexes) { + Q_FOREACH (QModelIndex index, indexes) { QVariant address = table->model()->data(index); returnValue = address.toString(); } diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 0a623cb4b3..f61131e205 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -46,7 +46,7 @@ class AddressBookPage : public QDialog void setModel(AddressTableModel* model); const QString& getReturnValue() const { return returnValue; } -public slots: +public Q_SLOTS: void done(int retval); private: @@ -60,7 +60,7 @@ public slots: QAction* deleteAction; // to be able to explicitly disable it QString newAddressToSelect; -private slots: +private Q_SLOTS: /** Delete currently selected address entry */ void on_deleteAddress_clicked(); /** Create a new address for receiving coins and / or add a new address book entry */ @@ -81,7 +81,7 @@ private slots: /** New entry/entries were added to address table */ void selectNewAddress(const QModelIndex& parent, int begin, int /*end*/); -signals: +Q_SIGNALS: void sendCoins(QString addr); }; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 6537599d00..051b4083a7 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -423,5 +423,5 @@ int AddressTableModel::lookupAddress(const QString& address) const void AddressTableModel::emitDataChanged(int idx) { - emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length() - 1, QModelIndex())); + Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length() - 1, QModelIndex())); } diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index b17ef73356..a7b293e0c0 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -84,7 +84,7 @@ class AddressTableModel : public QAbstractTableModel /** Notify listeners that data changed. */ void emitDataChanged(int index); -public slots: +public Q_SLOTS: /* Update address list from core. */ void updateEntry(const QString& address, const QString& label, bool isMine, const QString& purpose, int status); diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 213b873806..ba8243135c 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -55,7 +55,7 @@ class AskPassphraseDialog : public QDialog Context context; bool fCapsLock; -private slots: +private Q_SLOTS: void textChanged(); protected: diff --git a/src/qt/bip38tooldialog.h b/src/qt/bip38tooldialog.h index 33b209f0b0..a4148403fa 100644 --- a/src/qt/bip38tooldialog.h +++ b/src/qt/bip38tooldialog.h @@ -36,7 +36,7 @@ class Bip38ToolDialog : public QDialog Ui::Bip38ToolDialog* ui; WalletModel* model; -private slots: +private Q_SLOTS: /* encrypt key */ void on_addressBookButton_ENC_clicked(); void on_pasteButton_ENC_clicked(); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 5e018f81ad..d50b06f1d9 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -59,7 +59,7 @@ class AmountSpinBox : public QAbstractSpinBox void setValue(const CAmount& value) { lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); - emit valueChanged(); + Q_EMIT valueChanged(); } void stepBy(int steps) @@ -173,7 +173,7 @@ class AmountSpinBox : public QAbstractSpinBox return rv; } -signals: +Q_SIGNALS: void valueChanged(); }; diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 179e6fcff7..6e1165f81a 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -56,7 +56,7 @@ class BitcoinAmountField : public QWidget */ QWidget* setupTabChain(QWidget* prev); -signals: +Q_SIGNALS: void valueChanged(); protected: @@ -67,7 +67,7 @@ class BitcoinAmountField : public QWidget AmountSpinBox* amount; QValueComboBox* unit; -private slots: +private Q_SLOTS: void unitChanged(int idx); }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0d76a6b691..7018448e94 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -978,7 +978,7 @@ void BitcoinGUI::openClicked() { OpenURIDialog dlg(this); if (dlg.exec()) { - emit receivedURI(dlg.getURI()); + Q_EMIT receivedURI(dlg.getURI()); } } @@ -1292,8 +1292,8 @@ bool BitcoinGUI::eventFilter(QObject *obj, QEvent *event) void BitcoinGUI::dropEvent(QDropEvent* event) { if (event->mimeData()->hasUrls()) { - foreach (const QUrl& uri, event->mimeData()->urls()) { - emit receivedURI(uri.toString()); + Q_FOREACH (const QUrl& uri, event->mimeData()->urls()) { + Q_EMIT receivedURI(uri.toString()); } } event->acceptProposedAction(); @@ -1483,7 +1483,7 @@ void BitcoinGUI::unsubscribeFromCoreSignals() void BitcoinGUI::handleRestart(QStringList args) { if (!ShutdownRequested()) - emit requestedRestart(args); + Q_EMIT requestedRestart(args); } UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() : optionsModel(0), @@ -1504,7 +1504,7 @@ void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); - foreach (BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { + Q_FOREACH (BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { QAction* menuAction = new QAction(QString(BitcoinUnits::name(u)), this); menuAction->setData(QVariant(u)); menu->addAction(menuAction); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index b7cda24f98..317ae44fde 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -180,13 +180,13 @@ class BitcoinGUI : public QMainWindow /** Disconnect core signals from GUI client */ void unsubscribeFromCoreSignals(); -signals: +Q_SIGNALS: /** Signal raised when a URI was entered or dragged to the GUI */ void receivedURI(const QString& uri); /** Restart handling */ void requestedRestart(QStringList args); -public slots: +public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ @@ -219,7 +219,7 @@ public slots: void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& confirmations); #endif // ENABLE_WALLET -private slots: +private Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -310,7 +310,7 @@ class UnitDisplayStatusBarControl : public QLabel /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */ void createContextMenu(); -private slots: +private Q_SLOTS: /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */ void updateDisplayUnit(int newUnits); /** Tells underlying optionsModel to update its current display unit. */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 43f906cc47..b3cde3eb12 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -135,7 +135,7 @@ void ClientModel::updateTimer() // Get required lock upfront. This avoids the GUI from getting stuck on // periodical polls if the core is holding the locks for a longer time - // for example, during a wallet rescan. - emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); + Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent()); } void ClientModel::updateMnTimer() @@ -151,18 +151,18 @@ void ClientModel::updateMnTimer() if (cachedMasternodeCountString != newMasternodeCountString) { cachedMasternodeCountString = newMasternodeCountString; - emit strMasternodesChanged(cachedMasternodeCountString); + Q_EMIT strMasternodesChanged(cachedMasternodeCountString); } } void ClientModel::updateNumConnections(int numConnections) { - emit numConnectionsChanged(numConnections); + Q_EMIT numConnectionsChanged(numConnections); } void ClientModel::updateAlert() { - emit alertsChanged(getStatusBarWarnings()); + Q_EMIT alertsChanged(getStatusBarWarnings()); } bool ClientModel::inInitialBlockDownload() const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index dfa0a23176..f1abfc0dd2 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -104,7 +104,7 @@ class ClientModel : public QObject void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); -signals: +Q_SIGNALS: void numConnectionsChanged(int count); void numBlocksChanged(int count); void strMasternodesChanged(const QString& strMasternodes); @@ -117,7 +117,7 @@ class ClientModel : public QObject // Show progress dialog e.g. for verifychain void showProgress(const QString& title, int nProgress); -public slots: +public Q_SLOTS: void updateTimer(); void updateMnTimer(); void updateNumConnections(int numConnections); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 45229a3f38..5c05cb1c04 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -529,7 +529,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; - foreach (const CAmount& amount, CoinControlDialog::payAmounts) { + Q_FOREACH (const CAmount& amount, CoinControlDialog::payAmounts) { nPayAmount += amount; if (amount > 0) { diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index ce3a040434..dc557635b7 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -87,7 +87,7 @@ class CoinControlDialog : public QDialog friend class CCoinControlWidgetItem; -private slots: +private Q_SLOTS: void showMenu(const QPoint&); void copyAmount(); void copyLabel(); diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index f23ad325b8..d48fbea951 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -175,13 +175,13 @@ class BitcoinCore : public QObject public: explicit BitcoinCore(); -public slots: +public Q_SLOTS: void initialize(); void registerNodeSignal(); void shutdown(); void restart(QStringList args); -signals: +Q_SIGNALS: void initializeResult(int retval); void shutdownResult(int retval); void runawayException(const QString& message); @@ -226,13 +226,13 @@ class BitcoinApplication : public QApplication /// Get window identifier of QMainWindow (BitcoinGUI) WId getMainWinId() const; -public slots: +public Q_SLOTS: void initializeResult(int retval); void shutdownResult(int retval); /// Handle runaway exceptions. Shows a message box with the problem and quits the program. void handleRunawayException(const QString& message); -signals: +Q_SIGNALS: void requestedInitialize(); void requestedRegisterNodeSignal(); void requestedRestart(QStringList args); @@ -264,7 +264,7 @@ BitcoinCore::BitcoinCore() : QObject() void BitcoinCore::handleRunawayException(std::exception* e) { PrintExceptionContinue(e, "Runaway exception"); - emit runawayException(QString::fromStdString(strMiscWarning)); + Q_EMIT runawayException(QString::fromStdString(strMiscWarning)); } void BitcoinCore::registerNodeSignal() @@ -279,7 +279,7 @@ void BitcoinCore::initialize() try { qDebug() << __func__ << ": Running AppInit2 in thread"; int rv = AppInit2(false); - emit initializeResult(rv); + Q_EMIT initializeResult(rv); } catch (std::exception& e) { handleRunawayException(&e); } catch (...) { @@ -296,7 +296,7 @@ void BitcoinCore::restart(QStringList args) Interrupt(); PrepareShutdown(); qDebug() << __func__ << ": Shutdown finished"; - emit shutdownResult(1); + Q_EMIT shutdownResult(1); CExplicitNetCleanup::callCleanup(); QProcess::startDetached(QApplication::applicationFilePath(), args); qDebug() << __func__ << ": Restart initiated..."; @@ -316,7 +316,7 @@ void BitcoinCore::shutdown() Interrupt(); Shutdown(); qDebug() << __func__ << ": Shutdown finished"; - emit shutdownResult(1); + Q_EMIT shutdownResult(1); } catch (std::exception& e) { handleRunawayException(&e); } catch (...) { @@ -343,7 +343,7 @@ BitcoinApplication::~BitcoinApplication() { if (coreThread) { qDebug() << __func__ << ": Stopping thread"; - emit stopThread(); + Q_EMIT stopThread(); coreThread->wait(); qDebug() << __func__ << ": Stopped thread"; } @@ -428,7 +428,7 @@ void BitcoinApplication::requestInitialize() { qDebug() << __func__ << ": Requesting initialize"; startThread(); - emit requestedInitialize(); + Q_EMIT requestedInitialize(); } void BitcoinApplication::requestShutdown() @@ -451,7 +451,7 @@ void BitcoinApplication::requestShutdown() ShutdownWindow::showShutdownWindow(window); // Request shutdown from core thread - emit requestedShutdown(); + Q_EMIT requestedShutdown(); } void BitcoinApplication::initializeResult(int retval) @@ -495,7 +495,7 @@ void BitcoinApplication::initializeResult(int retval) } else { window->show(); } - emit splashFinished(window); + Q_EMIT splashFinished(window); #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line @@ -514,7 +514,7 @@ void BitcoinApplication::initializeResult(int retval) pwalletMain->WriteStakingStatus(false); } } - emit requestedRegisterNodeSignal(); + Q_EMIT requestedRegisterNodeSignal(); } if (!walletUnlocked && walletModel->getEncryptionStatus() == WalletModel::Unencrypted) { EncryptDialog dlg; @@ -523,7 +523,7 @@ void BitcoinApplication::initializeResult(int retval) dlg.setStyleSheet(GUIUtil::loadStyleSheet()); dlg.exec(); - emit requestedRegisterNodeSignal(); + Q_EMIT requestedRegisterNodeSignal(); walletModel->updateStatus(); } } diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index ceb3ab4f1c..a04eac3a89 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -41,7 +41,7 @@ class EditAddressDialog : public QDialog QString getAddress() const; void setAddress(const QString& address); -public slots: +public Q_SLOTS: void accept(); private: diff --git a/src/qt/encryptdialog.h b/src/qt/encryptdialog.h index 368c3f434d..c0bf39fcd5 100644 --- a/src/qt/encryptdialog.h +++ b/src/qt/encryptdialog.h @@ -19,7 +19,7 @@ class EncryptDialog : public QDialog void setModel(WalletModel* model); bool matchNewPasswords(); -private slots: +private Q_SLOTS: void on_btnCancel(); void on_acceptPassphrase(); void validateNewPass(); diff --git a/src/qt/entermnemonics.h b/src/qt/entermnemonics.h index e498be966d..657bd70111 100644 --- a/src/qt/entermnemonics.h +++ b/src/qt/entermnemonics.h @@ -17,7 +17,7 @@ class EnterMnemonics : public QDialog public: explicit EnterMnemonics(QWidget *parent = 0); ~EnterMnemonics(); -private slots: +private Q_SLOTS: void on_next(); private: diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 4c74b9747b..fd7711590e 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -839,7 +839,7 @@ QString loadStyleSheet() void refreshStyleSheet(){ qApp->setStyleSheet(GUIUtil::loadStyleSheet()); - foreach (QWidget *widget, QApplication::topLevelWidgets()){ + Q_FOREACH (QWidget *widget, QApplication::topLevelWidgets()){ widget->setStyleSheet(GUIUtil::loadStyleSheet()); widget->update(); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c195c06c23..9673142bee 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -197,7 +197,7 @@ class TableViewLastColumnResizingFixer : public QObject void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode); void resizeColumn(int nColumnIndex, int width); -private slots: +private Q_SLOTS: void on_sectionResized(int logicalIndex, int oldSize, int newSize); void on_geometriesChanged(); }; diff --git a/src/qt/historypage.h b/src/qt/historypage.h index ef6e63ee42..983f9196ef 100644 --- a/src/qt/historypage.h +++ b/src/qt/historypage.h @@ -43,7 +43,7 @@ class HistoryPage : public QDialog ~HistoryPage(); void setModel(WalletModel* model); -public slots: +public Q_SLOTS: void updateFilter(); void syncTime(QDateTimeEdit* calendar, QTimeEdit* clock); @@ -67,7 +67,7 @@ public slots: void updateTableData(CWallet *wallet); void updateAddressBookData(CWallet *wallet); -public slots: +public Q_SLOTS: void on_cellClicked(int row, int column); void updateTableData(); }; diff --git a/src/qt/importorcreate.h b/src/qt/importorcreate.h index c0558c6db5..15d88c5807 100644 --- a/src/qt/importorcreate.h +++ b/src/qt/importorcreate.h @@ -18,7 +18,7 @@ class ImportOrCreate : public QDialog explicit ImportOrCreate(QWidget *parent = 0); ~ImportOrCreate(); bool willRecover = false; -private slots: +private Q_SLOTS: void on_next(); private: diff --git a/src/qt/include/qgoogleauth/base32.h b/src/qt/include/qgoogleauth/base32.h index 52109a5a8a..366a8039d1 100644 --- a/src/qt/include/qgoogleauth/base32.h +++ b/src/qt/include/qgoogleauth/base32.h @@ -10,9 +10,9 @@ class Base32 : public QObject explicit Base32(QObject *parent = 0); static int base32_decode(const quint8 *encoded, quint8 *result, int bufSize); -signals: +Q_SIGNALS: -public slots: +public Q_SLOTS: }; diff --git a/src/qt/include/qgoogleauth/hmac.h b/src/qt/include/qgoogleauth/hmac.h index 91d8fab3d5..10b1f70445 100644 --- a/src/qt/include/qgoogleauth/hmac.h +++ b/src/qt/include/qgoogleauth/hmac.h @@ -10,9 +10,9 @@ class HMAC : public QObject explicit HMAC(QObject *parent = 0); static QByteArray hmacSha1(QByteArray key, QByteArray baseString); -signals: +Q_SIGNALS: -public slots: +public Q_SLOTS: }; diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index da834bb35c..a16aa635a9 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -44,10 +44,10 @@ class FreespaceChecker : public QObject ST_ERROR }; -public slots: +public Q_SLOTS: void check(); -signals: +Q_SIGNALS: void reply(int status, const QString& message, quint64 available); private: @@ -100,7 +100,7 @@ void FreespaceChecker::check() replyStatus = ST_ERROR; replyMessage = tr("Cannot create data directory here."); } - emit reply(replyStatus, replyMessage, freeBytesAvailable); + Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable); } @@ -118,7 +118,7 @@ Intro::~Intro() { delete ui; /* Ensure thread is finished before it is deleted */ - emit stopThread(); + Q_EMIT stopThread(); thread->wait(); } @@ -267,7 +267,7 @@ void Intro::checkPath(const QString& dataDir) pathToCheck = dataDir; if (!signalled) { signalled = true; - emit requestCheck(); + Q_EMIT requestCheck(); } mutex.unlock(); } diff --git a/src/qt/intro.h b/src/qt/intro.h index 9304d90acf..6e16a6f786 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -49,14 +49,14 @@ class Intro : public QDialog */ static QString getDefaultDataDirectory(); -signals: +Q_SIGNALS: void requestCheck(); void stopThread(); -public slots: +public Q_SLOTS: void setStatus(int status, const QString& message, quint64 bytesAvailable); -private slots: +private Q_SLOTS: void on_dataDirectory_textChanged(const QString& arg1); void on_ellipsisButton_clicked(); void on_dataDirDefault_clicked(); diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h index 083b8414c0..12e3533def 100644 --- a/src/qt/macdockiconhandler.h +++ b/src/qt/macdockiconhandler.h @@ -30,7 +30,7 @@ class MacDockIconHandler : public QObject static void cleanup(); void handleDockIconClickEvent(); -signals: +Q_SIGNALS: void dockIconClicked(); private: diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index 6acde903e4..4d0229d1de 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -121,5 +121,5 @@ void setupDockClickHandler() { this->mainWindow->show(); } - emit this->dockIconClicked(); + Q_EMIT this->dockIconClicked(); } diff --git a/src/qt/multisenddialog.h b/src/qt/multisenddialog.h index 2065243fbd..4f632a5b20 100644 --- a/src/qt/multisenddialog.h +++ b/src/qt/multisenddialog.h @@ -21,7 +21,7 @@ class MultiSendDialog : public QDialog void setModel(WalletModel* model); void setAddress(const QString& address); void setAddress(const QString& address, QLineEdit* addrEdit); -private slots: +private Q_SLOTS: void on_viewButton_clicked(); void on_addButton_clicked(); void on_deleteButton_clicked(); diff --git a/src/qt/multisigdialog.h b/src/qt/multisigdialog.h index 9cf7b3094a..12a6cb39b4 100644 --- a/src/qt/multisigdialog.h +++ b/src/qt/multisigdialog.h @@ -32,7 +32,7 @@ class MultisigDialog : public QDialog void setModel(WalletModel* model); void updateCoinControl(CAmount nAmount, unsigned int nQuantity); -public slots: +public Q_SLOTS: void showTab(int index); private: @@ -53,7 +53,7 @@ public slots: bool addMultisig(int m, std::vector keys); bool isFullyVerified(CMutableTransaction& txToVerify); -private slots: +private Q_SLOTS: void deleteFrame(); void pasteText(); void commitMultisigTx(); diff --git a/src/qt/notificator.h b/src/qt/notificator.h index a2ebffcd10..f2a47cd8ce 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -39,7 +39,7 @@ class Notificator : public QObject Critical /**< An error occurred */ }; -public slots: +public Q_SLOTS: /** Show notification message. @param[in] cls general message class @param[in] title title shown with message diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index 519e2ca8f2..c3fc32a95b 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -22,10 +22,10 @@ class OpenURIDialog : public QDialog QString getURI(); -protected slots: +protected Q_SLOTS: void accept(); -private slots: +private Q_SLOTS: void on_selectFileButton_clicked(); private: diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ca272eff8c..5c14ca34cd 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -84,7 +84,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren /* Language selector */ QDir translations(":translations"); ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); - foreach (const QString& langStr, translations.entryList()) { + Q_FOREACH (const QString& langStr, translations.entryList()) { QLocale locale(langStr); /** check if the locale name consists of 2 parts (language_country) */ @@ -303,7 +303,7 @@ bool OptionsDialog::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::FocusOut) { if (object == ui->proxyIp || object == ui->proxyPort) { - emit proxyIpChecks(ui->proxyIp, ui->proxyPort); + Q_EMIT proxyIpChecks(ui->proxyIp, ui->proxyPort); } } return QDialog::eventFilter(object, event); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 85c5234620..df6fb3914e 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -35,7 +35,7 @@ class OptionsDialog : public QDialog protected: bool eventFilter(QObject* object, QEvent* event); -private slots: +private Q_SLOTS: /* enable OK button */ void enableOkButton(); /* disable OK button */ @@ -52,7 +52,7 @@ private slots: void clearStatusLabel(); void doProxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); -signals: +Q_SIGNALS: void proxyIpChecks(QValidatedLineEdit* pUiProxyIp, QLineEdit* pUiProxyPort); private: diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 8667b6ad75..187b2b690f 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -313,12 +313,12 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int case HideOrphans: fHideOrphans = value.toBool(); settings.setValue("fHideOrphans", fHideOrphans); - emit hideOrphansChanged(fHideOrphans); + Q_EMIT hideOrphansChanged(fHideOrphans); break; case CoinControlFeatures: fCoinControlFeatures = value.toBool(); settings.setValue("fCoinControlFeatures", fCoinControlFeatures); - emit coinControlFeaturesChanged(fCoinControlFeatures); + Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures); break; case DatabaseCache: if (settings.value("nDatabaseCache") != value) { @@ -343,7 +343,7 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int } } - emit dataChanged(index, index); + Q_EMIT dataChanged(index, index); return successful; } @@ -355,7 +355,7 @@ void OptionsModel::setDisplayUnit(const QVariant& value) QSettings settings; nDisplayUnit = value.toInt(); settings.setValue("nDisplayUnit", nDisplayUnit); - emit displayUnitChanged(nDisplayUnit); + Q_EMIT displayUnitChanged(nDisplayUnit); } } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index d1212785f5..de37704fca 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -88,7 +88,7 @@ class OptionsModel : public QAbstractListModel /// Add option to list of GUI options overridden through command line/config file void addOverriddenOption(const std::string& option); -signals: +Q_SIGNALS: void displayUnitChanged(int unit); void zeromintPercentageChanged(int); void preferredDenomChanged(int); diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 93b4109a85..2f974044e3 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -70,7 +70,7 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu stkStatus = false; pwalletMain->walletStakingInProgress = false; pwalletMain->WriteStakingStatus(false); - //emit model->stakingStatusChanged(false); + //Q_EMIT model->stakingStatusChanged(false); } else { QString error; StakingStatusError stt = model->getStakingStatusError(error); @@ -78,7 +78,7 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu stkStatus = false; pwalletMain->walletStakingInProgress = false; pwalletMain->WriteStakingStatus(false); - //emit model->stakingStatusChanged(false); + //Q_EMIT model->stakingStatusChanged(false); } } } @@ -221,7 +221,7 @@ void OptionsPage::on_pushButtonSave_clicked() { CWalletDB walletdb(pwalletMain->strWalletFile); walletdb.WriteReserveAmount(nReserveBalance / COIN); - emit model->stakingStatusChanged(nLastCoinStakeSearchInterval); + Q_EMIT model->stakingStatusChanged(nLastCoinStakeSearchInterval); ui->lineEditWithhold->setStyleSheet(GUIUtil::loadStyleSheet()); QString reserveBalance = ui->lineEditWithhold->text().trimmed(); @@ -239,7 +239,7 @@ void OptionsPage::on_pushButtonDisable_clicked() { CWalletDB walletdb(pwalletMain->strWalletFile); walletdb.WriteReserveAmount(0); - emit model->stakingStatusChanged(nLastCoinStakeSearchInterval); + Q_EMIT model->stakingStatusChanged(nLastCoinStakeSearchInterval); QMessageBox msgBox; msgBox.setWindowTitle("Reserve Balance Disabled"); msgBox.setText("Reserve balance disabled."); @@ -479,13 +479,13 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) msgBox.exec(); widget->setState(false); nLastCoinStakeSearchInterval = 0; - emit model->stakingStatusChanged(false); + Q_EMIT model->stakingStatusChanged(false); pwalletMain->WriteStakingStatus(false); return; } if (stt == StakingStatusError::STAKING_OK) { pwalletMain->WriteStakingStatus(true); - emit model->stakingStatusChanged(true); + Q_EMIT model->stakingStatusChanged(true); model->generateCoins(true, 1); pwalletMain->fCombineDust = true; pwalletMain->stakingMode = StakingMode::STAKING_WITH_CONSOLIDATION; @@ -502,7 +502,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) reply = QMessageBox::question(this, "Staking Needs Consolidation", QString::fromStdString(errorMessage), QMessageBox::Yes|QMessageBox::No); if (reply == QMessageBox::Yes) { pwalletMain->WriteStakingStatus(true); - emit model->stakingStatusChanged(true); + Q_EMIT model->stakingStatusChanged(true); model->generateCoins(true, 1); pwalletMain->fCombineDust = true; pwalletMain->stakingMode = StakingMode::STAKING_WITH_CONSOLIDATION; @@ -532,14 +532,14 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) pwalletMain->stakingMode = StakingMode::STOPPED; nLastCoinStakeSearchInterval = 0; model->generateCoins(false, 0); - emit model->stakingStatusChanged(false); + Q_EMIT model->stakingStatusChanged(false); pwalletMain->walletStakingInProgress = false; pwalletMain->WriteStakingStatus(false); return; } /* if (!error.length()) { pwalletMain->WriteStakingStatus(true); - emit model->stakingStatusChanged(true); + Q_EMIT model->stakingStatusChanged(true); model->generateCoins(true, 1); } else { if (stt != StakingStatusError::UTXO_UNDER_THRESHOLD) { @@ -552,7 +552,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) msgBox.exec(); widget->setState(false); nLastCoinStakeSearchInterval = 0; - emit model->stakingStatusChanged(false); + Q_EMIT model->stakingStatusChanged(false); pwalletMain->WriteStakingStatus(false); } else { QMessageBox::StandardButton reply; @@ -603,7 +603,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) } else { widget->setState(false); nLastCoinStakeSearchInterval = 0; - emit model->stakingStatusChanged(false); + Q_EMIT model->stakingStatusChanged(false); pwalletMain->WriteStakingStatus(false); } } @@ -612,7 +612,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) pwalletMain->stakingMode = StakingMode::STOPPED; nLastCoinStakeSearchInterval = 0; model->generateCoins(false, 0); - emit model->stakingStatusChanged(false); + Q_EMIT model->stakingStatusChanged(false); pwalletMain->walletStakingInProgress = false; pwalletMain->WriteStakingStatus(false); } diff --git a/src/qt/optionspage.h b/src/qt/optionspage.h index 265a6dbe58..382714a607 100644 --- a/src/qt/optionspage.h +++ b/src/qt/optionspage.h @@ -55,7 +55,7 @@ class OptionsPage : public QDialog bool matchNewPasswords(); StakingStatusError getStakingStatusError(QString&); -public slots: +public Q_SLOTS: void on_EnableStaking(ToggleButton*); protected: @@ -77,7 +77,7 @@ public slots: QTimer* timerStakingToggleSync; void saveConsolidationSettingTime(bool); -private slots: +private Q_SLOTS: void validateNewPass(); void validateNewPassRepeat(); void onOldPassChanged(); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 3c12b3542f..1c81c6421b 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -130,7 +130,7 @@ OverviewPage::OverviewPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMe void OverviewPage::handleTransactionClicked(const QModelIndex& index) { if (filter) - emit transactionClicked(filter->mapToSource(index)); + Q_EMIT transactionClicked(filter->mapToSource(index)); } OverviewPage::~OverviewPage() diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 032c4ddc6a..8823c4311d 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -44,7 +44,7 @@ class OverviewPage : public QDialog QTimer* animTicker; QElapsedTimer* animClock; -public slots: +public Q_SLOTS: void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); void hideOrphans(bool fHide); @@ -57,7 +57,7 @@ public slots: void showBlockCurrentHeight(int count); void updateBalance(); -signals: +Q_SIGNALS: void transactionClicked(const QModelIndex& index); private: @@ -90,7 +90,7 @@ public slots: void moveSyncCircle(QWidget* anchor, QWidget* animated, int deltaRadius, float degreesPerSecond, float angleOffset=0); QRect getCircleGeometry(QWidget* parent, float ratioToParent); -private slots: +private Q_SLOTS: void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex& index); void updateAlerts(const QString& warnings); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 2463a33cd5..d1cb6d51b4 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -137,7 +137,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); - foreach (const QSslCertificate& cert, certList) { + Q_FOREACH (const QSslCertificate& cert, certList) { if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) { ReportInvalidCertificate(cert); continue; @@ -180,7 +180,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) // when uiReady() is called. // // Warning: ipcSendCommandLine() is called early in init, -// so don't use "emit message()", but "QMessageBox::"! +// so don't use "Q_EMIT message()", but "QMessageBox::"! // void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) { @@ -236,7 +236,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) bool PaymentServer::ipcSendCommandLine() { bool fResult = false; - foreach (const QString& r, savedPaymentRequests) { + Q_FOREACH (const QString& r, savedPaymentRequests) { QLocalSocket* socket = new QLocalSocket(); socket->connectToServer(ipcServerName(), QIODevice::WriteOnly); if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT)) { @@ -289,7 +289,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(p uriServer = new QLocalServer(this); if (!uriServer->listen(name)) { - // constructor is called early in init, so don't use "emit message()" here + // constructor is called early in init, so don't use "Q_EMIT message()" here QMessageBox::critical(0, tr("Payment request error"), tr("Cannot start dapscoin: click-to-pay handler")); } else { @@ -355,7 +355,7 @@ void PaymentServer::uiReady() initNetManager(); saveURIs = false; - foreach (const QString& s, savedPaymentRequests) { + Q_FOREACH (const QString& s, savedPaymentRequests) { handleURIOrFile(s); } savedPaymentRequests.clear(); @@ -375,12 +375,12 @@ void PaymentServer::handleURIOrFile(const QString& s) if (GUIUtil::parseBitcoinURI(s, &recipient)) { CBitcoinAddress address(recipient.address.toStdString()); if (!address.IsValid()) { - emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), + Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address), CClientUIInterface::MSG_ERROR); } else - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); } else - emit message(tr("URI handling"), + Q_EMIT message(tr("URI handling"), tr("URI cannot be parsed! This can be caused by an invalid DAPS address or malformed URI parameters."), CClientUIInterface::ICON_WARNING); @@ -392,11 +392,11 @@ void PaymentServer::handleURIOrFile(const QString& s) PaymentRequestPlus request; SendCoinsRecipient recipient; if (!readPaymentRequestFromFile(s, request)) { - emit message(tr("Payment request file handling"), + Q_EMIT message(tr("Payment request file handling"), tr("Payment request file cannot be read! This can be caused by an invalid payment request file."), CClientUIInterface::ICON_WARNING); } else if (processPaymentRequest(request, recipient)) - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); return; } @@ -425,7 +425,7 @@ void PaymentServer::handleURIConnection() // // Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine() -// so don't use "emit message()", but "QMessageBox::"! +// so don't use "Q_EMIT message()", but "QMessageBox::"! // bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request) { @@ -460,7 +460,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Payment request network matches client network? if (details.network() != Params().NetworkIDString()) { - emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), + Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), CClientUIInterface::MSG_ERROR); return false; @@ -468,13 +468,13 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Expired payment request? if (details.has_expires() && (int64_t)details.expires() < GetTime()) { - emit message(tr("Payment request rejected"), tr("Payment request has expired."), + Q_EMIT message(tr("Payment request rejected"), tr("Payment request has expired."), CClientUIInterface::MSG_ERROR); return false; } } else { - emit message(tr("Payment request error"), tr("Payment request is not initialized."), + Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."), CClientUIInterface::MSG_ERROR); return false; @@ -488,7 +488,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins QList > sendingTos = request.getPayTo(); QStringList addresses; - foreach (const PAIRTYPE(CScript, CAmount) & sendingTo, sendingTos) { + Q_FOREACH (const PAIRTYPE(CScript, CAmount) & sendingTo, sendingTos) { // Extract and check destination addresses CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) { @@ -498,7 +498,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Insecure payments to custom dapscoin addresses are not supported // (there is no good way to tell the user where they are paying in a way // they'd have a chance of understanding). - emit message(tr("Payment request rejected"), + Q_EMIT message(tr("Payment request rejected"), tr("Unverified payment requests to custom payment scripts are unsupported."), CClientUIInterface::MSG_ERROR); return false; @@ -507,7 +507,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins // Extract and check amounts CTxOut txOut(sendingTo.second, sendingTo.first); if (txOut.IsDust(::minRelayTxFee)) { - emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).").arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), + Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).").arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), CClientUIInterface::MSG_ERROR); return false; @@ -601,7 +601,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(BIP70_MAX_PAYMENTREQUEST_SIZE); qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg; - emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR); return; } @@ -611,7 +611,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(reply->errorString()); qWarning() << "PaymentServer::netRequestFinished: " << msg; - emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); return; } @@ -623,11 +623,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) SendCoinsRecipient recipient; if (!request.parse(data)) { qWarning() << "PaymentServer::netRequestFinished : Error parsing payment request"; - emit message(tr("Payment request error"), + Q_EMIT message(tr("Payment request error"), tr("Payment request cannot be parsed!"), CClientUIInterface::MSG_ERROR); } else if (processPaymentRequest(request, recipient)) - emit receivedPaymentRequest(recipient); + Q_EMIT receivedPaymentRequest(recipient); return; } else if (requestType == BIP70_MESSAGE_PAYMENTACK) { @@ -637,9 +637,9 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply) .arg(reply->request().url().toString()); qWarning() << "PaymentServer::netRequestFinished : " << msg; - emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR); } else { - emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); + Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo())); } } } @@ -649,11 +649,11 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList Q_UNUSED(reply); QString errString; - foreach (const QSslError& err, errs) { + Q_FOREACH (const QSslError& err, errs) { qWarning() << "PaymentServer::reportSslErrors : " << err; errString += err.errorString() + "\n"; } - emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); + Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); } void PaymentServer::setOptionsModel(OptionsModel* optionsModel) @@ -664,7 +664,7 @@ void PaymentServer::setOptionsModel(OptionsModel* optionsModel) void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) { // currently we don't futher process or store the paymentACK message - emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); + Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); } X509_STORE* PaymentServer::getCertStore() diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 33cb14f531..9331498b05 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -91,7 +91,7 @@ class PaymentServer : public QObject // This is now public, because we use it in paymentservertests.cpp static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request); -signals: +Q_SIGNALS: // Fired when a valid payment request is received void receivedPaymentRequest(SendCoinsRecipient); @@ -101,7 +101,7 @@ class PaymentServer : public QObject // Fired when a message should be reported to the user void message(const QString& title, const QString& message, unsigned int style); -public slots: +public Q_SLOTS: // Signal this when the main window's UI is ready // to display payment requests to the user void uiReady(); @@ -112,7 +112,7 @@ public slots: // Handle an incoming URI, URI with local file scheme or file void handleURIOrFile(const QString& s); -private slots: +private Q_SLOTS: void handleURIConnection(); void netRequestFinished(QNetworkReply*); void reportSslErrors(QNetworkReply*, const QList&); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 30c45164db..a56021edf8 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -214,9 +214,9 @@ const CNodeCombinedStats* PeerTableModel::getNodeStats(int idx) void PeerTableModel::refresh() { - emit layoutAboutToBeChanged(); + Q_EMIT layoutAboutToBeChanged(); priv->refreshPeers(); - emit layoutChanged(); + Q_EMIT layoutChanged(); } int PeerTableModel::getRowByNodeId(NodeId nodeid) diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index a7421ff580..55133881c6 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -68,7 +68,7 @@ class PeerTableModel : public QAbstractTableModel void sort(int column, Qt::SortOrder order); /*@}*/ -public slots: +public Q_SLOTS: void refresh(); private: diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index fe991e1966..1aa4600b8c 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -27,11 +27,11 @@ class QValidatedLineEdit : public QLineEdit bool valid; const QValidator* checkValidator; -public slots: +public Q_SLOTS: void setValid(bool valid); void setEnabled(bool enabled); -private slots: +private Q_SLOTS: void markValid(); void checkValidity(); }; diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index 367659980e..ab63c94327 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -26,5 +26,5 @@ void QValueComboBox::setRole(int role) void QValueComboBox::handleSelectionChanged(int idx) { - emit valueChanged(); + Q_EMIT valueChanged(); } diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index 2065b563a9..28d5f115a5 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -24,13 +24,13 @@ class QValueComboBox : public QComboBox /** Specify model role to use as ordinal value (defaults to Qt::UserRole) */ void setRole(int role); -signals: +Q_SIGNALS: void valueChanged(); private: int role; -private slots: +private Q_SLOTS: void handleSelectionChanged(int idx); }; diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index ce5ae7dc1e..7f3548860c 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -48,7 +48,7 @@ class ReceiveCoinsDialog : public QDialog void setModel(WalletModel* model); void loadAccount(); -public slots: +public Q_SLOTS: void clear(); void reject(); void accept(); @@ -66,7 +66,7 @@ public slots: virtual void resizeEvent(QResizeEvent* event); CAmount getValidatedAmount(); -private slots: +private Q_SLOTS: void on_receiveButton_clicked(); void updateDisplayUnit(); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index b3167de229..9f5c1eaecd 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -33,7 +33,7 @@ class QRImageWidget : public QLabel explicit QRImageWidget(QWidget* parent = 0); QImage exportImage(); -public slots: +public Q_SLOTS: void saveImage(); void copyImage(); @@ -56,7 +56,7 @@ class ReceiveRequestDialog : public QDialog void setModel(OptionsModel* model); void setInfo(const SendCoinsRecipient& info); -private slots: +private Q_SLOTS: void on_btnCopyURI_clicked(); void on_btnCopyAddress_clicked(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index cc899973d0..62198b56e6 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -107,7 +107,7 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien void RecentRequestsTableModel::updateAmountColumnTitle() { columns[Amount] = getAmountTitle(); - emit headerDataChanged(Qt::Horizontal, Amount, Amount); + Q_EMIT headerDataChanged(Qt::Horizontal, Amount, Amount); } /** Gets title for amount column including current display unit if optionsModel reference available. */ @@ -199,7 +199,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry& recipient) void RecentRequestsTableModel::sort(int column, Qt::SortOrder order) { std::sort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order)); - emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); + Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex())); } void RecentRequestsTableModel::updateDisplayUnit() diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 210a782c67..25f64d9d05 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -90,7 +90,7 @@ class RecentRequestsTableModel : public QAbstractTableModel void addNewRequest(const std::string& recipient); void addNewRequest(RecentRequestEntry& recipient); -public slots: +public Q_SLOTS: void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); void updateDisplayUnit(); diff --git a/src/qt/revealtxdialog.h b/src/qt/revealtxdialog.h index f6364a1c76..ca5c42e0ea 100644 --- a/src/qt/revealtxdialog.h +++ b/src/qt/revealtxdialog.h @@ -21,7 +21,7 @@ class RevealTxDialog : public QDialog void setTxPrivKey(QString strPrivKey); void setTxFee(CAmount fee); -private slots: +private Q_SLOTS: void on_buttonBox_accepted(); void copyID(); void copyAddress(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 6e9dcf0473..65d264f7eb 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -70,10 +70,10 @@ class RPCExecutor : public QObject { Q_OBJECT -public slots: +public Q_SLOTS: void request(const QString& command); -signals: +Q_SIGNALS: void reply(int category, const QString& command); }; @@ -93,7 +93,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase timer.start(millis); } ~QtRPCTimerBase() {} -private slots: +private Q_SLOTS: void timeout() { func(); } private: QTimer timer; @@ -138,7 +138,7 @@ bool parseCommandLine(std::vector& args, const std::string& strComm STATE_ESCAPE_DOUBLEQUOTED } state = STATE_EATING_SPACES; std::string curarg; - foreach (char ch, strCommand) { + Q_FOREACH (char ch, strCommand) { switch (state) { case STATE_ARGUMENT: // In or after argument case STATE_EATING_SPACES: // Handle runs of whitespace @@ -215,7 +215,7 @@ void RPCExecutor::request(const QString& command) { std::vector args; if (!parseCommandLine(args, command.toStdString())) { - emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; } if (args.empty()) @@ -236,19 +236,19 @@ void RPCExecutor::request(const QString& command) else strPrint = result.write(2); - emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); + Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); } catch (UniValue& objError) { try // Nice formatting for standard-format error { int code = find_value(objError, "code").get_int(); std::string message = find_value(objError, "message").get_str(); - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); } } catch (std::exception& e) { - emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); } } @@ -309,7 +309,7 @@ RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHi RPCConsole::~RPCConsole() { GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); - emit stopExecutor(); + Q_EMIT stopExecutor(); delete peersTableContextMenu; delete banTableContextMenu; RPCUnsetTimerInterface(rpcTimerInterface); @@ -354,7 +354,7 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent* event) break; default: // Typing in messages widget brings focus to line edit, and redirects key there - // Exclude most combinations and keys that emit no text, except paste shortcuts + // Exclude most combinations and keys that Q_EMIT no text, except paste shortcuts if (obj == ui->messagesWidget && ((!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) || ((mod & Qt::ControlModifier) && key == Qt::Key_V) || ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) { @@ -583,7 +583,7 @@ void RPCConsole::buildParameterlist(QString arg) args.append(arg); // Send command-line arguments to BitcoinGUI::handleRestart() - emit handleRestart(args); + Q_EMIT handleRestart(args); } void RPCConsole::clear() @@ -684,7 +684,7 @@ void RPCConsole::on_lineEdit_returnPressed() if (!cmd.isEmpty()) { message(CMD_REQUEST, cmd); - emit cmdRequest(cmd); + Q_EMIT cmdRequest(cmd); // Remove command, if already in history history.removeOne(cmd); // Append command to history diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index ea0cd3f228..487d82e05c 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -48,7 +48,7 @@ class RPCConsole : public QDialog protected: virtual bool eventFilter(QObject* obj, QEvent* event); -private slots: +private Q_SLOTS: void on_lineEdit_returnPressed(); void on_tabWidget_currentChanged(int index); /** open the debug.log from the current datadir */ @@ -69,7 +69,7 @@ private slots: /** clear the selected node */ void clearSelectedNode(); -public slots: +public Q_SLOTS: void clear(); /** Wallet repair options */ @@ -122,7 +122,7 @@ public slots: /** Show folder with wallet backups in default browser */ void showBackups(); -signals: +Q_SIGNALS: // For RPC command executor void stopExecutor(); void cmdRequest(const QString& command); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index acffcd991a..ccd773fc29 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -40,7 +40,7 @@ class SendCoinsDialog : public QDialog void setModel(WalletModel* model); bool fSplitBlock; -public slots: +public Q_SLOTS: SendCoinsEntry* addEntry(); private: @@ -55,7 +55,7 @@ public slots: private: void sendTx(); -private slots: +private Q_SLOTS: void dialogIsFinished(int result); void on_sendButton_clicked(); void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, @@ -74,7 +74,7 @@ private slots: void coinControlClipboardLowOutput(); void coinControlClipboardChange(); -signals: +Q_SIGNALS: }; diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index e81a5e86e4..702129082d 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -120,7 +120,7 @@ void SendCoinsEntry::clear() void SendCoinsEntry::deleteClicked() { - emit removeEntry(this); + Q_EMIT removeEntry(this); } static inline int64_t roundint64(double d) diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index b2f7db668b..4104a810d3 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -48,15 +48,15 @@ class SendCoinsEntry : public QStackedWidget void setFocus(); -public slots: +public Q_SLOTS: void clear(); -signals: +Q_SIGNALS: void removeEntry(SendCoinsEntry* entry); void payAmountChanged(); void validateAmount(const QString& textAmount); -private slots: +private Q_SLOTS: void deleteClicked(); void on_payTo_textChanged(const QString& address); void on_addressBookButton_clicked(); diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index 02c88ebd49..6a4ee50c96 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -36,7 +36,7 @@ class SignVerifyMessageDialog : public QDialog Ui::SignVerifyMessageDialog* ui; WalletModel* model; -private slots: +private Q_SLOTS: /* sign message */ void on_addressBookButton_SM_clicked(); void on_pasteButton_SM_clicked(); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index 6b07ea55eb..267a03166f 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -27,7 +27,7 @@ class SplashScreen : public QWidget void paintEvent(QPaintEvent* event); void closeEvent(QCloseEvent* event); -public slots: +public Q_SLOTS: /** Slot to call finish() method as it's not defined as slot */ void slotFinish(QWidget* mainWin); diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h index 0717111f66..b56ad66fbe 100644 --- a/src/qt/test/paymentservertests.h +++ b/src/qt/test/paymentservertests.h @@ -14,7 +14,7 @@ class PaymentServerTests : public QObject { Q_OBJECT -private slots: +private Q_SLOTS: void paymentServerTests(); }; @@ -25,7 +25,7 @@ class RecipientCatcher : public QObject { Q_OBJECT -public slots: +public Q_SLOTS: void getRecipient(SendCoinsRecipient r); public: diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h index ed30a9f4a7..45c1afecb2 100644 --- a/src/qt/test/uritests.h +++ b/src/qt/test/uritests.h @@ -12,7 +12,7 @@ class URITests : public QObject { Q_OBJECT -private slots: +private Q_SLOTS: void uriTests(); }; diff --git a/src/qt/togglebutton.cpp b/src/qt/togglebutton.cpp index caa53de773..2b949bfabe 100644 --- a/src/qt/togglebutton.cpp +++ b/src/qt/togglebutton.cpp @@ -93,7 +93,7 @@ void ToggleButton::setState(bool value) void ToggleButton::toggle() { state=!state; - emit stateChanged(this); + Q_EMIT stateChanged(this); update(); } diff --git a/src/qt/togglebutton.h b/src/qt/togglebutton.h index 91004b6417..3723142fed 100644 --- a/src/qt/togglebutton.h +++ b/src/qt/togglebutton.h @@ -30,12 +30,12 @@ class ToggleButton : public QWidget void resizeEvent(QResizeEvent * event); void paintEvent(QPaintEvent *); -public slots: +public Q_SLOTS: void toggle(); -signals: +Q_SIGNALS: void stateChanged(ToggleButton* widget); -private slots: +private Q_SLOTS: private: Ui::ToggleButton* ui; diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 42da216846..360304a8aa 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -138,10 +138,10 @@ void TrafficGraphWidget::updateRates() } float tmax = 0.0f; - foreach (float f, vSamplesIn) { + Q_FOREACH (float f, vSamplesIn) { if (f > tmax) tmax = f; } - foreach (float f, vSamplesOut) { + Q_FOREACH (float f, vSamplesOut) { if (f > tmax) tmax = f; } fMax = tmax; diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 0fe01746c9..991d3a6028 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -27,7 +27,7 @@ class TrafficGraphWidget : public QWidget protected: void paintEvent(QPaintEvent*); -public slots: +public Q_SLOTS: void updateRates(); void setGraphRangeMins(int mins); void clear(); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 5721ada2a6..e06bdbaf15 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -258,14 +258,14 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
    "; // Message from normal dapscoin:URI (dapscoin:XyZ...?message=example) - foreach (const PAIRTYPE(string, string) & r, wtx.vOrderForm) + Q_FOREACH (const PAIRTYPE(string, string) & r, wtx.vOrderForm) if (r.first == "Message") strHTML += "
    " + tr("Message") + ":
    " + GUIUtil::HtmlEscape(r.second, true) + "
    "; // // PaymentRequest info: // - foreach (const PAIRTYPE(string, string) & r, wtx.vOrderForm) { + Q_FOREACH (const PAIRTYPE(string, string) & r, wtx.vOrderForm) { if (r.first == "PaymentRequest") { PaymentRequestPlus req; req.parse(QByteArray::fromRawData(r.second.data(), r.second.size())); diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 9fcdfc7032..16a4ecf8ce 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -210,7 +210,7 @@ class TransactionTablePriv { parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex + toInsert.size() - 1); int insert_idx = lowerIndex; - foreach (const TransactionRecord& rec, toInsert) { + Q_FOREACH (const TransactionRecord& rec, toInsert) { cachedWallet.insert(insert_idx, rec); insert_idx += 1; } @@ -305,7 +305,7 @@ TransactionTableModel::~TransactionTableModel() void TransactionTableModel::updateAmountColumnTitle() { columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); - emit headerDataChanged(Qt::Horizontal, Amount, Amount); + Q_EMIT headerDataChanged(Qt::Horizontal, Amount, Amount); } void TransactionTableModel::updateTransaction(const QString& hash, int status, bool showTransaction) @@ -314,7 +314,7 @@ void TransactionTableModel::updateTransaction(const QString& hash, int status, b updated.SetHex(hash.toStdString()); priv->updateWallet(updated, status, showTransaction); - emit walletModel->RefreshRecent(); + Q_EMIT walletModel->RefreshRecent(); } void TransactionTableModel::updateConfirmations() @@ -323,8 +323,8 @@ void TransactionTableModel::updateConfirmations() // Invalidate status (number of confirmations) and (possibly) description // for all rows. Qt is smart enough to only actually request the data for the // visible rows. - emit dataChanged(index(0, Status), index(priv->size() - 1, Status)); - emit dataChanged(index(0, ToAddress), index(priv->size() - 1, ToAddress)); + Q_EMIT dataChanged(index(0, Status), index(priv->size() - 1, Status)); + Q_EMIT dataChanged(index(0, ToAddress), index(priv->size() - 1, ToAddress)); } int TransactionTableModel::rowCount(const QModelIndex& parent) const @@ -717,9 +717,9 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex& void TransactionTableModel::updateDisplayUnit() { - // emit dataChanged to update Amount column with the current unit + // Q_EMIT dataChanged to update Amount column with the current unit updateAmountColumnTitle(); - emit dataChanged(index(0, Amount), index(priv->size() - 1, Amount)); + Q_EMIT dataChanged(index(0, Amount), index(priv->size() - 1, Amount)); } // queue notifications to show a non freezing progress dialog e.g. for rescan diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 1fb4d54af2..121ff9a526 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -98,7 +98,7 @@ class TransactionTableModel : public QAbstractTableModel QVariant txWatchonlyDecoration(const TransactionRecord* wtx) const; QVariant txAddressDecoration(const TransactionRecord* wtx) const; -public slots: +public Q_SLOTS: /* New transaction, or transaction changed status */ void updateTransaction(const QString& hash, int status, bool showTransaction); void updateConfirmations(); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 9b662876d5..97c2c9ad74 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -326,7 +326,7 @@ void TransactionView::updateHideOrphans(bool fHide) if (settings.value("fHideOrphans", false).toBool() != fHide) { settings.setValue("fHideOrphans", fHide); if (model && model->getOptionsModel()) - emit model->getOptionsModel()->hideOrphansChanged(fHide); + Q_EMIT model->getOptionsModel()->hideOrphansChanged(fHide); } hideOrphans(fHide); // retain consistency with other checkboxes @@ -399,11 +399,11 @@ void TransactionView::exportClicked() } if (fExport) { - emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), + Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), CClientUIInterface::MSG_INFORMATION); } else { - emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), + Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), CClientUIInterface::MSG_ERROR); } } @@ -495,12 +495,12 @@ void TransactionView::computeSum() return; QModelIndexList selection = transactionView->selectionModel()->selectedRows(); - foreach (QModelIndex index, selection) { + Q_FOREACH (QModelIndex index, selection) { amount += index.data(TransactionTableModel::AmountRole).toLongLong(); } QString strAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, amount, true, BitcoinUnits::separatorAlways)); if (amount < 0) strAmount = "" + strAmount + ""; - emit trxAmount(strAmount); + Q_EMIT trxAmount(strAmount); } void TransactionView::openThirdPartyTxUrl(QString url) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 01d8b4e1a2..a07657c2f7 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -85,7 +85,7 @@ class TransactionView : public QWidget bool eventFilter(QObject* obj, QEvent* event); -private slots: +private Q_SLOTS: void contextualMenu(const QPoint&); void dateRangeChanged(); void showDetails(); @@ -97,7 +97,7 @@ private slots: void openThirdPartyTxUrl(QString url); void updateWatchOnlyColumn(bool fHaveWatchOnly); -signals: +Q_SIGNALS: void doubleClicked(const QModelIndex&); /** Fired when a message should be reported to the user */ @@ -106,7 +106,7 @@ private slots: /** Send computed sum back to wallet-view */ void trxAmount(QString amount); -public slots: +public Q_SLOTS: void chooseDate(int idx); void chooseType(int idx); void hideOrphans(bool fHide); diff --git a/src/qt/txentry.h b/src/qt/txentry.h index 9b62dd81f3..4b8e9dddda 100644 --- a/src/qt/txentry.h +++ b/src/qt/txentry.h @@ -30,11 +30,11 @@ class TxEntry : public QWidget protected: void resizeEvent(QResizeEvent *event); -public slots: +public Q_SLOTS: -signals: +Q_SIGNALS: -private slots: +private Q_SLOTS: void on_pushButtonExpand_clicked(); private: diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 0c42325c3b..28192cec81 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -32,7 +32,7 @@ class HelpMessageDialog : public QDialog Ui::HelpMessageDialog* ui; QString text; -private slots: +private Q_SLOTS: void on_okButton_accepted(); }; diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 6bd812fd90..aa7ca841ea 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -44,7 +44,7 @@ class WalletFrame : public QFrame bool bOutOfSync; WalletView* currentWalletView(); -public slots: +public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); /** Switch to history (transactions) page */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 393a8f0292..b1cbacd425 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -126,7 +126,7 @@ void WalletModel::updateStatus() EncryptionStatus newEncryptionStatus = getEncryptionStatus(); if (cachedEncryptionStatus != newEncryptionStatus) - emit encryptionStatusChanged(newEncryptionStatus); + Q_EMIT encryptionStatusChanged(newEncryptionStatus); } bool IsImportingOrReindexing() { @@ -136,7 +136,7 @@ bool IsImportingOrReindexing() { void WalletModel::pollBalanceChanged() { if (wallet->walletUnlockCountStatus == 1) { - emit WalletUnlocked(); + Q_EMIT WalletUnlocked(); wallet->walletUnlockCountStatus++; } @@ -181,7 +181,7 @@ void WalletModel::emitBalanceChanged() if (cachedBalance == 0 && !checkBalanceChanged()) return; - emit balanceChanged(cachedBalance, cachedUnconfirmedBalance, cachedImmatureBalance, + Q_EMIT balanceChanged(cachedBalance, cachedUnconfirmedBalance, cachedImmatureBalance, cachedWatchOnlyBalance, cachedWatchUnconfBalance, cachedWatchImmatureBalance); } @@ -226,7 +226,7 @@ bool WalletModel::checkBalanceChanged() cachedWatchImmatureBalance = newWatchImmatureBalance; stkEnabled = (nLastCoinStakeSearchInterval > 0); walletLocked = pwalletMain->IsLocked(); - emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, + Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance); return true; } @@ -255,13 +255,13 @@ void WalletModel::updateAddressBook(const QString& pubCoin, const QString& isUse void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) { fHaveWatchOnly = fHaveWatchonly; - emit notifyWatchonlyChanged(fHaveWatchonly); + Q_EMIT notifyWatchonlyChanged(fHaveWatchonly); } void WalletModel::updateMultiSigFlag(bool fHaveMultiSig) { this->fHaveMultiSig = fHaveMultiSig; - emit notifyMultiSigChanged(fHaveMultiSig); + Q_EMIT notifyMultiSigChanged(fHaveMultiSig); } bool WalletModel::validateAddress(const QString& address) @@ -289,7 +289,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nAddresses = 0; // Pre-check input data for validity - foreach (const SendCoinsRecipient& rcp, recipients) { + Q_FOREACH (const SendCoinsRecipient& rcp, recipients) { if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... CAmount subtotal = 0; const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); @@ -348,7 +348,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact if ((total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } - emit message(tr("Send Coins"), QString::fromStdString(strFailReason), + Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } @@ -557,7 +557,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock(AskPassphraseDialog::Conte if (was_locked) { // Request UI to unlock wallet - emit requireUnlock(context); + Q_EMIT requireUnlock(context); } // If wallet is still locked, unlock was failed or cancelled, mark context as invalid bool valid = getEncryptionStatus() != Locked; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 68e1baafbc..9c5838d9b0 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -258,7 +258,7 @@ class WalletModel : public QObject void unsubscribeFromCoreSignals(); bool checkBalanceChanged(); -signals: +Q_SIGNALS: // Signal that balance in wallet changed void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); void stakingStatusChanged(bool isStaking); @@ -288,7 +288,7 @@ class WalletModel : public QObject void RefreshRecent(); void WalletUnlocked(); -public slots: +public Q_SLOTS: /* Wallet status might have changed */ void updateStatus(); /* New transaction, or transaction changed status */ @@ -300,7 +300,7 @@ public slots: void updateWatchOnlyFlag(bool fHaveWatchonly); /* MultiSig added */ void updateMultiSigFlag(bool fHaveMultiSig); - /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ + /* Current, immature or unconfirmed balance might have changed - Q_EMIT 'balanceChanged' if so */ void pollBalanceChanged(); }; diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 1a6d20aee7..d0e119e9c8 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -48,7 +48,7 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee) CAmount WalletModelTransaction::getTotalTransactionAmount() { CAmount totalTransactionAmount = 0; - foreach (const SendCoinsRecipient& rcp, recipients) { + Q_FOREACH (const SendCoinsRecipient& rcp, recipients) { totalTransactionAmount += rcp.amount; } return totalTransactionAmount; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 3fe33f89b4..2312197c32 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -120,7 +120,7 @@ void WalletView::setBitcoinGUI(BitcoinGUI* gui) void WalletView::stakingStatus(bool stt) { - emit stakingStatusChanged(stt); + Q_EMIT stakingStatusChanged(stt); } void WalletView::setClientModel(ClientModel* clientModel) @@ -182,7 +182,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int QString address = ttm->index(start, TransactionTableModel::ToAddress, parent).data().toString(); QString confirmations = ttm->index(start, TransactionTableModel::Confirmations, parent).data().toString(); - emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, confirmations); + Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, confirmations); } void WalletView::gotoOverviewPage() @@ -248,7 +248,7 @@ void WalletView::showSyncStatus(bool fShow) void WalletView::updateEncryptionStatus() { - emit encryptionStatusChanged(walletModel->getEncryptionStatus()); + Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus()); } void WalletView::encryptWallet(bool status) @@ -272,10 +272,10 @@ void WalletView::backupWallet() return; if (!walletModel->backupWallet(filename)) { - emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), + Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename), CClientUIInterface::MSG_ERROR); } else { - emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), + Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename), CClientUIInterface::MSG_INFORMATION); } } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index bbc5f192de..f8b8be94d4 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -75,7 +75,7 @@ class WalletView : public QStackedWidget QProgressDialog* progressDialog; QLabel* transactionSum; -public slots: +public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); /** Switch to history (transactions) page */ @@ -118,7 +118,7 @@ public slots: /** Show used receiving addresses */ void usedReceivingAddresses(); - /** Re-emit encryption status signal */ + /** Re-Q_EMIT encryption status signal */ void updateEncryptionStatus(); /** Show progress dialog e.g. for rescan */ @@ -128,7 +128,7 @@ public slots: void trxAmount(QString amount); void stakingStatus(bool); -signals: +Q_SIGNALS: /** Signal that we want to show the main window */ void showNormalIfMinimized(); /** Fired when a message should be reported to the user */ From 3f77137f3eaad64bffbb9695e0f435b65b27f5f2 Mon Sep 17 00:00:00 2001 From: Mr-Vaelen Date: Fri, 20 Mar 2020 16:01:34 +1000 Subject: [PATCH 0282/1888] Applying transaction patch to remove decoy decoding from getrawtransaction so that only the actual tx values are decoded. --- src/rpc/rawtransaction.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d05e45c514..c8d1e63a0b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -103,11 +103,17 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) const CWalletTx& prev = (*mi).second; if (allDecoys[i].n < prev.vout.size()) { if (pwalletMain->IsMine(prev.vout[allDecoys[i].n])) { - CAmount decodedAmount; - CKey blind; - pwalletMain->RevealTxOutAmount(prev, prev.vout[allDecoys[i].n], decodedAmount, blind); - decoy.push_back(Pair("decoded_amount", ValueFromAmount(decodedAmount))); - decoy.push_back(Pair("isMine", true)); + std::string outString = allDecoys[i].hash.GetHex() + std::to_string(allDecoys[i].n); + if (pwalletMain->outpointToKeyImages.count(outString) == 1) { + CKeyImage ki = pwalletMain->outpointToKeyImages[outString]; + if (ki == txin.keyImage) { + CAmount decodedAmount; + CKey blind; + pwalletMain->RevealTxOutAmount(prev, prev.vout[allDecoys[i].n], decodedAmount, blind); + decoy.push_back(Pair("decoded_amount", ValueFromAmount(decodedAmount))); + decoy.push_back(Pair("isMine", true)); + } + } } else { decoy.push_back(Pair("isMine", false)); } From c386ef3243882eb9b676078b830c7a493ed1ff64 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Mar 2020 11:47:35 -0400 Subject: [PATCH 0283/1888] Replace qWarning() with qDebug() for cleaner debug.log (Windows only) --- src/qt/winshutdownmonitor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index e960037ac0..c5903b49ab 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -55,13 +55,13 @@ void WinShutdownMonitor::registerShutdownBlockReason(const QString& strReason, c typedef BOOL(WINAPI * PSHUTDOWNBRCREATE)(HWND, LPCWSTR); PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress(GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate"); if (shutdownBRCreate == NULL) { - qWarning() << "registerShutdownBlockReason: GetProcAddress for ShutdownBlockReasonCreate failed"; + qDebug() << "registerShutdownBlockReason: GetProcAddress for ShutdownBlockReasonCreate failed"; return; } if (shutdownBRCreate(mainWinId, strReason.toStdWString().c_str())) - qWarning() << "registerShutdownBlockReason: Successfully registered: " + strReason; + qDebug() << "registerShutdownBlockReason: Successfully registered: " + strReason; else - qWarning() << "registerShutdownBlockReason: Failed to register: " + strReason; + qDebug() << "registerShutdownBlockReason: Failed to register: " + strReason; } #endif From 1bc521c9e9fc137e0475a5c6c94ba8946b9a5a46 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Mar 2020 12:40:05 -0400 Subject: [PATCH 0284/1888] [Qt] Add Tor service icon to status bar Tor Icon is displayed when the client is initialized with a successful tor service connection. Icon is hidden otherwise. --- src/Makefile.qt.include | 1 + src/qt/bitcoingui.cpp | 28 ++++++++++++++++++++++++++-- src/qt/bitcoingui.h | 5 +++++ src/qt/clientmodel.cpp | 18 ++++++++++++++++++ src/qt/clientmodel.h | 2 ++ src/qt/dapscoin.qrc | 1 + 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index a38823a7ee..bf93d3e995 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -260,6 +260,7 @@ RES_ICONS = \ qt/res/icons/lock_closed.png \ qt/res/icons/lock_open.png \ qt/res/icons/masternodes.png \ + qt/res/icons/onion.png \ qt/res/icons/overview.png \ qt/res/icons/qrcode.png \ qt/res/icons/qr-code.png \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 7018448e94..8fbd1adccb 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -75,6 +75,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai unitDisplayControl(0), labelStakingIcon(0), labelEncryptionIcon(0), + labelTorIcon(0), labelConnectionsIcon(0), labelBlocksIcon(0), appMenuBar(0), @@ -196,6 +197,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai labelEncryptionIcon->setFlat(true); // Make the button look like a label, but clickable labelEncryptionIcon->setStyleSheet(".QPushButton { background-color: rgba(255, 255, 255, 0);}"); labelEncryptionIcon->setMaximumSize(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); + labelTorIcon = new QLabel(); labelConnectionsIcon = new QPushButton(); labelConnectionsIcon->setFlat(true); // Make the button look like a label, but clickable labelConnectionsIcon->setStyleSheet(".QPushButton { background-color: rgba(255, 255, 255, 0);}"); @@ -207,9 +209,10 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai frameBlocksLayout->addWidget(unitDisplayControl); frameBlocksLayout->addStretch(); frameBlocksLayout->addWidget(labelEncryptionIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelStakingIcon); } - frameBlocksLayout->addStretch(); - frameBlocksLayout->addWidget(labelStakingIcon); + frameBlocksLayout->addWidget(labelTorIcon); frameBlocksLayout->addStretch(); frameBlocksLayout->addWidget(labelConnectionsIcon); frameBlocksLayout->addStretch(); @@ -689,6 +692,9 @@ void BitcoinGUI::setClientModel(ClientModel* clientModel) connect(clientModel, SIGNAL(message(QString, QString, unsigned int)), this, SLOT(message(QString, QString, unsigned int))); rpcConsole->setClientModel(clientModel); + + updateTorIcon(); + #ifdef ENABLE_WALLET if (walletFrame) { walletFrame->setClientModel(clientModel); @@ -1414,6 +1420,24 @@ void BitcoinGUI::setEncryptionStatus(int status) } #endif // ENABLE_WALLET +void BitcoinGUI::updateTorIcon() +{ + std::string ip_port; + bool tor_enabled = clientModel->getTorInfo(ip_port); + + if (tor_enabled) { + if (labelTorIcon->pixmap() == 0) { + QString ip_port_q = QString::fromStdString(ip_port); + labelTorIcon->setPixmap(QIcon(":/icons/onion").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelTorIcon->setToolTip(tr("Tor is enabled: %1").arg(ip_port_q)); + } else { + labelTorIcon->show(); + } + } else { + labelTorIcon->hide(); + } +} + void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { if (!clientModel) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 317ae44fde..5a9d82ffd1 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -86,6 +86,7 @@ class BitcoinGUI : public QMainWindow UnitDisplayStatusBarControl* unitDisplayControl; QLabel* labelStakingIcon; QPushButton* labelEncryptionIcon; + QLabel* labelTorIcon; QPushButton* labelConnectionsIcon; QLabel* labelBlocksIcon; @@ -219,6 +220,10 @@ public Q_SLOTS: void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& confirmations); #endif // ENABLE_WALLET +private: + /** Set the Tor-enabled icon as shown in the UI. */ + void updateTorIcon(); + private Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index b3cde3eb12..f98024c5d0 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -304,3 +304,21 @@ void ClientModel::unsubscribeFromCoreSignals() uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); } + +bool ClientModel::getTorInfo(std::string& ip_port) const +{ + proxyType onion; + if (GetProxy((Network) 3, onion) && IsReachable((Network) 3)) { + { + LOCK(cs_mapLocalHost); + for (const std::pair &item : mapLocalHost) { + if (item.first.IsTor()) { + CService addrOnion = CService(item.first.ToString(), item.second.nPort); + ip_port = addrOnion.ToStringIPPort(); + return true; + } + } + } + } + return false; +} diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index f1abfc0dd2..1f713286ff 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -82,6 +82,8 @@ class ClientModel : public QObject QString formatClientStartupTime() const; QString dataDir() const; + bool getTorInfo(std::string& ip_port) const; + void setCacheTip(const CBlockIndex* const tip) { cacheTip = tip; }; void setCacheReindexing(bool reindex) { cachedReindexing = reindex; }; void setCacheImporting(bool import) { cachedImporting = import; }; diff --git a/src/qt/dapscoin.qrc b/src/qt/dapscoin.qrc index 410a266d9a..ed86130b3b 100644 --- a/src/qt/dapscoin.qrc +++ b/src/qt/dapscoin.qrc @@ -74,6 +74,7 @@ res/icons/steemit.png res/icons/telegram.png res/icons/twitter.png + res/icons/onion.png res/css/Light.css From 73ce0b0e3e1566ed2e257734a5beee893a1c4fc8 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Mar 2020 14:36:49 -0400 Subject: [PATCH 0285/1888] Remove unused variables in updateRecentTransactions --- src/qt/overviewpage.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 1c81c6421b..9e57861473 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -454,9 +454,6 @@ void OverviewPage::updateRecentTransactions(){ { LOCK2(cs_main, pwalletMain->cs_wallet); QLayoutItem* item; - QSettings settings; - QVariant theme = settings.value("theme"); - QString themeName = QString(theme.toString()); while ( ( item = ui->verticalLayoutRecent->takeAt( 0 ) ) != NULL ) { From 17a8cb94f0c6548801e575e29410d21249fb8a4d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Sat, 21 Mar 2020 14:37:51 -0400 Subject: [PATCH 0286/1888] Remove refreshRecentTransactions as it just calls updateRecentTransactions --- src/qt/overviewpage.cpp | 8 ++------ src/qt/overviewpage.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 9e57861473..94d16c0681 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -193,7 +193,7 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed font.setBold(true); ui->labelBalance_2->setFont(font); - refreshRecentTransactions(); + updateRecentTransactions(); } // show/hide watch-only labels @@ -449,7 +449,7 @@ int OverviewPage::tryNetworkBlockCount(){ return -1; } -void OverviewPage::updateRecentTransactions(){ +void OverviewPage::updateRecentTransactions() { if (!pwalletMain) return; { LOCK2(cs_main, pwalletMain->cs_wallet); @@ -516,10 +516,6 @@ void OverviewPage::updateRecentTransactions(){ } } -void OverviewPage::refreshRecentTransactions() { - updateRecentTransactions(); -} - void OverviewPage::on_lockUnlock() { if (walletModel->getEncryptionStatus() == WalletModel::Locked || walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly) { WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, true)); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 8823c4311d..6fe32d51f1 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -52,7 +52,6 @@ public Q_SLOTS: void updateTotalBlocksLabel(); int tryNetworkBlockCount(); void updateRecentTransactions(); - void refreshRecentTransactions(); void setSpendableBalance(bool isStaking); void showBlockCurrentHeight(int count); void updateBalance(); From e3163c87b7b7d0f698dafbea663406e11895a3f0 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Mar 2020 15:49:37 -0400 Subject: [PATCH 0287/1888] Show "???" instead of 0 blocks --- src/qt/overviewpage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 94d16c0681..a95c7e3d9e 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -330,7 +330,8 @@ void OverviewPage::showBlockSync(bool fShow) int count = clientModel->getNumBlocks(); ui->labelBlockCurrent->setText(QString::number(count)); - if (count == 0 & isSyncingBlocks){ + if (count == 0 && isSyncingBlocks){ + ui->labelBlockCurrent->setText("???"); ui->labelBlockStatus->setText("(loading)"); ui->labelBlockStatus->setToolTip("The displayed information may be out of date. Your wallet automatically synchronizes with the DAPS network after a connection is established, but this process has not completed yet."); ui->labelBlockCurrent->setAlignment((Qt::AlignRight|Qt::AlignVCenter)); From 91514ccee472f9ecf98c91e5be96cb4c4637a8cd Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Mar 2020 15:56:28 -0400 Subject: [PATCH 0288/1888] Remove TRY_LOCK --- src/qt/overviewpage.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index a95c7e3d9e..0901959edc 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -348,9 +348,6 @@ void OverviewPage::showBlockSync(bool fShow) void OverviewPage::showBlockCurrentHeight(int count) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) - return; ui->labelBlockCurrent->setText(QString::number(count)); } From 819af1c10ad9dd666b3870ab427d6dcd5636f663 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Mar 2020 16:16:28 -0400 Subject: [PATCH 0289/1888] Add missing line break between animTicker / animClock starts --- src/qt/overviewpage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 0901959edc..768fb7f399 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -357,7 +357,8 @@ void OverviewPage::initSyncCircle(float ratioToParent) animTicker->setInterval(17); //17 mSecs or ~60 fps animClock = new QElapsedTimer(); connect(animTicker, SIGNAL(timeout()), this, SLOT(onAnimTick())); - animTicker->start(); animClock->start(); + animTicker->start(); + animClock->start(); blockAnimSyncCircle = new QWidget(ui->widgetSyncBlocks); blockAnimSyncCircle->setStyleSheet("image:url(':/images/syncb')");//"background-image: ./image.png"); From f56dd5007cc436f0a542c15a4d48d4d4a75ca937 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 24 Mar 2020 09:21:54 -0400 Subject: [PATCH 0290/1888] [Compilation] Pass caught exceptions by reference Gets rid of compiler warnings such as "warning: catching polymorphic type 'class std::runtime_error' by value [-Wcatch-value=]" --- src/dapscoin-cli.cpp | 2 +- src/dapscoin-tx.cpp | 2 +- src/main.cpp | 2 +- src/miner.cpp | 2 +- src/net.cpp | 14 +++++++------- src/rest.cpp | 2 +- src/rpc/server.cpp | 4 ++-- src/util.cpp | 2 +- src/util.h | 6 +++--- src/wallet/walletdb.cpp | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/dapscoin-cli.cpp b/src/dapscoin-cli.cpp index 39f80d9527..8eca4718d2 100644 --- a/src/dapscoin-cli.cpp +++ b/src/dapscoin-cli.cpp @@ -274,7 +274,7 @@ int CommandLineRPC(int argc, char* argv[]) throw; } } while (fWait); - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { throw; } catch (std::exception& e) { strPrint = string("error: ") + e.what(); diff --git a/src/dapscoin-tx.cpp b/src/dapscoin-tx.cpp index 8fc4769a66..2b29b35772 100644 --- a/src/dapscoin-tx.cpp +++ b/src/dapscoin-tx.cpp @@ -598,7 +598,7 @@ static int CommandLineRawTx(int argc, char* argv[]) OutputTx(tx); } - catch (boost::thread_interrupted) { + catch (boost::thread_interrupted&) { throw; } catch (std::exception& e) { strPrint = string("error: ") + e.what(); diff --git a/src/main.cpp b/src/main.cpp index 8c53438223..48584536a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6565,7 +6565,7 @@ bool ProcessMessages(CNode* pfrom) } else { PrintExceptionContinue(&e, "ProcessMessages()"); } - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { throw; } catch (std::exception& e) { PrintExceptionContinue(&e, "ProcessMessages()"); diff --git a/src/miner.cpp b/src/miner.cpp index 9a3dd58ebf..4998dfa205 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -917,7 +917,7 @@ void ThreadStakeMinter() { try { BitcoinMiner(pwallet, true); boost::this_thread::interruption_point(); - } catch (std::exception &e) { + } catch (std::exception& e) { LogPrintf("ThreadStakeMinter() exception \n"); } catch (...) { LogPrintf("ThreadStakeMinter() error \n"); diff --git a/src/net.cpp b/src/net.cpp index 5a46a06b18..4415b6123d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1150,7 +1150,7 @@ void ThreadMapPort() MilliSleep(20 * 60 * 1000); // Refresh every 20 minutes } - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); LogPrintf("UPNP_DeletePortMapping() returned : %d\n", r); freeUPNPDevlist(devlist); @@ -1944,7 +1944,7 @@ bool CAddrDB::Write(const CAddrMan &addr) { // Write and commit header, data try { fileout << ssPeers; - } catch (std::exception &e) { + } catch (std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } FileCommit(fileout.Get()); @@ -1977,7 +1977,7 @@ bool CAddrDB::Read(CAddrMan &addr) { try { filein.read((char *) &vchData[0], dataSize); filein >> hashIn; - } catch (std::exception &e) { + } catch (std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } filein.fclose(); @@ -2005,7 +2005,7 @@ bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) // de-serialize address data into one CAddrMan object ssPeers >> addr; - } catch (std::exception &e) { + } catch (std::exception& e) { // de-serialization has failed, ensure addrman is left in a clean state addr.Clear(); return error("%s : Deserialize or I/O error - %s", __func__, e.what()); @@ -2202,7 +2202,7 @@ bool CBanDB::Write(const banmap_t &banSet) { try { fileout << ssBanlist; } - catch (const std::exception &e) { + catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } FileCommit(fileout.Get()); @@ -2233,7 +2233,7 @@ bool CBanDB::Read(banmap_t &banSet) { filein.read((char *) &vchData[0], dataSize); filein >> hashIn; } - catch (const std::exception &e) { + catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } filein.fclose(); @@ -2252,7 +2252,7 @@ bool CBanDB::Read(banmap_t &banSet) { // de-serialize address data into one CAddrMan object ssBanlist >> banSet; } - catch (const std::exception &e) { + catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } return true; diff --git a/src/rest.cpp b/src/rest.cpp index d310f73bb5..05cde21248 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -456,7 +456,7 @@ static bool rest_getutxos(HTTPRequest *req, const std::string &strURIPart) { oss >> fCheckMemPool; oss >> vOutPoints; } - } catch (const std::ios_base::failure &e) { + } catch (const std::ios_base::failure& e) { // abort in case of unreadable binary data return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error"); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 69ab3006e0..7e1e162265 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -203,7 +203,7 @@ string CRPCTable::help(string strCommand) const { rpcfn_type pfn = pcmd->actor; if (setDone.insert(pfn).second) (*pfn)(params, true); - } catch (std::exception &e) { + } catch (std::exception& e) { // Help text is returned in an exception string strHelp = string(e.what()); if (strCommand == "") { @@ -563,7 +563,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms try { return pcmd->actor(params, false); - } catch (std::exception &e) { + } catch (std::exception& e) { throw JSONRPCError(RPC_MISC_ERROR, e.what()); } diff --git a/src/util.cpp b/src/util.cpp index e7dd24d149..1af83c0072 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -596,7 +596,7 @@ bool TryCreateDirectory(const boost::filesystem::path& p) { try { return boost::filesystem::create_directory(p); - } catch (boost::filesystem::filesystem_error) { + } catch (boost::filesystem::filesystem_error&) { if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p)) throw; } diff --git a/src/util.h b/src/util.h index 5c99abc9a2..73b96aac51 100644 --- a/src/util.h +++ b/src/util.h @@ -81,7 +81,7 @@ template std::string FormatStringFromLogArgs(const char *fmt, std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ try { \ _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ - } catch (std::runtime_error &e) { \ + } catch (std::runtime_error& e) { \ _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ } \ return LogPrintStr(_log_msg_); \ @@ -93,7 +93,7 @@ template std::string FormatStringFromLogArgs(const char *fmt, std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ try { \ _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ - } catch (std::runtime_error &e) { \ + } catch (std::runtime_error& e) { \ _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ } \ LogPrintStr(std::string("ERROR: ") + _log_msg_ + "\n"); \ @@ -227,7 +227,7 @@ void TraceThread(const char* name, Callable func) LogPrintf("%s thread start\n", name); func(); LogPrintf("%s thread exit\n", name); - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { LogPrintf("%s thread interrupt\n", name); throw; } catch (std::exception& e) { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 2579be18df..5b50804ab9 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -871,7 +871,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) LogPrintf("%s\n", strErr); } pcursor->close(); - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { throw; } catch (...) { result = DB_CORRUPT; @@ -964,7 +964,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec } } pcursor->close(); - } catch (boost::thread_interrupted) { + } catch (boost::thread_interrupted&) { throw; } catch (...) { result = DB_CORRUPT; From fd7bb3efbe8e51394536eb242b7bad42cb21ead7 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 24 Mar 2020 10:30:10 -0400 Subject: [PATCH 0291/1888] [Refactor] Add const qualifier to exception catching --- src/dapscoin-cli.cpp | 10 +++++----- src/dapscoin-tx.cpp | 8 ++++---- src/dapscoind.cpp | 4 ++-- src/init.cpp | 12 ++++++------ src/main.cpp | 22 +++++++++++----------- src/masternode-budget.cpp | 6 +++--- src/masternode-payments.cpp | 6 +++--- src/masternodeman.cpp | 6 +++--- src/miner.cpp | 6 +++--- src/net.cpp | 8 ++++---- src/qt/dapscoin.cpp | 14 +++++++------- src/qt/entermnemonics.cpp | 2 +- src/qt/intro.cpp | 4 ++-- src/qt/paymentrequestplus.cpp | 2 +- src/qt/rpcconsole.cpp | 6 +++--- src/rpc/server.cpp | 6 +++--- src/test/wallet_tests.cpp | 6 +++--- src/txdb.cpp | 4 ++-- src/util.cpp | 6 +++--- src/util.h | 10 +++++----- src/wallet/test/wallet_tests.cpp | 6 +++--- src/wallet/wallet.cpp | 2 +- src/wallet/walletdb.cpp | 4 ++-- 23 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/dapscoin-cli.cpp b/src/dapscoin-cli.cpp index 8eca4718d2..a70edd4baa 100644 --- a/src/dapscoin-cli.cpp +++ b/src/dapscoin-cli.cpp @@ -92,7 +92,7 @@ static bool AppInitRPC(int argc, char* argv[]) } try { ReadConfigFile(mapArgs, mapMultiArgs); - } catch (std::exception& e) { + } catch (const std::exception& e) { fprintf(stderr, "Error reading configuration file: %s\n", e.what()); return false; } @@ -274,9 +274,9 @@ int CommandLineRPC(int argc, char* argv[]) throw; } } while (fWait); - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { throw; - } catch (std::exception& e) { + } catch (const std::exception& e) { strPrint = string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { @@ -301,7 +301,7 @@ int main(int argc, char* argv[]) try { if (!AppInitRPC(argc, argv)) return EXIT_FAILURE; - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInitRPC()"); return EXIT_FAILURE; } catch (...) { @@ -312,7 +312,7 @@ int main(int argc, char* argv[]) int ret = EXIT_FAILURE; try { ret = CommandLineRPC(argc, argv); - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "CommandLineRPC()"); } catch (...) { PrintExceptionContinue(NULL, "CommandLineRPC()"); diff --git a/src/dapscoin-tx.cpp b/src/dapscoin-tx.cpp index 2b29b35772..c4a3f0f8f5 100644 --- a/src/dapscoin-tx.cpp +++ b/src/dapscoin-tx.cpp @@ -598,9 +598,9 @@ static int CommandLineRawTx(int argc, char* argv[]) OutputTx(tx); } - catch (boost::thread_interrupted&) { + catch (const boost::thread_interrupted&) { throw; - } catch (std::exception& e) { + } catch (const std::exception& e) { strPrint = string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { @@ -621,7 +621,7 @@ int main(int argc, char* argv[]) try { if (!AppInitRawTx(argc, argv)) return EXIT_FAILURE; - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInitRawTx()"); return EXIT_FAILURE; } catch (...) { @@ -632,7 +632,7 @@ int main(int argc, char* argv[]) int ret = EXIT_FAILURE; try { ret = CommandLineRawTx(argc, argv); - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "CommandLineRawTx()"); } catch (...) { PrintExceptionContinue(NULL, "CommandLineRawTx()"); diff --git a/src/dapscoind.cpp b/src/dapscoind.cpp index 4bade08cbb..6d33b1255a 100644 --- a/src/dapscoind.cpp +++ b/src/dapscoind.cpp @@ -93,7 +93,7 @@ bool AppInit(int argc, char* argv[]) } try { ReadConfigFile(mapArgs, mapMultiArgs); - } catch (std::exception& e) { + } catch (const std::exception& e) { fprintf(stderr, "Error reading configuration file: %s\n", e.what()); return false; } @@ -153,7 +153,7 @@ bool AppInit(int argc, char* argv[]) InitLogging(); InitParameterInteraction(); fRet = AppInit2(true); - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); } catch (...) { PrintExceptionContinue(NULL, "AppInit()"); diff --git a/src/init.cpp b/src/init.cpp index 3ee6420769..393e1b4290 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1126,7 +1126,7 @@ bool AppInit2(bool isDaemon) try { boost::filesystem::copy_file(sourceFile, backupFile); LogPrintf("Creating backup of %s -> %s\n", sourceFile, backupFile); - } catch (boost::filesystem::filesystem_error& error) { + } catch (const boost::filesystem::filesystem_error& error) { LogPrintf("Failed to create backup %s\n", error.what()); } #else @@ -1162,7 +1162,7 @@ bool AppInit2(bool isDaemon) try { boost::filesystem::remove(file.second); LogPrintf("Old backup deleted: %s\n", file.second); - } catch (boost::filesystem::filesystem_error& error) { + } catch (const boost::filesystem::filesystem_error& error) { LogPrintf("Failed to delete backup %s\n", error.what()); } } @@ -1187,7 +1187,7 @@ bool AppInit2(bool isDaemon) boost::filesystem::remove_all(chainstateDir); LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); } - } catch (boost::filesystem::filesystem_error& error) { + } catch (const boost::filesystem::filesystem_error& error) { LogPrintf("Failed to delete blockchain folders %s\n", error.what()); } } @@ -1202,7 +1202,7 @@ bool AppInit2(bool isDaemon) try { boost::filesystem::rename(pathDatabase, pathDatabaseBak); LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string()); - } catch (boost::filesystem::filesystem_error& error) { + } catch (const boost::filesystem::filesystem_error& error) { // failure is ok (well, not really, but it's not worse than what we started with) } @@ -1485,7 +1485,7 @@ bool AppInit2(bool isDaemon) break; } } - } catch (std::exception& e) { + } catch (const std::exception& e) { if (fDebug) LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); fVerifyingBlocks = false; @@ -1524,7 +1524,7 @@ bool AppInit2(bool isDaemon) boost::filesystem::create_directories(blocksDir); boost::filesystem::create_directories(chainstateDir); - } catch (boost::filesystem::filesystem_error& error) { + } catch (const boost::filesystem::filesystem_error& error) { LogPrintf("Failed to delete blockchain folders %s\n", error.what()); } diff --git a/src/main.cpp b/src/main.cpp index 48584536a7..0e5ad48f60 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2032,7 +2032,7 @@ bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock file >> header; fseek(file.Get(), postx.nTxOffset, SEEK_CUR); file >> txOut; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } hashBlock = header.GetHash(); @@ -2113,7 +2113,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) // Read block try { filein >> block; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } @@ -4477,7 +4477,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return state.Abort("Failed to write block"); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("AcceptBlock() : ReceivedBlockTransactions failed"); - } catch (std::runtime_error& e) { + } catch (const std::runtime_error& e) { return state.Abort(std::string("System error: ") + e.what()); } @@ -5079,7 +5079,7 @@ bool InitBlockIndex() return error("LoadBlockIndex() : genesis block not accepted"); // Force a chainstate write so that when we VerifyDB in a moment, it doesnt check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); - } catch (std::runtime_error& e) { + } catch (const std::runtime_error& e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); } } @@ -5180,11 +5180,11 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) mapBlocksUnknownParent.erase(it); } } - } catch (std::exception& e) { + } catch (const std::exception& e) { LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - } catch (std::runtime_error& e) { + } catch (const std::runtime_error& e) { AbortNode(std::string("System error: ") + e.what()); } if (nLoaded > 0) @@ -6457,7 +6457,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ss << ": hash " << hash.ToString(); } LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); - } catch (std::ios_base::failure& e) { + } catch (const std::ios_base::failure& e) { // Avoid feedback loops by preventing reject messages from triggering a new reject message. LogPrint("net", "Unparseable reject message received\n"); } @@ -6551,7 +6551,7 @@ bool ProcessMessages(CNode* pfrom) try { fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); boost::this_thread::interruption_point(); - } catch (std::ios_base::failure& e) { + } catch (const std::ios_base::failure& e) { pfrom->PushMessage("reject", strCommand, REJECT_MALFORMED, string("error parsing message")); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -6565,9 +6565,9 @@ bool ProcessMessages(CNode* pfrom) } else { PrintExceptionContinue(&e, "ProcessMessages()"); } - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { throw; - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "ProcessMessages()"); } catch (...) { PrintExceptionContinue(NULL, "ProcessMessages()"); @@ -6856,7 +6856,7 @@ bool CBlockUndo::ReadFromDisk(const CDiskBlockPos& pos, const uint256& hashBlock try { filein >> *this; filein >> hashChecksum; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index ba68dfcfce..eadc3465da 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -274,7 +274,7 @@ bool CBudgetDB::Write(const CBudgetManager& objToSave) // Write and commit header, data try { fileout << ssObj; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } fileout.fclose(); @@ -311,7 +311,7 @@ CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) try { filein.read((char*)&vchData[0], dataSize); filein >> hashIn; - } catch (std::exception& e) { + } catch (const std::exception& e) { error("%s : Deserialize or I/O error - %s", __func__, e.what()); return HashReadError; } @@ -351,7 +351,7 @@ CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) // de-serialize data into CBudgetManager object ssObj >> objToLoad; - } catch (std::exception& e) { + } catch (const std::exception& e) { objToLoad.Clear(); error("%s : Deserialize or I/O error - %s", __func__, e.what()); return IncorrectFormat; diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 0e574e346d..a3dfb4b181 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -53,7 +53,7 @@ bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave) // Write and commit header, data try { fileout << ssObj; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } fileout.fclose(); @@ -88,7 +88,7 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& try { filein.read((char*)&vchData[0], dataSize); filein >> hashIn; - } catch (std::exception& e) { + } catch (const std::exception& e) { error("%s : Deserialize or I/O error - %s", __func__, e.what()); return HashReadError; } @@ -127,7 +127,7 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& // de-serialize data into CMasternodePayments object ssObj >> objToLoad; - } catch (std::exception& e) { + } catch (const std::exception& e) { objToLoad.Clear(); error("%s : Deserialize or I/O error - %s", __func__, e.what()); return IncorrectFormat; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 4ebfa7228b..adbc7d00a9 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -72,7 +72,7 @@ bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave) // Write and commit header, data try { fileout << ssMasternodes; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } @@ -109,7 +109,7 @@ CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad, bo try { filein.read((char*)&vchData[0], dataSize); filein >> hashIn; - } catch (std::exception& e) { + } catch (const std::exception& e) { error("%s : Deserialize or I/O error - %s", __func__, e.what()); return HashReadError; } @@ -147,7 +147,7 @@ CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad, bo } // de-serialize data into CMasternodeMan object ssMasternodes >> mnodemanToLoad; - } catch (std::exception& e) { + } catch (const std::exception& e) { mnodemanToLoad.Clear(); error("%s : Deserialize or I/O error - %s", __func__, e.what()); return IncorrectFormat; diff --git a/src/miner.cpp b/src/miner.cpp index 4998dfa205..826cc2b23c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -840,7 +840,7 @@ void static ThreadBitcoinMiner(void* parg) BitcoinMiner(pwallet, false); } boost::this_thread::interruption_point(); - } catch (std::exception& e) { + } catch (const std::exception& e) { LogPrintf("ThreadBitcoinMiner() exception\n"); } catch (...) { LogPrintf("ThreadBitcoinMiner() exception\n"); @@ -859,7 +859,7 @@ void static ThreadDapscoinMiner(void* parg) //TODO: call CreateNewPoABlock function to create PoA blocks } boost::this_thread::interruption_point(); - } catch (std::exception& e) { + } catch (const std::exception& e) { LogPrintf("ThreadBitcoinMiner() exception\n"); } catch (...) { LogPrintf("ThreadBitcoinMiner() exception\n"); @@ -917,7 +917,7 @@ void ThreadStakeMinter() { try { BitcoinMiner(pwallet, true); boost::this_thread::interruption_point(); - } catch (std::exception& e) { + } catch (const std::exception& e) { LogPrintf("ThreadStakeMinter() exception \n"); } catch (...) { LogPrintf("ThreadStakeMinter() error \n"); diff --git a/src/net.cpp b/src/net.cpp index 4415b6123d..8d2b04df6d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1150,7 +1150,7 @@ void ThreadMapPort() MilliSleep(20 * 60 * 1000); // Refresh every 20 minutes } - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); LogPrintf("UPNP_DeletePortMapping() returned : %d\n", r); freeUPNPDevlist(devlist); @@ -1944,7 +1944,7 @@ bool CAddrDB::Write(const CAddrMan &addr) { // Write and commit header, data try { fileout << ssPeers; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } FileCommit(fileout.Get()); @@ -1977,7 +1977,7 @@ bool CAddrDB::Read(CAddrMan &addr) { try { filein.read((char *) &vchData[0], dataSize); filein >> hashIn; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } filein.fclose(); @@ -2005,7 +2005,7 @@ bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) // de-serialize address data into one CAddrMan object ssPeers >> addr; - } catch (std::exception& e) { + } catch (const std::exception& e) { // de-serialization has failed, ensure addrman is left in a clean state addr.Clear(); return error("%s : Deserialize or I/O error - %s", __func__, e.what()); diff --git a/src/qt/dapscoin.cpp b/src/qt/dapscoin.cpp index d48fbea951..cad2f40f36 100644 --- a/src/qt/dapscoin.cpp +++ b/src/qt/dapscoin.cpp @@ -191,7 +191,7 @@ public Q_SLOTS: bool execute_restart; /// Pass fatal exception message to UI thread - void handleRunawayException(std::exception* e); + void handleRunawayException(const std::exception* e); }; /** Main DAPS application object */ @@ -261,7 +261,7 @@ BitcoinCore::BitcoinCore() : QObject() { } -void BitcoinCore::handleRunawayException(std::exception* e) +void BitcoinCore::handleRunawayException(const std::exception* e) { PrintExceptionContinue(e, "Runaway exception"); Q_EMIT runawayException(QString::fromStdString(strMiscWarning)); @@ -280,7 +280,7 @@ void BitcoinCore::initialize() qDebug() << __func__ << ": Running AppInit2 in thread"; int rv = AppInit2(false); Q_EMIT initializeResult(rv); - } catch (std::exception& e) { + } catch (const std::exception& e) { handleRunawayException(&e); } catch (...) { handleRunawayException(NULL); @@ -301,7 +301,7 @@ void BitcoinCore::restart(QStringList args) QProcess::startDetached(QApplication::applicationFilePath(), args); qDebug() << __func__ << ": Restart initiated..."; QApplication::quit(); - } catch (std::exception& e) { + } catch (const std::exception& e) { handleRunawayException(&e); } catch (...) { handleRunawayException(NULL); @@ -317,7 +317,7 @@ void BitcoinCore::shutdown() Shutdown(); qDebug() << __func__ << ": Shutdown finished"; Q_EMIT shutdownResult(1); - } catch (std::exception& e) { + } catch (const std::exception& e) { handleRunawayException(&e); } catch (...) { handleRunawayException(NULL); @@ -644,7 +644,7 @@ int main(int argc, char* argv[]) } try { ReadConfigFile(mapArgs, mapMultiArgs); - } catch (std::exception& e) { + } catch (const std::exception& e) { QMessageBox::critical(0, QObject::tr("DAPS"), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); return 0; @@ -726,7 +726,7 @@ int main(int argc, char* argv[]) app.exec(); app.requestShutdown(); app.exec(); - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, "Runaway exception"); app.handleRunawayException(QString::fromStdString(strMiscWarning)); } catch (...) { diff --git a/src/qt/entermnemonics.cpp b/src/qt/entermnemonics.cpp index c3d9896754..ce624a50a7 100644 --- a/src/qt/entermnemonics.cpp +++ b/src/qt/entermnemonics.cpp @@ -35,7 +35,7 @@ void EnterMnemonics::on_next() pwalletMain->SetBestChain(loc); CWalletDB(pwalletMain->strWalletFile).WriteScannedBlockHeight(0); //reschedule to rescan entire chain to recover all funds and history accept(); - } catch (std::exception& ex) { + } catch (const std::exception& ex) { QMessageBox::warning(this, "Recovery Phrase Invalid", "Recovery phrase is invalid. Please try again and double check all words.", QMessageBox::Ok); } } diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index a16aa635a9..b32617ab7c 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -95,7 +95,7 @@ void FreespaceChecker::check() replyMessage = tr("Path already exists, and is not a directory."); } } - } catch (fs::filesystem_error& e) { + } catch (const fs::filesystem_error& e) { /* Parent directory does not exist or is not accessible */ replyStatus = ST_ERROR; replyMessage = tr("Cannot create data directory here."); @@ -174,7 +174,7 @@ bool Intro::pickDataDirectory() try { TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir)); break; - } catch (fs::filesystem_error& e) { + } catch (const fs::filesystem_error& e) { QMessageBox::critical(0, tr("DAPS"), tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir)); /* fall through, back to choosing screen */ diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index d76fafc4e9..5cdbc135d9 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -172,7 +172,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c throw SSLVerifyError("Bad certificate, missing common name."); } // TODO: detect EV certificates and set merchant = business name instead of unfriendly NID_commonName ? - } catch (SSLVerifyError& err) { + } catch (const SSLVerifyError& err) { fResult = false; qWarning() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what(); } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 65d264f7eb..06b0d1760b 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -237,17 +237,17 @@ void RPCExecutor::request(const QString& command) strPrint = result.write(2); Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); - } catch (UniValue& objError) { + } catch (const UniValue& objError) { try // Nice formatting for standard-format error { int code = find_value(objError, "code").get_int(); std::string message = find_value(objError, "message").get_str(); Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); - } catch (std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message + } catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); } - } catch (std::exception& e) { + } catch (const std::exception& e) { Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); } } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 7e1e162265..d974450f5d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -203,7 +203,7 @@ string CRPCTable::help(string strCommand) const { rpcfn_type pfn = pcmd->actor; if (setDone.insert(pfn).second) (*pfn)(params, true); - } catch (std::exception& e) { + } catch (const std::exception& e) { // Help text is returned in an exception string strHelp = string(e.what()); if (strCommand == "") { @@ -536,7 +536,7 @@ static UniValue JSONRPCExecOne(const UniValue& req) rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id); } catch (const UniValue& objError) { rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id); - } catch (std::exception& e) { + } catch (const std::exception& e) { rpc_result = JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); } @@ -563,7 +563,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms try { return pcmd->actor(params, false); - } catch (std::exception& e) { + } catch (const std::exception& e) { throw JSONRPCError(RPC_MISC_ERROR, e.what()); } diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index 5f1aaa2a4d..ab8a251fd1 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(!ret, "Sending to stealth address have to be failed on 0 balance wallet"); @@ -370,7 +370,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success with reservebalance wallet"); @@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success on enough balance wallet"); diff --git a/src/txdb.cpp b/src/txdb.cpp index d15c36d975..aeef049553 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -151,7 +151,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats& stats) const ss << VARINT(0); } pcursor->Next(); - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } @@ -310,7 +310,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() } else { break; // if shutdown requested or finished loading block index } - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } diff --git a/src/util.cpp b/src/util.cpp index 1af83c0072..dc621bc85c 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -416,7 +416,7 @@ std::string HelpMessageOpt(const std::string &option, const std::string &message std::string("\n\n"); } -static std::string FormatException(std::exception* pex, const char* pszThread) +static std::string FormatException(const std::exception* pex, const char* pszThread) { #ifdef WIN32 char pszModule[MAX_PATH] = ""; @@ -432,7 +432,7 @@ static std::string FormatException(std::exception* pex, const char* pszThread) "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); } -void PrintExceptionContinue(std::exception* pex, const char* pszThread) +void PrintExceptionContinue(const std::exception* pex, const char* pszThread) { std::string message = FormatException(pex, pszThread); LogPrintf("\n\n************************\n%s\n", message); @@ -596,7 +596,7 @@ bool TryCreateDirectory(const boost::filesystem::path& p) { try { return boost::filesystem::create_directory(p); - } catch (boost::filesystem::filesystem_error&) { + } catch (const boost::filesystem::filesystem_error&) { if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p)) throw; } diff --git a/src/util.h b/src/util.h index 73b96aac51..9c5314df22 100644 --- a/src/util.h +++ b/src/util.h @@ -81,7 +81,7 @@ template std::string FormatStringFromLogArgs(const char *fmt, std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ try { \ _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ - } catch (std::runtime_error& e) { \ + } catch (const std::runtime_error& e) { \ _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ } \ return LogPrintStr(_log_msg_); \ @@ -93,7 +93,7 @@ template std::string FormatStringFromLogArgs(const char *fmt, std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ try { \ _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ - } catch (std::runtime_error& e) { \ + } catch (const std::runtime_error& e) { \ _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ } \ LogPrintStr(std::string("ERROR: ") + _log_msg_ + "\n"); \ @@ -117,7 +117,7 @@ static inline bool error(const char* format) return false; } -void PrintExceptionContinue(std::exception* pex, const char* pszThread); +void PrintExceptionContinue(const std::exception* pex, const char* pszThread); void ParseParameters(int argc, const char* const argv[]); void FileCommit(FILE* fileout); bool TruncateFile(FILE* file, unsigned int length); @@ -227,10 +227,10 @@ void TraceThread(const char* name, Callable func) LogPrintf("%s thread start\n", name); func(); LogPrintf("%s thread exit\n", name); - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { LogPrintf("%s thread interrupt\n", name); throw; - } catch (std::exception& e) { + } catch (const std::exception& e) { PrintExceptionContinue(&e, name); throw; } catch (...) { diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 772944806e..d157897382 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(!ret, "Sending to stealth address have to be failed on 0 balance wallet"); @@ -370,7 +370,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success with reservebalance wallet"); @@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(test_StealthSend) printf("Balance = %f, ReserveBalance = %f\n", pwalletMain->GetBalance() * 1.0f / COIN, nReserveBalance * 1.0f / COIN); try { ret = pwalletMain->SendToStealthAddress(stealthAddr, nAmount, wtx); - } catch (std::exception& e) { + } catch (const std::exception& e) { ret = false; } BOOST_CHECK_MESSAGE(ret, "Sending to stealth address have to be success on enough balance wallet"); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 31b62ea9fd..24801e3c64 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1139,7 +1139,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl if (!IsLocked()) { try { CWalletDB(strWalletFile).WriteScannedBlockHeight(mapBlockIndex[pblock->GetHash()]->nHeight); - } catch (std::exception& e) { + } catch (const std::exception& e) { LogPrintf("Cannot open data base or wallet is locked\n"); } } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5b50804ab9..6237a2e761 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -871,7 +871,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) LogPrintf("%s\n", strErr); } pcursor->close(); - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { throw; } catch (...) { result = DB_CORRUPT; @@ -964,7 +964,7 @@ DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& vTxHash, vec } } pcursor->close(); - } catch (boost::thread_interrupted&) { + } catch (const boost::thread_interrupted&) { throw; } catch (...) { result = DB_CORRUPT; From 65773128b7444c51403fdd4918e3d8a55632ba55 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 24 Mar 2020 10:11:39 -0500 Subject: [PATCH 0292/1888] [Refactor] Replace tabs with spaces --- src/activemasternode.cpp | 32 +- src/blocksignature.cpp | 6 +- src/bloom.cpp | 6 +- src/chain.h | 6 +- src/chainparams.h | 2 +- src/crypto/sph_blake.h | 28 +- src/crypto/sph_bmw.h | 26 +- src/crypto/sph_cubehash.h | 14 +- src/crypto/sph_echo.h | 38 +- src/crypto/sph_groestl.h | 40 +- src/crypto/sph_jh.h | 24 +- src/crypto/sph_keccak.h | 20 +- src/crypto/sph_luffa.h | 30 +- src/crypto/sph_shavite.h | 28 +- src/crypto/sph_simd.h | 24 +- src/crypto/sph_skein.h | 16 +- src/crypto/sph_types.h | 612 +++++++++--------- src/init.cpp | 14 +- src/kernel.cpp | 2 +- src/main.cpp | 62 +- src/masternode-budget.cpp | 4 +- src/masternode-payments.cpp | 104 +-- src/masternode-payments.h | 2 +- src/masternode.cpp | 4 +- src/masternodeman.cpp | 22 +- src/miner.cpp | 228 +++---- src/net.cpp | 2 +- src/obfuscation.cpp | 28 +- src/primitives/block.cpp | 4 +- src/primitives/block.h | 4 +- src/primitives/transaction.h | 100 +-- src/protocol.cpp | 2 +- src/protocol.h | 6 +- src/qt/2faqrdialog.cpp | 2 +- src/qt/bitcoingui.cpp | 6 +- src/qt/encryptdialog.cpp | 2 +- src/qt/encryptdialog.h | 8 +- src/qt/historypage.cpp | 72 +-- src/qt/optionspage.cpp | 136 ++-- src/qt/overviewpage.cpp | 6 +- src/qt/revealtxdialog.cpp | 8 +- src/qt/transactionrecord.cpp | 4 +- src/qt/txentry.cpp | 2 +- src/qt/walletmodel.cpp | 130 ++-- src/qt/walletview.cpp | 2 +- src/rpc/blockchain.cpp | 8 +- src/rpc/client.cpp | 4 +- src/rpc/masternode.cpp | 2 +- src/rpc/mining.cpp | 76 +-- src/rpc/rawtransaction.cpp | 6 +- src/rpc/server.cpp | 4 +- src/script/interpreter.cpp | 2 +- src/script/sign.cpp | 2 +- src/secp256k1-mw/include/secp256k1_2.h | 4 +- .../include/secp256k1_commitment.h | 12 +- .../bulletproofs/circuit_compress_impl.h | 2 +- .../src/modules/bulletproofs/tests_impl.h | 154 ++--- .../src/modules/commitment/main_impl.h | 92 +-- .../src/modules/surjection/main_impl.h | 2 +- src/streams.h | 20 +- src/txdb.h | 2 +- src/txmempool.cpp | 10 +- src/univalue/lib/univalue_escapes.h | 512 +++++++-------- src/univalue/test/object.cpp | 12 +- src/util.cpp | 2 +- src/wallet/rpcwallet.cpp | 20 +- src/wallet/wallet.cpp | 92 +-- src/wallet/wallet.h | 8 +- src/wallet/walletdb.cpp | 12 +- 69 files changed, 1489 insertions(+), 1489 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 7b2a6a046b..f70230e1f5 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -303,10 +303,10 @@ bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCol ser << ss << masterNodeSignatureTime << pubKeyCollateralAddress << pubKeyMasternode << PROTOCOL_VERSION; /*uint256 h = Hash(BEGIN(ss), END(ss), - BEGIN(masterNodeSignatureTime), END(masterNodeSignatureTime), - pubKeyCollateralAddress.begin(), pubKeyCollateralAddress.end(), - pubKeyMasternode.begin(), pubKeyMasternode.end(), - BEGIN(PROTOCOL_VERSION), END(PROTOCOL_VERSION));*/ + BEGIN(masterNodeSignatureTime), END(masterNodeSignatureTime), + pubKeyCollateralAddress.begin(), pubKeyCollateralAddress.end(), + pubKeyMasternode.begin(), pubKeyMasternode.end(), + BEGIN(PROTOCOL_VERSION), END(PROTOCOL_VERSION));*/ std::string strMessage = HexStr(ser.begin(), ser.end()); if (!obfuScationSigner.SignMessage(strMessage, retErrorMessage, vchMasterNodeSignature, keyCollateralAddress)) { errorMessage = "dsee sign message failed: " + retErrorMessage; @@ -417,19 +417,19 @@ bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubke pwalletMain->ComputeStealthPublicAddress("masteraccount", msa); std::copy(msa.begin(), msa.end(), std::back_inserter(vin.masternodeStealthAddress)); if (!pwalletMain->generateKeyImage(out.tx->vout[out.i].scriptPubKey, vin.keyImage)) { - LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to generate key image\n"); - return false; + LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to generate key image\n"); + return false; } if (!pwalletMain->MakeShnorrSignatureTxIn(vin, GetTxInSignatureHash(vin))) { - LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to make Shnorr signature\n"); - return false; + LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to make Shnorr signature\n"); + return false; } //test verification masternode broadcast if (!VerifyShnorrKeyImageTxIn(vin, GetTxInSignatureHash(vin))) { - LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to verify Shnorr signature\n"); - return false; + LogPrintf("CActiveMasternode::GetMasterNodeVin - Failed to verify Shnorr signature\n"); + return false; } //Test the commitment and decoded value, if everything goes right, other nodes can verify it as well @@ -437,8 +437,8 @@ bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubke CTransaction prev; uint256 bh; if (!GetTransaction(prevout.hash, prev, bh, true)) { - LogPrint("masternode","dsee - failed to read transaction hash %s\n", vin.prevout.hash.ToString()); - return false; + LogPrint("masternode","dsee - failed to read transaction hash %s\n", vin.prevout.hash.ToString()); + return false; } CTxOut txout = prev.vout[prevout.n]; @@ -450,13 +450,13 @@ bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubke std::vector commitment; CWallet::CreateCommitment(mask.begin(), amount, commitment); if (commitment != txout.commitment) { - LogPrintf("dsee - decoded masternode collateralization not match %s\n", vin.prevout.hash.ToString()); - return false; + LogPrintf("dsee - decoded masternode collateralization not match %s\n", vin.prevout.hash.ToString()); + return false; } if (amount != 1000000 * COIN) { - LogPrintf("dsee - masternode collateralization not equal to 1M %s\n", vin.prevout.hash.ToString()); - return false; + LogPrintf("dsee - masternode collateralization not equal to 1M %s\n", vin.prevout.hash.ToString()); + return false; } return true; diff --git a/src/blocksignature.cpp b/src/blocksignature.cpp index 6ca133c2f9..7b3603b8a5 100644 --- a/src/blocksignature.cpp +++ b/src/blocksignature.cpp @@ -70,10 +70,10 @@ bool CheckBlockSignature(const CBlock& block) std::vector vSolutions; const CTxOut& txout = block.vtx[1].vout[1]; if (!Solver(txout.scriptPubKey, whichType, vSolutions)) - return false; + return false; if (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) { - valtype& vchPubKey = vSolutions[0]; - pubkey = CPubKey(vchPubKey); + valtype& vchPubKey = vSolutions[0]; + pubkey = CPubKey(vchPubKey); } if (!pubkey.IsValid()) diff --git a/src/bloom.cpp b/src/bloom.cpp index 06ab6c513f..e8b48278af 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -24,14 +24,14 @@ CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int * - nElements * log(fp rate) / ln(2)^2 * We ignore filter parameters which will create a bloom filter larger than the protocol limits */ - vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), + vData(min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8), /** * The ideal number of hash functions is filter size * ln(2) / number of elements * Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits * See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas */ - isFull(false), - isEmpty(false), + isFull(false), + isEmpty(false), nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)), nTweak(nTweakIn), nFlags(nFlagsIn) diff --git a/src/chain.h b/src/chain.h index 7909b58e3e..e8c7f1062b 100644 --- a/src/chain.h +++ b/src/chain.h @@ -441,9 +441,9 @@ class CDiskBlockIndex : public CBlockIndex { hashPrev = (pprev ? pprev->GetBlockHash() : uint256(0)); if (IsProofOfAudit()) { - hashPoAMerkleRoot = pindex->hashPoAMerkleRoot; - minedHash = pindex->minedHash; - hashPrevPoABlock = pindex->hashPrevPoABlock; + hashPoAMerkleRoot = pindex->hashPoAMerkleRoot; + minedHash = pindex->minedHash; + hashPrevPoABlock = pindex->hashPrevPoABlock; } } diff --git a/src/chainparams.h b/src/chainparams.h index befe3e5a9a..2f95a04a43 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -149,7 +149,7 @@ class CChainParams int nPoolMaxTransactions; std::string strObfuscationPoolDummyAddress; int64_t nStartMasternodePayments; - int64_t nBudget_Fee_Confirmations; + int64_t nBudget_Fee_Confirmations; int nBlockEnforceSerialRange; int nBlockRecalculateAccumulators; int nBlockFirstFraudulent; diff --git a/src/crypto/sph_blake.h b/src/crypto/sph_blake.h index d8d794399d..bad7a5aa4b 100644 --- a/src/crypto/sph_blake.h +++ b/src/crypto/sph_blake.h @@ -80,11 +80,11 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 H[8]; - sph_u32 S[4]; - sph_u32 T0, T1; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[8]; + sph_u32 S[4]; + sph_u32 T0, T1; #endif } sph_blake_small_context; @@ -114,11 +114,11 @@ typedef sph_blake_small_context sph_blake256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u64 H[8]; - sph_u64 S[4]; - sph_u64 T0, T1; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[8]; + sph_u64 S[4]; + sph_u64 T0, T1; #endif } sph_blake_big_context; @@ -179,7 +179,7 @@ void sph_blake224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BLAKE-256 context. This process performs no memory allocation. @@ -224,7 +224,7 @@ void sph_blake256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #if SPH_64 @@ -271,7 +271,7 @@ void sph_blake384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BLAKE-512 context. This process performs no memory allocation. @@ -316,7 +316,7 @@ void sph_blake512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_blake512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_bmw.h b/src/crypto/sph_bmw.h index d386b0c140..aeae2fb4fd 100644 --- a/src/crypto/sph_bmw.h +++ b/src/crypto/sph_bmw.h @@ -79,13 +79,13 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 H[16]; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[16]; #if SPH_64 - sph_u64 bit_count; + sph_u64 bit_count; #else - sph_u32 bit_count_high, bit_count_low; + sph_u32 bit_count_high, bit_count_low; #endif #endif } sph_bmw_small_context; @@ -116,10 +116,10 @@ typedef sph_bmw_small_context sph_bmw256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u64 H[16]; - sph_u64 bit_count; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[16]; + sph_u64 bit_count; #endif } sph_bmw_big_context; @@ -180,7 +180,7 @@ void sph_bmw224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BMW-256 context. This process performs no memory allocation. @@ -225,7 +225,7 @@ void sph_bmw256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #if SPH_64 @@ -272,7 +272,7 @@ void sph_bmw384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a BMW-512 context. This process performs no memory allocation. @@ -317,7 +317,7 @@ void sph_bmw512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_bmw512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_cubehash.h b/src/crypto/sph_cubehash.h index 487a1946ad..f4f502cb50 100644 --- a/src/crypto/sph_cubehash.h +++ b/src/crypto/sph_cubehash.h @@ -76,9 +76,9 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[32]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; #endif } sph_cubehash_context; @@ -146,7 +146,7 @@ void sph_cubehash224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-256 context. This process performs no memory @@ -192,7 +192,7 @@ void sph_cubehash256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-384 context. This process performs no memory @@ -238,7 +238,7 @@ void sph_cubehash384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a CubeHash-512 context. This process performs no memory @@ -284,7 +284,7 @@ void sph_cubehash512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_cubehash512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_echo.h b/src/crypto/sph_echo.h index 1ae1e3dd62..7f685c9849 100644 --- a/src/crypto/sph_echo.h +++ b/src/crypto/sph_echo.h @@ -76,15 +76,15 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[192]; /* first field, for alignment */ - size_t ptr; - union { - sph_u32 Vs[4][4]; + unsigned char buf[192]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[4][4]; #if SPH_64 - sph_u64 Vb[4][2]; + sph_u64 Vb[4][2]; #endif - } u; - sph_u32 C0, C1, C2, C3; + } u; + sph_u32 C0, C1, C2, C3; #endif } sph_echo_small_context; @@ -101,15 +101,15 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - union { - sph_u32 Vs[8][4]; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[8][4]; #if SPH_64 - sph_u64 Vb[8][2]; + sph_u64 Vb[8][2]; #endif - } u; - sph_u32 C0, C1, C2, C3; + } u; + sph_u32 C0, C1, C2, C3; #endif } sph_echo_big_context; @@ -176,7 +176,7 @@ void sph_echo224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-256 context. This process performs no memory allocation. @@ -221,7 +221,7 @@ void sph_echo256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-384 context. This process performs no memory allocation. @@ -266,7 +266,7 @@ void sph_echo384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an ECHO-512 context. This process performs no memory allocation. @@ -311,8 +311,8 @@ void sph_echo512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_echo512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_groestl.h b/src/crypto/sph_groestl.h index 495f05e211..bb638e9bdb 100644 --- a/src/crypto/sph_groestl.h +++ b/src/crypto/sph_groestl.h @@ -74,18 +74,18 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[8]; + sph_u64 wide[8]; #endif - sph_u32 narrow[16]; - } state; + sph_u32 narrow[16]; + } state; #if SPH_64 - sph_u64 count; + sph_u64 count; #else - sph_u32 count_high, count_low; + sph_u32 count_high, count_low; #endif #endif } sph_groestl_small_context; @@ -114,18 +114,18 @@ typedef sph_groestl_small_context sph_groestl256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[16]; + sph_u64 wide[16]; #endif - sph_u32 narrow[32]; - } state; + sph_u32 narrow[32]; + } state; #if SPH_64 - sph_u64 count; + sph_u64 count; #else - sph_u32 count_high, count_low; + sph_u32 count_high, count_low; #endif #endif } sph_groestl_big_context; @@ -185,7 +185,7 @@ void sph_groestl224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-256 context. This process performs no memory allocation. @@ -230,7 +230,7 @@ void sph_groestl256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-384 context. This process performs no memory allocation. @@ -275,7 +275,7 @@ void sph_groestl384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Groestl-512 context. This process performs no memory allocation. @@ -320,7 +320,7 @@ void sph_groestl512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_groestl512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_jh.h b/src/crypto/sph_jh.h index 82fae58df8..c8a9fabc05 100644 --- a/src/crypto/sph_jh.h +++ b/src/crypto/sph_jh.h @@ -75,18 +75,18 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - union { + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { #if SPH_64 - sph_u64 wide[16]; + sph_u64 wide[16]; #endif - sph_u32 narrow[32]; - } H; + sph_u32 narrow[32]; + } H; #if SPH_64 - sph_u64 block_count; + sph_u64 block_count; #else - sph_u32 block_count_high, block_count_low; + sph_u32 block_count_high, block_count_low; #endif #endif } sph_jh_context; @@ -154,7 +154,7 @@ void sph_jh224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-256 context. This process performs no memory allocation. @@ -199,7 +199,7 @@ void sph_jh256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-384 context. This process performs no memory allocation. @@ -244,7 +244,7 @@ void sph_jh384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a JH-512 context. This process performs no memory allocation. @@ -289,7 +289,7 @@ void sph_jh512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_jh512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_keccak.h b/src/crypto/sph_keccak.h index bdafdb88db..233154209b 100644 --- a/src/crypto/sph_keccak.h +++ b/src/crypto/sph_keccak.h @@ -75,14 +75,14 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[144]; /* first field, for alignment */ - size_t ptr, lim; - union { + unsigned char buf[144]; /* first field, for alignment */ + size_t ptr, lim; + union { #if SPH_64 - sph_u64 wide[25]; + sph_u64 wide[25]; #endif - sph_u32 narrow[50]; - } u; + sph_u32 narrow[50]; + } u; #endif } sph_keccak_context; @@ -149,7 +149,7 @@ void sph_keccak224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-256 context. This process performs no memory allocation. @@ -194,7 +194,7 @@ void sph_keccak256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-384 context. This process performs no memory allocation. @@ -239,7 +239,7 @@ void sph_keccak384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Keccak-512 context. This process performs no memory allocation. @@ -284,7 +284,7 @@ void sph_keccak512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_keccak512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } diff --git a/src/crypto/sph_luffa.h b/src/crypto/sph_luffa.h index a32fd7b16b..fd96b7ff5b 100644 --- a/src/crypto/sph_luffa.h +++ b/src/crypto/sph_luffa.h @@ -75,9 +75,9 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[3][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[3][8]; #endif } sph_luffa224_context; @@ -92,9 +92,9 @@ typedef sph_luffa224_context sph_luffa256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[4][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[4][8]; #endif } sph_luffa384_context; @@ -103,9 +103,9 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[32]; /* first field, for alignment */ - size_t ptr; - sph_u32 V[5][8]; + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[5][8]; #endif } sph_luffa512_context; @@ -152,7 +152,7 @@ void sph_luffa224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-256 context. This process performs no memory allocation. @@ -197,7 +197,7 @@ void sph_luffa256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-384 context. This process performs no memory allocation. @@ -242,7 +242,7 @@ void sph_luffa384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Luffa-512 context. This process performs no memory allocation. @@ -287,10 +287,10 @@ void sph_luffa512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_luffa512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } #endif - + #endif diff --git a/src/crypto/sph_shavite.h b/src/crypto/sph_shavite.h index 0957e42a9f..0ac02d57ec 100644 --- a/src/crypto/sph_shavite.h +++ b/src/crypto/sph_shavite.h @@ -77,10 +77,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 h[8]; - sph_u32 count0, count1; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[8]; + sph_u32 count0, count1; #endif } sph_shavite_small_context; @@ -108,10 +108,10 @@ typedef sph_shavite_small_context sph_shavite256_context; */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u32 h[16]; - sph_u32 count0, count1, count2, count3; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[16]; + sph_u32 count0, count1, count2, count3; #endif } sph_shavite_big_context; @@ -170,7 +170,7 @@ void sph_shavite224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-256 context. This process performs no memory allocation. @@ -215,7 +215,7 @@ void sph_shavite256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-384 context. This process performs no memory allocation. @@ -260,7 +260,7 @@ void sph_shavite384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a SHAvite-512 context. This process performs no memory allocation. @@ -305,10 +305,10 @@ void sph_shavite512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_shavite512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); - + void *cc, unsigned ub, unsigned n, void *dst); + #ifdef __cplusplus } #endif - + #endif diff --git a/src/crypto/sph_simd.h b/src/crypto/sph_simd.h index 92ee1e7275..c674db2ce8 100644 --- a/src/crypto/sph_simd.h +++ b/src/crypto/sph_simd.h @@ -76,10 +76,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[16]; - sph_u32 count_low, count_high; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[16]; + sph_u32 count_low, count_high; #endif } sph_simd_small_context; @@ -96,10 +96,10 @@ typedef struct { */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[128]; /* first field, for alignment */ - size_t ptr; - sph_u32 state[32]; - sph_u32 count_low, count_high; + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; + sph_u32 count_low, count_high; #endif } sph_simd_big_context; @@ -166,7 +166,7 @@ void sph_simd224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-256 context. This process performs no memory allocation. @@ -211,7 +211,7 @@ void sph_simd256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-384 context. This process performs no memory allocation. @@ -256,7 +256,7 @@ void sph_simd384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize an SIMD-512 context. This process performs no memory allocation. @@ -301,7 +301,7 @@ void sph_simd512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_simd512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #ifdef __cplusplus } #endif diff --git a/src/crypto/sph_skein.h b/src/crypto/sph_skein.h index bddbc86fa5..924ba7413c 100644 --- a/src/crypto/sph_skein.h +++ b/src/crypto/sph_skein.h @@ -82,10 +82,10 @@ extern "C"{ */ typedef struct { #ifndef DOXYGEN_IGNORE - unsigned char buf[64]; /* first field, for alignment */ - size_t ptr; - sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; - sph_u64 bcount; + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; + sph_u64 bcount; #endif } sph_skein_big_context; @@ -152,7 +152,7 @@ void sph_skein224_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein224_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-256 context. This process performs no memory allocation. @@ -197,7 +197,7 @@ void sph_skein256_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein256_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-384 context. This process performs no memory allocation. @@ -242,7 +242,7 @@ void sph_skein384_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein384_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); /** * Initialize a Skein-512 context. This process performs no memory allocation. @@ -287,7 +287,7 @@ void sph_skein512_close(void *cc, void *dst); * @param dst the destination buffer */ void sph_skein512_addbits_and_close( - void *cc, unsigned ub, unsigned n, void *dst); + void *cc, unsigned ub, unsigned n, void *dst); #endif diff --git a/src/crypto/sph_types.h b/src/crypto/sph_types.h index 7295b0b370..cef79bde12 100644 --- a/src/crypto/sph_types.h +++ b/src/crypto/sph_types.h @@ -1028,7 +1028,7 @@ typedef long long sph_s64; * 64-bit Sparc architecture (implies v9). */ #elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ - || defined __sparcv9 + || defined __sparcv9 #define SPH_DETECT_BIG_ENDIAN 1 #define SPH_DETECT_UPTR sph_u64 @@ -1041,7 +1041,7 @@ typedef long long sph_s64; * 32-bit Sparc. */ #elif (defined __sparc__ || defined __sparc) \ - && !(defined __sparcv9 || defined __arch64__) + && !(defined __sparcv9 || defined __arch64__) #define SPH_DETECT_BIG_ENDIAN 1 #define SPH_DETECT_UPTR sph_u32 @@ -1075,7 +1075,7 @@ typedef long long sph_s64; * PowerPC. */ #elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ - || defined _ARCH_PPC + || defined _ARCH_PPC /* * Note: we do not declare cross-endian access to be "fast": even if @@ -1101,7 +1101,7 @@ typedef long long sph_s64; * Itanium, 64-bit. */ #elif defined __ia64 || defined __ia64__ \ - || defined __itanium__ || defined _M_IA64 + || defined __itanium__ || defined _M_IA64 #if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN #define SPH_DETECT_BIG_ENDIAN 1 @@ -1187,8 +1187,8 @@ typedef long long sph_s64; static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; } #if SPH_64 @@ -1196,8 +1196,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); } #endif @@ -1212,8 +1212,8 @@ sph_bswap64(sph_u64 x) static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; } #if SPH_64 @@ -1221,8 +1221,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); - return x; + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; } #endif @@ -1238,11 +1238,11 @@ sph_bswap64(sph_u64 x) static __inline sph_u32 __declspec(naked) __fastcall sph_bswap32(sph_u32 x) { - __asm { - bswap ecx - mov eax,ecx - ret - } + __asm { + bswap ecx + mov eax,ecx + ret + } } #if SPH_64 @@ -1250,8 +1250,8 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - return ((sph_u64)sph_bswap32((sph_u32)x) << 32) - | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); } #endif @@ -1265,10 +1265,10 @@ sph_bswap64(sph_u64 x) static SPH_INLINE sph_u32 sph_bswap32(sph_u32 x) { - x = SPH_T32((x << 16) | (x >> 16)); - x = ((x & SPH_C32(0xFF00FF00)) >> 8) - | ((x & SPH_C32(0x00FF00FF)) << 8); - return x; + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; } #if SPH_64 @@ -1282,12 +1282,12 @@ sph_bswap32(sph_u32 x) static SPH_INLINE sph_u64 sph_bswap64(sph_u64 x) { - x = SPH_T64((x << 32) | (x >> 32)); - x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) - | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); - x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) - | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); - return x; + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; } #endif @@ -1313,48 +1313,48 @@ sph_bswap64(sph_u64 x) */ #define SPH_SPARCV9_SET_ASI \ - sph_u32 sph_sparcv9_asi; \ - __asm__ __volatile__ ( \ - "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); #define SPH_SPARCV9_RESET_ASI \ - __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); #define SPH_SPARCV9_DEC32LE(base, idx) ({ \ - sph_u32 sph_sparcv9_tmp; \ - __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ - : "=r" (sph_sparcv9_tmp) : "r" (base)); \ - sph_sparcv9_tmp; \ - }) + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) #endif static SPH_INLINE void sph_enc16be(void *dst, unsigned val) { - ((unsigned char *)dst)[0] = (val >> 8); - ((unsigned char *)dst)[1] = val; + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; } static SPH_INLINE unsigned sph_dec16be(const void *src) { - return ((unsigned)(((const unsigned char *)src)[0]) << 8) - | (unsigned)(((const unsigned char *)src)[1]); + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); } static SPH_INLINE void sph_enc16le(void *dst, unsigned val) { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = val >> 8; + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; } static SPH_INLINE unsigned sph_dec16le(const void *src) { - return (unsigned)(((const unsigned char *)src)[0]) - | ((unsigned)(((const unsigned char *)src)[1]) << 8); + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); } /** @@ -1369,27 +1369,27 @@ sph_enc32be(void *dst, sph_u32 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - if (((SPH_UPTR)dst & 3) == 0) { + if (((SPH_UPTR)dst & 3) == 0) { #if SPH_LITTLE_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; - } + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } #endif #else - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; #endif } @@ -1404,14 +1404,14 @@ static SPH_INLINE void sph_enc32be_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); + *(sph_u32 *)dst = sph_bswap32(val); #elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - ((unsigned char *)dst)[0] = (val >> 24); - ((unsigned char *)dst)[1] = (val >> 16); - ((unsigned char *)dst)[2] = (val >> 8); - ((unsigned char *)dst)[3] = val; + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; #endif } @@ -1427,29 +1427,29 @@ sph_dec32be(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif #else - if (((SPH_UPTR)src & 3) == 0) { + if (((SPH_UPTR)src & 3) == 0) { #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif - } else { - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); - } + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } #endif #else - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); #endif } @@ -1464,14 +1464,14 @@ static SPH_INLINE sph_u32 sph_dec32be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #elif SPH_BIG_ENDIAN - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #else - return ((sph_u32)(((const unsigned char *)src)[0]) << 24) - | ((sph_u32)(((const unsigned char *)src)[1]) << 16) - | ((sph_u32)(((const unsigned char *)src)[2]) << 8) - | (sph_u32)(((const unsigned char *)src)[3]); + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); #endif } @@ -1487,27 +1487,27 @@ sph_enc32le(void *dst, sph_u32 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #else - if (((SPH_UPTR)dst & 3) == 0) { + if (((SPH_UPTR)dst & 3) == 0) { #if SPH_BIG_ENDIAN - val = sph_bswap32(val); + val = sph_bswap32(val); #endif - *(sph_u32 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - } + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } #endif #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); #endif } @@ -1522,14 +1522,14 @@ static SPH_INLINE void sph_enc32le_aligned(void *dst, sph_u32 val) { #if SPH_LITTLE_ENDIAN - *(sph_u32 *)dst = val; + *(sph_u32 *)dst = val; #elif SPH_BIG_ENDIAN - *(sph_u32 *)dst = sph_bswap32(val); + *(sph_u32 *)dst = sph_bswap32(val); #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); #endif } @@ -1545,25 +1545,25 @@ sph_dec32le(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif #else - if (((SPH_UPTR)src & 3) == 0) { + if (((SPH_UPTR)src & 3) == 0) { #if SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; - - /* - * "__volatile__" is needed here because without it, - * gcc-3.4.3 miscompiles the code and performs the - * access before the test on the address, thus triggering - * a bus error... - */ - __asm__ __volatile__ ( - "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * On PowerPC, this turns out not to be worth the effort: the inline * assembly makes GCC optimizer uncomfortable, which tends to nullify @@ -1577,30 +1577,30 @@ sph_dec32le(const void *src) * functions, the generic code appears to be efficient enough already. * #elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ( - "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #endif #else - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #endif - } else { - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); - } + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } #endif #else - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); #endif } @@ -1615,30 +1615,30 @@ static SPH_INLINE sph_u32 sph_dec32le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return *(const sph_u32 *)src; + return *(const sph_u32 *)src; #elif SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM - sph_u32 tmp; + sph_u32 tmp; - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap32(*(const sph_u32 *)src); + return sph_bswap32(*(const sph_u32 *)src); #endif #else - return (sph_u32)(((const unsigned char *)src)[0]) - | ((sph_u32)(((const unsigned char *)src)[1]) << 8) - | ((sph_u32)(((const unsigned char *)src)[2]) << 16) - | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); #endif } @@ -1656,35 +1656,35 @@ sph_enc64be(void *dst, sph_u64 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); + val = sph_bswap64(val); #endif - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - if (((SPH_UPTR)dst & 7) == 0) { + if (((SPH_UPTR)dst & 7) == 0) { #if SPH_LITTLE_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; - } + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } #endif #else - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; #endif } @@ -1699,18 +1699,18 @@ static SPH_INLINE void sph_enc64be_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); + *(sph_u64 *)dst = sph_bswap64(val); #elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - ((unsigned char *)dst)[0] = (val >> 56); - ((unsigned char *)dst)[1] = (val >> 48); - ((unsigned char *)dst)[2] = (val >> 40); - ((unsigned char *)dst)[3] = (val >> 32); - ((unsigned char *)dst)[4] = (val >> 24); - ((unsigned char *)dst)[5] = (val >> 16); - ((unsigned char *)dst)[6] = (val >> 8); - ((unsigned char *)dst)[7] = val; + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; #endif } @@ -1726,37 +1726,37 @@ sph_dec64be(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #endif #else - if (((SPH_UPTR)src & 7) == 0) { + if (((SPH_UPTR)src & 7) == 0) { #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; -#endif - } else { - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); - } + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } #endif #else - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); #endif } @@ -1771,18 +1771,18 @@ static SPH_INLINE sph_u64 sph_dec64be_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #elif SPH_BIG_ENDIAN - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #else - return ((sph_u64)(((const unsigned char *)src)[0]) << 56) - | ((sph_u64)(((const unsigned char *)src)[1]) << 48) - | ((sph_u64)(((const unsigned char *)src)[2]) << 40) - | ((sph_u64)(((const unsigned char *)src)[3]) << 32) - | ((sph_u64)(((const unsigned char *)src)[4]) << 24) - | ((sph_u64)(((const unsigned char *)src)[5]) << 16) - | ((sph_u64)(((const unsigned char *)src)[6]) << 8) - | (sph_u64)(((const unsigned char *)src)[7]); + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); #endif } @@ -1798,35 +1798,35 @@ sph_enc64le(void *dst, sph_u64 val) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - val = sph_bswap64(val); + val = sph_bswap64(val); #endif - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #else - if (((SPH_UPTR)dst & 7) == 0) { + if (((SPH_UPTR)dst & 7) == 0) { #if SPH_BIG_ENDIAN - val = sph_bswap64(val); -#endif - *(sph_u64 *)dst = val; - } else { - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); - } + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } #endif #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); #endif } @@ -1841,18 +1841,18 @@ static SPH_INLINE void sph_enc64le_aligned(void *dst, sph_u64 val) { #if SPH_LITTLE_ENDIAN - *(sph_u64 *)dst = val; + *(sph_u64 *)dst = val; #elif SPH_BIG_ENDIAN - *(sph_u64 *)dst = sph_bswap64(val); + *(sph_u64 *)dst = sph_bswap64(val); #else - ((unsigned char *)dst)[0] = val; - ((unsigned char *)dst)[1] = (val >> 8); - ((unsigned char *)dst)[2] = (val >> 16); - ((unsigned char *)dst)[3] = (val >> 24); - ((unsigned char *)dst)[4] = (val >> 32); - ((unsigned char *)dst)[5] = (val >> 40); - ((unsigned char *)dst)[6] = (val >> 48); - ((unsigned char *)dst)[7] = (val >> 56); + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); #endif } @@ -1868,59 +1868,59 @@ sph_dec64le(const void *src) #if defined SPH_UPTR #if SPH_UNALIGNED #if SPH_BIG_ENDIAN - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #else - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #endif #else - if (((SPH_UPTR)src & 7) == 0) { + if (((SPH_UPTR)src & 7) == 0) { #if SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ( - "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned( - (const char *)src + 4) << 32); + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); #elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ( - "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #endif #else - return *(const sph_u64 *)src; -#endif - } else { - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); - } + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } #endif #else - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); #endif } @@ -1935,37 +1935,37 @@ static SPH_INLINE sph_u64 sph_dec64le_aligned(const void *src) { #if SPH_LITTLE_ENDIAN - return *(const sph_u64 *)src; + return *(const sph_u64 *)src; #elif SPH_BIG_ENDIAN #if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; /* * Not worth it generally. * #elif SPH_PPC32_GCC && !SPH_NO_ASM - return (sph_u64)sph_dec32le_aligned(src) - | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); #elif SPH_PPC64_GCC && !SPH_NO_ASM - sph_u64 tmp; + sph_u64 tmp; - __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); - return tmp; + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; */ #else - return sph_bswap64(*(const sph_u64 *)src); + return sph_bswap64(*(const sph_u64 *)src); #endif #else - return (sph_u64)(((const unsigned char *)src)[0]) - | ((sph_u64)(((const unsigned char *)src)[1]) << 8) - | ((sph_u64)(((const unsigned char *)src)[2]) << 16) - | ((sph_u64)(((const unsigned char *)src)[3]) << 24) - | ((sph_u64)(((const unsigned char *)src)[4]) << 32) - | ((sph_u64)(((const unsigned char *)src)[5]) << 40) - | ((sph_u64)(((const unsigned char *)src)[6]) << 48) - | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); #endif } diff --git a/src/init.cpp b/src/init.cpp index 393e1b4290..b1e3515c5a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1643,7 +1643,7 @@ bool AppInit2(bool isDaemon) LogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nWalletStartTime); RegisterValidationInterface(pwalletMain); - int height = -1; + int height = -1; CBlockIndex* pindexRescan = chainActive.Tip(); if (GetBoolArg("-rescan", false)) { pindexRescan = chainActive.Genesis(); @@ -1654,13 +1654,13 @@ bool AppInit2(bool isDaemon) pindexRescan = FindForkInGlobalIndex(chainActive, locator); } else { if (!walletdb.ReadScannedBlockHeight(height)) { - if (height > chainActive.Height()) { - pindexRescan = chainActive.Genesis(); - } else { - pindexRescan = chainActive[height]; - } + if (height > chainActive.Height()) { + pindexRescan = chainActive.Genesis(); + } else { + pindexRescan = chainActive[height]; + } } else - pindexRescan = chainActive.Genesis(); + pindexRescan = chainActive.Genesis(); } } if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { diff --git a/src/kernel.cpp b/src/kernel.cpp index c179354f46..4eff7b8e2e 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -386,7 +386,7 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake) return error("CheckProofOfStake() : INFO: read txPrev failed"); //verify signature and script if (!VerifyScript(txin.scriptSig, txPrev.vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&tx, 0))) { - return error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString().c_str()); + return error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString().c_str()); } CBlockIndex* pindex = NULL; BlockMap::iterator it = mapBlockIndex.find(hashBlock); diff --git a/src/main.cpp b/src/main.cpp index 0e5ad48f60..321d4aa9fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -242,20 +242,20 @@ double GetPriority(const CTransaction& tx, int nHeight) return 0.0; double dResult = 0.0; /*for (const CTxIn& txin: tx.vin) { - std::vector alldecoys = txin.decoys; - alldecoys.push_back(txin.prevout); - for (size_t j = 0; j < alldecoys.size(); j++) { - CTransaction prev; - uint256 bh; - if (!GetTransaction(alldecoys[j].hash, prev, bh, true)) { - return false; - } - - if (mapBlockIndex.count(bh) < 1) continue; - if (mapBlockIndex[bh]->nHeight < nHeight) { - dResult += 1000 * COIN * (nHeight - mapBlockIndex[bh]->nHeight); - } - } + std::vector alldecoys = txin.decoys; + alldecoys.push_back(txin.prevout); + for (size_t j = 0; j < alldecoys.size(); j++) { + CTransaction prev; + uint256 bh; + if (!GetTransaction(alldecoys[j].hash, prev, bh, true)) { + return false; + } + + if (mapBlockIndex.count(bh) < 1) continue; + if (mapBlockIndex[bh]->nHeight < nHeight) { + dResult += 1000 * COIN * (nHeight - mapBlockIndex[bh]->nHeight); + } + } }*/ return 1000000000 + tx.ComputePriority(dResult); } @@ -1590,15 +1590,15 @@ bool CheckHaveInputs(const CCoinsViewCache& view, const CTransaction& tx) //TODO-NOTE: 07/06/2019 Remove this condition as colateral will be cheated as a normal tx //UTXO with 1M DAPS can only be consumed in a transaction with that single UTXO /*if (decoysSize > 1 && prev.vout[alldecoys[j].n].nValue == 1000000 * COIN) { - return false; - } + return false; + } - if (prev.vout[alldecoys[j].n].nValue == 1000000 * COIN) { - if (!VerifyKeyImages(tx)) { - LogPrintf("Failed to verify correctness of key image of collateralization spend\n"); - return false; - } - }*/ + if (prev.vout[alldecoys[j].n].nValue == 1000000 * COIN) { + if (!VerifyKeyImages(tx)) { + LogPrintf("Failed to verify correctness of key image of collateralization spend\n"); + return false; + } + }*/ if (mapBlockIndex.count(bh) < 1) return false; if (prev.IsCoinStake() || prev.IsCoinAudit() || prev.IsCoinBase()) { @@ -1647,7 +1647,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa if (pfMissingInputs) *pfMissingInputs = false; - // Check transaction + // Check transaction if (!CheckTransaction(tx, false, true, state)) return state.DoS(100, error("%s : CheckTransaction failed", __func__), REJECT_INVALID, "bad-tx"); @@ -2207,9 +2207,9 @@ int64_t GetBlockValue(const CBlockIndex* ptip) //zero rewards when total supply reach 70B DAPS return 0; } - if (pForkTip->nHeight < Params().LAST_POW_BLOCK()) { - nSubsidy = 120000000 * COIN; - } else { + if (pForkTip->nHeight < Params().LAST_POW_BLOCK()) { + nSubsidy = 120000000 * COIN; + } else { nSubsidy = PoSBlockReward(); nSubsidy += TeamRewards(pForkTip); } @@ -4073,11 +4073,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo set keyimages; for(size_t i = 0; i < block.vtx.size(); i++) { for (const CTxIn& txin : block.vtx[i].vin) { - if (!txin.keyImage.IsValid()) continue; - if (keyimages.count(txin.keyImage)) { - return state.DoS(100, error("CheckBlock() : duplicate inputs"), - REJECT_INVALID, "bad-txns-inputs-duplicate"); - } + if (!txin.keyImage.IsValid()) continue; + if (keyimages.count(txin.keyImage)) { + return state.DoS(100, error("CheckBlock() : duplicate inputs"), + REJECT_INVALID, "bad-txns-inputs-duplicate"); + } keyimages.insert(txin.keyImage); } } diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index eadc3465da..c306e45366 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -1706,8 +1706,8 @@ bool CBudgetVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) bool CBudgetVote::SignatureValid(bool fSignatureCheck) { std::string errorMessage; - HEX_DATA_STREAM << vin.prevout << nProposalHash << nVote << nTime; - std::string strMessage = HEX_STR(ser); + HEX_DATA_STREAM << vin.prevout << nProposalHash << nVote << nTime; + std::string strMessage = HEX_STR(ser); CMasternode* pmn = mnodeman.Find(vin); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index a3dfb4b181..07886f7b6d 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -261,15 +261,15 @@ bool CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe masternodePayments.GetBlockPayee(pindexPrev->nHeight + 1, payeeAddr); if (payeeAddr.size() != 0) { - bool isNotSpent = false; - std::vector mns = mnodeman.GetFullMasternodeVector(); - for (CMasternode& mn : mns) { - if (mn.vin.masternodeStealthAddress == payeeAddr && mn.IsEnabled()) { - isNotSpent = true; - break; - } - } - if (!isNotSpent) payeeAddr.clear(); + bool isNotSpent = false; + std::vector mns = mnodeman.GetFullMasternodeVector(); + for (CMasternode& mn : mns) { + if (mn.vin.masternodeStealthAddress == payeeAddr && mn.IsEnabled()) { + isNotSpent = true; + break; + } + } + if (!isNotSpent) payeeAddr.clear(); } if (payeeAddr.size() == 0) { //no masternode detected @@ -280,34 +280,34 @@ bool CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe } if (payeeAddr.size() != 0) { - bool isNotSpent = false; - std::vector mns = mnodeman.GetFullMasternodeVector(); + bool isNotSpent = false; + std::vector mns = mnodeman.GetFullMasternodeVector(); for (CMasternode& mn : mns) { - if (mn.vin.masternodeStealthAddress == payeeAddr && mn.IsEnabled()) { - isNotSpent = true; - break; - } - } - if (!isNotSpent) payeeAddr.clear(); + if (mn.vin.masternodeStealthAddress == payeeAddr && mn.IsEnabled()) { + isNotSpent = true; + break; + } + } + if (!isNotSpent) payeeAddr.clear(); } } /*std::string mnaddress = "41im5B4oiZ6WxMrQfXivfpZ5sMsPwbqhSSpDkvxxATq2QMvBa5nppNCYcESvLhGyEiZoEXyc8F5AJE3LymkrX24i17JicpNRAq8"; std::vector temp(mnaddress.begin(), mnaddress.end()); payeeAddr = temp;*/ if (payeeAddr.size() != 0) { - std::string mnsa(payeeAddr.begin(), payeeAddr.end()); - - //Parse stealth address - CPubKey pubViewKey, pubSpendKey, des; - bool hasPaymentID; - uint64_t paymentID; - if (!CWallet::DecodeStealthAddress(mnsa, pubViewKey, pubSpendKey, hasPaymentID, paymentID)) { - throw runtime_error("Stealth address mal-formatted"); - } - if (CWallet::ComputeStealthDestination(mnPaymentPrivTx, pubViewKey, pubSpendKey, des)) - payee = GetScriptForDestination(des); + std::string mnsa(payeeAddr.begin(), payeeAddr.end()); + + //Parse stealth address + CPubKey pubViewKey, pubSpendKey, des; + bool hasPaymentID; + uint64_t paymentID; + if (!CWallet::DecodeStealthAddress(mnsa, pubViewKey, pubSpendKey, hasPaymentID, paymentID)) { + throw runtime_error("Stealth address mal-formatted"); + } + if (CWallet::ComputeStealthDestination(mnPaymentPrivTx, pubViewKey, pubSpendKey, des)) + payee = GetScriptForDestination(des); } else { - hasPayment = false; + hasPayment = false; } CAmount posBlockReward = PoSBlockReward(); @@ -547,29 +547,29 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; for (CMasternodePayee& payee : vecPayments) { - bool found = false; - for (CTxOut out : txNew.vout) { - if (payee.masternodeStealthAddress == out.masternodeStealthAddress) { - if(out.nValue >= requiredMasternodePayment) - found = true; - else - LogPrint("masternode","Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); - } - } - - if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { - if (found) return true; - - std::string address2(payee.masternodeStealthAddress.begin(), payee.masternodeStealthAddress.end()); - - if (strPayeesPossible == "") { - strPayeesPossible += address2; - } else { - strPayeesPossible += "," + address2; - } - } - } - LogPrint("masternode","CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); + bool found = false; + for (CTxOut out : txNew.vout) { + if (payee.masternodeStealthAddress == out.masternodeStealthAddress) { + if(out.nValue >= requiredMasternodePayment) + found = true; + else + LogPrint("masternode","Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); + } + } + + if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { + if (found) return true; + + std::string address2(payee.masternodeStealthAddress.begin(), payee.masternodeStealthAddress.end()); + + if (strPayeesPossible == "") { + strPayeesPossible += address2; + } else { + strPayeesPossible += "," + address2; + } + } + } + LogPrint("masternode","CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); return false; } diff --git a/src/masternode-payments.h b/src/masternode-payments.h index dbe00ef24d..c101845fe9 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -214,7 +214,7 @@ class CMasternodePaymentWinner std::string ToString() { - std::string s(payee.begin(), payee.end()); + std::string s(payee.begin(), payee.end()); std::string ret = ""; ret += vinMasternode.ToString(); ret += ", " + std::to_string(nBlockHeight); diff --git a/src/masternode.cpp b/src/masternode.cpp index 6b815688cc..848123d0fa 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -741,8 +741,8 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) } bool CMasternodePing::VerifySignature(CPubKey& pubKeyMasternode, int &nDos) { - HEX_DATA_STREAM_PROTOCOL(PROTOCOL_VERSION) << vin.ToString() << blockHash.ToString() << sigTime; - std::string strMessage = HEX_STR(ser); + HEX_DATA_STREAM_PROTOCOL(PROTOCOL_VERSION) << vin.ToString() << blockHash.ToString() << sigTime; + std::string strMessage = HEX_STR(ser); std::string errorMessage = ""; if(!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)){ diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index adbc7d00a9..1e2c1a2c9a 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -875,7 +875,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData uint256 bh; if (!GetTransaction(prevout.hash, prev, bh, true)) { LogPrint("masternode","dsee - failed to read transaction hash %s\n", vin.prevout.hash.ToString()); - return; + return; } CTxOut out = prev.vout[prevout.n]; @@ -887,13 +887,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData std::vector commitment; CWallet::CreateCommitment(mask.begin(), amount, commitment); if (commitment != out.commitment) { - LogPrint("masternode","dsee - decoded masternode collateralization not match %s\n", vin.prevout.hash.ToString()); - return; + LogPrint("masternode","dsee - decoded masternode collateralization not match %s\n", vin.prevout.hash.ToString()); + return; } if (amount != 1000000 * COIN) { - LogPrint("masternode","dsee - masternode collateralization not equal to 1M %s\n", vin.prevout.hash.ToString()); - return; + LogPrint("masternode","dsee - masternode collateralization not equal to 1M %s\n", vin.prevout.hash.ToString()); + return; } std::string vchPubKey(pubkey.begin(), pubkey.end()); @@ -902,10 +902,10 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CDataStream ser(SER_NETWORK, protocolVersion); ser << ss << sigTime << pubkey << pubkey2 << protocolVersion; /*strMessage = Hash(BEGIN(ss), END(ss), - BEGIN(sigTime), END(sigTime), - pubkey.begin(), pubkey.end(), - pubkey2.begin(), pubkey2.end(), - BEGIN(protocolVersion), END(protocolVersion)).GetHex();*/ + BEGIN(sigTime), END(sigTime), + pubkey.begin(), pubkey.end(), + pubkey2.begin(), pubkey2.end(), + BEGIN(protocolVersion), END(protocolVersion)).GetHex();*/ strMessage = HexStr(ser.begin(), ser.end()); if (protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) { @@ -1066,7 +1066,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (!VerifyShnorrKeyImageTxIn(vin, GetTxInSignatureHash(vin))) { LogPrintf("dsee - Shnorr Signature rejected: %s\n", vin.prevout.hash.ToString()); - return; + return; } if (sigTime > GetAdjustedTime() + 60 * 60) { @@ -1092,7 +1092,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (pmn != NULL && pmn->protocolVersion >= masternodePayments.GetMinMasternodePaymentsProto()) { // take this only if it's newer if (sigTime - pmn->nLastDseep > MASTERNODE_MIN_MNP_SECONDS) { - std::string ss = pmn->addr.ToString(); + std::string ss = pmn->addr.ToString(); HEX_DATA_STREAM_PROTOCOL(PROTOCOL_VERSION) << pmn->addr.ToString() << sigTime << stop; std::string strMessage = HEX_STR(ser); diff --git a/src/miner.cpp b/src/miner.cpp index 826cc2b23c..7c0b1ebb81 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -98,15 +98,15 @@ void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) } uint32_t GetListOfPoSInfo(uint32_t currentHeight, std::vector& audits) { - //A PoA block should be mined only after at least 59 PoS blocks have not been audited - //Look for the previous PoA block - uint32_t nloopIdx = currentHeight; - while (nloopIdx >= Params().START_POA_BLOCK()) { - if (chainActive[nloopIdx]->GetBlockHeader().IsPoABlockByVersion()) { - break; - } - nloopIdx--; - } + //A PoA block should be mined only after at least 59 PoS blocks have not been audited + //Look for the previous PoA block + uint32_t nloopIdx = currentHeight; + while (nloopIdx >= Params().START_POA_BLOCK()) { + if (chainActive[nloopIdx]->GetBlockHeader().IsPoABlockByVersion()) { + break; + } + nloopIdx--; + } if (nloopIdx <= Params().START_POA_BLOCK()) { //this is the first PoA block ==> take all PoS blocks from LAST_POW_BLOCK up to currentHeight - 60 inclusive for (int i = Params().LAST_POW_BLOCK() + 1; i <= Params().LAST_POW_BLOCK() + 60; i++) { @@ -262,15 +262,15 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP bool fKeyImageCheck = true; // Check key images not duplicated with what in db for (const CTxIn& txin: tx.vin) { - const CKeyImage& keyImage = txin.keyImage; - if (IsKeyImageSpend1(keyImage.GetHex(), uint256())) { - fKeyImageCheck = false; - break; - } + const CKeyImage& keyImage = txin.keyImage; + if (IsKeyImageSpend1(keyImage.GetHex(), uint256())) { + fKeyImageCheck = false; + break; + } } if (!fKeyImageCheck) { - continue; + continue; } if (!CheckHaveInputs(view, tx)) continue; @@ -290,12 +290,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP bool isDuplicate = false; for (const CTxIn& txin: tx.vin) { - const CKeyImage& keyImage = txin.keyImage; - if (keyImages.count(keyImage)) { - isDuplicate = true; - break; - } - keyImages.insert(keyImage); + const CKeyImage& keyImage = txin.keyImage; + if (keyImages.count(keyImage)) { + isDuplicate = true; + break; + } + keyImages.insert(keyImage); } if (isDuplicate) continue; vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx())); @@ -359,7 +359,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP CTxUndo txundo; if (tx.IsCoinStake()) { - UpdateCoins(tx, state, view, txundo, nHeight); + UpdateCoins(tx, state, view, txundo, nHeight); } // Added @@ -412,8 +412,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP pblock->vtx[0].vout[0].nValue += nFees; pblocktemplate->vTxFees[0] = nFees; } else { - pblock->vtx[1].vout[2].nValue += nFees; - pblocktemplate->vTxFees[0] = nFees; + pblock->vtx[1].vout[2].nValue += nFees; + pblocktemplate->vTxFees[0] = nFees; } CPubKey sharedSec; @@ -438,14 +438,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP //Shnorr sign if (!pwalletMain->MakeShnorrSignature(pblock->vtx[1])) { - LogPrintf("%s : failed to make Shnorr signature\n", __func__); - return NULL; + LogPrintf("%s : failed to make Shnorr signature\n", __func__); + return NULL; } //Test verify shnorr signature if (!VerifyShnorrKeyImageTx(pblock->vtx[1])) { LogPrintf("%s: Failed to verify shnorr key image\n", __func__); - return NULL; + return NULL; } pwalletMain->IsTransactionForMe(pblock->vtx[1]); } @@ -465,53 +465,53 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, const CPubKey& txP } CBlockTemplate* CreateNewPoABlock(const CScript& scriptPubKeyIn, const CPubKey& txPub, const CKey& txPriv, CWallet* pwallet) { - CReserveKey reservekey(pwallet); - - if (chainActive.Tip()->nHeight < Params().START_POA_BLOCK()) { - return NULL; - } - - // Create new block - unique_ptr pblocktemplate(new CBlockTemplate()); - if (!pblocktemplate.get()) - return NULL; - CBlock* pblock = &pblocktemplate->block; // pointer for convenience - - pblock->SetNull(); - // Create coinbase tx - CMutableTransaction txNew; - txNew.vin.resize(1); - txNew.vin[0].prevout.SetNull(); - txNew.vout.resize(1); - //Value of this vout coinbase will be computed based on the number of audited PoS blocks - //This will be computed later - txNew.vout[0].scriptPubKey = scriptPubKeyIn; + CReserveKey reservekey(pwallet); + + if (chainActive.Tip()->nHeight < Params().START_POA_BLOCK()) { + return NULL; + } + + // Create new block + unique_ptr pblocktemplate(new CBlockTemplate()); + if (!pblocktemplate.get()) + return NULL; + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + + pblock->SetNull(); + // Create coinbase tx + CMutableTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vout.resize(1); + //Value of this vout coinbase will be computed based on the number of audited PoS blocks + //This will be computed later + txNew.vout[0].scriptPubKey = scriptPubKeyIn; std::copy(txPub.begin(), txPub.end(), std::back_inserter(txNew.vout[0].txPub)); std::copy(txPriv.begin(), txPriv.end(), std::back_inserter(txNew.vout[0].txPriv)); - pblock->vtx.push_back(txNew); - pblocktemplate->vTxFees.push_back(-1); // updated at end - pblocktemplate->vTxSigOps.push_back(-1); // updated at end + pblock->vtx.push_back(txNew); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end - boost::this_thread::interruption_point(); - pblock->nTime = GetAdjustedTime(); - CBlockIndex* pindexPrev = chainActive.Tip(); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); + boost::this_thread::interruption_point(); + pblock->nTime = GetAdjustedTime(); + CBlockIndex* pindexPrev = chainActive.Tip(); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); - int nprevPoAHeight; + int nprevPoAHeight; - nprevPoAHeight = GetListOfPoSInfo(pindexPrev->nHeight, pblock->posBlocksAudited); - if (pblock->posBlocksAudited.size() == 0) { - return NULL; - } - // Set block version to differentiate PoA blocks from PoS blocks - pblock->SetVersionPoABlock(); - pblock->nTime = GetAdjustedTime(); + nprevPoAHeight = GetListOfPoSInfo(pindexPrev->nHeight, pblock->posBlocksAudited); + if (pblock->posBlocksAudited.size() == 0) { + return NULL; + } + // Set block version to differentiate PoA blocks from PoS blocks + pblock->SetVersionPoABlock(); + pblock->nTime = GetAdjustedTime(); - //compute PoA block reward - CAmount nReward = pblock->posBlocksAudited.size() * 100 * COIN; - pblock->vtx[0].vout[0].nValue = nReward; + //compute PoA block reward + CAmount nReward = pblock->posBlocksAudited.size() * 100 * COIN; + pblock->vtx[0].vout[0].nValue = nReward; pblock->vtx[0].txType = TX_TYPE_REVEAL_AMOUNT; @@ -527,35 +527,35 @@ CBlockTemplate* CreateNewPoABlock(const CScript& scriptPubKeyIn, const CPubKey& pwallet->EncodeTxOutAmount(pblock->vtx[0].vout[0], pblock->vtx[0].vout[0].nValue, sharedSec.begin()); //Comment out all previous code, because a PoA block does not verify any transaction, except reward transactions to miners - // No need to collect memory pool transactions into the block - const int nHeight = pindexPrev->nHeight + 1; + // No need to collect memory pool transactions into the block + const int nHeight = pindexPrev->nHeight + 1; - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - if (nprevPoAHeight >= Params().START_POA_BLOCK()) { - pblock->hashPrevPoABlock = *(chainActive[nprevPoAHeight]->phashBlock); - } else { - pblock->hashPrevPoABlock.SetNull(); - } + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + if (nprevPoAHeight >= Params().START_POA_BLOCK()) { + pblock->hashPrevPoABlock = *(chainActive[nprevPoAHeight]->phashBlock); + } else { + pblock->hashPrevPoABlock.SetNull(); + } - //ATTENTION: This is used for setting always the easiest difficulty for PoA miners - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); - pblock->nNonce = 0; + //ATTENTION: This is used for setting always the easiest difficulty for PoA miners + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); + pblock->nNonce = 0; - pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - // Compute final coinbase transaction. - CMutableTransaction txCoinbase(pblock->vtx[0]); - txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(1)) + COINBASE_FLAGS; - assert(txCoinbase.vin[0].scriptSig.size() <= 100); + // Compute final coinbase transaction. + CMutableTransaction txCoinbase(pblock->vtx[0]); + txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(1)) + COINBASE_FLAGS; + assert(txCoinbase.vin[0].scriptSig.size() <= 100); - pblock->vtx[0] = txCoinbase; - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + pblock->vtx[0] = txCoinbase; + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->hashPoAMerkleRoot = pblock->BuildPoAMerkleTree(); - pblock->minedHash = pblock->ComputeMinedHash(); + pblock->minedHash = pblock->ComputeMinedHash(); - return pblocktemplate.release(); + return pblocktemplate.release(); } void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) @@ -667,7 +667,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) } while (fGenerateDapscoins || fProofOfStake) { - if (chainActive.Tip()->nHeight >= Params().LAST_POW_BLOCK()) fProofOfStake = true; + if (chainActive.Tip()->nHeight >= Params().LAST_POW_BLOCK()) fProofOfStake = true; if (fProofOfStake) { if (chainActive.Tip()->nHeight < Params().LAST_POW_BLOCK()) { MilliSleep(5000); @@ -675,35 +675,35 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) } while (vNodes.empty() || pwallet->IsLocked() || !fMintableCoins || nReserveBalance >= pwallet->GetBalance() || !masternodeSync.IsSynced()) { - nLastCoinStakeSearchInterval = 0; - if (!fMintableCoins) { - if (GetTime() - nMintableLastCheck > 1 * 60) // 1 minute check time - { - nMintableLastCheck = GetTime(); - fMintableCoins = pwallet->MintableCoins(); - } - } - MilliSleep(5000); + nLastCoinStakeSearchInterval = 0; + if (!fMintableCoins) { + if (GetTime() - nMintableLastCheck > 1 * 60) // 1 minute check time + { + nMintableLastCheck = GetTime(); + fMintableCoins = pwallet->MintableCoins(); + } + } + MilliSleep(5000); if (!fGenerateDapscoins) { - break; - } + break; + } if (!fGenerateDapscoins && !fProofOfStake) - continue; + continue; } if (!fGenerateDapscoins) { - LogPrintf("Stopping staking or mining\n"); - nLastCoinStakeSearchInterval = 0; - break; + LogPrintf("Stopping staking or mining\n"); + nLastCoinStakeSearchInterval = 0; + break; } if (mapHashedBlocks.count(chainActive.Tip()->nHeight)) //search our map of hashed blocks, see if bestblock has been hashed yet { - if (GetTime() - mapHashedBlocks[chainActive.Tip()->nHeight] < max(pwallet->nHashInterval, (unsigned int)1)) // wait half of the nHashDrift with max wait of 3 minutes - { - MilliSleep(5000); - continue; - } + if (GetTime() - mapHashedBlocks[chainActive.Tip()->nHeight] < max(pwallet->nHashInterval, (unsigned int)1)) // wait half of the nHashDrift with max wait of 3 minutes + { + MilliSleep(5000); + continue; + } } } @@ -736,7 +736,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake, MineType mineType) pwallet->AddComputedPrivateKey(pblock->vtx[1].vout[1]); } if (!pblock->SignBlock(*pwallet)) - continue; + continue; } LogPrintf("CPUMiner : proof-of-stake block was signed %s \n", pblock->GetHash().ToString().c_str()); @@ -853,11 +853,11 @@ void static ThreadDapscoinMiner(void* parg) { boost::this_thread::interruption_point(); try { - //create a PoA after every 3 minute if enough PoS blocks created - while (true) { - boost::this_thread::sleep_for(boost::chrono::milliseconds(180 * 1000)); - //TODO: call CreateNewPoABlock function to create PoA blocks - } + //create a PoA after every 3 minute if enough PoS blocks created + while (true) { + boost::this_thread::sleep_for(boost::chrono::milliseconds(180 * 1000)); + //TODO: call CreateNewPoABlock function to create PoA blocks + } boost::this_thread::interruption_point(); } catch (const std::exception& e) { LogPrintf("ThreadBitcoinMiner() exception\n"); diff --git a/src/net.cpp b/src/net.cpp index 8d2b04df6d..d83bfb0690 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2145,7 +2145,7 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend) { Fuzz(GetArg("-fuzzmessagestest", 10)); if (ssSend.size() == 0) { - LEAVE_CRITICAL_SECTION(cs_vSend); + LEAVE_CRITICAL_SECTION(cs_vSend); return; } diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index f20a1a0c25..20250f39cb 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -532,21 +532,21 @@ bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) CTransaction txVin; uint256 hash; if (GetTransaction(vin.prevout.hash, txVin, hash, true)) { - if (vin.prevout.n >= txVin.vout.size()) return false; - CTxOut out = txVin.vout[vin.prevout.n]; - CAmount amount; - CKey decodedMask; - CPubKey sharedSec(vin.encryptionKey.begin(), vin.encryptionKey.end()); - ECDHInfo::Decode(out.maskValue.mask.begin(), out.maskValue.amount.begin(), sharedSec, decodedMask, amount); + if (vin.prevout.n >= txVin.vout.size()) return false; + CTxOut out = txVin.vout[vin.prevout.n]; + CAmount amount; + CKey decodedMask; + CPubKey sharedSec(vin.encryptionKey.begin(), vin.encryptionKey.end()); + ECDHInfo::Decode(out.maskValue.mask.begin(), out.maskValue.amount.begin(), sharedSec, decodedMask, amount); std::vector commitment; - CWallet::CreateCommitment(decodedMask.begin(), amount, commitment); - if (commitment != out.commitment) { - return false; - } - - if (amount == 1000000 * COIN) { - if (out.scriptPubKey == payee2) return true; - } + CWallet::CreateCommitment(decodedMask.begin(), amount, commitment); + if (commitment != out.commitment) { + return false; + } + + if (amount == 1000000 * COIN) { + if (out.scriptPubKey == payee2) return true; + } } return false; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index f29ac929e0..2e1a826406 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -220,7 +220,7 @@ std::vector CBlock::GetPoAMerkleBranch(int nIndex) const uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) { if (nIndex == -1) - return uint256(); + return uint256(); for (std::vector::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it) { if (nIndex & 1) @@ -235,7 +235,7 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector& vMer uint256 CBlock::CheckPoAMerkleBranch(uint256 mhash, const std::vector& poaMerkleBranch, int nIndex) { if (nIndex == -1) - return uint256(); + return uint256(); for (std::vector::const_iterator it(poaMerkleBranch.begin()); it != poaMerkleBranch.end(); ++it) { if (nIndex & 1) diff --git a/src/primitives/block.h b/src/primitives/block.h index ca62786f0b..f58942c846 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -176,8 +176,8 @@ class CBlock : public CBlockHeader inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*(CBlockHeader*)this); READWRITE(vtx); - if(vtx.size() > 1 && vtx[1].IsCoinStake()) - READWRITE(vchBlockSig); + if(vtx.size() > 1 && vtx[1].IsCoinStake()) + READWRITE(vchBlockSig); if (IsProofOfAudit()) { READWRITE(posBlocksAudited); } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 4c3a4a1d61..d1ac87a507 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -438,55 +438,55 @@ struct CMutableTransaction struct CTransactionSignature { - int32_t nVersion; - std::vector vin; - std::vector vout; - uint32_t nLockTime; - //For stealth transactions - CKey txPrivM; - char hasPaymentID; - uint64_t paymentID; - uint32_t txType; - - CAmount nTxFee; - - CTransactionSignature(const CTransaction& tx) { - *const_cast(&nVersion) = tx.nVersion; - *const_cast*>(&vin) = tx.vin; - *const_cast*>(&vout) = tx.vout; - *const_cast(&nLockTime) = tx.nLockTime; - hasPaymentID = tx.hasPaymentID; - *const_cast(&paymentID) = tx.paymentID; - *const_cast(&txType) = tx.txType; - nTxFee = tx.nTxFee; - - //set transaction output amounts as 0 - for (size_t i = 0; i < vout.size(); i++) { - vout[i].nValue = 0; - } - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(vin); - READWRITE(vout); - READWRITE(nLockTime); - READWRITE(hasPaymentID); - if (hasPaymentID != 0) { - READWRITE(paymentID); - } - READWRITE(txType); - - READWRITE(nTxFee); - } - - uint256 GetHash() { - return SerializeHash(*this); - } + int32_t nVersion; + std::vector vin; + std::vector vout; + uint32_t nLockTime; + //For stealth transactions + CKey txPrivM; + char hasPaymentID; + uint64_t paymentID; + uint32_t txType; + + CAmount nTxFee; + + CTransactionSignature(const CTransaction& tx) { + *const_cast(&nVersion) = tx.nVersion; + *const_cast*>(&vin) = tx.vin; + *const_cast*>(&vout) = tx.vout; + *const_cast(&nLockTime) = tx.nLockTime; + hasPaymentID = tx.hasPaymentID; + *const_cast(&paymentID) = tx.paymentID; + *const_cast(&txType) = tx.txType; + nTxFee = tx.nTxFee; + + //set transaction output amounts as 0 + for (size_t i = 0; i < vout.size(); i++) { + vout[i].nValue = 0; + } + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(vin); + READWRITE(vout); + READWRITE(nLockTime); + READWRITE(hasPaymentID); + if (hasPaymentID != 0) { + READWRITE(paymentID); + } + READWRITE(txType); + + READWRITE(nTxFee); + } + + uint256 GetHash() { + return SerializeHash(*this); + } }; class CTxInShortDigest @@ -523,7 +523,7 @@ class CTxInShortDigest } uint256 GetHash() { - return SerializeHash(*this); + return SerializeHash(*this); } }; diff --git a/src/protocol.cpp b/src/protocol.cpp index 8279fd5483..73040b742a 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -135,7 +135,7 @@ bool CInv::IsKnownType() const } bool CInv::IsMasterNodeType() const{ - return (type >= 6); + return (type >= 6); } const char* CInv::GetCommand() const diff --git a/src/protocol.h b/src/protocol.h index 53e6678984..74567fd46f 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -72,10 +72,10 @@ enum { // but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION) NODE_BLOOM = (1 << 2), - // NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference - // that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here ) + // NODE_BLOOM_WITHOUT_MN means the node has the same features as NODE_BLOOM with the only difference + // that the node doens't want to receive master nodes messages. (the 1<<3 was not picked as constant because on bitcoin 0.14 is witness and we want that update here ) - NODE_BLOOM_WITHOUT_MN = (1 << 4), + NODE_BLOOM_WITHOUT_MN = (1 << 4), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the diff --git a/src/qt/2faqrdialog.cpp b/src/qt/2faqrdialog.cpp index 3dfb74f6a3..6d5919b4f9 100644 --- a/src/qt/2faqrdialog.cpp +++ b/src/qt/2faqrdialog.cpp @@ -36,7 +36,7 @@ TwoFAQRDialog::TwoFAQRDialog(QWidget *parent) : connect(ui->btnCopy, SIGNAL(clicked()), this, SLOT(on_btnCopyURI_clicked())); connect(ui->btnNext, SIGNAL(clicked()), this, SLOT(accept())); - connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(reject())); ui->label->setVisible(true); ui->label_2->setVisible(true); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 8fbd1adccb..0ab9b5b9b5 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1362,15 +1362,15 @@ void BitcoinGUI::setStakingStatus() } void BitcoinGUI::setStakingInProgress(bool inProgress) { - if (inProgress) { + if (inProgress) { stakingState->setText(tr("Enabling Staking...")); stakingState->setToolTip("Enabling Staking... Please wait up to 1.5 hours for it to be properly enabled after consolidation."); stakingAction->setIcon(QIcon(":/icons/staking_active")); - } else { + } else { stakingState->setText(tr("Disabling Staking...")); stakingState->setToolTip("Disabling Staking..."); stakingAction->setIcon(QIcon(":/icons/staking_inactive")); - } + } } #ifdef ENABLE_WALLET diff --git a/src/qt/encryptdialog.cpp b/src/qt/encryptdialog.cpp index 303b1576fc..2f3d820ce1 100644 --- a/src/qt/encryptdialog.cpp +++ b/src/qt/encryptdialog.cpp @@ -114,7 +114,7 @@ void EncryptDialog::on_acceptPassphrase() { msgBox.setIcon(QMessageBox::Information); msgBox.exec(); accept(); - } + } } else { QMessageBox msgBox; msgBox.setWindowTitle("Wallet Encryption Failed"); diff --git a/src/qt/encryptdialog.h b/src/qt/encryptdialog.h index c0bf39fcd5..cbed0cea04 100644 --- a/src/qt/encryptdialog.h +++ b/src/qt/encryptdialog.h @@ -20,10 +20,10 @@ class EncryptDialog : public QDialog bool matchNewPasswords(); private Q_SLOTS: - void on_btnCancel(); - void on_acceptPassphrase(); - void validateNewPass(); - void validateNewPassRepeat(); + void on_btnCancel(); + void on_acceptPassphrase(); + void validateNewPass(); + void validateNewPassRepeat(); private: Ui::EncryptDialog *ui; diff --git a/src/qt/historypage.cpp b/src/qt/historypage.cpp index 5a3bb8fe9f..9f8ec8d1c5 100644 --- a/src/qt/historypage.cpp +++ b/src/qt/historypage.cpp @@ -119,37 +119,37 @@ void HistoryPage::on_cellClicked(int row, int column) bool privkeyFound = false; std::string txHash = pwalletMain->addrToTxHashMap[stdAddress]; if (IsHex(txHash)) { - uint256 hash; - hash.SetHex(txHash); - - if (pwalletMain && pwalletMain->mapWallet.count(hash) == 1) { - CWalletTx tx = pwalletMain->mapWallet[hash]; - for (size_t i = 0; i < tx.vout.size(); i++) { - txnouttype type; - vector addresses; - int nRequired; - - if (ExtractDestinations(tx.vout[i].scriptPubKey, type, addresses, nRequired)) { - std::string parseddAddress = CBitcoinAddress(addresses[0]).ToString(); - if (stdAddress == parseddAddress) { - if (tx.IsCoinStake() && !tx.vout[i].txPriv.empty()) { - CKey txPriv; - txPriv.Set(tx.vout[i].txPriv.begin(), tx.vout[i].txPriv.end(), true); - txdlg.setTxPrivKey(CBitcoinSecret(txPriv).ToString().c_str()); - privkeyFound = true; - } else { - std::string key = txHash + std::to_string(i); - std::string secret; - if (CWalletDB(pwalletMain->strWalletFile).ReadTxPrivateKey(key, secret)) { - txdlg.setTxPrivKey(secret.c_str()); - privkeyFound = true; - } - } - } - } - } + uint256 hash; + hash.SetHex(txHash); + + if (pwalletMain && pwalletMain->mapWallet.count(hash) == 1) { + CWalletTx tx = pwalletMain->mapWallet[hash]; + for (size_t i = 0; i < tx.vout.size(); i++) { + txnouttype type; + vector addresses; + int nRequired; + + if (ExtractDestinations(tx.vout[i].scriptPubKey, type, addresses, nRequired)) { + std::string parseddAddress = CBitcoinAddress(addresses[0]).ToString(); + if (stdAddress == parseddAddress) { + if (tx.IsCoinStake() && !tx.vout[i].txPriv.empty()) { + CKey txPriv; + txPriv.Set(tx.vout[i].txPriv.begin(), tx.vout[i].txPriv.end(), true); + txdlg.setTxPrivKey(CBitcoinSecret(txPriv).ToString().c_str()); + privkeyFound = true; + } else { + std::string key = txHash + std::to_string(i); + std::string secret; + if (CWalletDB(pwalletMain->strWalletFile).ReadTxPrivateKey(key, secret)) { + txdlg.setTxPrivKey(secret.c_str()); + privkeyFound = true; + } + } + } + } + } txdlg.setTxFee(tx.nTxFee); - } + } } std::string txdlgMsg = "Request from Sender (if applicable)"; if (stdType == "Minted") { @@ -181,9 +181,9 @@ void HistoryPage::keyPressEvent(QKeyEvent* event) void HistoryPage::updateTableData() { - if (pwalletMain) { - updateTableData(pwalletMain); - } + if (pwalletMain) { + updateTableData(pwalletMain); + } } void HistoryPage::updateTableData(CWallet* wallet) @@ -316,7 +316,7 @@ void HistoryPage::syncTime(QDateTimeEdit* calendar, QTimeEdit* clock) void HistoryPage::setModel(WalletModel* model) { - this->model = model; - connect(model, SIGNAL(WalletUnlocked()), this, - SLOT(updateTableData())); + this->model = model; + connect(model, SIGNAL(WalletUnlocked()), this, + SLOT(updateTableData())); } diff --git a/src/qt/optionspage.cpp b/src/qt/optionspage.cpp index 2f974044e3..5d0a1cd412 100644 --- a/src/qt/optionspage.cpp +++ b/src/qt/optionspage.cpp @@ -156,7 +156,7 @@ OptionsPage::OptionsPage(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenu void OptionsPage::setStakingToggle() { - ui->toggleStaking->setState(fGenerateDapscoins); + ui->toggleStaking->setState(fGenerateDapscoins); } void OptionsPage::setModel(WalletModel* model) @@ -186,7 +186,7 @@ CAmount OptionsPage::getValidatedAmount() { OptionsPage::~OptionsPage() { - delete timerStakingToggleSync; + delete timerStakingToggleSync; delete ui; } @@ -223,7 +223,7 @@ void OptionsPage::on_pushButtonSave_clicked() { Q_EMIT model->stakingStatusChanged(nLastCoinStakeSearchInterval); ui->lineEditWithhold->setStyleSheet(GUIUtil::loadStyleSheet()); - + QString reserveBalance = ui->lineEditWithhold->text().trimmed(); QMessageBox msgBox; msgBox.setWindowTitle("Reserve Balance Set"); @@ -318,14 +318,14 @@ void OptionsPage::on_pushButtonPassword_clicked() msgBox.setIcon(QMessageBox::Critical); msgBox.exec(); } - else if (model->changePassphrase(oldPass, newPass)) { + else if (model->changePassphrase(oldPass, newPass)) { QMessageBox msgBox; msgBox.setWindowTitle("Passphrase Change Successful"); msgBox.setText("Wallet passphrase was successfully changed.\nPlease remember your passphrase as there is no way to recover it."); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.setIcon(QMessageBox::Information); msgBox.exec(); - success = true; + success = true; } } else { QMessageBox msgBox; @@ -436,7 +436,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) } if (chainActive.Height() < Params().LAST_POW_BLOCK()) { - if (widget->getState()) { + if (widget->getState()) { QString msg; msg.sprintf("PoW blocks are still being mined.\nPlease wait until Block %d.", Params().LAST_POW_BLOCK()); QMessageBox msgBox; @@ -445,13 +445,13 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) msgBox.setText(msg); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.exec(); - } - widget->setState(false); - pwalletMain->WriteStakingStatus(false); - pwalletMain->walletStakingInProgress = false; + } + widget->setState(false); + pwalletMain->WriteStakingStatus(false); + pwalletMain->walletStakingInProgress = false; return; } - if (widget->getState()){ + if (widget->getState()){ QString error; CAmount minFee, maxFee; StakingStatusError stt = pwalletMain->StakingCoinStatus(minFee, maxFee); @@ -471,16 +471,16 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) CAmount totalFee = maxFee + pwalletMain->ComputeFee(1, 2, MAX_RING_SIZE); errorMessage = "Your stakeable balance is under the threshold of 400 000 DAPS. This is due to your reserve balance of " + FormatMoney(nReserveBalance) + " DAPS being too high. The wallet software has tried to consolidate your funds with the reserve balance but without success because of a consolidation fee of " + FormatMoney(totalFee) + " DAPS. Please wait around 10 minutes for the wallet to resolve the reserve to enable staking."; } - QString msg = QString::fromStdString(errorMessage); - msgBox.setWindowTitle("Warning: Staking Issue"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setText(msg); + QString msg = QString::fromStdString(errorMessage); + msgBox.setWindowTitle("Warning: Staking Issue"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(msg); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); - msgBox.exec(); - widget->setState(false); - nLastCoinStakeSearchInterval = 0; - Q_EMIT model->stakingStatusChanged(false); - pwalletMain->WriteStakingStatus(false); + msgBox.exec(); + widget->setState(false); + nLastCoinStakeSearchInterval = 0; + Q_EMIT model->stakingStatusChanged(false); + pwalletMain->WriteStakingStatus(false); return; } if (stt == StakingStatusError::STAKING_OK) { @@ -500,7 +500,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) errorMessage = "In order to enable staking with 100% of your current balance except the reserve balance, your previous DAPS deposits must be consolidated and reorganized. This will incur a fee of between " + FormatMoney(minFee) + " to " + FormatMoney(maxFee) + " DAPS.\n\nWould you like to do this?"; } reply = QMessageBox::question(this, "Staking Needs Consolidation", QString::fromStdString(errorMessage), QMessageBox::Yes|QMessageBox::No); - if (reply == QMessageBox::Yes) { + if (reply == QMessageBox::Yes) { pwalletMain->WriteStakingStatus(true); Q_EMIT model->stakingStatusChanged(true); model->generateCoins(true, 1); @@ -508,12 +508,12 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) pwalletMain->stakingMode = StakingMode::STAKING_WITH_CONSOLIDATION; saveConsolidationSettingTime(ui->addNewFunds->isChecked()); bool success = false; - try { + try { uint32_t nTime = pwalletMain->ReadAutoConsolidateSettingTime(); nTime = (nTime == 0)? GetAdjustedTime() : nTime; - success = model->getCWallet()->CreateSweepingTransaction( - CWallet::MINIMUM_STAKE_AMOUNT, - CWallet::MINIMUM_STAKE_AMOUNT, nTime); + success = model->getCWallet()->CreateSweepingTransaction( + CWallet::MINIMUM_STAKE_AMOUNT, + CWallet::MINIMUM_STAKE_AMOUNT, nTime); if (success) { //nConsolidationTime = 1800; QString msg = "Consolidation transaction created!"; @@ -526,7 +526,7 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) } } catch (const std::exception& err) { LogPrintf("Sweeping failed, will be done automatically when coins become mature"); - } + } return; } else { pwalletMain->stakingMode = StakingMode::STOPPED; @@ -542,35 +542,35 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) Q_EMIT model->stakingStatusChanged(true); model->generateCoins(true, 1); } else { - if (stt != StakingStatusError::UTXO_UNDER_THRESHOLD) { - QMessageBox msgBox; - QString msg(error); - msgBox.setWindowTitle("Warning: Staking Issue"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setText(msg); - msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); - msgBox.exec(); - widget->setState(false); - nLastCoinStakeSearchInterval = 0; - Q_EMIT model->stakingStatusChanged(false); - pwalletMain->WriteStakingStatus(false); - } else { - QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Create Stakable Transaction?", error, QMessageBox::Yes|QMessageBox::No); - if (reply == QMessageBox::Yes) { - //ask yes or no - //send to this self wallet MIN staking amount - std::string masterAddr; - model->getCWallet()->ComputeStealthPublicAddress("masteraccount", masterAddr); - CWalletTx resultTx; - bool success = false; - try { - success = model->getCWallet()->SendToStealthAddress( - masterAddr, - CWallet::MINIMUM_STAKE_AMOUNT, - resultTx, - false - ); + if (stt != StakingStatusError::UTXO_UNDER_THRESHOLD) { + QMessageBox msgBox; + QString msg(error); + msgBox.setWindowTitle("Warning: Staking Issue"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(msg); + msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); + msgBox.exec(); + widget->setState(false); + nLastCoinStakeSearchInterval = 0; + Q_EMIT model->stakingStatusChanged(false); + pwalletMain->WriteStakingStatus(false); + } else { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "Create Stakable Transaction?", error, QMessageBox::Yes|QMessageBox::No); + if (reply == QMessageBox::Yes) { + //ask yes or no + //send to this self wallet MIN staking amount + std::string masterAddr; + model->getCWallet()->ComputeStealthPublicAddress("masteraccount", masterAddr); + CWalletTx resultTx; + bool success = false; + try { + success = model->getCWallet()->SendToStealthAddress( + masterAddr, + CWallet::MINIMUM_STAKE_AMOUNT, + resultTx, + false + ); } catch (const std::exception& err) { QMessageBox msgBox; @@ -579,10 +579,10 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) msgBox.setText(QString(err.what())); msgBox.setStyleSheet(GUIUtil::loadStyleSheet()); msgBox.exec(); - return; - } + return; + } - if (success){ + if (success){ WalletUtil::getTx(pwalletMain, resultTx.GetHash()); QString txhash = resultTx.GetHash().GetHex().c_str(); QMessageBox msgBox; @@ -599,14 +599,14 @@ void OptionsPage::on_EnableStaking(ToggleButton* widget) //Copy txhash to clipboard GUIUtil::setClipboard(txhash); } - } - } else { - widget->setState(false); - nLastCoinStakeSearchInterval = 0; - Q_EMIT model->stakingStatusChanged(false); - pwalletMain->WriteStakingStatus(false); - } - } + } + } else { + widget->setState(false); + nLastCoinStakeSearchInterval = 0; + Q_EMIT model->stakingStatusChanged(false); + pwalletMain->WriteStakingStatus(false); + } + } }*/ } else { pwalletMain->stakingMode = StakingMode::STOPPED; @@ -689,7 +689,7 @@ void OptionsPage::changeTheme(ToggleButton* widget) if (widget->getState()) settings.setValue("theme", "dark"); else settings.setValue("theme", "light"); - GUIUtil::refreshStyleSheet(); + GUIUtil::refreshStyleSheet(); } void OptionsPage::disable2FA() { @@ -857,7 +857,7 @@ void OptionsPage::onShowMnemonic() { return; } } - + CHDChain hdChainCurrent; if (!pwalletMain->GetDecryptedHDChain(hdChainCurrent)) return; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 768fb7f399..af5e464c97 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -274,9 +274,9 @@ void OverviewPage::setWalletModel(WalletModel* model) void OverviewPage::updateBalance() { - WalletModel* model = this->walletModel; - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), - model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); + WalletModel* model = this->walletModel; + setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), + model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); } void OverviewPage::updateDisplayUnit() diff --git a/src/qt/revealtxdialog.cpp b/src/qt/revealtxdialog.cpp index 22e54b2454..5e182141c8 100644 --- a/src/qt/revealtxdialog.cpp +++ b/src/qt/revealtxdialog.cpp @@ -34,22 +34,22 @@ RevealTxDialog::~RevealTxDialog() void RevealTxDialog::setTxID(QString strId) { - ui->lblTxID->setText(strId); + ui->lblTxID->setText(strId); } void RevealTxDialog::setTxAddress(QString strAddr) { - ui->lblAddress->setText(strAddr); + ui->lblAddress->setText(strAddr); } void RevealTxDialog::setTxPrivKey(QString strPrivKey) { - ui->lblPrivateKey->setText(strPrivKey); + ui->lblPrivateKey->setText(strPrivKey); } void RevealTxDialog::setTxFee(CAmount fee) { - ui->lblTxFee->setText(BitcoinUnits::floorHtmlWithUnit(BitcoinUnits::DAPS, fee, false, BitcoinUnits::separatorAlways)); + ui->lblTxFee->setText(BitcoinUnits::floorHtmlWithUnit(BitcoinUnits::DAPS, fee, false, BitcoinUnits::separatorAlways)); } void RevealTxDialog::on_buttonBox_accepted() diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 10d274fbc7..05513c417a 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -133,8 +133,8 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } CTxDestination address; if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { - // Sent to DAPS Address - sub.address = CBitcoinAddress(address).ToString(); + // Sent to DAPS Address + sub.address = CBitcoinAddress(address).ToString(); } //a sendtoself transaction has second output as change diff --git a/src/qt/txentry.cpp b/src/qt/txentry.cpp index 9e2d3962f2..eb3c3b49de 100644 --- a/src/qt/txentry.cpp +++ b/src/qt/txentry.cpp @@ -52,7 +52,7 @@ void TxEntry::resizeEvent(QResizeEvent* event) void TxEntry::setData(int64_t Date, QString Address, QString Amount, QString ID, QString Type) { - QDateTime dateTime = QDateTime::fromTime_t((qint32)Date); + QDateTime dateTime = QDateTime::fromTime_t((qint32)Date); ui->labelTxAmount->setText(Amount); ui->labelDate->setText(dateTime.date().toString("MMMM dd yyyy") + QString("\n") + dateTime.toString("hh:mm:ss")); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index b1cbacd425..d707c0a8f1 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -135,10 +135,10 @@ bool IsImportingOrReindexing() { void WalletModel::pollBalanceChanged() { - if (wallet->walletUnlockCountStatus == 1) { - Q_EMIT WalletUnlocked(); - wallet->walletUnlockCountStatus++; - } + if (wallet->walletUnlockCountStatus == 1) { + Q_EMIT WalletUnlocked(); + wallet->walletUnlockCountStatus++; + } // Wait a little bit more when the wallet is reindexing and/or importing, no need to lock cs_main so often. if (IsImportingOrReindexing()) { @@ -700,27 +700,27 @@ bool WalletModel::isMine(CBitcoinAddress address) StakingStatusError WalletModel::getStakingStatusError(QString& error) { /* { - bool fMintable = pwalletMain->MintableCoins(); - CAmount balance = pwalletMain->GetSpendableBalance(); - if (!fMintable || nReserveBalance > balance) { - if (balance < CWallet::MINIMUM_STAKE_AMOUNT) { - error = "\nBalance is under the minimum 400,000 staking threshold.\nPlease send more DAPS to this wallet.\n"; - return StakingStatusError::STAKING_OK; - } - if (nReserveBalance > balance || (balance > nReserveBalance && balance - nReserveBalance < CWallet::MINIMUM_STAKE_AMOUNT)) { - error = "Reserve balance is too high.\nPlease lower it in order to turn staking on."; - return StakingStatusError::RESERVE_TOO_HIGH; - } - if (!fMintable) { - if (balance > CWallet::MINIMUM_STAKE_AMOUNT) { - //10 is to cover transaction fees - if (balance >= CWallet::MINIMUM_STAKE_AMOUNT + 10*COIN) { - error = "Not enough mintable coins.\nDo you want to merge & make a sent-to-yourself transaction to make the wallet stakable?"; - return StakingStatusError::UTXO_UNDER_THRESHOLD; - } - } - } - } + bool fMintable = pwalletMain->MintableCoins(); + CAmount balance = pwalletMain->GetSpendableBalance(); + if (!fMintable || nReserveBalance > balance) { + if (balance < CWallet::MINIMUM_STAKE_AMOUNT) { + error = "\nBalance is under the minimum 400,000 staking threshold.\nPlease send more DAPS to this wallet.\n"; + return StakingStatusError::STAKING_OK; + } + if (nReserveBalance > balance || (balance > nReserveBalance && balance - nReserveBalance < CWallet::MINIMUM_STAKE_AMOUNT)) { + error = "Reserve balance is too high.\nPlease lower it in order to turn staking on."; + return StakingStatusError::RESERVE_TOO_HIGH; + } + if (!fMintable) { + if (balance > CWallet::MINIMUM_STAKE_AMOUNT) { + //10 is to cover transaction fees + if (balance >= CWallet::MINIMUM_STAKE_AMOUNT + 10*COIN) { + error = "Not enough mintable coins.\nDo you want to merge & make a sent-to-yourself transaction to make the wallet stakable?"; + return StakingStatusError::UTXO_UNDER_THRESHOLD; + } + } + } + } }*/ return StakingStatusError::STAKING_OK; } @@ -752,17 +752,17 @@ std::map getTx(CWallet* wallet, uint256 hash) vector > getTXs(CWallet* wallet) { - vector > txs; - if (!wallet || wallet->IsLocked()) return txs; - std::map txMap = wallet->mapWallet; - { - LOCK2(cs_main, wallet->cs_wallet); - for (std::map::iterator tx = txMap.begin(); tx != txMap.end(); ++tx) { - if (tx->second.GetDepthInMainChain() > 0) { - txs.push_back(getTx(wallet, tx->second)); - } - } - } + vector > txs; + if (!wallet || wallet->IsLocked()) return txs; + std::map txMap = wallet->mapWallet; + { + LOCK2(cs_main, wallet->cs_wallet); + for (std::map::iterator tx = txMap.begin(); tx != txMap.end(); ++tx) { + if (tx->second.GetDepthInMainChain() > 0) { + txs.push_back(getTx(wallet, tx->second)); + } + } + } return txs; } @@ -774,34 +774,34 @@ std::map getTx(CWallet* wallet, CWalletTx tx) CAmount totalamount = CAmount(0); CAmount totalIn = 0; if (wallet && !wallet->IsLocked()) { - for (CTxIn in: tx.vin) { - COutPoint prevout = wallet->findMyOutPoint(in); - map::const_iterator mi = wallet->mapWallet.find(prevout.hash); - if (mi != wallet->mapWallet.end()) { - const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) { - if (wallet->IsMine(prev.vout[prevout.n])) { - CAmount decodedAmount = 0; - CKey blind; - pwalletMain->RevealTxOutAmount(prev, prev.vout[prevout.n], decodedAmount, blind); - totalIn += decodedAmount; - } - } - } - } + for (CTxIn in: tx.vin) { + COutPoint prevout = wallet->findMyOutPoint(in); + map::const_iterator mi = wallet->mapWallet.find(prevout.hash); + if (mi != wallet->mapWallet.end()) { + const CWalletTx& prev = (*mi).second; + if (prevout.n < prev.vout.size()) { + if (wallet->IsMine(prev.vout[prevout.n])) { + CAmount decodedAmount = 0; + CKey blind; + pwalletMain->RevealTxOutAmount(prev, prev.vout[prevout.n], decodedAmount, blind); + totalIn += decodedAmount; + } + } + } + } } CAmount firstOut = 0; if (wallet && !wallet->IsLocked()) { - for (CTxOut out: tx.vout){ - CAmount vamount; - CKey blind; - if (wallet->IsMine(out) && wallet->RevealTxOutAmount(tx,out,vamount, blind)) { - if (vamount != 0 && firstOut == 0) { - firstOut = vamount; - } - totalamount+=vamount; //this is the total output - } - } + for (CTxOut out: tx.vout){ + CAmount vamount; + CKey blind; + if (wallet->IsMine(out) && wallet->RevealTxOutAmount(tx,out,vamount, blind)) { + if (vamount != 0 && firstOut == 0) { + firstOut = vamount; + } + totalamount+=vamount; //this is the total output + } + } } QList decomposedTx = TransactionRecord::decomposeTransaction(wallet, tx); std::string txHash = tx.GetHash().GetHex(); @@ -843,10 +843,10 @@ std::map getTx(CWallet* wallet, CWalletTx tx) return txData; break; case TransactionRecord::SendToSelf: - txData["type"] = QString("Payment to yourself"); - txData["amount"] = BitcoinUnits::format(0, TxRecord.debit); //absolute value of total amount - return txData; - break; + txData["type"] = QString("Payment to yourself"); + txData["amount"] = BitcoinUnits::format(0, TxRecord.debit); //absolute value of total amount + return txData; + break; case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: txData["type"] = QString("Sent"); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 2312197c32..5c78b1000c 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -120,7 +120,7 @@ void WalletView::setBitcoinGUI(BitcoinGUI* gui) void WalletView::stakingStatus(bool stt) { - Q_EMIT stakingStatusChanged(stt); + Q_EMIT stakingStatusChanged(stt); } void WalletView::setClientModel(ClientModel* clientModel) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6f52ca0097..dd5326be87 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -132,9 +132,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("moneysupply",ValueFromAmount(blockindex->nMoneySupply))); std::string minetype = "PoW"; if (blockindex->IsProofOfStake()) { - minetype = "PoS"; + minetype = "PoS"; } else if (blockindex->IsProofOfAudit()) { - minetype = "PoA"; + minetype = "PoA"; } result.push_back(Pair("minetype", minetype)); @@ -142,13 +142,13 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (blockindex->IsProofOfAudit()) { //This is a PoA block //Read information of PoS blocks audited by this PoA block - result.push_back(Pair("previouspoahash", block.hashPrevPoABlock.GetHex())); + result.push_back(Pair("previouspoahash", block.hashPrevPoABlock.GetHex())); UniValue posBlockInfos(UniValue::VARR); bool auditResult = true; for (int i = 0; i < block.posBlocksAudited.size(); i++) { UniValue objPoSBlockInfo(UniValue::VOBJ); PoSBlockInfoToJSON(block.posBlocksAudited[i].hash, - block.posBlocksAudited[i].nTime, block.posBlocksAudited[i].height, objPoSBlockInfo); + block.posBlocksAudited[i].nTime, block.posBlocksAudited[i].height, objPoSBlockInfo); posBlockInfos.push_back(objPoSBlockInfo); auditResult = auditResult & (block.posBlocksAudited[i].nTime > 0); } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index ff3aae7fb4..512755b6bc 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -33,8 +33,8 @@ static const CRPCConvertParam vRPCConvertParams[] = {"getaddednodeinfo", 0}, {"setgenerate", 0}, {"setgenerate", 1}, - {"generatepoa", 0}, - {"generatepoa", 1}, + {"generatepoa", 0}, + {"generatepoa", 1}, {"getnetworkhashps", 0}, {"getnetworkhashps", 1}, {"sendtoaddress", 1}, diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 82ed4b4930..f032bb235b 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -42,7 +42,7 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); if (mnodeman.GetCurrentMasterNode() != NULL) { - obj.push_back(Pair("current_masternode", mnodeman.GetCurrentMasterNode()->addr.ToString())); + obj.push_back(Pair("current_masternode", mnodeman.GetCurrentMasterNode()->addr.ToString())); } obj.push_back(Pair("state", obfuScationPool.GetState())); obj.push_back(Pair("entries", obfuScationPool.GetEntriesCount())); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 27039e0396..f8e576cdf2 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -229,43 +229,43 @@ UniValue generatepoa(const UniValue& params, bool fHelp) } // don't return until a poa block is successfully generated and added to the chain - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - int nGenerate = 1; - CReserveKey reservekey(pwalletMain); - - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart + nGenerate; - } - - unsigned int nExtraNonce = 0; - - UniValue blockHashes(UniValue::VARR); - - bool createPoABlock = false; - if (nHeight >= Params().LAST_POW_BLOCK()) { - createPoABlock = true; - } - - if (!createPoABlock) { - return NullUniValue; - } - - unique_ptr pblocktemplate(CreateNewPoABlockWithKey(reservekey, pwalletMain)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); - CBlock* pblock = &pblocktemplate->block; - - CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); - ++nHeight; - blockHashes.push_back(pblock->GetHash().GetHex()); - return blockHashes; + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = 1; + CReserveKey reservekey(pwalletMain); + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart + nGenerate; + } + + unsigned int nExtraNonce = 0; + + UniValue blockHashes(UniValue::VARR); + + bool createPoABlock = false; + if (nHeight >= Params().LAST_POW_BLOCK()) { + createPoABlock = true; + } + + if (!createPoABlock) { + return NullUniValue; + } + + unique_ptr pblocktemplate(CreateNewPoABlockWithKey(reservekey, pwalletMain)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + CBlock* pblock = &pblocktemplate->block; + + CValidationState state; + if (!ProcessNewBlock(state, NULL, pblock)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + ++nHeight; + blockHashes.push_back(pblock->GetHash().GetHex()); + return blockHashes; } UniValue gethashespersec(const UniValue& params, bool fHelp) @@ -568,7 +568,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) CPubKey des, txPub; CKey txPriv; if (!pwalletMain->GenerateAddress(des, txPub, txPriv)) { - throw runtime_error("Wallet is locked, please unlock it"); + throw runtime_error("Wallet is locked, please unlock it"); } CScript scriptDummy = CScript() << OP_TRUE; pblocktemplate = CreateNewBlock(scriptDummy, txPub, txPriv, pwalletMain, false); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index c8d1e63a0b..64c142308d 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -88,7 +88,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) else { { //decoys - UniValue decoys(UniValue::VARR); + UniValue decoys(UniValue::VARR); std::vector allDecoys = txin.decoys; srand (time(NULL)); allDecoys.insert(allDecoys.begin(), txin.prevout); @@ -159,9 +159,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) const unsigned char* pBlind; pwalletMain->RevealTxOutAmount(tx, txout, decodedAmount, blind); if (txout.nValue >0) { - pBlind = zeroBlind; + pBlind = zeroBlind; } else { - pBlind = blind.begin(); + pBlind = blind.begin(); } out.push_back(Pair("decoded_amount", ValueFromAmount(decodedAmount))); out.push_back(Pair("isMine", true)); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index d974450f5d..cd712e29a8 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -267,7 +267,7 @@ static const CRPCCommand vRPCCommands[] = // category name actor (function) okSafeMode threadSafe reqWallet // --------------------- ------------------------ ----------------------- ---------- ---------- --------- /* Overall control/query calls */ - {"control", "getinfo", &getinfo, true, false, false}, /* uses wallet if enabled */ + {"control", "getinfo", &getinfo, true, false, false}, /* uses wallet if enabled */ {"control", "help", &help, true, true, false}, {"control", "stop", &stop, true, true, false}, @@ -307,7 +307,7 @@ static const CRPCCommand vRPCCommands[] = /* Mining */ {"mining", "getblocktemplate", &getblocktemplate, true, false, false}, - {"mining", "getpoablocktemplate", &getpoablocktemplate, true, false, false}, + {"mining", "getpoablocktemplate", &getpoablocktemplate, true, false, false}, {"mining", "setminingnbits", &setminingnbits, true, false, false}, {"mining", "getmininginfo", &getmininginfo, true, false, false}, {"mining", "getnetworkhashps", &getnetworkhashps, true, false, false}, diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 3a73d46c66..23513a6942 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -50,7 +50,7 @@ bool CastToBool(const valtype& vch) } } if (vch.size() == 0) { - return true; + return true; } return false; } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index b7c33fcdd3..0eae8e687f 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -129,7 +129,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutabl if (VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn))) { LogPrintf("%s: successfully verified scriptSig=%s, fromPubKey=%s, txTo=%s\n", __func__, txin.scriptSig.ToString(), fromPubKey.ToString(), txTo.GetHash().GetHex()); - return true; + return true; } return false; } diff --git a/src/secp256k1-mw/include/secp256k1_2.h b/src/secp256k1-mw/include/secp256k1_2.h index 9f75ad9a05..f4e44a0a0c 100644 --- a/src/secp256k1-mw/include/secp256k1_2.h +++ b/src/secp256k1-mw/include/secp256k1_2.h @@ -299,8 +299,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse2( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_raw_negate2( - unsigned char *pub, - size_t size + unsigned char *pub, + size_t size ) SECP256K1_ARG_NONNULL(1); /** Serialize a pubkey object into a serialized byte sequence. diff --git a/src/secp256k1-mw/include/secp256k1_commitment.h b/src/secp256k1-mw/include/secp256k1_commitment.h index ba08c15513..f641d44feb 100644 --- a/src/secp256k1-mw/include/secp256k1_commitment.h +++ b/src/secp256k1-mw/include/secp256k1_commitment.h @@ -141,15 +141,15 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_sum ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_to_serialized_pubkey( - secp256k1_pedersen_commitment* commit, - unsigned char* pubkey, - size_t* length + secp256k1_pedersen_commitment* commit, + unsigned char* pubkey, + size_t* length ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); SECP256K1_API void secp256k1_pedersen_serialized_pubkey_to_commitment( - const unsigned char* pubkey, - size_t length, - secp256k1_pedersen_commitment* commit + const unsigned char* pubkey, + size_t length, + secp256k1_pedersen_commitment* commit ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); /** Sets the final Pedersen blinding factor correctly when the generators themselves diff --git a/src/secp256k1-mw/src/modules/bulletproofs/circuit_compress_impl.h b/src/secp256k1-mw/src/modules/bulletproofs/circuit_compress_impl.h index a8ad204110..a73d58cc3d 100644 --- a/src/secp256k1-mw/src/modules/bulletproofs/circuit_compress_impl.h +++ b/src/secp256k1-mw/src/modules/bulletproofs/circuit_compress_impl.h @@ -232,7 +232,7 @@ void secp256k1_bulletproof_pf_compress_circuit(secp256k1_bulletproof_pf_compress /* Compute l1 */ if (i < assn->n_gates) { secp256k1_scalar_add(&ret->l1[i], &wr, &assn->al[i]); - } + } /* Compute r0 */ secp256k1_scalar_negate(&ret->r0[i], &yn); secp256k1_scalar_add(&ret->r0[i], &ret->r0[i], &wo); diff --git a/src/secp256k1-mw/src/modules/bulletproofs/tests_impl.h b/src/secp256k1-mw/src/modules/bulletproofs/tests_impl.h index 3b32324eb3..cb04880960 100644 --- a/src/secp256k1-mw/src/modules/bulletproofs/tests_impl.h +++ b/src/secp256k1-mw/src/modules/bulletproofs/tests_impl.h @@ -121,92 +121,92 @@ static void test1() { } void build_proof(const uint64_t* value, int size, unsigned char* proof, size_t* plen, secp256k1_pedersen_commitment* pcommit) { - secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); - secp256k1_bulletproof_generators *gens; - const unsigned char *proof_ptr = proof; - const unsigned char blind[32] = " i am not a blinding factor "; - plen = 2000; - uint64_t min_value[4] = { 0, 0, 0, 5000 } ; - const unsigned char *blind_ptr[4]; - blind_ptr[0] = blind; - blind_ptr[1] = blind; - blind_ptr[2] = blind; - blind_ptr[3] = blind; - - int32_t ecount = 0; - - CHECK(secp256k1_pedersen_commit(both, &pcommit[0], blind, value[0], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[1], blind, value[1], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[2], blind, value[2], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[3], blind, value[3], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - - /* generators - // gens = secp256k1_bulletproof_generators_create(none, NULL, 256); - // CHECK(gens == NULL && ecount == 1);*/ - gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); - CHECK(gens != NULL); - - CHECK(secp256k1_bulletproof_rangeproof_prove(both, scratch, gens, proof, &plen, value, min_value, blind_ptr, 1, &secp256k1_generator_const_g, 64, blind, NULL, 0) == 1); + secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); + secp256k1_bulletproof_generators *gens; + const unsigned char *proof_ptr = proof; + const unsigned char blind[32] = " i am not a blinding factor "; + plen = 2000; + uint64_t min_value[4] = { 0, 0, 0, 5000 } ; + const unsigned char *blind_ptr[4]; + blind_ptr[0] = blind; + blind_ptr[1] = blind; + blind_ptr[2] = blind; + blind_ptr[3] = blind; + + int32_t ecount = 0; + + CHECK(secp256k1_pedersen_commit(both, &pcommit[0], blind, value[0], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[1], blind, value[1], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[2], blind, value[2], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[3], blind, value[3], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + + /* generators + // gens = secp256k1_bulletproof_generators_create(none, NULL, 256); + // CHECK(gens == NULL && ecount == 1);*/ + gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); + CHECK(gens != NULL); + + CHECK(secp256k1_bulletproof_rangeproof_prove(both, scratch, gens, proof, &plen, value, min_value, blind_ptr, 1, &secp256k1_generator_const_g, 64, blind, NULL, 0) == 1); } void verify_proof(unsigned char* proof, size_t plen, secp256k1_pedersen_commitment* pcommit) { - secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); - secp256k1_bulletproof_generators *gens; - const unsigned char *proof_ptr = proof; - const unsigned char blind[32] = " i am not a blinding factor "; - uint64_t min_value[4] = { 0, 0, 0, 5000 } ; - gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); - CHECK(gens != NULL); - /* rangeproof_verify */ - CHECK(secp256k1_bulletproof_rangeproof_verify(both, scratch, gens, proof, plen, min_value, pcommit, 1, 64, &secp256k1_generator_const_g, NULL, 0) == 1); + secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); + secp256k1_bulletproof_generators *gens; + const unsigned char *proof_ptr = proof; + const unsigned char blind[32] = " i am not a blinding factor "; + uint64_t min_value[4] = { 0, 0, 0, 5000 } ; + gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); + CHECK(gens != NULL); + /* rangeproof_verify */ + CHECK(secp256k1_bulletproof_rangeproof_verify(both, scratch, gens, proof, plen, min_value, pcommit, 1, 64, &secp256k1_generator_const_g, NULL, 0) == 1); } static void test_build_verify() { - secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); - secp256k1_generator value_gen; - secp256k1_bulletproof_generators *gens; - secp256k1_pedersen_commitment pcommit[4]; - const secp256k1_pedersen_commitment *pcommit_arr[1]; - unsigned char proof[2000]; - const unsigned char *proof_ptr = proof; - const unsigned char blind[32] = " i am not a blinding factor "; - const unsigned char *blind_ptr[4]; - size_t blindlen = sizeof(blind); - size_t plen = sizeof(proof); - uint64_t value[4] = { 1234, 4567, 8910, 1112 } ; - uint64_t min_value[4] = { 0, 0, 0, 5000 } ; - const uint64_t *mv_ptr = min_value; - unsigned char rewind_blind[32]; - size_t rewind_v; - - int32_t ecount = 0; - - blind_ptr[0] = blind; - blind_ptr[1] = blind; - blind_ptr[2] = blind; - blind_ptr[3] = blind; - pcommit_arr[0] = pcommit; - - /*CHECK(secp256k1_generator_generate(both, &value_gen, blind) != 0);*/ - CHECK(secp256k1_pedersen_commit(both, &pcommit[0], blind, value[0], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[1], blind, value[1], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[2], blind, value[2], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - CHECK(secp256k1_pedersen_commit(both, &pcommit[3], blind, value[3], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); - - /* generators + secp256k1_context2 *both = secp256k1_context_create2(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_scratch *scratch = secp256k1_scratch_space_create(both, 1024 * 1024); + secp256k1_generator value_gen; + secp256k1_bulletproof_generators *gens; + secp256k1_pedersen_commitment pcommit[4]; + const secp256k1_pedersen_commitment *pcommit_arr[1]; + unsigned char proof[2000]; + const unsigned char *proof_ptr = proof; + const unsigned char blind[32] = " i am not a blinding factor "; + const unsigned char *blind_ptr[4]; + size_t blindlen = sizeof(blind); + size_t plen = sizeof(proof); + uint64_t value[4] = { 1234, 4567, 8910, 1112 } ; + uint64_t min_value[4] = { 0, 0, 0, 5000 } ; + const uint64_t *mv_ptr = min_value; + unsigned char rewind_blind[32]; + size_t rewind_v; + + int32_t ecount = 0; + + blind_ptr[0] = blind; + blind_ptr[1] = blind; + blind_ptr[2] = blind; + blind_ptr[3] = blind; + pcommit_arr[0] = pcommit; + + /*CHECK(secp256k1_generator_generate(both, &value_gen, blind) != 0);*/ + CHECK(secp256k1_pedersen_commit(both, &pcommit[0], blind, value[0], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[1], blind, value[1], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[2], blind, value[2], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + CHECK(secp256k1_pedersen_commit(both, &pcommit[3], blind, value[3], &secp256k1_generator_const_g, &secp256k1_generator_const_h) != 0); + + /* generators // gens = secp256k1_bulletproof_generators_create(none, NULL, 256); // CHECK(gens == NULL && ecount == 1);*/ - gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); - CHECK(gens != NULL); + gens = secp256k1_bulletproof_generators_create(both, &secp256k1_generator_const_h, 256); + CHECK(gens != NULL); - CHECK(secp256k1_bulletproof_rangeproof_prove(both, scratch, gens, proof, &plen, value, min_value, blind_ptr, 2, &secp256k1_generator_const_g, 64, blind, NULL, 0) == 1); + CHECK(secp256k1_bulletproof_rangeproof_prove(both, scratch, gens, proof, &plen, value, min_value, blind_ptr, 2, &secp256k1_generator_const_g, 64, blind, NULL, 0) == 1); - /* rangeproof_verify */ - ecount = 0; - CHECK(secp256k1_bulletproof_rangeproof_verify(both, scratch, gens, proof, plen, min_value, pcommit, 2, 64, &secp256k1_generator_const_g, NULL, 0) == 1); + /* rangeproof_verify */ + ecount = 0; + CHECK(secp256k1_bulletproof_rangeproof_verify(both, scratch, gens, proof, plen, min_value, pcommit, 2, 64, &secp256k1_generator_const_g, NULL, 0) == 1); } static void test_bulletproof_api(void) { @@ -226,7 +226,7 @@ static void test_bulletproof_api(void) { size_t blindlen = sizeof(blind); size_t plen = sizeof(proof); uint64_t value[4] = { 1234, 4567, 8910, 1112 } ; - uint64_t min_value[4] = { 1000, 4567, 0, 5000 } ; + uint64_t min_value[4] = { 1000, 4567, 0, 5000 } ; const uint64_t *mv_ptr = min_value; unsigned char rewind_blind[32]; size_t rewind_v; diff --git a/src/secp256k1-mw/src/modules/commitment/main_impl.h b/src/secp256k1-mw/src/modules/commitment/main_impl.h index 058d9e9253..35e96994df 100644 --- a/src/secp256k1-mw/src/modules/commitment/main_impl.h +++ b/src/secp256k1-mw/src/modules/commitment/main_impl.h @@ -173,55 +173,55 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context2* ctx, const secp256 } int secp256k1_pedersen_commitment_sum( - const secp256k1_context2* ctx, - const secp256k1_pedersen_commitment * const* pos, - size_t n_pos, - const secp256k1_pedersen_commitment * const* neg, - size_t n_neg, - secp256k1_pedersen_commitment* out) { - secp256k1_gej accj; - secp256k1_ge add; - secp256k1_ge outGe; - size_t i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(!n_pos || (pos != NULL)); - ARG_CHECK(!n_neg || (neg != NULL)); - (void) ctx; - secp256k1_gej_set_infinity(&accj); - for (i = 0; i < n_neg; i++) { - secp256k1_pedersen_commitment_load(&add, neg[i]); - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - secp256k1_gej_neg(&accj, &accj); - for (i = 0; i < n_pos; i++) { - secp256k1_pedersen_commitment_load(&add, pos[i]); - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - secp256k1_ge_set_gej(&outGe, &accj); - secp256k1_pedersen_commitment_save(out, &outGe); - return 1; + const secp256k1_context2* ctx, + const secp256k1_pedersen_commitment * const* pos, + size_t n_pos, + const secp256k1_pedersen_commitment * const* neg, + size_t n_neg, + secp256k1_pedersen_commitment* out) { + secp256k1_gej accj; + secp256k1_ge add; + secp256k1_ge outGe; + size_t i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(!n_pos || (pos != NULL)); + ARG_CHECK(!n_neg || (neg != NULL)); + (void) ctx; + secp256k1_gej_set_infinity(&accj); + for (i = 0; i < n_neg; i++) { + secp256k1_pedersen_commitment_load(&add, neg[i]); + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_gej_neg(&accj, &accj); + for (i = 0; i < n_pos; i++) { + secp256k1_pedersen_commitment_load(&add, pos[i]); + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_ge_set_gej(&outGe, &accj); + secp256k1_pedersen_commitment_save(out, &outGe); + return 1; } int secp256k1_pedersen_commitment_sum_pos( - const secp256k1_context2* ctx, - const secp256k1_pedersen_commitment * const* pos, - size_t n_pos, - secp256k1_pedersen_commitment* out) { - secp256k1_gej accj; - secp256k1_ge add; - secp256k1_ge outGe; - size_t i; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(!n_pos || (pos != NULL)); - (void) ctx; - secp256k1_gej_set_infinity(&accj); - for (i = 0; i < n_pos; i++) { - secp256k1_pedersen_commitment_load(&add, pos[i]); - secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); - } - secp256k1_ge_set_gej(&outGe, &accj); - secp256k1_pedersen_commitment_save(out, &outGe); - return 1; + const secp256k1_context2* ctx, + const secp256k1_pedersen_commitment * const* pos, + size_t n_pos, + secp256k1_pedersen_commitment* out) { + secp256k1_gej accj; + secp256k1_ge add; + secp256k1_ge outGe; + size_t i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(!n_pos || (pos != NULL)); + (void) ctx; + secp256k1_gej_set_infinity(&accj); + for (i = 0; i < n_pos; i++) { + secp256k1_pedersen_commitment_load(&add, pos[i]); + secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_ge_set_gej(&outGe, &accj); + secp256k1_pedersen_commitment_save(out, &outGe); + return 1; } int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context2* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) { diff --git a/src/secp256k1-mw/src/modules/surjection/main_impl.h b/src/secp256k1-mw/src/modules/surjection/main_impl.h index 416c59e1ac..5c94d99059 100644 --- a/src/secp256k1-mw/src/modules/surjection/main_impl.h +++ b/src/secp256k1-mw/src/modules/surjection/main_impl.h @@ -20,7 +20,7 @@ static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) size_t i; for (i = 0; i < count; i++) { #ifdef HAVE_BUILTIN_POPCOUNT - ret += __builtin_popcount(data[i]); + ret += __builtin_popcount(data[i]); #else ret += !!(data[i] & 0x1); ret += !!(data[i] & 0x2); diff --git a/src/streams.h b/src/streams.h index 8de7de4a54..a671c977c1 100644 --- a/src/streams.h +++ b/src/streams.h @@ -374,16 +374,16 @@ class CAutoFile CAutoFile& ignore(size_t nSize) { - if (!file) - throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL"); - unsigned char data[4096]; - while (nSize > 0) { - size_t nNow = std::min(nSize, sizeof(data)); - if (fread(data, 1, nNow, file) != nNow) - throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed"); - nSize -= nNow; - } - return (*this); + if (!file) + throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL"); + unsigned char data[4096]; + while (nSize > 0) { + size_t nNow = std::min(nSize, sizeof(data)); + if (fread(data, 1, nNow, file) != nNow) + throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed"); + nSize -= nNow; + } + return (*this); } CAutoFile& write(const char* pch, size_t nSize) diff --git a/src/txdb.h b/src/txdb.h index 8ffdaab9d9..c76519b128 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -54,7 +54,7 @@ class CBlockTreeDB : public CLevelDBWrapper public: bool WriteBlockIndex(const CDiskBlockIndex& blockindex); - bool WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo); + bool WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo); bool ReadBlockFileInfo(int nFile, CBlockFileInfo& fileinfo); bool ReadLastBlockFile(int& nFile); bool WriteReindexing(bool fReindex); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 9f0f4fc0b5..a8d7b33070 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -38,7 +38,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { - return ::GetPriority(tx, currentHeight); + return ::GetPriority(tx, currentHeight); } /** @@ -410,10 +410,10 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry) mapTx[hash] = entry; const CTransaction& tx = mapTx[hash].GetTx(); { - if (tx.IsCoinStake()) { - for (unsigned int i = 0; i < tx.vin.size(); i++) - mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); - } + if (tx.IsCoinStake()) { + for (unsigned int i = 0; i < tx.vin.size(); i++) + mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + } } nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); diff --git a/src/univalue/lib/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h index 74596aab6d..9219979d30 100644 --- a/src/univalue/lib/univalue_escapes.h +++ b/src/univalue/lib/univalue_escapes.h @@ -2,261 +2,261 @@ #ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H #define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H static const char *escapes[256] = { - "\\u0000", - "\\u0001", - "\\u0002", - "\\u0003", - "\\u0004", - "\\u0005", - "\\u0006", - "\\u0007", - "\\b", - "\\t", - "\\n", - "\\u000b", - "\\f", - "\\r", - "\\u000e", - "\\u000f", - "\\u0010", - "\\u0011", - "\\u0012", - "\\u0013", - "\\u0014", - "\\u0015", - "\\u0016", - "\\u0017", - "\\u0018", - "\\u0019", - "\\u001a", - "\\u001b", - "\\u001c", - "\\u001d", - "\\u001e", - "\\u001f", - NULL, - NULL, - "\\\"", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\\\", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "\\u007f", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", + "\\b", + "\\t", + "\\n", + "\\u000b", + "\\f", + "\\r", + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", + NULL, + NULL, + "\\\"", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\\\", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "\\u007f", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, }; #endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index f1f2e63b3d..24f1f605b9 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -20,16 +20,16 @@ try { \ (stmt); \ } catch (excMatch & e) { \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } #define BOOST_CHECK_NO_THROW(stmt) { \ try { \ (stmt); \ - } catch (...) { \ - assert(0); \ - } \ + } catch (...) { \ + assert(0); \ + } \ } BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) diff --git a/src/util.cpp b/src/util.cpp index dc621bc85c..a7b51d93a0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -253,7 +253,7 @@ bool LogAcceptCategory(const char* category) std::string FilterInjection(const std::string& str) { - //std::cout << "filtering" << std::endl; + //std::cout << "filtering" << std::endl; int n = str.length(); char char_array[n + 1]; strcpy(char_array, str.c_str()); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 74f87d3f70..2fabd47a7d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -138,7 +138,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) // Generate a new key if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(); if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); @@ -2495,7 +2495,7 @@ UniValue createprivacyaccount(const UniValue& params, bool fHelp) std::string stealthAddr; if (pwalletMain->EncodeStealthPublicAddress(viewAccount.vchPubKey, spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); + ret.push_back(Pair("stealthaddress", stealthAddr)); } break; } @@ -2693,7 +2693,7 @@ UniValue createprivacysubaddress(const UniValue& params, bool fHelp) std::string stealthAddr; if (pwalletMain->EncodeStealthPublicAddress(account.viewAccount.vchPubKey, account.spendAccount.vchPubKey, stealthAddr)) { - ret.push_back(Pair("stealthaddress", stealthAddr)); + ret.push_back(Pair("stealthaddress", stealthAddr)); } return ret; } @@ -2925,11 +2925,11 @@ UniValue showtxprivatekeys(const UniValue& params, bool fHelp) { UniValue ret(UniValue::VOBJ); CWalletDB db(pwalletMain->strWalletFile); for(int i = 0; i < 10; i++) { - std::string key = params[0].get_str() + std::to_string(i); - std::string secret; - if (db.ReadTxPrivateKey(key, secret)) { - ret.push_back(Pair(std::to_string(i), secret)); - } else break; + std::string key = params[0].get_str() + std::to_string(i); + std::string secret; + if (db.ReadTxPrivateKey(key, secret)) { + ret.push_back(Pair(std::to_string(i), secret)); + } else break; } return ret; } @@ -2984,10 +2984,10 @@ UniValue rescanwallettransactions(const UniValue& params, bool fHelp) { int nHeight = 0; if (params.size() == 1) { - nHeight = params[0].get_int(); + nHeight = params[0].get_int(); } if (!pwalletMain->RescanAfterUnlock(nHeight)) { - return "Failed to rescan"; + return "Failed to rescan"; } return "Done"; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 24801e3c64..5bf347f9c8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5400,54 +5400,54 @@ bool CWallet::estimateStakingConsolidationFees(CAmount& minFee, CAmount& maxFee) //finding all spendable UTXOs < MIN_STAKING CAmount total = 0; std::vector vCoins, underStakingThresholdCoins; - { - LOCK2(cs_main, cs_wallet); - { - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const uint256& wtxid = it->first; - const CWalletTx* pcoin = &(*it).second; - - int nDepth = pcoin->GetDepthInMainChain(false); - if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0) - continue; - if (nDepth == 0 && !pcoin->InMempool()) - continue; - for(size_t i = 0; i < pcoin->vout.size(); i++) { - if (pcoin->vout[i].IsEmpty()) continue; - isminetype mine = IsMine(pcoin->vout[i]); - if (mine == ISMINE_NO) - continue; - if (mine == ISMINE_WATCH_ONLY) - continue; - CAmount decodedAmount; - CKey decodedBlind; - RevealTxOutAmount(*pcoin, pcoin->vout[i], decodedAmount, decodedBlind); - - std::vector commitment; - if (!decodedBlind.IsValid()) { - unsigned char blind[32]; - CreateCommitmentWithZeroBlind(decodedAmount, blind, commitment); - } else { - CreateCommitment(decodedBlind.begin(), decodedAmount, commitment); - } - if (pcoin->vout[i].commitment != commitment) { + { + LOCK2(cs_main, cs_wallet); + { + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + const uint256& wtxid = it->first; + const CWalletTx* pcoin = &(*it).second; + + int nDepth = pcoin->GetDepthInMainChain(false); + if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0) + continue; + if (nDepth == 0 && !pcoin->InMempool()) + continue; + for(size_t i = 0; i < pcoin->vout.size(); i++) { + if (pcoin->vout[i].IsEmpty()) continue; + isminetype mine = IsMine(pcoin->vout[i]); + if (mine == ISMINE_NO) + continue; + if (mine == ISMINE_WATCH_ONLY) + continue; + CAmount decodedAmount; + CKey decodedBlind; + RevealTxOutAmount(*pcoin, pcoin->vout[i], decodedAmount, decodedBlind); + + std::vector commitment; + if (!decodedBlind.IsValid()) { + unsigned char blind[32]; + CreateCommitmentWithZeroBlind(decodedAmount, blind, commitment); + } else { + CreateCommitment(decodedBlind.begin(), decodedAmount, commitment); + } + if (pcoin->vout[i].commitment != commitment) { LogPrintf("%s: Commitment not match hash = %s, i = %d, commitment = %s, recomputed = %s, revealed mask = %s\n", __func__, pcoin->GetHash().GetHex(), i, HexStr(&pcoin->vout[i].commitment[0], &pcoin->vout[i].commitment[0] + 33), HexStr(&commitment[0], &commitment[0] + 33), HexStr(decodedBlind.begin(), decodedBlind.begin() + 32)); - continue; - } - - if (IsSpent(wtxid, i)) continue; - - { - COutPoint outpoint(wtxid, i); - if (inSpendQueueOutpoints.count(outpoint)) { - continue; - } - } - vCoins.push_back(COutput(pcoin, i, nDepth, true)); - total += decodedAmount; + continue; + } + + if (IsSpent(wtxid, i)) continue; + + { + COutPoint outpoint(wtxid, i); + if (inSpendQueueOutpoints.count(outpoint)) { + continue; + } + } + vCoins.push_back(COutput(pcoin, i, nDepth, true)); + total += decodedAmount; if (decodedAmount < MINIMUM_STAKE_AMOUNT) underStakingThresholdCoins.push_back(COutput(pcoin, i, nDepth, true)); - } - } + } + } } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 05923482f0..6c1ff288c1 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -217,10 +217,10 @@ enum StakingStatusError }; enum StakingMode { - STOPPED, //staking disabled or balance < 400k - STAKING_WITHOUT_CONSOLIDATION, - STAKING_WITH_CONSOLIDATION, - STAKING_WITH_CONSOLIDATION_WITH_STAKING_NEWW_FUNDS + STOPPED, //staking disabled or balance < 400k + STAKING_WITHOUT_CONSOLIDATION, + STAKING_WITH_CONSOLIDATION, + STAKING_WITH_CONSOLIDATION_WITH_STAKING_NEWW_FUNDS }; /** diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 6237a2e761..67aee45952 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -301,11 +301,11 @@ bool CWalletDB::ReadStakingStatus() { bool CWalletDB::WriteScannedBlockHeight(int height) { - return Write(std::string("scannedblockheight"), height); + return Write(std::string("scannedblockheight"), height); } bool CWalletDB::ReadScannedBlockHeight(int& height) { - return Read(std::string("scannedblockheight"), height); + return Read(std::string("scannedblockheight"), height); } bool CWalletDB::Write2FA(bool status) @@ -1175,21 +1175,21 @@ bool CWalletDB::WriteDestData(const std::string& address, const std::string& key bool CWalletDB::WriteTxPrivateKey(const std::string& outpointKey, const std::string& k) { - return Write(std::make_pair(std::string("txpriv"), outpointKey), k); + return Write(std::make_pair(std::string("txpriv"), outpointKey), k); } bool CWalletDB::ReadTxPrivateKey(const std::string& outpointKey, std::string& k) { - return Read(std::make_pair(std::string("txpriv"), outpointKey), k); + return Read(std::make_pair(std::string("txpriv"), outpointKey), k); } bool CWalletDB::WriteKeyImage(const std::string& outpointKey, const CKeyImage& k) { - return Write(std::make_pair(std::string("outpointkeyimage"), outpointKey), k); + return Write(std::make_pair(std::string("outpointkeyimage"), outpointKey), k); } bool CWalletDB::ReadKeyImage(const std::string& outpointKey, CKeyImage& k) { - return Read(std::make_pair(std::string("outpointkeyimage"), outpointKey), k); + return Read(std::make_pair(std::string("outpointkeyimage"), outpointKey), k); } From a7a2f7baef0ec9dc4a92db97ff105f67c3567d60 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Mar 2020 17:11:55 -0400 Subject: [PATCH 0293/1888] Bump version to v1.0.6.4 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fb7896227f..b2fb1d21cb 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 3) +define(_CLIENT_VERSION_BUILD, 4) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From a9f785efbe801c8a1efed123be55f056220ea80f Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Mar 2020 16:37:42 -0400 Subject: [PATCH 0294/1888] [Bug] Fix g_best_block_initialization in ABC --- src/init.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index b1e3515c5a..cfb531fe54 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1723,6 +1723,14 @@ bool AppInit2(bool isDaemon) CValidationState state; if (!ActivateBestChain(state)) strErrors << "Failed to connect best block"; + // update g_best_block if needed + { + LOCK(g_best_block_mutex); + if (g_best_block.IsNull() && chainActive.Tip()) { + g_best_block = chainActive.Tip()->GetBlockHash(); + g_best_block_cv.notify_all(); + } + } std::vector vImportFiles; if (mapArgs.count("-loadblock")) { From 1d4b9c33900e089d5e0488b9940d172a918b65d5 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Mar 2020 16:46:18 -0400 Subject: [PATCH 0295/1888] netbase: Make InterruptibleRecv return an error code instead of bool. Coming from upstream https://github.com/PIVX-Project/PIVX/commit/13f608582c1d941ad71cae49a79084f346da0938 --- src/netbase.cpp | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 8289fe88d4..1b048e5c87 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -239,6 +239,14 @@ struct timeval MillisToTimeval(int64_t nTimeout) return timeout; } +enum class IntrRecvError { + OK, + Timeout, + Disconnected, + NetworkError, + Interrupted +}; + /** * Read bytes from socket. This will either read the full number of bytes requested * or return False on error or timeout. @@ -250,7 +258,7 @@ struct timeval MillisToTimeval(int64_t nTimeout) * * @note This function requires that hSocket is in non-blocking mode. */ -bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket) +static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket) { int64_t curTime = GetTimeMillis(); int64_t endTime = curTime + timeout; @@ -263,12 +271,12 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock len -= ret; data += ret; } else if (ret == 0) { // Unexpected disconnection - return false; + return IntrRecvError::Disconnected; } else { // Other error or blocking int nErr = WSAGetLastError(); if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { if (!IsSelectableSocket(hSocket)) { - return false; + return IntrRecvError::NetworkError; } struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); fd_set fdset; @@ -276,16 +284,16 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock FD_SET(hSocket, &fdset); int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval); if (nRet == SOCKET_ERROR) { - return false; + return IntrRecvError::NetworkError; } } else { - return false; + return IntrRecvError::NetworkError; } } boost::this_thread::interruption_point(); curTime = GetTimeMillis(); } - return len == 0; + return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; } struct ProxyCredentials @@ -297,6 +305,7 @@ struct ProxyCredentials /** Connect using SOCKS5 (as described in RFC1928) */ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) { + IntrRecvError recvr; LogPrintf("SOCKS5 connecting %s\n", strDest); if (strDest.size() > 255) { CloseSocket(hSocket); @@ -319,7 +328,7 @@ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKE return error("Error sending to proxy"); } char pchRet1[2]; - if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading proxy response"); } @@ -344,7 +353,7 @@ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKE } LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); char pchRetA[2]; - if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading proxy authentication response"); } @@ -373,9 +382,9 @@ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKE return error("Error sending to proxy"); } char pchRet2[4]; - if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); - return error("Error reading proxy response"); + return error("Error while reading proxy response"); } if (pchRet2[0] != 0x05) { CloseSocket(hSocket); @@ -411,30 +420,30 @@ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKE char pchRet3[256]; switch (pchRet2[3]) { case 0x01: - ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); + recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x04: - ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); + recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x03: { - ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); - if (!ret) { + recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); + if (recvr != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); } int nRecv = pchRet3[0]; - ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); + recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); break; } default: CloseSocket(hSocket); return error("Error: malformed proxy response"); } - if (!ret) { + if (recvr != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); } - if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); return error("Error reading from proxy"); } From 151980bc4d83b72c96a49c1539866914d0e5547c Mon Sep 17 00:00:00 2001 From: lyricidal Date: Wed, 25 Mar 2020 16:47:28 -0400 Subject: [PATCH 0296/1888] netbase: Do not print an error on connection timeouts through proxy If a timeout happens while reading the proxy response, this effectively means we timed out while connecting to the remote node. This is very common for Tor, so do not print an error message. Coming from upstream https://github.com/PIVX-Project/PIVX/commit/3ddfe298375c2484ac281d8a6d731ad8616f3542 --- src/netbase.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 1b048e5c87..cc12e952ff 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -384,7 +384,14 @@ bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKE char pchRet2[4]; if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) { CloseSocket(hSocket); - return error("Error while reading proxy response"); + if (recvr == IntrRecvError::Timeout) { + /* If a timeout happens here, this effectively means we timed out while connecting + * to the remote node. This is very common for Tor, so do not print an + * error message. */ + return false; + } else { + return error("Error while reading proxy response"); + } } if (pchRet2[0] != 0x05) { CloseSocket(hSocket); From 1f5c509412216f460227b39598cfdfd513657dec Mon Sep 17 00:00:00 2001 From: lyricidal Date: Thu, 26 Mar 2020 15:26:30 -0400 Subject: [PATCH 0297/1888] Consolidate scattered max peer connection values into single declaration Coming from upstream https://github.com/PIVX-Project/PIVX/commit/19dd40a25f061fb8b16b9332826293f5d0b58a56 --- src/init.cpp | 4 ++-- src/net.cpp | 2 +- src/net.h | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index b1e3515c5a..0beecaba58 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -411,7 +411,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0)); strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); - strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), 125)); + strUsage += HelpMessageOpt("-maxconnections=", strprintf(_("Maintain at most connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=", strprintf(_("Maximum per-connection receive buffer, *1000 bytes (default: %u)"), 5000)); strUsage += HelpMessageOpt("-maxsendbuffer=", strprintf(_("Maximum per-connection send buffer, *1000 bytes (default: %u)"), 1000)); strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); @@ -915,7 +915,7 @@ bool AppInit2(bool isDaemon) // Make sure enough file descriptors are available int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); - nMaxConnections = GetArg("-maxconnections", 125); + nMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); if (nFD < MIN_CORE_FILEDESCRIPTORS) diff --git a/src/net.cpp b/src/net.cpp index d83bfb0690..ff3bcea5dc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -85,7 +85,7 @@ static CNode *pnodeLocalHost = NULL; uint64_t nLocalHostNonce = 0; static std::vector vhListenSocket; CAddrMan addrman; -int nMaxConnections = 125; +int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS; bool fAddressesInitialized = false; std::string strSubVersion; diff --git a/src/net.h b/src/net.h index c61d959004..983781c421 100644 --- a/src/net.h +++ b/src/net.h @@ -65,6 +65,8 @@ static const bool DEFAULT_UPNP = false; #endif /** The maximum number of entries in mapAskFor */ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; +/** The maximum number of peer connections to maintain. */ +static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); From 04bb418a00add3ec90cb6d5608aae25e78fb0757 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 23 Mar 2020 20:17:01 -0400 Subject: [PATCH 0298/1888] Add support for dnsseeds with option to filter by servicebits --- src/chainparams.cpp | 10 ++++++++++ src/chainparams.h | 7 +++++-- src/net.cpp | 5 +++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1530c6cd84..82c315d7ce 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -25,6 +25,14 @@ struct SeedSpec6 { #include "chainparamsseeds.h" +std::string CDNSSeedData::getHost(uint64_t requiredServiceBits) const { + //use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK) + if (!supportsServiceBitsFiltering || requiredServiceBits == NODE_NETWORK) + return host; + + return strprintf("x%x.%s", requiredServiceBits, host); +} + /** * Main network */ @@ -250,6 +258,7 @@ class CMainParams : public CChainParams assert(hashGenesisBlock == uint256("0000039a711dba61e12c29fb86542fa059e9616aafe9b4c61e065d393f31535e")); assert(genesis.hashMerkleRoot == uint256("4dc798fa29a037570075a87a39c9a54c210f005c4c59c72f32036a87273f4cf8")); + // nodes with support for servicebits filtering should be at the top vSeeds.push_back(CDNSSeedData("seed.dapscoin.com", "seed.dapscoin.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed1.dapscoin.com", "seed1.dapscoin.com")); // Single node address vSeeds.push_back(CDNSSeedData("seed2.dapscoin.com", "seed2.dapscoin.com")); // Single node address @@ -373,6 +382,7 @@ class CTestNetParams : public CMainParams vFixedSeeds.clear(); vSeeds.clear(); + // nodes with support for servicebits filtering should be at the top vSeeds.push_back(CDNSSeedData("192.168.2.202", "192.168.2.202")); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 139); // Testnet dapscoin addresses start with 'x' or 'y' diff --git a/src/chainparams.h b/src/chainparams.h index 2f95a04a43..b3e084f7b8 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -19,9 +19,12 @@ typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; -struct CDNSSeedData { +class CDNSSeedData { +public: std::string name, host; - CDNSSeedData(const std::string& strName, const std::string& strHost) : name(strName), host(strHost) {} + bool supportsServiceBitsFiltering; + std::string getHost(uint64_t requiredServiceBits) const; + CDNSSeedData(const std::string& strName, const std::string& strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {} }; /** diff --git a/src/net.cpp b/src/net.cpp index ff3bcea5dc..e2408d442e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1219,11 +1219,12 @@ void ThreadDNSAddressSeed() { } else { vector vIPs; vector vAdd; - if (LookupHost(seed.host.c_str(), vIPs, 0, true)) { + uint64_t requiredServiceBits = NODE_NETWORK; + if (LookupHost(seed.getHost(requiredServiceBits).c_str(), vIPs, 0, true)) { for (CNetAddr & ip : vIPs) { int nOneDay = 24 * 3600; - CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); + CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits); addr.nTime = GetTime() - 3 * nOneDay - GetRand(4 * nOneDay); // use a random age between 3 and 7 days old vAdd.push_back(addr); From 8ef621ec7b7fbd48a61d45d9305810aaab959b3b Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 30 Mar 2020 08:41:56 -0400 Subject: [PATCH 0299/1888] [GUI] clientModel return cached IsImporting & IsReindexing fields. --- src/qt/clientmodel.cpp | 3 ++- src/qt/clientmodel.h | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f98024c5d0..25fb08a2c6 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -167,7 +167,7 @@ void ClientModel::updateAlert() bool ClientModel::inInitialBlockDownload() const { - return IsInitialBlockDownload(); + return cachedInitialSync; } enum BlockSource ClientModel::getBlockSource() const @@ -252,6 +252,7 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB clientmodel->setCacheTip(pIndex); clientmodel->setCacheImporting(fImporting); clientmodel->setCacheReindexing(fReindex); + clientmodel->setCacheInitialSync(initialSync); Q_EMIT clientmodel->numBlocksChanged(pIndex->nHeight); nLastBlockTipUpdateNotification = now; } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 1f713286ff..7dd0fb428c 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -84,9 +84,10 @@ class ClientModel : public QObject bool getTorInfo(std::string& ip_port) const; - void setCacheTip(const CBlockIndex* const tip) { cacheTip = tip; }; - void setCacheReindexing(bool reindex) { cachedReindexing = reindex; }; - void setCacheImporting(bool import) { cachedImporting = import; }; + void setCacheTip(const CBlockIndex* const tip) { cacheTip = tip; } + void setCacheReindexing(bool reindex) { cachedReindexing = reindex; } + void setCacheImporting(bool import) { cachedImporting = import; } + void setCacheInitialSync(bool _initialSync) { cachedInitialSync = _initialSync; } private: OptionsModel* optionsModel; @@ -97,6 +98,7 @@ class ClientModel : public QObject QString cachedMasternodeCountString; bool cachedReindexing; bool cachedImporting; + bool cachedInitialSync; int numBlocksAtStartup; From 4aa1eb38251e5575cfe504ff8960701b679c13f2 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 3 Apr 2020 08:35:33 -0400 Subject: [PATCH 0300/1888] [GUI] ClientModel try to initialize cacheTip if it's null. Fixing cacheTip not sync with the back-end information if the node has no connection and the tip signal was not broadcasted. --- src/qt/clientmodel.cpp | 8 ++++++-- src/qt/clientmodel.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 25fb08a2c6..32767e127e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -83,9 +83,13 @@ QString ClientModel::getMasternodeCountString() const return tr("Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5)").arg(QString::number((int)mnodeman.size())).arg(QString::number((int)ipv4)).arg(QString::number((int)ipv6)).arg(QString::number((int)onion)).arg(QString::number((int)nUnknown)); } -int ClientModel::getNumBlocks() const +int ClientModel::getNumBlocks() { - return cacheTip == nullptr ? 0 : cacheTip->nHeight; + if (!cacheTip) { + cacheTip = WITH_LOCK(cs_main, return chainActive.Tip();); + } + + return cacheTip ? cacheTip->nHeight : 0; } int ClientModel::getNumBlocksAtStartup() diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 7dd0fb428c..fbf50c0f14 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -59,7 +59,7 @@ class ClientModel : public QObject QString getMasternodeCountString() const; // from cached block index - int getNumBlocks() const; + int getNumBlocks(); QDateTime getLastBlockDate() const; QString getLastBlockHash() const; int getChainHeight() const; @@ -94,7 +94,7 @@ class ClientModel : public QObject PeerTableModel* peerTableModel; BanTableModel *banTableModel; - const CBlockIndex* cacheTip; + const CBlockIndex* cacheTip{nullptr}; QString cachedMasternodeCountString; bool cachedReindexing; bool cachedImporting; From 6d4cba5e752cc6aaf900791632f303b0c84b5c08 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Fri, 3 Apr 2020 16:56:17 -0400 Subject: [PATCH 0301/1888] [Depends] Update OpenSSL download URL The URL for OpenSSL 1.0.1k has changed, so update it here. --- depends/packages/openssl.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index fdfd372806..432f19bd35 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,6 +1,6 @@ package=openssl $(package)_version=1.0.1k -$(package)_download_path=https://www.openssl.org/source +$(package)_download_path=https://www.openssl.org/source/old $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c From d51463cf0c19d075962c2f3a93a426f56b319396 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Mon, 6 Apr 2020 13:33:52 -0400 Subject: [PATCH 0302/1888] [GUI] Update MNs GUI count every 40 seconds. --- src/qt/clientmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 32767e127e..b7b31a1ef9 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -50,7 +50,7 @@ ClientModel::ClientModel(OptionsModel* optionsModel, QObject* parent) : QObject( pollMnTimer = new QTimer(this); connect(pollMnTimer, SIGNAL(timeout()), this, SLOT(updateMnTimer())); // no need to update as frequent as data for balances/txes/blocks - pollMnTimer->start(MODEL_UPDATE_DELAY * 4); + pollMnTimer->start(MODEL_UPDATE_DELAY * 40); subscribeToCoreSignals(); } From 5feb37ff1a21e9c5fbea3f8995b4eae642bdffe9 Mon Sep 17 00:00:00 2001 From: daps_spain <35898975+lopeed@users.noreply.github.com> Date: Sat, 11 Apr 2020 19:34:23 +0200 Subject: [PATCH 0303/1888] Fix size to low resolution --- src/qt/bitcoingui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0ab9b5b9b5..80deefc36c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -63,9 +63,9 @@ #include #include -#define BASE_WINDOW_WIDTH 1147 +#define BASE_WINDOW_WIDTH 800 #define BASE_WINDOW_HEIGHT 768 -#define BASE_WINDOW_MIN_HEIGHT 720 +#define BASE_WINDOW_MIN_HEIGHT 600 const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; From 68a1eb526fcb4a1a521452bda7f80f07e2df917d Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 14 Apr 2020 08:57:04 -0400 Subject: [PATCH 0304/1888] Bump version to v1.0.6.5 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b2fb1d21cb..de49a2efef 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 6) -define(_CLIENT_VERSION_BUILD, 4) +define(_CLIENT_VERSION_BUILD, 5) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) From 590d64901bc844fc3c7e11817395fb801f5e7889 Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 14 Apr 2020 18:45:06 -0400 Subject: [PATCH 0305/1888] Update version.txt to v1.0.6.5 for Check For Updates --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6990b2ceea..a262b0d849 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.6.0 \ No newline at end of file +1.0.6.5 \ No newline at end of file From c9bd1a0cbfa1935a7f545656e8791f309080b98a Mon Sep 17 00:00:00 2001 From: lyricidal Date: Tue, 14 Apr 2020 18:48:53 -0400 Subject: [PATCH 0306/1888] Update translations --- src/qt/dapscoinstrings.cpp | 182 +++----- src/qt/locale/dapscoin_en.ts | 820 +++++++++++++---------------------- 2 files changed, 353 insertions(+), 649 deletions(-) diff --git a/src/qt/dapscoinstrings.cpp b/src/qt/dapscoinstrings.cpp index b477798732..80ee4ae271 100644 --- a/src/qt/dapscoinstrings.cpp +++ b/src/qt/dapscoinstrings.cpp @@ -9,9 +9,6 @@ #define UNUSED #endif static const char UNUSED *dapscoin_strings[] = { -QT_TRANSLATE_NOOP("dapscoin-core", " mints deleted\n"), -QT_TRANSLATE_NOOP("dapscoin-core", " mints updated, "), -QT_TRANSLATE_NOOP("dapscoin-core", " unconfirmed transactions removed\n"), QT_TRANSLATE_NOOP("dapscoin-core", "" "(1 = keep tx meta data e.g. account owner and payment request information, 2 " "= drop tx meta data)"), @@ -20,9 +17,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or " "a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"An error occurred while setting up the RPC address %s port %u for listening: " -"%s"), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Bind to given address and always listen on it. Use [host]:port notation for " "IPv6"), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -33,10 +27,7 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "notation for IPv6. This option can be specified multiple times (default: " "bind to all interfaces)"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Calculated accumulator checkpoint is not what is recorded by block index"), -QT_TRANSLATE_NOOP("dapscoin-core", "" -"Cannot obtain a lock on data directory %s. DAPS is probably already " -"running."), +"Cannot obtain a lock on data directory %s. DAPS is probably already running."), QT_TRANSLATE_NOOP("dapscoin-core", "" "Change automatic finalized budget voting behavior. mode=auto: Vote for only " "exact finalized budget match to my generated budget. (string, default: auto)"), @@ -50,9 +41,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Delete all wallet transactions and only recover those parts of the " "blockchain through -rescan on startup"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Disable all DAPS specific functionality (Masternodes, SwiftX, " -"Budgeting) (0-1, default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Distributed under the MIT software license, see the accompanying file " "COPYING or ."), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -67,11 +55,6 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "in your wallet were already spent, such as if you used a copy of wallet.dat " "and coins were spent in the copy but not marked as spent here."), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Error: This transaction requires a transaction fee of at least %s because of " -"its amount, complexity, or use of recently received funds!"), -QT_TRANSLATE_NOOP("dapscoin-core", "" -"Error: Unsupported argument -checklevel found. Checklevel must be level 4."), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Error: Unsupported argument -socks found. Setting SOCKS version isn't " "possible anymore, only SOCKS5 proxies are supported."), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -84,6 +67,9 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Execute command when the best block changes (%s in cmd is replaced by block " "hash)"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"Execute command when the best block changes and its size is over (%s in cmd " +"is replaced by block hash, %d with the block size)"), +QT_TRANSLATE_NOOP("dapscoin-core", "" "Fees (in DAPS/Kb) smaller than this are considered zero fee for relaying " "(default: %s)"), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -93,23 +79,20 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Flush database activity from memory pool to disk log every megabytes " "(default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Found unconfirmed denominated outputs, will wait till they confirm to " -"continue."), -QT_TRANSLATE_NOOP("dapscoin-core", "" "If paytxfee is not set, include enough fee so transactions begin " "confirmation on average within n blocks (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "In this mode -genproclimit controls how many blocks are generated " "immediately."), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Insufficient or insufficient confirmed funds, you might need to wait a few " -"minutes and try again."), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay " "fee of %s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "Keep the specified amount available for spending at all times (default: 0)"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"Loading... Please do not interrupt this process as it could lead to a " +"corrupt wallet."), +QT_TRANSLATE_NOOP("dapscoin-core", "" "Log transaction priority and fee per kB when mining blocks (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "Maintain a full transaction index, used by the getrawtransaction rpc call " @@ -123,14 +106,8 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" QT_TRANSLATE_NOOP("dapscoin-core", "" "Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Obfuscation uses exact denominated amounts to send funds, you might simply " -"need to anonymize some more coins."), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Output debugging information (default: %u, supplying is optional)"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Preferred Denomination" -"(1/5/10/50/100/500/1000/5000), 0 for no preference. default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Query for peer addresses via DNS lookup, if low on addresses (default: 1 " "unless -connect)"), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -139,6 +116,9 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" QT_TRANSLATE_NOOP("dapscoin-core", "" "Require high priority for relaying free or low-fee transactions (default:%u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"Rescanning... Please do not interrupt this process as it could lead to a " +"corrupt wallet."), +QT_TRANSLATE_NOOP("dapscoin-core", "" "Send trace/debug info to console instead of debug.log file (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" "Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), @@ -154,8 +134,13 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" QT_TRANSLATE_NOOP("dapscoin-core", "" "Support filtering of blocks and transaction with bloom filters (default: %u)"), QT_TRANSLATE_NOOP("dapscoin-core", "" -"SwiftX requires inputs with at least 6 confirmations, you might need to wait " -"a few minutes and try again."), +"The block database contains a block which appears to be from the future. " +"This may be due to your computer's date and time being set incorrectly. Only " +"rebuild the block database if you are sure that your computer's date and " +"time are correct"), +QT_TRANSLATE_NOOP("dapscoin-core", "" +"There is an internal error in generating bulletproofs. Please try again " +"later."), QT_TRANSLATE_NOOP("dapscoin-core", "" "This is a pre-release test build - use at your own risk - do not use for " "staking or merchant applications!"), @@ -164,26 +149,11 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "the OpenSSL Toolkit and cryptographic software " "written by Eric Young and UPnP software written by Thomas Bernard."), QT_TRANSLATE_NOOP("dapscoin-core", "" -"To use dapscoind, or the -server option to dapscoin-qt, you must set an rpcpassword " -"in the configuration file:\n" -"%s\n" -"It is recommended you use the following random password:\n" -"rpcuser=dapscoinrpc\n" -"rpcpassword=%s\n" -"(you do not need to remember this password)\n" -"The username and password MUST NOT be the same.\n" -"If the file does not exist, create it with owner-readable-only file " -"permissions.\n" -"It is also recommended to set alertnotify so you are notified of problems;\n" -"for example: alertnotify=echo %%s | mail -s \"DAPS Alert\" admin@foo.com\n"), +"Total length of network version string (%i) exceeds maximum length (%i). " +"Reduce the number or size of uacomments."), QT_TRANSLATE_NOOP("dapscoin-core", "" "Unable to bind to %s on this computer. DAPS is probably already running."), QT_TRANSLATE_NOOP("dapscoin-core", "" -"Unable to locate enough Obfuscation denominated funds for this transaction."), -QT_TRANSLATE_NOOP("dapscoin-core", "" -"Unable to locate enough Obfuscation non-denominated funds for this " -"transaction that are not equal 10000 DAPS."), -QT_TRANSLATE_NOOP("dapscoin-core", "" "Unable to locate enough funds for this transaction that are not equal 10000 " "DAPS."), QT_TRANSLATE_NOOP("dapscoin-core", "" @@ -218,6 +188,16 @@ QT_TRANSLATE_NOOP("dapscoin-core", "" "Whitelisted peers cannot be DoS banned and their transactions are always " "relayed, even if they are already in the mempool, useful e.g. for a gateway"), QT_TRANSLATE_NOOP("dapscoin-core", "" +"You have attempted to send a total value that is comprised of more than 50 " +"smaller deposits. This is a rare occurrence, and lowering the total value " +"sent, or sending the same total value in two separate transactions will " +"usually work around this limitation."), +QT_TRANSLATE_NOOP("dapscoin-core", "" +"You have attempted to send more than 50 UTXOs in a single transaction. This " +"is a rare occurrence, and to work around this limitation, please either " +"lower the total amount of the transaction, or send two separate transactions " +"with 50% of your total desired amount."), +QT_TRANSLATE_NOOP("dapscoin-core", "" "You must specify a masternodeprivkey in the configuration. Please see " "documentation for help."), QT_TRANSLATE_NOOP("dapscoin-core", "(53572 could be used only on mainnet)"), @@ -228,25 +208,26 @@ QT_TRANSLATE_NOOP("dapscoin-core", " can be:"), QT_TRANSLATE_NOOP("dapscoin-core", "Accept command line and JSON-RPC commands"), QT_TRANSLATE_NOOP("dapscoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"), QT_TRANSLATE_NOOP("dapscoin-core", "Accept public REST requests (default: %u)"), -QT_TRANSLATE_NOOP("dapscoin-core", "Acceptable ciphers (default: %s)"), QT_TRANSLATE_NOOP("dapscoin-core", "Add a node to connect to and attempt to keep the connection open"), +QT_TRANSLATE_NOOP("dapscoin-core", "All inputs should have the same number of decoys"), QT_TRANSLATE_NOOP("dapscoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), -QT_TRANSLATE_NOOP("dapscoin-core", "Already have that input."), QT_TRANSLATE_NOOP("dapscoin-core", "Always query for peer addresses via DNS lookup (default: %u)"), +QT_TRANSLATE_NOOP("dapscoin-core", "Append comment to the user agent string"), QT_TRANSLATE_NOOP("dapscoin-core", "Attempt to force blockchain corruption recovery"), QT_TRANSLATE_NOOP("dapscoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), QT_TRANSLATE_NOOP("dapscoin-core", "Automatically create Tor hidden service (default: %d)"), QT_TRANSLATE_NOOP("dapscoin-core", "Block creation options:"), -QT_TRANSLATE_NOOP("dapscoin-core", "Calculating missing accumulators..."), -QT_TRANSLATE_NOOP("dapscoin-core", "Can't denominate: no compatible inputs left."), -QT_TRANSLATE_NOOP("dapscoin-core", "Can't find random Masternode."), -QT_TRANSLATE_NOOP("dapscoin-core", "Can't mix while sync in progress."), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot compute LIJ for ring signature in secp256k1_ec_pubkey_tweak_add"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot compute LIJ for ring signature in secp256k1_ec_pubkey_tweak_mul"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot compute RIJ for ring signature in secp256k1_ec_pubkey_tweak_mul"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot compute two elements and serialize it to pubkey"), QT_TRANSLATE_NOOP("dapscoin-core", "Cannot downgrade wallet"), -QT_TRANSLATE_NOOP("dapscoin-core", "Cannot resolve -bind address: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Cannot resolve -externalip address: '%s'"), -QT_TRANSLATE_NOOP("dapscoin-core", "Cannot resolve -whitebind address: '%s'"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot extract public key from script pubkey"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot find corresponding private key"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot parse the commitment for inputs"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot parse the commitment for transaction fee"), +QT_TRANSLATE_NOOP("dapscoin-core", "Cannot resolve -%s address: '%s'"), QT_TRANSLATE_NOOP("dapscoin-core", "Cannot write default address"), -QT_TRANSLATE_NOOP("dapscoin-core", "Collateral not valid."), QT_TRANSLATE_NOOP("dapscoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("dapscoin-core", "Connect through SOCKS5 proxy"), QT_TRANSLATE_NOOP("dapscoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), @@ -256,8 +237,8 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2014-%i The Dash Core Develope QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2015-%i The PIVX Core Developers"), QT_TRANSLATE_NOOP("dapscoin-core", "Copyright (C) 2018-%i The DAPS Project developers"), QT_TRANSLATE_NOOP("dapscoin-core", "Corrupted block database detected"), -QT_TRANSLATE_NOOP("dapscoin-core", "Could not parse -rpcbind value %s as network address"), QT_TRANSLATE_NOOP("dapscoin-core", "Could not parse masternode.conf"), +QT_TRANSLATE_NOOP("dapscoin-core", "Currently the Number of supported recipients must be 1"), QT_TRANSLATE_NOOP("dapscoin-core", "Debugging/Testing options:"), QT_TRANSLATE_NOOP("dapscoin-core", "Delete blockchain folders and resync from scratch"), QT_TRANSLATE_NOOP("dapscoin-core", "Disable OS notifications for incoming transactions (default: %u)"), @@ -276,8 +257,8 @@ QT_TRANSLATE_NOOP("dapscoin-core", "Enable publish raw transaction (locked via S QT_TRANSLATE_NOOP("dapscoin-core", "Enable publish raw transaction in