diff --git a/src/Makefile.am b/src/Makefile.am index 3fb8890b5..206d28698 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -177,6 +177,7 @@ BITCOIN_CORE_H = \ script/sigcache.h \ script/sign.h \ script/standard.h \ + script/ismine.h \ serialize.h \ spentindex.h \ streams.h \ @@ -217,7 +218,6 @@ BITCOIN_CORE_H = \ wallet/paymentdisclosuredb.h \ wallet/rpcwallet.h \ wallet/wallet.h \ - wallet/wallet_ismine.h \ wallet/walletdb.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ @@ -266,6 +266,7 @@ libbitcoin_server_a_SOURCES = \ rpc/rawtransaction.cpp \ rpc/server.cpp \ script/sigcache.cpp \ + script/ismine.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ @@ -312,7 +313,6 @@ libbitcoin_wallet_a_SOURCES = \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ - wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c7b0c9749..fe05248f5 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -108,9 +108,11 @@ BITCOIN_TESTS =\ if ENABLE_WALLET BITCOIN_TESTS += \ - test/accounting_tests.cpp \ + wallet/test/wallet_test_fixture.cpp \ + wallet/test/wallet_test_fixture.h \ + wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ - test/rpc_wallet_tests.cpp + wallet/test/rpc_wallet_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) diff --git a/src/init.cpp b/src/init.cpp index fd4824fbc..2c4727a56 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -77,16 +77,12 @@ extern void ThreadSendAlert(); ZCJoinSplit* pzcashParams = NULL; -#ifdef ENABLE_WALLET -CWallet* pwalletMain = NULL; -#endif bool fFeeEstimatesInitialized = false; static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_DISABLE_SAFEMODE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; -static const char * const DEFAULT_WALLET_DAT = "wallet.dat"; #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -411,27 +407,7 @@ std::string HelpMessage(HelpMessageMode mode) " " + _("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")); #ifdef ENABLE_WALLET - strUsage += HelpMessageGroup(_("Wallet options:")); - strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); - strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), DEFAULT_KEYPOOL_SIZE)); - strUsage += HelpMessageOpt("-migration", _("Enable the Sprout to Sapling migration")); - strUsage += HelpMessageOpt("-migrationdestaddress=", _("Set the Sapling migration address")); - strUsage += HelpMessageOpt("-mintxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), - CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); - strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), - CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); - strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat on startup")); - strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); - strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); - strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (min: %u, default: %u (pre-Blossom) or %u (post-Blossom))"), TX_EXPIRING_SOON_THRESHOLD + 1, DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA)); - strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); - strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); - strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); - strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); - strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + - " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + strUsage += CWallet::GetWalletHelpString(showDebug); #endif #if ENABLE_ZMQ @@ -454,16 +430,10 @@ std::string HelpMessage(HelpMessageMode mode) if (showDebug) { strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED)); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); -#endif strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE)); strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE)); strUsage += HelpMessageOpt("-dropmessagestest=", "Randomly drop 1 of every network messages"); strUsage += HelpMessageOpt("-fuzzmessagestest=", "Randomly fuzz 1 of every network messages"); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); -#endif strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT)); strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)"); } @@ -490,9 +460,6 @@ std::string HelpMessage(HelpMessageMode mode) if (showDebug) { strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY)); -#ifdef ENABLE_WALLET - strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); -#endif } // strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); @@ -1042,63 +1009,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #ifdef ENABLE_WALLET - if (mapArgs.count("-mintxfee")) - { - CAmount n = 0; - if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) - CWallet::minTxFee = CFeeRate(n); - else - return InitError(strprintf(_("Invalid amount for -mintxfee=: '%s'"), mapArgs["-mintxfee"])); - } - if (mapArgs.count("-paytxfee")) - { - CAmount nFeePerK = 0; - if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), mapArgs["-paytxfee"])); - if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); - payTxFee = CFeeRate(nFeePerK, 1000); - if (payTxFee < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), - mapArgs["-paytxfee"], ::minRelayTxFee.ToString())); - } - } - if (mapArgs.count("-maxtxfee")) - { - CAmount nMaxFee = 0; - if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s'"), mapArgs["-maptxfee"])); - if (nMaxFee > HIGH_MAX_TX_FEE) - InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); - maxTxFee = nMaxFee; - if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) - { - return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), - mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); - } - } - nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); - if (mapArgs.count("-txexpirydelta")) { - int64_t expiryDelta = atoi64(mapArgs["-txexpirydelta"]); - uint32_t minExpiryDelta = TX_EXPIRING_SOON_THRESHOLD + 1; - if (expiryDelta < minExpiryDelta) { - return InitError(strprintf(_("Invalid value for -txexpirydelta='%u' (must be least %u)"), expiryDelta, minExpiryDelta)); - } - expiryDeltaArg = expiryDelta; - } - bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); - fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); - - std::string strWalletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); - // Check Sapling migration address if set and is a valid Sapling address - if (mapArgs.count("-migrationdestaddress")) { - std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; - libzcash::PaymentAddress address = DecodePaymentAddress(migrationDestAddress); - if (boost::get(&address) == nullptr) { - return InitError(_("-migrationdestaddress must be a valid Sapling address.")); - } - } + if (!CWallet::ParameterInteraction()) + return false; #endif // ENABLE_WALLET fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); @@ -1175,11 +1087,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Initialization sanity check failed. Zcash is shutting down.")); std::string strDataDir = GetDataDir().string(); -#ifdef ENABLE_WALLET - // Wallet file must be a plain filename without a directory - if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) - return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir)); -#endif + // Make sure only a single Bitcoin process is using the data directory. boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. @@ -1255,20 +1163,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET if (!fDisableWallet) { - LogPrintf("Using wallet %s\n", strWalletFile); - uiInterface.InitMessage(_("Verifying wallet...")); - - std::string warningString; - std::string errorString; - - if (!CWallet::Verify(strWalletFile, warningString, errorString)) + if (!CWallet::Verify()) return false; - - if (!warningString.empty()) - InitWarning(warningString); - if (!errorString.empty()) - return InitError(errorString); - } // (!fDisableWallet) #endif // ENABLE_WALLET // ********************************************************* Step 6: network initialization @@ -1593,164 +1489,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); } else { - - // needed to restore wallet transaction meta data after -zapwallettxes - std::vector vWtx; - - if (GetBoolArg("-zapwallettxes", false)) { - uiInterface.InitMessage(_("Zapping all transactions from wallet...")); - - pwalletMain = new CWallet(strWalletFile); - DBErrors nZapWalletRet = pwalletMain->ZapWalletTx(vWtx); - if (nZapWalletRet != DB_LOAD_OK) { - uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted")); - return false; - } - - delete pwalletMain; - pwalletMain = NULL; - } - - uiInterface.InitMessage(_("Loading wallet...")); - - nStart = GetTimeMillis(); - bool fFirstRun = true; - pwalletMain = new CWallet(strWalletFile); - DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) - { - if (nLoadWalletRet == DB_CORRUPT) - strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; - else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) - { - string msg(_("error reading wallet.dat! All keys read correctly, but transaction data" - " or address book entries might be missing or incorrect.")); - InitWarning(msg); - } - else if (nLoadWalletRet == DB_TOO_NEW) - strErrors << _("Error loading wallet.dat: Wallet requires newer version of Zcash") << "\n"; - else if (nLoadWalletRet == DB_NEED_REWRITE) - { - strErrors << _("Wallet needed to be rewritten: restart Zcash to complete") << "\n"; - LogPrintf("%s", strErrors.str()); - return InitError(strErrors.str()); - } - else - strErrors << _("Error loading wallet.dat") << "\n"; - } - - if (GetBoolArg("-upgradewallet", fFirstRun)) - { - int nMaxVersion = GetArg("-upgradewallet", 0); - if (nMaxVersion == 0) // the -upgradewallet without argument case - { - LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = CLIENT_VERSION; - pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately - } - else - LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); - if (nMaxVersion < pwalletMain->GetVersion()) - strErrors << _("Cannot downgrade wallet") << "\n"; - pwalletMain->SetMaxVersion(nMaxVersion); - } - - if (!pwalletMain->HaveHDSeed()) - { - // We can't set the new HD seed until the wallet is decrypted. - // https://github.com/zcash/zcash/issues/3607 - if (!pwalletMain->IsCrypted()) { - // generate a new HD seed - pwalletMain->GenerateNewSeed(); - } - } - - // Set sapling migration status - pwalletMain->fSaplingMigrationEnabled = GetBoolArg("-migration", false); - - if (fFirstRun) - { - // Create new keyUser and set as default key - CPubKey newDefaultKey; - 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("%s", strErrors.str()); - LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); - - RegisterValidationInterface(pwalletMain); - - CBlockIndex *pindexRescan = chainActive.Tip(); - if (clearWitnessCaches || GetBoolArg("-rescan", false)) - { - pwalletMain->ClearNoteWitnessCache(); - pindexRescan = chainActive.Genesis(); - } - else - { - CWalletDB walletdb(strWalletFile); - CBlockLocator locator; - if (walletdb.ReadBestBlock(locator)) - pindexRescan = FindForkInGlobalIndex(chainActive, locator); - else - pindexRescan = chainActive.Genesis(); - } - if (chainActive.Tip() && chainActive.Tip() != pindexRescan) - { - // We can't rescan beyond non-pruned blocks, so stop and throw an error. - // This might happen if a user uses a old wallet within a pruned node, - // or if they ran -disablewallet for a longer time, then decided to re-enable. - if (fPruneMode) - { - CBlockIndex *block = chainActive.Tip(); - while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) - block = block->pprev; - - if (pindexRescan != block) - return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); - } - - 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); - pwalletMain->SetBestChain(chainActive.GetLocator()); - nWalletDBUpdated++; - - // Restore wallet transaction metadata after -zapwallettxes=1 - if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") - { - CWalletDB walletdb(strWalletFile); - - BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) - { - uint256 hash = wtxOld.GetHash(); - std::map::iterator mi = pwalletMain->mapWallet.find(hash); - if (mi != pwalletMain->mapWallet.end()) - { - const CWalletTx* copyFrom = &wtxOld; - CWalletTx* copyTo = &mi->second; - copyTo->mapValue = copyFrom->mapValue; - copyTo->vOrderForm = copyFrom->vOrderForm; - copyTo->nTimeReceived = copyFrom->nTimeReceived; - copyTo->nTimeSmart = copyFrom->nTimeSmart; - copyTo->fFromMe = copyFrom->fFromMe; - copyTo->strFromAccount = copyFrom->strFromAccount; - copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); - } - } - } - } - pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); - } // (!fDisableWallet) + CWallet::InitLoadWallet(clearWitnessCaches); + if (!pwalletMain) + return false; + } #else // ENABLE_WALLET LogPrintf("No wallet support compiled in!\n"); #endif // !ENABLE_WALLET diff --git a/src/init.h b/src/init.h index 8d1d92b9e..1f3b1aea2 100644 --- a/src/init.h +++ b/src/init.h @@ -18,7 +18,6 @@ namespace boost class thread_group; } // namespace boost -extern CWallet* pwalletMain; extern ZCJoinSplit* pzcashParams; void StartShutdown(); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 5bf9cc5e3..727a30c82 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -21,6 +21,9 @@ #include "txmempool.h" #include "util.h" #include "validationinterface.h" +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" +#endif #include diff --git a/src/wallet/wallet_ismine.cpp b/src/script/ismine.cpp similarity index 99% rename from src/wallet/wallet_ismine.cpp rename to src/script/ismine.cpp index 7631f1d91..b0d452cb1 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/script/ismine.cpp @@ -3,7 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php . -#include "wallet_ismine.h" +#include "ismine.h" #include "key.h" #include "keystore.h" diff --git a/src/wallet/wallet_ismine.h b/src/script/ismine.h similarity index 90% rename from src/wallet/wallet_ismine.h rename to src/script/ismine.h index 56eb86b30..be437802c 100644 --- a/src/wallet/wallet_ismine.h +++ b/src/script/ismine.h @@ -3,8 +3,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php . -#ifndef BITCOIN_WALLET_WALLET_ISMINE_H -#define BITCOIN_WALLET_WALLET_ISMINE_H +#ifndef BITCOIN_SCRIPT_ISMINE_H +#define BITCOIN_SCRIPT_ISMINE_H #include "key.h" #include "script/standard.h" @@ -30,4 +30,4 @@ typedef uint8_t isminefilter; isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest); -#endif // BITCOIN_WALLET_WALLET_ISMINE_H +#endif // BITCOIN_SCRIPT_ISMINE_H diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index f61d54734..8789549dd 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -10,12 +10,10 @@ #include "script/script_error.h" #include "script/interpreter.h" #include "script/sign.h" +#include "script/ismine.h" #include "uint256.h" #include "test/test_bitcoin.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet_ismine.h" -#endif #include #include @@ -215,10 +213,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); -#endif } { vector solutions; @@ -230,10 +226,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); -#endif } { vector solutions; @@ -244,11 +238,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); -#endif } { vector solutions; @@ -263,11 +255,9 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired == 1); -#ifdef ENABLE_WALLET BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); -#endif } { vector solutions; diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index c3e09444b..ba6fbc322 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -11,12 +11,9 @@ #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" +#include "script/ismine.h" #include "test/test_bitcoin.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet_ismine.h" -#endif - #include #include @@ -106,9 +103,7 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast(Conse txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; -#ifdef ENABLE_WALLET BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); -#endif } for (int i = 0; i < 8; i++) { @@ -210,9 +205,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast(Consen txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].scriptPubKey = inner[i]; -#ifdef ENABLE_WALLET BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); -#endif } for (int i = 0; i < 4; i++) { diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index ac83ceadd..273a83662 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -24,11 +24,6 @@ #include "ui_interface.h" #include "rpc/server.h" #include "rpc/register.h" -#include "util.h" -#ifdef ENABLE_WALLET -#include "wallet/db.h" -#include "wallet/wallet.h" -#endif #include #include @@ -37,7 +32,6 @@ #include "librustzcash.h" CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h -CWallet* pwalletMain; ZCJoinSplit *pzcashParams; extern bool fPrintToConsole; @@ -99,10 +93,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : JoinSplitTestingSetup // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); -#ifdef ENABLE_WALLET - bitdb.MakeMock(); - RegisterWalletRPCCommands(tableRPC); -#endif // Save current path, in case a test changes it orig_current_path = boost::filesystem::current_path(); @@ -115,12 +105,6 @@ TestingSetup::TestingSetup(const std::string& chainName) : JoinSplitTestingSetup pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); InitBlockIndex(chainparams); -#ifdef ENABLE_WALLET - bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); - pwalletMain->LoadWallet(fFirstRun); - RegisterValidationInterface(pwalletMain); -#endif nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); @@ -132,19 +116,10 @@ TestingSetup::~TestingSetup() UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); -#ifdef ENABLE_WALLET - UnregisterValidationInterface(pwalletMain); - delete pwalletMain; - pwalletMain = NULL; -#endif UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; delete pblocktree; -#ifdef ENABLE_WALLET - bitdb.Flush(true); - bitdb.Reset(); -#endif // Restore the previous current path so temporary directory can be deleted boost::filesystem::current_path(orig_current_path); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 8dd626a95..d61f85622 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -27,8 +27,7 @@ struct JoinSplitTestingSetup: public BasicTestingSetup { }; /** Testing setup that configures a complete environment. - * Included are data directory, coins database, script check threads - * and wallet (if enabled) setup. + * Included are data directory, coins database, script check threads setup. */ struct TestingSetup: public JoinSplitTestingSetup { CCoinsViewDB *pcoinsdbview; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d8bd574db..058346dfe 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -405,7 +405,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, strError); } if (!pwalletMain->CommitTransaction(wtxNew, reservekey)) - 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."); + 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 the wallet and coins were spent in the copy but not marked as spent here."); } UniValue sendtoaddress(const UniValue& params, bool fHelp) @@ -1806,7 +1806,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "backupwallet \"destination\"\n" - "\nSafely copies wallet.dat to destination filename\n" + "\nSafely copies current wallet file to destination filename\n" "\nArguments:\n" "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n" "\nResult:\n" diff --git a/src/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp similarity index 97% rename from src/test/accounting_tests.cpp rename to src/wallet/test/accounting_tests.cpp index dcf28ed85..e1ab10963 100644 --- a/src/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -5,7 +5,7 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include @@ -14,7 +14,7 @@ extern CWallet* pwalletMain; -BOOST_FIXTURE_TEST_SUITE(accounting_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup) static void GetResults(CWalletDB& walletdb, std::map& results) diff --git a/src/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp similarity index 99% rename from src/test/rpc_wallet_tests.cpp rename to src/wallet/test/rpc_wallet_tests.cpp index 503babc93..48705f90a 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/wallet/test/rpc_wallet_tests.cpp @@ -9,7 +9,7 @@ #include "main.h" #include "wallet/wallet.h" -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include "zcash/Address.hpp" @@ -55,7 +55,7 @@ static UniValue ValueFromString(const std::string &str) return value; } -BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(rpc_addmultisig) { diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp new file mode 100644 index 000000000..31e790988 --- /dev/null +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -0,0 +1,27 @@ +#include "wallet/test/wallet_test_fixture.h" + +#include "rpc/server.h" +#include "wallet/db.h" +#include "wallet/wallet.h" + +WalletTestingSetup::WalletTestingSetup(): TestingSetup() +{ + bitdb.MakeMock(); + + bool fFirstRun; + pwalletMain = new CWallet("wallet_test.dat"); + pwalletMain->LoadWallet(fFirstRun); + RegisterValidationInterface(pwalletMain); + + RegisterWalletRPCCommands(tableRPC); +} + +WalletTestingSetup::~WalletTestingSetup() +{ + UnregisterValidationInterface(pwalletMain); + delete pwalletMain; + pwalletMain = NULL; + + bitdb.Flush(true); + bitdb.Reset(); +} diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h new file mode 100644 index 000000000..3b87e94d5 --- /dev/null +++ b/src/wallet/test/wallet_test_fixture.h @@ -0,0 +1,18 @@ +// Copyright (c) 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. + +#ifndef BITCOIN_WALLET_TEST_FIXTURE_H +#define BITCOIN_WALLET_TEST_FIXTURE_H + +#include "test/test_bitcoin.h" + +/** Testing setup and teardown for wallet. + */ +struct WalletTestingSetup: public TestingSetup { + WalletTestingSetup(); + ~WalletTestingSetup(); +}; + +#endif + diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 95edadef1..8037dc7e7 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -9,7 +9,7 @@ #include #include -#include "test/test_bitcoin.h" +#include "wallet/test/wallet_test_fixture.h" #include #include @@ -25,7 +25,7 @@ using namespace std; typedef set > CoinSet; -BOOST_FIXTURE_TEST_SUITE(wallet_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup) static CWallet wallet; static vector vCoins; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 223e6b8c2..cfe20b9e8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -37,6 +37,7 @@ using namespace std; using namespace libzcash; +CWallet* pwalletMain = NULL; /** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; @@ -44,6 +45,8 @@ bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; bool fPayAtLeastCustomFee = true; +const char * DEFAULT_WALLET_DAT = "wallet.dat"; + /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee @@ -816,8 +819,33 @@ void CWallet::Flush(bool shutdown) bitdb.Flush(shutdown); } -bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString) +bool static UIError(const std::string &str) { + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); + return false; +} + +void static UIWarning(const std::string &str) +{ + uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); +} + +static std::string AmountErrMsg(const char * const optname, const std::string& strValue) +{ + return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); +} + +bool CWallet::Verify() +{ + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); + + LogPrintf("Using wallet %s\n", walletFile); + uiInterface.InitMessage(_("Verifying wallet...")); + + // Wallet file must be a plain filename without a directory + if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) + return UIError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string())); + if (!bitdb.Open(GetDataDir())) { // try moving the database env out of the way @@ -833,9 +861,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er // try again if (!bitdb.Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env - string msg = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()); - errorString += msg; - return true; + return UIError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir())); } } @@ -851,13 +877,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { - warningString += strprintf(_("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."), GetDataDir()); + UIWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!" + " Original %s saved as %s in %s; if" + " your balance or transactions are incorrect you should" + " restore from a backup."), + walletFile, "wallet.{timestamp}.bak", GetDataDir())); } if (r == CDBEnv::RECOVER_FAIL) - errorString += _("wallet.dat corrupt, salvage failed"); + return UIError(strprintf(_("%s corrupt, salvage failed"), walletFile)); } return true; @@ -4363,6 +4390,268 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st return false; } +std::string CWallet::GetWalletHelpString(bool showDebug) +{ + std::string strUsage = HelpMessageGroup(_("Wallet options:")); + strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); + strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), DEFAULT_KEYPOOL_SIZE)); + strUsage += HelpMessageOpt("-migration", _("Enable the Sprout to Sapling migration")); + strUsage += HelpMessageOpt("-migrationdestaddress=", _("Set the Sapling migration address")); + strUsage += HelpMessageOpt("-mintxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), + CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); + strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), + CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); + strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); + strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); + strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); + strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); + strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (min: %u, default: %u (pre-Blossom) or %u (post-Blossom))"), TX_EXPIRING_SOON_THRESHOLD + 1, DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA)); + strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); + strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); + strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); + strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); + strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); + + if (showDebug) + { + strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); + + strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); + strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); + strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); + } + + return strUsage; +} + +bool CWallet::InitLoadWallet(bool clearWitnessCaches) +{ + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); + + // needed to restore wallet transaction meta data after -zapwallettxes + std::vector vWtx; + + if (GetBoolArg("-zapwallettxes", false)) { + uiInterface.InitMessage(_("Zapping all transactions from wallet...")); + + CWallet *tempWallet = new CWallet(walletFile); + DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); + if (nZapWalletRet != DB_LOAD_OK) { + return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + } + + delete tempWallet; + tempWallet = NULL; + } + + uiInterface.InitMessage(_("Loading wallet...")); + + int64_t nStart = GetTimeMillis(); + bool fFirstRun = true; + CWallet *walletInstance = new CWallet(walletFile); + DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) + { + if (nLoadWalletRet == DB_CORRUPT) + return UIError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + { + UIWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect."), + walletFile)); + } + else if (nLoadWalletRet == DB_TOO_NEW) + return UIError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), + walletFile, _(PACKAGE_NAME))); + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + return UIError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); + } + else + return UIError(strprintf(_("Error loading %s"), walletFile)); + } + + if (GetBoolArg("-upgradewallet", fFirstRun)) + { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) // the -upgradewallet without argument case + { + LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); + nMaxVersion = CLIENT_VERSION; + walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } + else + LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); + if (nMaxVersion < walletInstance->GetVersion()) + { + return UIError(_("Cannot downgrade wallet")); + } + walletInstance->SetMaxVersion(nMaxVersion); + } + + if (!walletInstance->HaveHDSeed()) + { + // We can't set the new HD seed until the wallet is decrypted. + // https://github.com/zcash/zcash/issues/3607 + if (!walletInstance->IsCrypted()) { + // generate a new HD seed + walletInstance->GenerateNewSeed(); + } + } + + // Set sapling migration status + walletInstance->fSaplingMigrationEnabled = GetBoolArg("-migration", false); + + if (fFirstRun) + { + // Create new keyUser and set as default key + CPubKey newDefaultKey; + if (walletInstance->GetKeyFromPool(newDefaultKey)) { + walletInstance->SetDefaultKey(newDefaultKey); + if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) + return UIError(_("Cannot write default address") += "\n"); + } + + walletInstance->SetBestChain(chainActive.GetLocator()); + } + + LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); + + RegisterValidationInterface(walletInstance); + + CBlockIndex *pindexRescan = chainActive.Tip(); + if (clearWitnessCaches || GetBoolArg("-rescan", false)) + { + walletInstance->ClearNoteWitnessCache(); + pindexRescan = chainActive.Genesis(); + } + else + { + CWalletDB walletdb(walletFile); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) + pindexRescan = FindForkInGlobalIndex(chainActive, locator); + else + pindexRescan = chainActive.Genesis(); + } + if (chainActive.Tip() && chainActive.Tip() != pindexRescan) + { + // We can't rescan beyond non-pruned blocks, stop and throw an error. + // This might happen if a user uses a old wallet within a pruned node, + // or if they ran -disablewallet for a longer time, then decided to re-enable. + if (fPruneMode) + { + CBlockIndex *block = chainActive.Tip(); + while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) + block = block->pprev; + + if (pindexRescan != block) + return UIError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); + } + + uiInterface.InitMessage(_("Rescanning...")); + LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + nStart = GetTimeMillis(); + walletInstance->ScanForWalletTransactions(pindexRescan, true); + LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); + walletInstance->SetBestChain(chainActive.GetLocator()); + nWalletDBUpdated++; + + // Restore wallet transaction metadata after -zapwallettxes=1 + if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") + { + CWalletDB walletdb(walletFile); + + BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) + { + uint256 hash = wtxOld.GetHash(); + std::map::iterator mi = walletInstance->mapWallet.find(hash); + if (mi != walletInstance->mapWallet.end()) + { + const CWalletTx* copyFrom = &wtxOld; + CWalletTx* copyTo = &mi->second; + copyTo->mapValue = copyFrom->mapValue; + copyTo->vOrderForm = copyFrom->vOrderForm; + copyTo->nTimeReceived = copyFrom->nTimeReceived; + copyTo->nTimeSmart = copyFrom->nTimeSmart; + copyTo->fFromMe = copyFrom->fFromMe; + copyTo->strFromAccount = copyFrom->strFromAccount; + copyTo->nOrderPos = copyFrom->nOrderPos; + copyTo->WriteToDisk(&walletdb); + } + } + } + } + walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); + + pwalletMain = walletInstance; + return true; +} + +bool CWallet::ParameterInteraction() +{ + if (mapArgs.count("-mintxfee")) + { + CAmount n = 0; + if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) + CWallet::minTxFee = CFeeRate(n); + else + return UIError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); + } + if (mapArgs.count("-paytxfee")) + { + CAmount nFeePerK = 0; + if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) + return UIError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); + if (nFeePerK > HIGH_TX_FEE_PER_KB) + UIWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + payTxFee = CFeeRate(nFeePerK, 1000); + if (payTxFee < ::minRelayTxFee) + { + return UIError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), + mapArgs["-paytxfee"], ::minRelayTxFee.ToString())); + } + } + if (mapArgs.count("-maxtxfee")) + { + CAmount nMaxFee = 0; + if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee)) + return UIError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"])); + if (nMaxFee > HIGH_MAX_TX_FEE) + UIWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + maxTxFee = nMaxFee; + if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) + { + return UIError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + mapArgs["-maxtxfee"], ::minRelayTxFee.ToString())); + } + } + nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); + if (mapArgs.count("-txexpirydelta")) { + int64_t expiryDelta = atoi64(mapArgs["-txexpirydelta"]); + uint32_t minExpiryDelta = TX_EXPIRING_SOON_THRESHOLD + 1; + if (expiryDelta < minExpiryDelta) { + return UIError(strprintf(_("Invalid value for -txexpirydelta='%u' (must be least %u)"), expiryDelta, minExpiryDelta)); + } + expiryDeltaArg = expiryDelta; + } + bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); + fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); + + // Check Sapling migration address if set and is a valid Sapling address + if (mapArgs.count("-migrationdestaddress")) { + std::string migrationDestAddress = mapArgs["-migrationdestaddress"]; + libzcash::PaymentAddress address = DecodePaymentAddress(migrationDestAddress); + if (boost::get(&address) == nullptr) { + return UIError(_("-migrationdestaddress must be a valid Sapling address.")); + } + } + + return true; +} + CKeyPool::CKeyPool() { nTime = GetTime(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b15dc9872..d73d98303 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -19,8 +19,8 @@ #include "util.h" #include "utilstrencodings.h" #include "validationinterface.h" +#include "script/ismine.h" #include "wallet/crypter.h" -#include "wallet/wallet_ismine.h" #include "wallet/walletdb.h" #include "wallet/rpcwallet.h" #include "zcash/Address.hpp" @@ -38,6 +38,8 @@ #include +extern CWallet* pwalletMain; + /** * Settings */ @@ -71,6 +73,8 @@ static const unsigned int WITNESS_CACHE_SIZE = MAX_REORG_LENGTH + 1; //! Size of HD seed in bytes static const size_t HD_WALLET_SEED_LENGTH = 32; +extern const char * DEFAULT_WALLET_DAT; + class CBlockIndex; class CCoinControl; class COutput; @@ -1289,7 +1293,7 @@ public: void Flush(bool shutdown=false); //! Verify the wallet database and perform salvage if required - static bool Verify(const std::string& walletFile, std::string& warningString, std::string& errorString); + static bool Verify(); /** * Address book entry changed. @@ -1360,6 +1364,15 @@ public: bool ignoreSpent=true, bool requireSpendingKey=true, bool ignoreLocked=true); + + /* Returns the wallets help message */ + static std::string GetWalletHelpString(bool showDebug); + + /* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */ + static bool InitLoadWallet(bool clearWitnessCaches); + + /* Wallets parameter interaction */ + static bool ParameterInteraction(); }; /** A key allocated from the key pool. */ diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 4ded74273..3d3dea796 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1108,16 +1108,16 @@ void ThreadFlushWalletDB(const string& strFile) map::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { - LogPrint("db", "Flushing wallet.dat\n"); + LogPrint("db", "Flushing %s\n", strFile); nLastFlushed = nWalletDBUpdated; int64_t nStart = GetTimeMillis(); - // Flush wallet.dat so it's self contained + // Flush wallet file so it's self contained bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(mi++); - LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); } } } @@ -1140,7 +1140,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) bitdb.CheckpointLSN(wallet.strWalletFile); bitdb.mapFileUseCount.erase(wallet.strWalletFile); - // Copy wallet.dat + // Copy wallet file boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile; boost::filesystem::path pathDest(strDest); if (boost::filesystem::is_directory(pathDest)) @@ -1148,10 +1148,10 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) try { boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists); - LogPrintf("copied wallet.dat to %s\n", pathDest.string()); + LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string()); return true; } catch (const boost::filesystem::filesystem_error& e) { - LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what()); + LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what()); return false; } } @@ -1162,15 +1162,15 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) } // -// Try to (very carefully!) recover wallet.dat if there is a problem. +// Try to (very carefully!) recover wallet file if there is a problem. // bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys) { // Recovery procedure: - // move wallet.dat to wallet.timestamp.bak + // move wallet file to wallet.timestamp.bak // Call Salvage with fAggressive=true to // get as much data as possible. - // Rewrite salvaged data to wallet.dat + // Rewrite salvaged data to fresh wallet file // Set -rescan so any missing transactions will be // found. int64_t now = GetTime(); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index ddba7cc6e..95face9b4 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -119,7 +119,7 @@ public: } }; -/** Access to the wallet database (wallet.dat) */ +/** Access to the wallet database */ class CWalletDB : public CDB { public: