diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index d83c67f0c..3cfe32164 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -1,347 +1,347 @@
 // Copyright (c) 2011-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_QT_BITCOINGUI_H
 #define BITCOIN_QT_BITCOINGUI_H
 
 #if defined(HAVE_CONFIG_H)
 #include <config/bitcoin-config.h>
 #endif
 
 #include <qt/optionsdialog.h>
 
 #include <amount.h>
 
 #include <QLabel>
 #include <QMainWindow>
 #include <QMap>
 #include <QMenu>
 #include <QPoint>
 #include <QSystemTrayIcon>
 
 #include <memory>
 
 class ClientModel;
 class NetworkStyle;
 class Notificator;
 class OptionsModel;
 class PlatformStyle;
 class RPCConsole;
 class SendCoinsRecipient;
 class UnitDisplayStatusBarControl;
 class WalletController;
 class WalletFrame;
 class WalletModel;
 class HelpMessageDialog;
 class ModalOverlay;
 
 class Config;
 
 namespace interfaces {
 class Handler;
 class Node;
 } // namespace interfaces
 
 QT_BEGIN_NAMESPACE
 class QAction;
 class QComboBox;
 class QProgressBar;
 class QProgressDialog;
 QT_END_NAMESPACE
 
 namespace GUIUtil {
 class ClickableLabel;
 class ClickableProgressBar;
 } // namespace GUIUtil
 
 /**
  * Bitcoin GUI main class. This class represents the main window of the Bitcoin
  * UI. It communicates with both the client and wallet models to give the user
  * an up-to-date view of the current core state.
  */
 class BitcoinGUI : public QMainWindow {
     Q_OBJECT
 
 public:
     static const std::string DEFAULT_UIPLATFORM;
 
     explicit BitcoinGUI(interfaces::Node &node, const Config *,
                         const PlatformStyle *platformStyle,
                         const NetworkStyle *networkStyle,
                         QWidget *parent = nullptr);
     ~BitcoinGUI();
 
     /**
      * Set the client model.
      * The client model represents the part of the core that communicates with
      * the P2P network, and is wallet-agnostic.
      */
     void setClientModel(ClientModel *clientModel);
 #ifdef ENABLE_WALLET
     void setWalletController(WalletController *wallet_controller);
 #endif
 
 #ifdef ENABLE_WALLET
     /**
      * Set the wallet model.
      * The wallet model represents a bitcoin wallet, and offers access to the
      * list of transactions, address book and sending functionality.
      */
     void addWallet(WalletModel *walletModel);
     void removeWallet(WalletModel *walletModel);
     void removeAllWallets();
 #endif // ENABLE_WALLET
     bool enableWallet = false;
 
     /** Disconnect core signals from GUI client */
     void unsubscribeFromCoreSignals();
 
 protected:
     void changeEvent(QEvent *e) override;
     void closeEvent(QCloseEvent *event) override;
     void showEvent(QShowEvent *event) override;
     void dragEnterEvent(QDragEnterEvent *event) override;
     void dropEvent(QDropEvent *event) override;
     bool eventFilter(QObject *object, QEvent *event) override;
 
 private:
     interfaces::Node &m_node;
     WalletController *m_wallet_controller{nullptr};
     std::unique_ptr<interfaces::Handler> m_handler_message_box;
     std::unique_ptr<interfaces::Handler> m_handler_question;
     ClientModel *clientModel = nullptr;
     WalletFrame *walletFrame = nullptr;
 
     UnitDisplayStatusBarControl *unitDisplayControl = nullptr;
     QLabel *labelWalletEncryptionIcon = nullptr;
     QLabel *labelWalletHDStatusIcon = nullptr;
     GUIUtil::ClickableLabel *labelProxyIcon = nullptr;
     GUIUtil::ClickableLabel *connectionsControl = nullptr;
     GUIUtil::ClickableLabel *labelBlocksIcon = nullptr;
     QLabel *progressBarLabel = nullptr;
     GUIUtil::ClickableProgressBar *progressBar = nullptr;
     QProgressDialog *progressDialog = nullptr;
 
     QMenuBar *appMenuBar = nullptr;
     QToolBar *appToolBar = nullptr;
     QAction *overviewAction = nullptr;
     QAction *historyAction = nullptr;
     QAction *quitAction = nullptr;
     QAction *sendCoinsAction = nullptr;
     QAction *sendCoinsMenuAction = nullptr;
     QAction *usedSendingAddressesAction = nullptr;
     QAction *usedReceivingAddressesAction = nullptr;
     QAction *signMessageAction = nullptr;
     QAction *verifyMessageAction = nullptr;
     QAction *aboutAction = nullptr;
     QAction *receiveCoinsAction = nullptr;
     QAction *receiveCoinsMenuAction = nullptr;
     QAction *optionsAction = nullptr;
     QAction *toggleHideAction = nullptr;
     QAction *encryptWalletAction = nullptr;
     QAction *backupWalletAction = nullptr;
     QAction *changePassphraseAction = nullptr;
     QAction *aboutQtAction = nullptr;
     QAction *openRPCConsoleAction = nullptr;
     QAction *openAction = nullptr;
     QAction *showHelpMessageAction = nullptr;
     QAction *m_open_wallet_action{nullptr};
     QMenu *m_open_wallet_menu{nullptr};
     QAction *m_close_wallet_action{nullptr};
     QAction *m_wallet_selector_label_action = nullptr;
     QAction *m_wallet_selector_action = nullptr;
 
     QLabel *m_wallet_selector_label = nullptr;
     QComboBox *m_wallet_selector = nullptr;
 
     QSystemTrayIcon *trayIcon = nullptr;
     QMenu *trayIconMenu = nullptr;
     Notificator *notificator = nullptr;
     RPCConsole *rpcConsole = nullptr;
     HelpMessageDialog *helpMessageDialog = nullptr;
     ModalOverlay *modalOverlay = nullptr;
 
     /** Keep track of previous number of blocks, to detect progress */
     int prevBlocks = 0;
     int spinnerFrame = 0;
 
     const Config *config;
     const PlatformStyle *platformStyle;
     const NetworkStyle *const m_network_style;
 
     /** Create the main UI actions. */
     void createActions();
     /** Create the menu bar and sub-menus. */
     void createMenuBar();
     /** Create the toolbars */
     void createToolBars();
     /** Create system tray icon and notification */
     void createTrayIcon();
     /** Create system tray menu (or setup the dock menu) */
     void createTrayIconMenu();
 
     /** Enable or disable all wallet-related actions */
     void setWalletActionsEnabled(bool enabled);
 
     /** Connect core signals to GUI client */
     void subscribeToCoreSignals();
 
     /** Update UI with latest network info from model. */
     void updateNetworkState();
 
     void updateHeadersSyncProgressLabel();
 
     /** Open the OptionsDialog on the specified tab index */
     void openOptionsDialogWithTab(OptionsDialog::Tab tab);
 
 Q_SIGNALS:
     /** Signal raised when a URI was entered or dragged to the GUI */
     void receivedURI(const QString &uri);
     /** Signal raised when RPC console shown */
     void consoleShown(RPCConsole *console);
 
 public Q_SLOTS:
     /** Set number of connections shown in the UI */
     void setNumConnections(int count);
     /** Set network state shown in the UI */
     void setNetworkActive(bool networkActive);
     /** Set number of blocks and last block date shown in the UI */
     void setNumBlocks(int count, const QDateTime &blockDate,
                       double nVerificationProgress, bool headers);
 
     /** Notify the user of an event from the core network or transaction
        handling code.
        @param[in] title     the message box / notification title
        @param[in] message   the displayed text
        @param[in] style     modality and style definitions (icon and used
        buttons - buttons only for message boxes)
                             @see CClientUIInterface::MessageBoxFlags
        @param[in] ret       pointer to a bool that will be modified to whether
        Ok was clicked (modal only)
      */
     void message(const QString &title, const QString &message,
                  unsigned int style, bool *ret = nullptr);
 
 #ifdef ENABLE_WALLET
     void setCurrentWallet(WalletModel *wallet_model);
     void setCurrentWalletBySelectorIndex(int index);
     /** Set the UI status indicators based on the currently selected wallet.
      */
     void updateWalletStatus();
 
 private:
     /** Set the encryption status as shown in the UI.
        @param[in] status            current encryption status
        @see WalletModel::EncryptionStatus
      */
     void setEncryptionStatus(int status);
 
     /** Set the hd-enabled status as shown in the UI.
-     @param[in] status            current hd enabled status
+     @param[in] hdEnabled         current hd enabled status
      @see WalletModel::EncryptionStatus
      */
     void setHDStatus(int hdEnabled);
 
 public Q_SLOTS:
     bool handlePaymentRequest(const SendCoinsRecipient &recipient);
 
     /** Show incoming transaction notification for new transactions. */
     void incomingTransaction(const QString &date, int unit, const Amount amount,
                              const QString &type, const QString &address,
                              const QString &label, const QString &walletName);
 #endif // ENABLE_WALLET
 
 private:
     /** Set the proxy-enabled icon as shown in the UI. */
     void updateProxyIcon();
     void updateWindowTitle();
 
 public Q_SLOTS:
 #ifdef ENABLE_WALLET
     /** Switch to overview (home) page */
     void gotoOverviewPage();
     /** Switch to history (transactions) page */
     void gotoHistoryPage();
     /** Switch to receive coins page */
     void gotoReceiveCoinsPage();
     /** Switch to send coins page */
     void gotoSendCoinsPage(QString addr = "");
 
     /** Show Sign/Verify Message dialog and switch to sign message tab */
     void gotoSignMessageTab(QString addr = "");
     /** Show Sign/Verify Message dialog and switch to verify message tab */
     void gotoVerifyMessageTab(QString addr = "");
 
     /** Show open dialog */
     void openClicked();
 #endif // ENABLE_WALLET
     /** Show configuration dialog */
     void optionsClicked();
     /** Show about dialog */
     void aboutClicked();
     /** Show debug window */
     void showDebugWindow();
     /** Show debug window and set focus to the console */
     void showDebugWindowActivateConsole();
     /** Show help message dialog */
     void showHelpMessageClicked();
 #ifndef Q_OS_MAC
     /** Handle tray icon clicked */
     void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
 #else
     /** Handle macOS Dock icon clicked */
     void macosDockIconActivated();
 #endif
 
     /** Show window if hidden, unminimize when minimized, rise when obscured or
      * show if hidden and fToggleHidden is true */
     void showNormalIfMinimized() { showNormalIfMinimized(false); }
     void showNormalIfMinimized(bool fToggleHidden);
     /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */
     void toggleHidden();
 
     /** called by a timer to check if ShutdownRequested() has been set **/
     void detectShutdown();
 
     /** Show progress dialog e.g. for verifychain */
     void showProgress(const QString &title, int nProgress);
 
     /** When hideTrayIcon setting is changed in OptionsModel hide or show the
      * icon accordingly. */
     void setTrayIconVisible(bool);
 
     void showModalOverlay();
 };
 
 class UnitDisplayStatusBarControl : public QLabel {
     Q_OBJECT
 
 public:
     explicit UnitDisplayStatusBarControl(const PlatformStyle *platformStyle);
     /** Lets the control know about the Options Model (and its signals) */
     void setOptionsModel(OptionsModel *optionsModel);
 
 protected:
     /** So that it responds to left-button clicks */
     void mousePressEvent(QMouseEvent *event) override;
 
 private:
     OptionsModel *optionsModel;
     QMenu *menu;
 
     /** Shows context menu with Display Unit options by the mouse coordinates */
     void onDisplayUnitsClicked(const QPoint &point);
     /** Creates context menu, its actions, and wires up all the relevant signals
      * for mouse events. */
     void createContextMenu();
 
 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. */
     void onMenuSelection(QAction *action);
 };
 
 #endif // BITCOIN_QT_BITCOINGUI_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index a56ee8fe9..f2fb609df 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1,1470 +1,1470 @@
 // Copyright (c) 2011-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 <config/bitcoin-config.h>
 #endif
 
 #include <qt/rpcconsole.h>
 
 #include <chainparams.h>
 #include <config.h>
 #include <interfaces/node.h>
 #include <netbase.h>
 #include <qt/bantablemodel.h>
 #include <qt/clientmodel.h>
 #include <qt/forms/ui_debugwindow.h>
 #include <qt/platformstyle.h>
 #include <qt/walletmodel.h>
 #include <rpc/client.h>
 #include <rpc/server.h>
 #include <util/strencodings.h>
 #include <util/system.h>
 
 #ifdef ENABLE_WALLET
 #include <wallet/wallet.h>
 
 #include <db_cxx.h>
 #endif
 
 #include <univalue.h>
 
 #include <QKeyEvent>
 #include <QMenu>
 #include <QMessageBox>
 #include <QScreen>
 #include <QScrollBar>
 #include <QSettings>
 #include <QSignalMapper>
 #include <QStringList>
 #include <QTime>
 #include <QTimer>
 
 // 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
 
 const int CONSOLE_HISTORY = 50;
 const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
 const QSize FONT_RANGE(4, 40);
 const char fontSizeSettingsKey[] = "consoleFontSize";
 
 const struct {
     const char *url;
     const char *source;
 } ICON_MAPPING[] = {{"cmd-request", ":/icons/tx_input"},
                     {"cmd-reply", ":/icons/tx_output"},
                     {"cmd-error", ":/icons/tx_output"},
                     {"misc", ":/icons/tx_inout"},
                     {nullptr, nullptr}};
 
 namespace {
 
 // don't add private key handling cmd's to the history
 const QStringList historyFilter = QStringList() << "importprivkey"
                                                 << "importmulti"
                                                 << "sethdseed"
                                                 << "signmessagewithprivkey"
                                                 << "signrawtransactionwithkey"
                                                 << "walletpassphrase"
                                                 << "walletpassphrasechange"
                                                 << "encryptwallet";
 } // namespace
 
 /* Object for executing console RPC commands in a separate thread.
  */
 class RPCExecutor : public QObject {
     Q_OBJECT
 public:
     explicit RPCExecutor(interfaces::Node &node) : m_node(node) {}
 
 public Q_SLOTS:
     void request(const QString &command, const WalletModel *wallet_model);
 
 Q_SIGNALS:
     void reply(int category, const QString &command);
 
 private:
     interfaces::Node &m_node;
 };
 
 /** Class for handling RPC timers
  * (used for e.g. re-locking the wallet after a timeout)
  */
 class QtRPCTimerBase : public QObject, public RPCTimerBase {
     Q_OBJECT
 public:
     QtRPCTimerBase(std::function<void()> &_func, int64_t millis) : func(_func) {
         timer.setSingleShot(true);
         connect(&timer, &QTimer::timeout, [this] { func(); });
         timer.start(millis);
     }
     ~QtRPCTimerBase() {}
 
 private:
     QTimer timer;
     std::function<void()> func;
 };
 
 class QtRPCTimerInterface : public RPCTimerInterface {
 public:
     ~QtRPCTimerInterface() {}
     const char *Name() override { return "Qt"; }
     RPCTimerBase *NewTimer(std::function<void()> &func,
                            int64_t millis) override {
         return new QtRPCTimerBase(func, millis);
     }
 };
 
 #include <qt/rpcconsole.moc>
 
 /**
  * Split shell command line into a list of arguments and optionally execute the
  * command(s).
  * Aims to emulate \c bash and friends.
  *
  * - Command nesting is possible with parenthesis; for example:
  * validateaddress(getnewaddress())
  * - Arguments are delimited with whitespace or comma
  * - Extra whitespace at the beginning and end and between arguments will be
  * ignored
  * - Text can be "double" or 'single' quoted
  * - The backslash \c \ is used as escape character
  *   - Outside quotes, any character can be escaped
  *   - Within double quotes, only escape \c " and backslashes before a \c " or
  * another backslash
  *   - Within single quotes, no escaping is possible and no special
  * interpretation takes place
  *
  * @param[in]    node    optional node to execute command on
- * @param[out]   result      stringified Result from the executed command(chain)
+ * @param[out]   strResult   stringified result from the executed command(chain)
  * @param[in]    strCommand  Command line to split
  * @param[in]    fExecute    set true if you want the command to be executed
  * @param[out]   pstrFilteredOut  Command line, filtered to remove any sensitive
  * data
  */
 
 bool RPCConsole::RPCParseCommandLine(interfaces::Node *node,
                                      std::string &strResult,
                                      const std::string &strCommand,
                                      const bool fExecute,
                                      std::string *const pstrFilteredOut,
                                      const WalletModel *wallet_model) {
     std::vector<std::vector<std::string>> stack;
     stack.push_back(std::vector<std::string>());
 
     enum CmdParseState {
         STATE_EATING_SPACES,
         STATE_EATING_SPACES_IN_ARG,
         STATE_EATING_SPACES_IN_BRACKETS,
         STATE_ARGUMENT,
         STATE_SINGLEQUOTED,
         STATE_DOUBLEQUOTED,
         STATE_ESCAPE_OUTER,
         STATE_ESCAPE_DOUBLEQUOTED,
         STATE_COMMAND_EXECUTED,
         STATE_COMMAND_EXECUTED_INNER
     } state = STATE_EATING_SPACES;
     std::string curarg;
     UniValue lastResult;
     unsigned nDepthInsideSensitive = 0;
     size_t filter_begin_pos = 0, chpos;
     std::vector<std::pair<size_t, size_t>> filter_ranges;
 
     auto add_to_current_stack = [&](const std::string &strArg) {
         if (stack.back().empty() && (!nDepthInsideSensitive) &&
             historyFilter.contains(QString::fromStdString(strArg),
                                    Qt::CaseInsensitive)) {
             nDepthInsideSensitive = 1;
             filter_begin_pos = chpos;
         }
         // Make sure stack is not empty before adding something
         if (stack.empty()) {
             stack.push_back(std::vector<std::string>());
         }
         stack.back().push_back(strArg);
     };
 
     auto close_out_params = [&]() {
         if (nDepthInsideSensitive) {
             if (!--nDepthInsideSensitive) {
                 assert(filter_begin_pos);
                 filter_ranges.push_back(
                     std::make_pair(filter_begin_pos, chpos));
                 filter_begin_pos = 0;
             }
         }
         stack.pop_back();
     };
 
     std::string strCommandTerminated = strCommand;
     if (strCommandTerminated.back() != '\n') {
         strCommandTerminated += "\n";
     }
     for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos) {
         char ch = strCommandTerminated[chpos];
         switch (state) {
             case STATE_COMMAND_EXECUTED_INNER:
             case STATE_COMMAND_EXECUTED: {
                 bool breakParsing = true;
                 switch (ch) {
                     case '[':
                         curarg.clear();
                         state = STATE_COMMAND_EXECUTED_INNER;
                         break;
                     default:
                         if (state == STATE_COMMAND_EXECUTED_INNER) {
                             if (ch != ']') {
                                 // append char to the current argument (which is
                                 // also used for the query command)
                                 curarg += ch;
                                 break;
                             }
                             if (curarg.size() && fExecute) {
                                 // if we have a value query, query arrays with
                                 // index and objects with a string key
                                 UniValue subelement;
                                 if (lastResult.isArray()) {
                                     for (char argch : curarg) {
                                         if (!IsDigit(argch)) {
                                             throw std::runtime_error(
                                                 "Invalid result query");
                                         }
                                     }
                                     subelement =
                                         lastResult[atoi(curarg.c_str())];
                                 } else if (lastResult.isObject()) {
                                     subelement = find_value(lastResult, curarg);
                                 } else {
                                     // no array or object: abort
                                     throw std::runtime_error(
                                         "Invalid result query");
                                 }
                                 lastResult = subelement;
                             }
 
                             state = STATE_COMMAND_EXECUTED;
                             break;
                         }
                         // don't break parsing when the char is required for the
                         // next argument
                         breakParsing = false;
 
                         // pop the stack and return the result to the current
                         // command arguments
                         close_out_params();
 
                         // don't stringify the json in case of a string to avoid
                         // doublequotes
                         if (lastResult.isStr()) {
                             curarg = lastResult.get_str();
                         } else {
                             curarg = lastResult.write(2);
                         }
 
                         // if we have a non empty result, use it as stack
                         // argument otherwise as general result
                         if (curarg.size()) {
                             if (stack.size()) {
                                 add_to_current_stack(curarg);
                             } else {
                                 strResult = curarg;
                             }
                         }
                         curarg.clear();
                         // assume eating space state
                         state = STATE_EATING_SPACES;
                 }
 
                 if (breakParsing) {
                     break;
                 }
             }
             // FALLTHROUGH
             case STATE_ARGUMENT: // In or after argument
             case STATE_EATING_SPACES_IN_ARG:
             case STATE_EATING_SPACES_IN_BRACKETS:
             case STATE_EATING_SPACES: // Handle runs of whitespace
                 switch (ch) {
                     case '"':
                         state = STATE_DOUBLEQUOTED;
                         break;
                     case '\'':
                         state = STATE_SINGLEQUOTED;
                         break;
                     case '\\':
                         state = STATE_ESCAPE_OUTER;
                         break;
                     case '(':
                     case ')':
                     case '\n':
                         if (state == STATE_EATING_SPACES_IN_ARG) {
                             throw std::runtime_error("Invalid Syntax");
                         }
                         if (state == STATE_ARGUMENT) {
                             if (ch == '(' && stack.size() &&
                                 stack.back().size() > 0) {
                                 if (nDepthInsideSensitive) {
                                     ++nDepthInsideSensitive;
                                 }
                                 stack.push_back(std::vector<std::string>());
                             }
 
                             // don't allow commands after executed commands on
                             // baselevel
                             if (!stack.size()) {
                                 throw std::runtime_error("Invalid Syntax");
                             }
 
                             add_to_current_stack(curarg);
                             curarg.clear();
                             state = STATE_EATING_SPACES_IN_BRACKETS;
                         }
                         if ((ch == ')' || ch == '\n') && stack.size() > 0) {
                             if (fExecute) {
                                 // Convert argument list to JSON objects in
                                 // method-dependent way, and pass it along with
                                 // the method name to the dispatcher.
                                 UniValue params = RPCConvertValues(
                                     stack.back()[0],
                                     std::vector<std::string>(
                                         stack.back().begin() + 1,
                                         stack.back().end()));
                                 std::string method = stack.back()[0];
                                 std::string uri;
 
 #ifdef ENABLE_WALLET
                                 if (wallet_model) {
                                     QByteArray encodedName =
                                         QUrl::toPercentEncoding(
                                             wallet_model->getWalletName());
                                     uri = "/wallet/" +
                                           std::string(encodedName.constData(),
                                                       encodedName.length());
                                 }
 #endif
 
                                 GlobalConfig config;
                                 assert(node);
                                 lastResult = node->executeRpc(config, method,
                                                               params, uri);
                             }
 
                             state = STATE_COMMAND_EXECUTED;
                             curarg.clear();
                         }
                         break;
                     case ' ':
                     case ',':
                     case '\t':
                         if (state == STATE_EATING_SPACES_IN_ARG &&
                             curarg.empty() && ch == ',') {
                             throw std::runtime_error("Invalid Syntax");
                         } else if (state == STATE_ARGUMENT) {
                             // Space ends argument
                             add_to_current_stack(curarg);
                             curarg.clear();
                         }
                         if ((state == STATE_EATING_SPACES_IN_BRACKETS ||
                              state == STATE_ARGUMENT) &&
                             ch == ',') {
                             state = STATE_EATING_SPACES_IN_ARG;
                             break;
                         }
                         state = STATE_EATING_SPACES;
                         break;
                     default:
                         curarg += ch;
                         state = STATE_ARGUMENT;
                 }
                 break;
             case STATE_SINGLEQUOTED: // Single-quoted string
                 switch (ch) {
                     case '\'':
                         state = STATE_ARGUMENT;
                         break;
                     default:
                         curarg += ch;
                 }
                 break;
             case STATE_DOUBLEQUOTED: // Double-quoted string
                 switch (ch) {
                     case '"':
                         state = STATE_ARGUMENT;
                         break;
                     case '\\':
                         state = STATE_ESCAPE_DOUBLEQUOTED;
                         break;
                     default:
                         curarg += ch;
                 }
                 break;
             case STATE_ESCAPE_OUTER: // '\' outside quotes
                 curarg += ch;
                 state = STATE_ARGUMENT;
                 break;
             case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
                 if (ch != '"' && ch != '\\') {
                     // keep '\' for everything but the quote and '\' itself
                     curarg += '\\';
                 }
                 curarg += ch;
                 state = STATE_DOUBLEQUOTED;
                 break;
         }
     }
     if (pstrFilteredOut) {
         if (STATE_COMMAND_EXECUTED == state) {
             assert(!stack.empty());
             close_out_params();
         }
         *pstrFilteredOut = strCommand;
         for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
             pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
         }
     }
 
     // final state
     switch (state) {
         case STATE_COMMAND_EXECUTED:
             if (lastResult.isStr()) {
                 strResult = lastResult.get_str();
             } else {
                 strResult = lastResult.write(2);
             }
         // FALLTHROUGH
         case STATE_ARGUMENT:
         case STATE_EATING_SPACES:
             return true;
         default: // ERROR to end in one of the other states
             return false;
     }
 }
 
 void RPCExecutor::request(const QString &command,
                           const WalletModel *wallet_model) {
     try {
         std::string result;
         std::string executableCommand = command.toStdString() + "\n";
 
         // Catch the console-only-help command before RPC call is executed and
         // reply with help text as-if a RPC reply.
         if (executableCommand == "help-console\n") {
             Q_EMIT reply(
                 RPCConsole::CMD_REPLY,
                 QString(("\n"
                          "This console accepts RPC commands using the standard "
                          "syntax.\n"
                          "   example:    getblockhash 0\n\n"
 
                          "This console can also accept RPC commands using "
                          "parenthesized syntax.\n"
                          "   example:    getblockhash(0)\n\n"
 
                          "Commands may be nested when specified with the "
                          "parenthesized syntax.\n"
                          "   example:    getblock(getblockhash(0) 1)\n\n"
 
                          "A space or a comma can be used to delimit arguments "
                          "for either syntax.\n"
                          "   example:    getblockhash 0\n"
                          "               getblockhash,0\n\n"
 
                          "Named results can be queried with a non-quoted key "
                          "string in brackets.\n"
                          "   example:    getblock(getblockhash(0) true)[tx]\n\n"
 
                          "Results without keys can be queried using an integer "
                          "in brackets.\n"
                          "   example:    "
                          "getblock(getblockhash(0),true)[tx][0]\n\n")));
             return;
         }
         if (!RPCConsole::RPCExecuteCommandLine(
                 m_node, result, executableCommand, nullptr, wallet_model)) {
             Q_EMIT reply(RPCConsole::CMD_ERROR,
                          QString("Parse error: unbalanced ' or \""));
             return;
         }
 
         Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
     } catch (UniValue &objError) {
         // Nice formatting for standard-format error
         try {
             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 (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 (const std::exception &e) {
         Q_EMIT reply(RPCConsole::CMD_ERROR,
                      QString("Error: ") + QString::fromStdString(e.what()));
     }
 }
 
 RPCConsole::RPCConsole(interfaces::Node &node,
                        const PlatformStyle *_platformStyle, QWidget *parent)
     : QWidget(parent), m_node(node), ui(new Ui::RPCConsole),
       platformStyle(_platformStyle) {
     ui->setupUi(this);
     QSettings settings;
     if (!restoreGeometry(
             settings.value("RPCConsoleWindowGeometry").toByteArray())) {
         // Restore failed (perhaps missing setting), center the window
         move(QGuiApplication::primaryScreen()->availableGeometry().center() -
              frameGeometry().center());
     }
 
     QChar nonbreaking_hyphen(8209);
     ui->dataDir->setToolTip(
         ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
     ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(
         QString(nonbreaking_hyphen) + "blocksdir"));
     ui->openDebugLogfileButton->setToolTip(
         ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
 
     if (platformStyle->getImagesOnButtons()) {
         ui->openDebugLogfileButton->setIcon(
             platformStyle->SingleColorIcon(":/icons/export"));
     }
     ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
     ui->fontBiggerButton->setIcon(
         platformStyle->SingleColorIcon(":/icons/fontbigger"));
     ui->fontSmallerButton->setIcon(
         platformStyle->SingleColorIcon(":/icons/fontsmaller"));
 
     // Install event filter for up and down arrow
     ui->lineEdit->installEventFilter(this);
     ui->messagesWidget->installEventFilter(this);
 
     connect(ui->clearButton, &QPushButton::clicked, this, &RPCConsole::clear);
     connect(ui->fontBiggerButton, &QPushButton::clicked, this,
             &RPCConsole::fontBigger);
     connect(ui->fontSmallerButton, &QPushButton::clicked, this,
             &RPCConsole::fontSmaller);
     connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph,
             &TrafficGraphWidget::clear);
 
     // disable the wallet selector by default
     ui->WalletSelector->setVisible(false);
     ui->WalletSelectorLabel->setVisible(false);
 
 // set library version labels
 #ifdef ENABLE_WALLET
     ui->berkeleyDBVersion->setText(DbEnv::version(nullptr, nullptr, nullptr));
 #else
     ui->label_berkeleyDBVersion->hide();
     ui->berkeleyDBVersion->hide();
 #endif
     // Register RPC timer interface
     rpcTimerInterface = new QtRPCTimerInterface();
     // avoid accidentally overwriting an existing, non QTThread
     // based timer interface
     m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);
 
     setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
 
     ui->detailWidget->hide();
     ui->peerHeading->setText(tr("Select a peer to view detailed information."));
 
     consoleFontSize =
         settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize())
             .toInt();
     clear();
 }
 
 RPCConsole::~RPCConsole() {
     QSettings settings;
     settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
     m_node.rpcUnsetTimerInterface(rpcTimerInterface);
     delete rpcTimerInterface;
     delete ui;
 }
 
 bool RPCConsole::eventFilter(QObject *obj, QEvent *event) {
     // Special key handling
     if (event->type() == QEvent::KeyPress) {
         QKeyEvent *keyevt = static_cast<QKeyEvent *>(event);
         int key = keyevt->key();
         Qt::KeyboardModifiers mod = keyevt->modifiers();
         switch (key) {
             case Qt::Key_Up:
                 if (obj == ui->lineEdit) {
                     browseHistory(-1);
                     return true;
                 }
                 break;
             case Qt::Key_Down:
                 if (obj == ui->lineEdit) {
                     browseHistory(1);
                     return true;
                 }
                 break;
             case Qt::Key_PageUp: /* pass paging keys to messages widget */
             case Qt::Key_PageDown:
                 if (obj == ui->lineEdit) {
                     QApplication::postEvent(ui->messagesWidget,
                                             new QKeyEvent(*keyevt));
                     return true;
                 }
                 break;
             case Qt::Key_Return:
             case Qt::Key_Enter:
                 // forward these events to lineEdit
                 if (obj == autoCompleter->popup()) {
                     QApplication::postEvent(ui->lineEdit,
                                             new QKeyEvent(*keyevt));
                     return true;
                 }
                 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.
                 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))) {
                     ui->lineEdit->setFocus();
                     QApplication::postEvent(ui->lineEdit,
                                             new QKeyEvent(*keyevt));
                     return true;
                 }
         }
     }
     return QWidget::eventFilter(obj, event);
 }
 
 void RPCConsole::setClientModel(ClientModel *model) {
     clientModel = model;
     ui->trafficGraph->setClientModel(model);
     if (model && clientModel->getPeerTableModel() &&
         clientModel->getBanTableModel()) {
         // Keep up to date with client
         setNumConnections(model->getNumConnections());
         connect(model, &ClientModel::numConnectionsChanged, this,
                 &RPCConsole::setNumConnections);
 
         interfaces::Node &node = clientModel->node();
         setNumBlocks(node.getNumBlocks(),
                      QDateTime::fromTime_t(node.getLastBlockTime()),
                      node.getVerificationProgress(), false);
         connect(model, &ClientModel::numBlocksChanged, this,
                 &RPCConsole::setNumBlocks);
 
         updateNetworkState();
         connect(model, &ClientModel::networkActiveChanged, this,
                 &RPCConsole::setNetworkActive);
 
         updateTrafficStats(node.getTotalBytesRecv(), node.getTotalBytesSent());
         connect(model, &ClientModel::bytesChanged, this,
                 &RPCConsole::updateTrafficStats);
 
         connect(model, &ClientModel::mempoolSizeChanged, this,
                 &RPCConsole::setMempoolSize);
 
         // set up peer table
         ui->peerWidget->setModel(model->getPeerTableModel());
         ui->peerWidget->verticalHeader()->hide();
         ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
         ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
         ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
         ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
         ui->peerWidget->setColumnWidth(PeerTableModel::Address,
                                        ADDRESS_COLUMN_WIDTH);
         ui->peerWidget->setColumnWidth(PeerTableModel::Subversion,
                                        SUBVERSION_COLUMN_WIDTH);
         ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
         ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
 
         // create peer table context menu actions
         QAction *disconnectAction = new QAction(tr("&Disconnect"), this);
         QAction *banAction1h =
             new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
         QAction *banAction24h =
             new QAction(tr("Ban for") + " " + tr("1 &day"), this);
         QAction *banAction7d =
             new QAction(tr("Ban for") + " " + tr("1 &week"), this);
         QAction *banAction365d =
             new QAction(tr("Ban for") + " " + tr("1 &year"), this);
 
         // create peer table context menu
         peersTableContextMenu = new QMenu(this);
         peersTableContextMenu->addAction(disconnectAction);
         peersTableContextMenu->addAction(banAction1h);
         peersTableContextMenu->addAction(banAction24h);
         peersTableContextMenu->addAction(banAction7d);
         peersTableContextMenu->addAction(banAction365d);
 
         // Add a signal mapping to allow dynamic context menu arguments. We need
         // to use int (instead of int64_t), because signal mapper only supports
         // int or objects, which is okay because max bantime (1 year) is <
         // int_max.
         QSignalMapper *signalMapper = new QSignalMapper(this);
         signalMapper->setMapping(banAction1h, 60 * 60);
         signalMapper->setMapping(banAction24h, 60 * 60 * 24);
         signalMapper->setMapping(banAction7d, 60 * 60 * 24 * 7);
         signalMapper->setMapping(banAction365d, 60 * 60 * 24 * 365);
         connect(banAction1h, &QAction::triggered, signalMapper,
                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
         connect(banAction24h, &QAction::triggered, signalMapper,
                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
         connect(banAction7d, &QAction::triggered, signalMapper,
                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
         connect(banAction365d, &QAction::triggered, signalMapper,
                 static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map));
 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
         const auto mappedIntEvent = &QSignalMapper::mappedInt;
 #else
         const auto mappedIntEvent =
             static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped);
 #endif
         connect(signalMapper, mappedIntEvent, this,
                 &RPCConsole::banSelectedNode);
 
         // peer table context menu signals
         connect(ui->peerWidget, &QTableView::customContextMenuRequested, this,
                 &RPCConsole::showPeersTableContextMenu);
         connect(disconnectAction, &QAction::triggered, this,
                 &RPCConsole::disconnectSelectedNode);
 
         // peer table signal handling - update peer details when selecting new
         // node
         connect(ui->peerWidget->selectionModel(),
                 &QItemSelectionModel::selectionChanged, this,
                 &RPCConsole::peerSelected);
         // peer table signal handling - update peer details when new nodes are
         // added to the model
         connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged,
                 this, &RPCConsole::peerLayoutChanged);
         // peer table signal handling - cache selected node ids
         connect(model->getPeerTableModel(),
                 &PeerTableModel::layoutAboutToBeChanged, this,
                 &RPCConsole::peerLayoutAboutToChange);
 
         // set up ban table
         ui->banlistWidget->setModel(model->getBanTableModel());
         ui->banlistWidget->verticalHeader()->hide();
         ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
         ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
         ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
         ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
         ui->banlistWidget->setColumnWidth(BanTableModel::Address,
                                           BANSUBNET_COLUMN_WIDTH);
         ui->banlistWidget->setColumnWidth(BanTableModel::Bantime,
                                           BANTIME_COLUMN_WIDTH);
         ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
 
         // create ban table context menu action
         QAction *unbanAction = new QAction(tr("&Unban"), this);
 
         // create ban table context menu
         banTableContextMenu = new QMenu(this);
         banTableContextMenu->addAction(unbanAction);
 
         // ban table context menu signals
         connect(ui->banlistWidget, &QTableView::customContextMenuRequested,
                 this, &RPCConsole::showBanTableContextMenu);
         connect(unbanAction, &QAction::triggered, this,
                 &RPCConsole::unbanSelectedNode);
 
         // ban table signal handling - clear peer details when clicking a peer
         // in the ban table
         connect(ui->banlistWidget, &QTableView::clicked, this,
                 &RPCConsole::clearSelectedNode);
         // ban table signal handling - ensure ban table is shown or hidden (if
         // empty)
         connect(model->getBanTableModel(), &BanTableModel::layoutChanged, this,
                 &RPCConsole::showOrHideBanTableIfRequired);
         showOrHideBanTableIfRequired();
 
         // Provide initial values
         ui->clientVersion->setText(model->formatFullVersion());
         ui->clientUserAgent->setText(model->formatSubVersion());
         ui->dataDir->setText(model->dataDir());
         ui->blocksDir->setText(model->blocksDir());
         ui->startupTime->setText(model->formatClientStartupTime());
         ui->networkName->setText(
             QString::fromStdString(Params().NetworkIDString()));
 
         // Setup autocomplete and attach it
         QStringList wordList;
         std::vector<std::string> commandList = m_node.listRpcCommands();
         for (size_t i = 0; i < commandList.size(); ++i) {
             wordList << commandList[i].c_str();
             wordList << ("help " + commandList[i]).c_str();
         }
 
         wordList << "help-console";
         wordList.sort();
         autoCompleter = new QCompleter(wordList, this);
         autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
         ui->lineEdit->setCompleter(autoCompleter);
         autoCompleter->popup()->installEventFilter(this);
         // Start thread to execute RPC commands.
         startExecutor();
     }
     if (!model) {
         // Client model is being set to 0, this means shutdown() is about to be
         // called. Make sure we clean up the executor thread
         Q_EMIT stopExecutor();
         thread.wait();
     }
 }
 
 #ifdef ENABLE_WALLET
 void RPCConsole::addWallet(WalletModel *const walletModel) {
     // use name for text and wallet model for internal data object (to allow to
     // move to a wallet id later)
     ui->WalletSelector->addItem(walletModel->getDisplayName(),
                                 QVariant::fromValue(walletModel));
     if (ui->WalletSelector->count() == 2 && !isVisible()) {
         // First wallet added, set to default so long as the window isn't
         // presently visible (and potentially in use)
         ui->WalletSelector->setCurrentIndex(1);
     }
     if (ui->WalletSelector->count() > 2) {
         ui->WalletSelector->setVisible(true);
         ui->WalletSelectorLabel->setVisible(true);
     }
 }
 
 void RPCConsole::removeWallet(WalletModel *const walletModel) {
     ui->WalletSelector->removeItem(
         ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
     if (ui->WalletSelector->count() == 2) {
         ui->WalletSelector->setVisible(false);
         ui->WalletSelectorLabel->setVisible(false);
     }
 }
 #endif
 
 static QString categoryClass(int category) {
     switch (category) {
         case RPCConsole::CMD_REQUEST:
             return "cmd-request";
             break;
         case RPCConsole::CMD_REPLY:
             return "cmd-reply";
             break;
         case RPCConsole::CMD_ERROR:
             return "cmd-error";
             break;
         default:
             return "misc";
     }
 }
 
 void RPCConsole::fontBigger() {
     setFontSize(consoleFontSize + 1);
 }
 
 void RPCConsole::fontSmaller() {
     setFontSize(consoleFontSize - 1);
 }
 
 void RPCConsole::setFontSize(int newSize) {
     QSettings settings;
 
     // don't allow an insane font size
     if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height()) {
         return;
     }
 
     // temp. store the console content
     QString str = ui->messagesWidget->toHtml();
 
     // replace font tags size in current content
     str.replace(QString("font-size:%1pt").arg(consoleFontSize),
                 QString("font-size:%1pt").arg(newSize));
 
     // store the new font size
     consoleFontSize = newSize;
     settings.setValue(fontSizeSettingsKey, consoleFontSize);
 
     // clear console (reset icon sizes, default stylesheet) and re-add the
     // content
     float oldPosFactor = 1.0 /
                          ui->messagesWidget->verticalScrollBar()->maximum() *
                          ui->messagesWidget->verticalScrollBar()->value();
     clear(false);
     ui->messagesWidget->setHtml(str);
     ui->messagesWidget->verticalScrollBar()->setValue(
         oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
 }
 
 void RPCConsole::clear(bool clearHistory) {
     ui->messagesWidget->clear();
     if (clearHistory) {
         history.clear();
         historyPtr = 0;
     }
     ui->lineEdit->clear();
     ui->lineEdit->setFocus();
 
     // Add smoothly scaled icon images.
     // (when using width/height on an img, Qt uses nearest instead of linear
     // interpolation)
     for (int i = 0; ICON_MAPPING[i].url; ++i) {
         ui->messagesWidget->document()->addResource(
             QTextDocument::ImageResource, QUrl(ICON_MAPPING[i].url),
             platformStyle->SingleColorImage(ICON_MAPPING[i].source)
                 .scaled(QSize(consoleFontSize * 2, consoleFontSize * 2),
                         Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
     }
 
     // Set default style sheet
     QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
     ui->messagesWidget->document()->setDefaultStyleSheet(
         QString("table { }"
                 "td.time { color: #808080; font-size: %2; padding-top: 3px; } "
                 "td.message { font-family: %1; font-size: %2; "
                 "white-space:pre-wrap; } "
                 "td.cmd-request { color: #006060; } "
                 "td.cmd-error { color: red; } "
                 ".secwarning { color: red; }"
                 "b { color: #006060; } ")
             .arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize)));
 
 #ifdef Q_OS_MAC
     QString clsKey = "(⌘)-L";
 #else
     QString clsKey = "Ctrl-L";
 #endif
 
     message(CMD_REPLY,
             (tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
              tr("Use up and down arrows to navigate history, and "
                 "%1 to clear screen.")
                  .arg("<b>" + clsKey + "</b>") +
              "<br>" +
              tr("Type %1 for an overview of available commands.")
                  .arg("<b>help</b>") +
              "<br>" +
              tr("For more information on using this console type %1.")
                  .arg("<b>help-console</b>") +
              "<br><span class=\"secwarning\"><br>" +
              tr("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.") +
              "</span>"),
             true);
 }
 
 void RPCConsole::keyPressEvent(QKeyEvent *event) {
     if (windowType() != Qt::Widget && event->key() == Qt::Key_Escape) {
         close();
     }
 }
 
 void RPCConsole::message(int category, const QString &message, bool html) {
     QTime time = QTime::currentTime();
     QString timeString = time.toString();
     QString out;
     out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
     out += "<td class=\"icon\" width=\"32\"><img src=\"" +
            categoryClass(category) + "\"></td>";
     out += "<td class=\"message " + categoryClass(category) +
            "\" valign=\"middle\">";
     if (html) {
         out += message;
     } else {
         out += GUIUtil::HtmlEscape(message, false);
     }
     out += "</td></tr></table>";
     ui->messagesWidget->append(out);
 }
 
 void RPCConsole::updateNetworkState() {
     QString connections =
         QString::number(clientModel->getNumConnections()) + " (";
     connections += tr("In:") + " " +
                    QString::number(clientModel->getNumConnections(
                        ClientModel::CONNECTIONS_IN)) +
                    " / ";
     connections += tr("Out:") + " " +
                    QString::number(clientModel->getNumConnections(
                        ClientModel::CONNECTIONS_OUT)) +
                    ")";
 
     if (!clientModel->node().getNetworkActive()) {
         connections += " (" + tr("Network activity disabled") + ")";
     }
 
     ui->numberOfConnections->setText(connections);
 }
 
 void RPCConsole::setNumConnections(int count) {
     if (!clientModel) {
         return;
     }
 
     updateNetworkState();
 }
 
 void RPCConsole::setNetworkActive(bool networkActive) {
     updateNetworkState();
 }
 
 void RPCConsole::setNumBlocks(int count, const QDateTime &blockDate,
                               double nVerificationProgress, bool headers) {
     if (!headers) {
         ui->numberOfBlocks->setText(QString::number(count));
         ui->lastBlockTime->setText(blockDate.toString());
     }
 }
 
 void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) {
     ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
 
     if (dynUsage < 1000000) {
         ui->mempoolSize->setText(QString::number(dynUsage / 1000.0, 'f', 2) +
                                  " KB");
     } else {
         ui->mempoolSize->setText(QString::number(dynUsage / 1000000.0, 'f', 2) +
                                  " MB");
     }
 }
 
 void RPCConsole::on_lineEdit_returnPressed() {
     QString cmd = ui->lineEdit->text();
 
     if (!cmd.isEmpty()) {
         std::string strFilteredCmd;
         try {
             std::string dummy;
             if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false,
                                      &strFilteredCmd)) {
                 // Failed to parse command, so we cannot even filter it for the
                 // history
                 throw std::runtime_error("Invalid command line");
             }
         } catch (const std::exception &e) {
             QMessageBox::critical(this, "Error",
                                   QString("Error: ") +
                                       QString::fromStdString(e.what()));
             return;
         }
 
         ui->lineEdit->clear();
 
         cmdBeforeBrowsing = QString();
 
 #ifdef ENABLE_WALLET
         WalletModel *wallet_model{nullptr};
         const int wallet_index = ui->WalletSelector->currentIndex();
         if (wallet_index > 0) {
             wallet_model = ui->WalletSelector->itemData(wallet_index)
                                .value<WalletModel *>();
         }
 
         if (m_last_wallet_model != wallet_model) {
             if (wallet_model) {
                 message(CMD_REQUEST, tr("Executing command using \"%1\" wallet")
                                          .arg(wallet_model->getWalletName()));
             } else {
                 message(CMD_REQUEST,
                         tr("Executing command without any wallet"));
             }
             m_last_wallet_model = wallet_model;
         }
 #endif
 
         message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
         Q_EMIT cmdRequest(cmd, m_last_wallet_model);
 
         cmd = QString::fromStdString(strFilteredCmd);
 
         // Remove command, if already in history
         history.removeOne(cmd);
         // Append command to history
         history.append(cmd);
         // Enforce maximum history size
         while (history.size() > CONSOLE_HISTORY) {
             history.removeFirst();
         }
         // Set pointer to end of history
         historyPtr = history.size();
 
         // Scroll console view to end
         scrollToEnd();
     }
 }
 
 void RPCConsole::browseHistory(int offset) {
     // store current text when start browsing through the history
     if (historyPtr == history.size()) {
         cmdBeforeBrowsing = ui->lineEdit->text();
     }
 
     historyPtr += offset;
     if (historyPtr < 0) {
         historyPtr = 0;
     }
     if (historyPtr > history.size()) {
         historyPtr = history.size();
     }
     QString cmd;
     if (historyPtr < history.size()) {
         cmd = history.at(historyPtr);
     } else if (!cmdBeforeBrowsing.isNull()) {
         cmd = cmdBeforeBrowsing;
     }
     ui->lineEdit->setText(cmd);
 }
 
 void RPCConsole::startExecutor() {
     RPCExecutor *executor = new RPCExecutor(m_node);
     executor->moveToThread(&thread);
 
     // Replies from executor object must go to this object
     connect(executor, &RPCExecutor::reply, this,
             static_cast<void (RPCConsole::*)(int, const QString &)>(
                 &RPCConsole::message));
 
     // Requests from this object must go to executor
     connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
 
     // On stopExecutor signal
     // - quit the Qt event loop in the execution thread
     connect(this, &RPCConsole::stopExecutor, &thread, &QThread::quit);
     // - queue executor for deletion (in execution thread)
     connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater,
             Qt::DirectConnection);
 
     // Default implementation of QThread::run() simply spins up an event loop in
     // the thread, which is what we want.
     thread.start();
 }
 
 void RPCConsole::on_tabWidget_currentChanged(int index) {
     if (ui->tabWidget->widget(index) == ui->tab_console) {
         ui->lineEdit->setFocus();
     } else if (ui->tabWidget->widget(index) != ui->tab_peers) {
         clearSelectedNode();
     }
 }
 
 void RPCConsole::on_openDebugLogfileButton_clicked() {
     GUIUtil::openDebugLogfile();
 }
 
 void RPCConsole::scrollToEnd() {
     QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
     scrollbar->setValue(scrollbar->maximum());
 }
 
 void RPCConsole::on_sldGraphRange_valueChanged(int value) {
     const int multiplier = 5; // each position on the slider represents 5 min
     int mins = value * multiplier;
     setTrafficGraphRange(mins);
 }
 
 void RPCConsole::setTrafficGraphRange(int mins) {
     ui->trafficGraph->setGraphRangeMins(mins);
     ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60));
 }
 
 void RPCConsole::updateTrafficStats(quint64 totalBytesIn,
                                     quint64 totalBytesOut) {
     ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
     ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
 }
 
 void RPCConsole::peerSelected(const QItemSelection &selected,
                               const QItemSelection &deselected) {
     Q_UNUSED(deselected);
 
     if (!clientModel || !clientModel->getPeerTableModel() ||
         selected.indexes().isEmpty()) {
         return;
     }
 
     const CNodeCombinedStats *stats =
         clientModel->getPeerTableModel()->getNodeStats(
             selected.indexes().first().row());
     if (stats) {
         updateNodeDetail(stats);
     }
 }
 
 void RPCConsole::peerLayoutAboutToChange() {
     QModelIndexList selected =
         ui->peerWidget->selectionModel()->selectedIndexes();
     cachedNodeids.clear();
     for (int i = 0; i < selected.size(); i++) {
         const CNodeCombinedStats *stats =
             clientModel->getPeerTableModel()->getNodeStats(
                 selected.at(i).row());
         cachedNodeids.append(stats->nodeStats.nodeid);
     }
 }
 
 void RPCConsole::peerLayoutChanged() {
     if (!clientModel || !clientModel->getPeerTableModel()) {
         return;
     }
 
     const CNodeCombinedStats *stats = nullptr;
     bool fUnselect = false;
     bool fReselect = false;
 
     // no node selected yet
     if (cachedNodeids.empty()) {
         return;
     }
 
     // find the currently selected row
     int selectedRow = -1;
     QModelIndexList selectedModelIndex =
         ui->peerWidget->selectionModel()->selectedIndexes();
     if (!selectedModelIndex.isEmpty()) {
         selectedRow = selectedModelIndex.first().row();
     }
 
     // check if our detail node has a row in the table (it may not necessarily
     // be at selectedRow since its position can change after a layout change)
     int detailNodeRow =
         clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.first());
 
     if (detailNodeRow < 0) {
         // detail node disappeared from table (node disconnected)
         fUnselect = true;
     } else {
         if (detailNodeRow != selectedRow) {
             // detail node moved position
             fUnselect = true;
             fReselect = true;
         }
 
         // get fresh stats on the detail node.
         stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
     }
 
     if (fUnselect && selectedRow >= 0) {
         clearSelectedNode();
     }
 
     if (fReselect) {
         for (int i = 0; i < cachedNodeids.size(); i++) {
             ui->peerWidget->selectRow(
                 clientModel->getPeerTableModel()->getRowByNodeId(
                     cachedNodeids.at(i)));
         }
     }
 
     if (stats) {
         updateNodeDetail(stats);
     }
 }
 
 void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) {
     // update the detail ui with latest node information
     QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) +
                             " ");
     peerAddrDetails +=
         tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
     if (!stats->nodeStats.addrLocal.empty()) {
         peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(
                                           stats->nodeStats.addrLocal));
     }
     ui->peerHeading->setText(peerAddrDetails);
     ui->peerServices->setText(
         GUIUtil::formatServicesStr(stats->nodeStats.nServices));
     ui->peerLastSend->setText(
         stats->nodeStats.nLastSend
             ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() -
                                          stats->nodeStats.nLastSend)
             : tr("never"));
     ui->peerLastRecv->setText(
         stats->nodeStats.nLastRecv
             ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() -
                                          stats->nodeStats.nLastRecv)
             : tr("never"));
     ui->peerBytesSent->setText(
         GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
     ui->peerBytesRecv->setText(
         GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
     ui->peerConnTime->setText(GUIUtil::formatDurationStr(
         GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
     ui->peerPingTime->setText(
         GUIUtil::formatPingTime(stats->nodeStats.m_ping_usec));
     ui->peerPingWait->setText(
         GUIUtil::formatPingTime(stats->nodeStats.m_ping_wait_usec));
     ui->peerMinPing->setText(
         GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
     ui->timeoffset->setText(
         GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
     ui->peerVersion->setText(
         QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
     ui->peerSubversion->setText(
         QString::fromStdString(stats->nodeStats.cleanSubVer));
     ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound")
                                                          : tr("Outbound"));
     ui->peerHeight->setText(
         QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
     ui->peerWhitelisted->setText(
         stats->nodeStats.m_legacyWhitelisted ? tr("Yes") : tr("No"));
 
     // This check fails for example if the lock was busy and
     // nodeStateStats couldn't be fetched.
     if (stats->fNodeStateStatsAvailable) {
         // Ban score is init to 0
         ui->peerBanScore->setText(
             QString("%1").arg(stats->nodeStateStats.nMisbehavior));
 
         // Sync height is init to -1
         if (stats->nodeStateStats.nSyncHeight > -1) {
             ui->peerSyncHeight->setText(
                 QString("%1").arg(stats->nodeStateStats.nSyncHeight));
         } else {
             ui->peerSyncHeight->setText(tr("Unknown"));
         }
 
         // Common height is init to -1
         if (stats->nodeStateStats.nCommonHeight > -1) {
             ui->peerCommonHeight->setText(
                 QString("%1").arg(stats->nodeStateStats.nCommonHeight));
         } else {
             ui->peerCommonHeight->setText(tr("Unknown"));
         }
     }
 
     ui->detailWidget->show();
 }
 
 void RPCConsole::resizeEvent(QResizeEvent *event) {
     QWidget::resizeEvent(event);
 }
 
 void RPCConsole::showEvent(QShowEvent *event) {
     QWidget::showEvent(event);
 
     if (!clientModel || !clientModel->getPeerTableModel()) {
         return;
     }
 
     // start PeerTableModel auto refresh
     clientModel->getPeerTableModel()->startAutoRefresh();
 }
 
 void RPCConsole::hideEvent(QHideEvent *event) {
     QWidget::hideEvent(event);
 
     if (!clientModel || !clientModel->getPeerTableModel()) {
         return;
     }
 
     // stop PeerTableModel auto refresh
     clientModel->getPeerTableModel()->stopAutoRefresh();
 }
 
 void RPCConsole::showPeersTableContextMenu(const QPoint &point) {
     QModelIndex index = ui->peerWidget->indexAt(point);
     if (index.isValid()) {
         peersTableContextMenu->exec(QCursor::pos());
     }
 }
 
 void RPCConsole::showBanTableContextMenu(const QPoint &point) {
     QModelIndex index = ui->banlistWidget->indexAt(point);
     if (index.isValid()) {
         banTableContextMenu->exec(QCursor::pos());
     }
 }
 
 void RPCConsole::disconnectSelectedNode() {
     // Get selected peer addresses
     QList<QModelIndex> nodes =
         GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
     for (int i = 0; i < nodes.count(); i++) {
         // Get currently selected peer address
         NodeId id = nodes.at(i).data().toLongLong();
         // Find the node, disconnect it and clear the selected node
         if (m_node.disconnect(id)) {
             clearSelectedNode();
         }
     }
 }
 
 void RPCConsole::banSelectedNode(int bantime) {
     if (!clientModel) {
         return;
     }
 
     // Get selected peer addresses
     QList<QModelIndex> nodes =
         GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
     for (int i = 0; i < nodes.count(); i++) {
         // Get currently selected peer address
         NodeId id = nodes.at(i).data().toLongLong();
 
         // Get currently selected peer address
         int detailNodeRow =
             clientModel->getPeerTableModel()->getRowByNodeId(id);
         if (detailNodeRow < 0) {
             return;
         }
 
         // Find possible nodes, ban it and clear the selected node
         const CNodeCombinedStats *stats =
             clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
         if (stats) {
             m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
             m_node.disconnect(stats->nodeStats.addr);
         }
     }
     clearSelectedNode();
     clientModel->getBanTableModel()->refresh();
 }
 
 void RPCConsole::unbanSelectedNode() {
     if (!clientModel) {
         return;
     }
 
     // Get selected ban addresses
     QList<QModelIndex> nodes =
         GUIUtil::getEntryData(ui->banlistWidget, BanTableModel::Address);
     for (int i = 0; i < nodes.count(); i++) {
         // Get currently selected ban address
         QString strNode = nodes.at(i).data().toString();
         CSubNet possibleSubnet;
 
         LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
         if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet)) {
             clientModel->getBanTableModel()->refresh();
         }
     }
 }
 
 void RPCConsole::clearSelectedNode() {
     ui->peerWidget->selectionModel()->clearSelection();
     cachedNodeids.clear();
     ui->detailWidget->hide();
     ui->peerHeading->setText(tr("Select a peer to view detailed information."));
 }
 
 void RPCConsole::showOrHideBanTableIfRequired() {
     if (!clientModel) {
         return;
     }
 
     bool visible = clientModel->getBanTableModel()->shouldShow();
     ui->banlistWidget->setVisible(visible);
     ui->banHeading->setVisible(visible);
 }
 
 void RPCConsole::setTabFocus(enum TabTypes tabType) {
     ui->tabWidget->setCurrentIndex(tabType);
 }
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 09c359eea..e736f5e76 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,1746 +1,1746 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2016 The Bitcoin Core developers
 // Copyright (c) 2018-2020 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_WALLET_WALLET_H
 #define BITCOIN_WALLET_WALLET_H
 
 #include <amount.h>
 #include <interfaces/chain.h>
 #include <interfaces/handler.h>
 #include <outputtype.h>
 #include <primitives/blockhash.h>
 #include <streams.h>
 #include <tinyformat.h>
 #include <ui_interface.h>
 #include <util/strencodings.h>
 #include <util/system.h>
 #include <validationinterface.h>
 #include <wallet/coinselection.h>
 #include <wallet/crypter.h>
 #include <wallet/ismine.h>
 #include <wallet/rpcwallet.h>
 #include <wallet/walletdb.h>
 #include <wallet/walletutil.h>
 
 #include <algorithm>
 #include <atomic>
 #include <cstdint>
 #include <map>
 #include <memory>
 #include <set>
 #include <stdexcept>
 #include <string>
 #include <utility>
 #include <vector>
 
 #include <boost/signals2/signal.hpp>
 
 //! Explicitly unload and delete the wallet.
 //! Blocks the current thread after signaling the unload intent so that all
 //! wallet clients release the wallet.
 //! Note that, when blocking is not required, the wallet is implicitly unloaded
 //! by the shared pointer deleter.
 void UnloadWallet(std::shared_ptr<CWallet> &&wallet);
 
 bool AddWallet(const std::shared_ptr<CWallet> &wallet);
 bool RemoveWallet(const std::shared_ptr<CWallet> &wallet);
 bool HasWallets();
 std::vector<std::shared_ptr<CWallet>> GetWallets();
 std::shared_ptr<CWallet> GetWallet(const std::string &name);
 std::shared_ptr<CWallet> LoadWallet(const CChainParams &chainParams,
                                     interfaces::Chain &chain,
                                     const WalletLocation &location,
                                     std::string &error, std::string &warning);
 
 enum class WalletCreationStatus { SUCCESS, CREATION_FAILED, ENCRYPTION_FAILED };
 
 WalletCreationStatus
 CreateWallet(const CChainParams &params, interfaces::Chain &chain,
              const SecureString &passphrase, uint64_t wallet_creation_flags,
              const std::string &name, std::string &error, std::string &warning,
              std::shared_ptr<CWallet> &result);
 
 //! Default for -keypool
 static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
 //! -paytxfee default
 constexpr Amount DEFAULT_PAY_TX_FEE = Amount::zero();
 //! -fallbackfee default
 static const Amount DEFAULT_FALLBACK_FEE(20000 * SATOSHI);
 //! -mintxfee default
 static const Amount DEFAULT_TRANSACTION_MINFEE_PER_KB = 1000 * SATOSHI;
 //! minimum recommended increment for BIP 125 replacement txs
 static const Amount WALLET_INCREMENTAL_RELAY_FEE(5000 * SATOSHI);
 //! Default for -spendzeroconfchange
 static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
 //! Default for -walletrejectlongchains
 static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
 //! Default for -avoidpartialspends
 static const bool DEFAULT_AVOIDPARTIALSPENDS = false;
 static const bool DEFAULT_WALLETBROADCAST = true;
 static const bool DEFAULT_DISABLE_WALLET = false;
 //! -maxtxfee default
 constexpr Amount DEFAULT_TRANSACTION_MAXFEE{COIN / 10};
 //! Discourage users to set fees higher than this amount (in satoshis) per kB
 constexpr Amount HIGH_TX_FEE_PER_KB{COIN / 100};
 //! -maxtxfee will warn if called with a higher fee than this amount (in
 //! satoshis)
 constexpr Amount HIGH_MAX_TX_FEE{100 * HIGH_TX_FEE_PER_KB};
 
 class CChainParams;
 class CCoinControl;
 class COutput;
 class CScript;
 class CTxMemPool;
 class CWalletTx;
 class ReserveDestination;
 
 /** (client) version numbers for particular wallet features */
 enum WalletFeature {
     // the earliest version new wallets supports (only useful for
     // getwalletinfo's clientversion output)
     FEATURE_BASE = 10500,
 
     // wallet encryption
     FEATURE_WALLETCRYPT = 40000,
     // compressed public keys
     FEATURE_COMPRPUBKEY = 60000,
 
     // Hierarchical key derivation after BIP32 (HD Wallet)
     FEATURE_HD = 130000,
 
     // Wallet with HD chain split (change outputs will use m/0'/1'/k)
     FEATURE_HD_SPLIT = 160300,
 
     // Wallet without a default key written
     FEATURE_NO_DEFAULT_KEY = 190700,
 
     // Upgraded to HD SPLIT and can have a pre-split keypool
     FEATURE_PRE_SPLIT_KEYPOOL = 200300,
 
     FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL,
 };
 
 //! Default for -addresstype
 constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::LEGACY};
 
 //! Default for -changetype
 constexpr OutputType DEFAULT_CHANGE_TYPE{OutputType::CHANGE_AUTO};
 
 enum WalletFlags : uint64_t {
     // Wallet flags in the upper section (> 1 << 31) will lead to not opening
     // the wallet if flag is unknown.
     // Unknown wallet flags in the lower section <= (1 << 31) will be tolerated.
 
     // will categorize coins as clean (not reused) and dirty (reused), and
     // handle
     // them with privacy considerations in mind
     WALLET_FLAG_AVOID_REUSE = (1ULL << 0),
 
     // Indicates that the metadata has already been upgraded to contain key
     // origins
     WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
 
     // Will enforce the rule that the wallet can't contain any private keys
     // (only watch-only/pubkeys).
     WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
 
     //! Flag set when a wallet contains no HD seed and no private keys, scripts,
     //! addresses, and other watch only things, and is therefore "blank."
     //!
     //! The only function this flag serves is to distinguish a blank wallet from
     //! a newly created wallet when the wallet database is loaded, to avoid
     //! initialization that should only happen on first run.
     //!
     //! This flag is also a mandatory flag to prevent previous versions of
     //! bitcoin from opening the wallet, thinking it was newly created, and
     //! then improperly reinitializing it.
     WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
 };
 
 static constexpr uint64_t KNOWN_WALLET_FLAGS =
     WALLET_FLAG_AVOID_REUSE | WALLET_FLAG_BLANK_WALLET |
     WALLET_FLAG_KEY_ORIGIN_METADATA | WALLET_FLAG_DISABLE_PRIVATE_KEYS;
 
 static constexpr uint64_t MUTABLE_WALLET_FLAGS = WALLET_FLAG_AVOID_REUSE;
 
 static const std::map<std::string, WalletFlags> WALLET_FLAG_MAP{
     {"avoid_reuse", WALLET_FLAG_AVOID_REUSE},
     {"blank", WALLET_FLAG_BLANK_WALLET},
     {"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA},
     {"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS},
 };
 
 extern const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS;
 
 /**
  * A key from a CWallet's keypool
  *
  * The wallet holds one (for pre HD-split wallets) or several keypools. These
  * are sets of keys that have not yet been used to provide addresses or receive
  * change.
  *
  * The Bitcoin ABC wallet was originally a collection of unrelated private
  * keys with their associated addresses. If a non-HD wallet generated a
  * key/address, gave that address out and then restored a backup from before
  * that key's generation, then any funds sent to that address would be
  * lost definitively.
  *
  * The keypool was implemented to avoid this scenario (commit: 10384941). The
  * wallet would generate a set of keys (100 by default). When a new public key
  * was required, either to give out as an address or to use in a change output,
  * it would be drawn from the keypool. The keypool would then be topped up to
  * maintain 100 keys. This ensured that as long as the wallet hadn't used more
  * than 100 keys since the previous backup, all funds would be safe, since a
  * restored wallet would be able to scan for all owned addresses.
  *
  * A keypool also allowed encrypted wallets to give out addresses without
  * having to be decrypted to generate a new private key.
  *
  * With the introduction of HD wallets (commit: f1902510), the keypool
  * essentially became an address look-ahead pool. Restoring old backups can no
  * longer definitively lose funds as long as the addresses used were from the
  * wallet's HD seed (since all private keys can be rederived from the seed).
  * However, if many addresses were used since the backup, then the wallet may
  * not know how far ahead in the HD chain to look for its addresses. The
  * keypool is used to implement a 'gap limit'. The keypool maintains a set of
  * keys (by default 1000) ahead of the last used key and scans for the
  * addresses of those keys.  This avoids the risk of not seeing transactions
  * involving the wallet's addresses, or of re-using the same address.
  *
  * The HD-split wallet feature added a second keypool (commit: 02592f4c). There
  * is an external keypool (for addresses to hand out) and an internal keypool
  * (for change addresses).
  *
  * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
  * stored as sets of indexes in the wallet (setInternalKeyPool,
  * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
  * index (m_pool_key_to_index). The CKeyPool object is used to
  * serialize/deserialize the pool data to/from the database.
  */
 class CKeyPool {
 public:
     //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
     int64_t nTime;
     //! The public key
     CPubKey vchPubKey;
     //! Whether this keypool entry is in the internal keypool (for change
     //! outputs)
     bool fInternal;
     //! Whether this key was generated for a keypool before the wallet was
     //! upgraded to HD-split
     bool m_pre_split;
 
     CKeyPool();
     CKeyPool(const CPubKey &vchPubKeyIn, bool internalIn);
 
     ADD_SERIALIZE_METHODS;
 
     template <typename Stream, typename Operation>
     inline void SerializationOp(Stream &s, Operation ser_action) {
         int nVersion = s.GetVersion();
         if (!(s.GetType() & SER_GETHASH)) {
             READWRITE(nVersion);
         }
 
         READWRITE(nTime);
         READWRITE(vchPubKey);
         if (ser_action.ForRead()) {
             try {
                 READWRITE(fInternal);
             } catch (std::ios_base::failure &) {
                 /**
                  * flag as external address if we can't read the internal
                  * boolean (this will be the case for any wallet before the HD
                  * chain split version)
                  */
                 fInternal = false;
             }
             try {
                 READWRITE(m_pre_split);
             } catch (std::ios_base::failure &) {
                 /**
                  * flag as postsplit address if we can't read the m_pre_split
                  * boolean (this will be the case for any wallet that upgrades
                  * to HD chain split)
                  */
                 m_pre_split = false;
             }
         } else {
             READWRITE(fInternal);
             READWRITE(m_pre_split);
         }
     }
 };
 
 /**
  * A wrapper to reserve an address from a wallet
  *
  * ReserveDestination is used to reserve an address.
  * It is currently only used inside of CreateTransaction.
  *
  * Instantiating a ReserveDestination does not reserve an address. To do so,
  * GetReservedDestination() needs to be called on the object. Once an address
  * has been reserved, call KeepDestination() on the ReserveDestination object to
  * make sure it is not returned. Call ReturnDestination() to return the address
  * so it can be re-used (for example, if the address was used in a new
  * transaction and that transaction was not completed and needed to be aborted).
  *
  * If an address is reserved and KeepDestination() is not called, then the
  * address will be returned when the ReserveDestination goes out of scope.
  */
 class ReserveDestination {
 protected:
     //! The wallet to reserve from
     CWallet *pwallet;
     //! The index of the address's key in the keypool
     int64_t nIndex{-1};
     //! The public key for the address
     CPubKey vchPubKey;
     //! The destination
     CTxDestination address;
     //! Whether this is from the internal (change output) keypool
     bool fInternal{false};
 
 public:
     //! Construct a ReserveDestination object. This does NOT reserve an address
     //! yet
     explicit ReserveDestination(CWallet *pwalletIn) { pwallet = pwalletIn; }
 
     ReserveDestination(const ReserveDestination &) = delete;
     ReserveDestination &operator=(const ReserveDestination &) = delete;
 
     //! Destructor. If a key has been reserved and not KeepKey'ed, it will be
     //! returned to the keypool
     ~ReserveDestination() { ReturnDestination(); }
 
     //! Reserve an address
     bool GetReservedDestination(const OutputType type, CTxDestination &pubkey,
                                 bool internal);
     //! Return reserved address
     void ReturnDestination();
     //! Keep the address. Do not return it's key to the keypool when this object
     //! goes out of scope
     void KeepDestination();
 };
 
 /** Address book data */
 class CAddressBookData {
 public:
     std::string name;
     std::string purpose;
 
     CAddressBookData() : purpose("unknown") {}
 
     typedef std::map<std::string, std::string> StringMap;
     StringMap destdata;
 };
 
 struct CRecipient {
     CScript scriptPubKey;
     Amount nAmount;
     bool fSubtractFeeFromAmount;
 };
 
 typedef std::map<std::string, std::string> mapValue_t;
 
 static inline void ReadOrderPos(int64_t &nOrderPos, mapValue_t &mapValue) {
     if (!mapValue.count("n")) {
         // TODO: calculate elsewhere
         nOrderPos = -1;
         return;
     }
 
     nOrderPos = atoi64(mapValue["n"].c_str());
 }
 
 static inline void WriteOrderPos(const int64_t &nOrderPos,
                                  mapValue_t &mapValue) {
     if (nOrderPos == -1) {
         return;
     }
     mapValue["n"] = i64tostr(nOrderPos);
 }
 
 struct COutputEntry {
     CTxDestination destination;
     Amount amount;
     int vout;
 };
 
 /**
  * Legacy class used for deserializing vtxPrev for backwards compatibility.
  * vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3,
  * but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs.
  * These need to get deserialized for field alignment when deserializing
  * a CWalletTx, but the deserialized values are discarded.
  */
 class CMerkleTx {
 public:
     template <typename Stream> void Unserialize(Stream &s) {
         CTransactionRef tx;
         BlockHash hashBlock;
         std::vector<uint256> vMerkleBranch;
         int nIndex = 0;
 
         s >> tx >> hashBlock >> vMerkleBranch >> nIndex;
     }
 };
 
 // Get the marginal bytes of spending the specified output
 int CalculateMaximumSignedInputSize(const CTxOut &txout, const CWallet *pwallet,
                                     bool use_max_sig = false);
 
 /**
  * A transaction with a bunch of additional info that only the owner cares
  * about. It includes any unrecorded transactions needed to link it back to the
  * block chain.
  */
 class CWalletTx {
 private:
     const CWallet *pwallet;
 
     /**
      * Constant used in hashBlock to indicate tx has been abandoned, only used
      * at serialization/deserialization to avoid ambiguity with conflicted.
      */
     static const BlockHash ABANDON_HASH;
 
 public:
     /**
      * Key/value map with information about the transaction.
      *
      * The following keys can be read and written through the map and are
      * serialized in the wallet database:
      *
      *     "comment", "to"   - comment strings provided to sendtoaddress,
      *                         and sendmany wallet RPCs
      *     "replaces_txid"   - txid (as HexStr) of transaction replaced by
      *                         bumpfee on transaction created by bumpfee
      *     "replaced_by_txid" - txid (as HexStr) of transaction created by
      *                         bumpfee on transaction replaced by bumpfee
      *     "from", "message" - obsolete fields that could be set in UI prior to
      *                         2011 (removed in commit 4d9b223)
      *
      * The following keys are serialized in the wallet database, but shouldn't
      * be read or written through the map (they will be temporarily added and
      * removed from the map during serialization):
      *
      *     "fromaccount"     - serialized strFromAccount value
      *     "n"               - serialized nOrderPos value
      *     "timesmart"       - serialized nTimeSmart value
      *     "spent"           - serialized vfSpent value that existed prior to
      *                         2014 (removed in commit 93a18a3)
      */
     mapValue_t mapValue;
     std::vector<std::pair<std::string, std::string>> vOrderForm;
     unsigned int fTimeReceivedIsTxTime;
     //! time received by this node
     unsigned int nTimeReceived;
     /**
      * Stable timestamp that never changes, and reflects the order a transaction
      * was added to the wallet. Timestamp is based on the block time for a
      * transaction added as part of a block, or else the time when the
      * transaction was received if it wasn't part of a block, with the timestamp
      * adjusted in both cases so timestamp order matches the order transactions
      * were added to the wallet. More details can be found in
      * CWallet::ComputeTimeSmart().
      */
     unsigned int nTimeSmart;
     /**
      * From me flag is set to 1 for transactions that were created by the wallet
      * on this bitcoin node, and set to 0 for transactions that were created
      * externally and came in through the network or sendrawtransaction RPC.
      */
     bool fFromMe;
     //! position in ordered transaction list
     int64_t nOrderPos;
     std::multimap<int64_t, CWalletTx *>::const_iterator m_it_wtxOrdered;
 
     // memory only
     enum AmountType {
         DEBIT,
         CREDIT,
         IMMATURE_CREDIT,
         AVAILABLE_CREDIT,
         AMOUNTTYPE_ENUM_ELEMENTS
     };
     Amount GetCachableAmount(AmountType type, const isminefilter &filter,
                              bool recalculate = false) const;
     mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
     mutable bool fChangeCached;
     mutable bool fInMempool;
     mutable Amount nChangeCached;
 
     CWalletTx(const CWallet *pwalletIn, CTransactionRef arg)
         : tx(std::move(arg)) {
         Init(pwalletIn);
     }
 
     void Init(const CWallet *pwalletIn) {
         pwallet = pwalletIn;
         mapValue.clear();
         vOrderForm.clear();
         fTimeReceivedIsTxTime = false;
         nTimeReceived = 0;
         nTimeSmart = 0;
         fFromMe = false;
         fChangeCached = false;
         fInMempool = false;
         nChangeCached = Amount::zero();
         nOrderPos = -1;
         m_confirm = Confirmation{};
     }
 
     CTransactionRef tx;
 
     /**
      * New transactions start as UNCONFIRMED. At BlockConnected,
      * they will transition to CONFIRMED. In case of reorg, at
      * BlockDisconnected, they roll back to UNCONFIRMED. If we detect a
      * conflicting transaction at block connection, we update conflicted tx and
      * its dependencies as CONFLICTED. If tx isn't confirmed and outside of
      * mempool, the user may switch it to ABANDONED by using the
      * abandontransaction call. This last status may be override by a CONFLICTED
      * or CONFIRMED transition.
      */
     enum Status { UNCONFIRMED, CONFIRMED, CONFLICTED, ABANDONED };
 
     /**
      * Confirmation includes tx status and a pair of {block hash/tx index in
      * block} at which tx has been confirmed. This pair is both 0 if tx hasn't
      * confirmed yet. Meaning of these fields changes with CONFLICTED state
      * where they instead point to block hash and index of the deepest
      * conflicting tx.
      */
     struct Confirmation {
         Status status = UNCONFIRMED;
         BlockHash hashBlock = BlockHash();
         int nIndex = 0;
     };
 
     Confirmation m_confirm;
 
     template <typename Stream> void Serialize(Stream &s) const {
         mapValue_t mapValueCopy = mapValue;
 
         mapValueCopy["fromaccount"] = "";
         WriteOrderPos(nOrderPos, mapValueCopy);
         if (nTimeSmart) {
             mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
         }
 
         //! Used to be vMerkleBranch
         std::vector<char> dummy_vector1;
         //! Used to be vtxPrev
         std::vector<char> dummy_vector2;
         //! Used to be fSpent
         bool dummy_bool = false;
         uint256 serializedHash =
             isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock;
         int serializedIndex =
             isAbandoned() || isConflicted() ? -1 : m_confirm.nIndex;
         s << tx << serializedHash << dummy_vector1 << serializedIndex
           << dummy_vector2 << mapValueCopy << vOrderForm
           << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool;
     }
 
     template <typename Stream> void Unserialize(Stream &s) {
         Init(nullptr);
 
         //! Used to be vMerkleBranch
         std::vector<uint256> dummy_vector1;
         //! Used to be vtxPrev
         std::vector<CMerkleTx> dummy_vector2;
         //! Used to be fSpent
         bool dummy_bool;
         int serializedIndex;
         s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >>
             dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >>
             nTimeReceived >> fFromMe >> dummy_bool;
 
         /*
          * At serialization/deserialization, an nIndex == -1 means that
          * hashBlock refers to the earliest block in the chain we know this or
          * any in-wallet ancestor conflicts with. If nIndex == -1 and hashBlock
          * is ABANDON_HASH, it means transaction is abandoned. In same context,
          * an nIndex >= 0 refers to a confirmed transaction (if hashBlock set)
          * or unconfirmed one. Older clients interpret nIndex == -1 as
          * unconfirmed for backward compatibility (pre-commit 9ac63d6).
          */
         if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) {
             m_confirm.hashBlock = BlockHash();
             setAbandoned();
         } else if (serializedIndex == -1) {
             setConflicted();
         } else if (!m_confirm.hashBlock.IsNull()) {
             m_confirm.nIndex = serializedIndex;
             setConfirmed();
         }
 
         ReadOrderPos(nOrderPos, mapValue);
         nTimeSmart = mapValue.count("timesmart")
                          ? (unsigned int)atoi64(mapValue["timesmart"])
                          : 0;
 
         mapValue.erase("fromaccount");
         mapValue.erase("spent");
         mapValue.erase("n");
         mapValue.erase("timesmart");
     }
 
     void SetTx(CTransactionRef arg) { tx = std::move(arg); }
 
     //! make sure balances are recalculated
     void MarkDirty() {
         m_amounts[DEBIT].Reset();
         m_amounts[CREDIT].Reset();
         m_amounts[IMMATURE_CREDIT].Reset();
         m_amounts[AVAILABLE_CREDIT].Reset();
         fChangeCached = false;
     }
 
     void BindWallet(CWallet *pwalletIn) {
         pwallet = pwalletIn;
         MarkDirty();
     }
 
     //! filter decides which addresses will count towards the debit
     Amount GetDebit(const isminefilter &filter) const;
     Amount GetCredit(interfaces::Chain::Lock &locked_chain,
                      const isminefilter &filter) const;
     Amount GetImmatureCredit(interfaces::Chain::Lock &locked_chain,
                              bool fUseCache = true) const;
     // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
     // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
     // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
     // having to resolve the issue of member access into incomplete type
     // CWallet.
     Amount GetAvailableCredit(interfaces::Chain::Lock &locked_chain,
                               bool fUseCache = true,
                               const isminefilter &filter = ISMINE_SPENDABLE)
         const NO_THREAD_SAFETY_ANALYSIS;
     Amount GetImmatureWatchOnlyCredit(interfaces::Chain::Lock &locked_chain,
                                       const bool fUseCache = true) const;
     Amount GetChange() const;
 
     // Get the marginal bytes if spending the specified output from this
     // transaction
     int GetSpendSize(unsigned int out, bool use_max_sig = false) const {
         return CalculateMaximumSignedInputSize(tx->vout[out], pwallet,
                                                use_max_sig);
     }
 
     void GetAmounts(std::list<COutputEntry> &listReceived,
                     std::list<COutputEntry> &listSent, Amount &nFee,
                     const isminefilter &filter) const;
 
     bool IsFromMe(const isminefilter &filter) const {
         return GetDebit(filter) > Amount::zero();
     }
 
     // True if only scriptSigs are different
     bool IsEquivalentTo(const CWalletTx &tx) const;
 
     bool InMempool() const;
     bool IsTrusted(interfaces::Chain::Lock &locked_chain) const;
 
     int64_t GetTxTime() const;
 
     // Pass this transaction to node for mempool insertion and relay to peers if
     // flag set to true
     bool SubmitMemoryPoolAndRelay(std::string &err_string, bool relay,
                                   interfaces::Chain::Lock &locked_chain);
 
     // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
     // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
     // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
     // resolve the issue of member access into incomplete type CWallet. Note
     // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
     // in place.
     std::set<TxId> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
 
     void SetConf(Status status, const BlockHash &block_hash, int posInBlock);
 
     /**
      * Return depth of transaction in blockchain:
      * <0  : conflicts with a transaction this deep in the blockchain
      *  0  : in memory pool, waiting to be included in a block
      * >=1 : this many blocks deep in the main chain
      */
     int GetDepthInMainChain(interfaces::Chain::Lock &locked_chain) const;
     bool IsInMainChain(interfaces::Chain::Lock &locked_chain) const {
         return GetDepthInMainChain(locked_chain) > 0;
     }
 
     /**
      * @return number of blocks to maturity for this transaction:
      *  0 : is not a coinbase transaction, or is a mature coinbase transaction
      * >0 : is a coinbase transaction which matures in this many blocks
      */
     int GetBlocksToMaturity(interfaces::Chain::Lock &locked_chain) const;
     bool isAbandoned() const {
         return m_confirm.status == CWalletTx::ABANDONED;
     }
     void setAbandoned() {
         m_confirm.status = CWalletTx::ABANDONED;
         m_confirm.hashBlock = BlockHash();
         m_confirm.nIndex = 0;
     }
     bool isConflicted() const {
         return m_confirm.status == CWalletTx::CONFLICTED;
     }
     void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; }
     bool isUnconfirmed() const {
         return m_confirm.status == CWalletTx::UNCONFIRMED;
     }
     void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; }
     void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
     TxId GetId() const { return tx->GetId(); }
     bool IsCoinBase() const { return tx->IsCoinBase(); }
     bool IsImmatureCoinBase(interfaces::Chain::Lock &locked_chain) const;
 };
 
 class COutput {
 public:
     const CWalletTx *tx;
     int i;
     int nDepth;
 
     /**
      * Pre-computed estimated size of this output as a fully-signed input in a
      * transaction. Can be -1 if it could not be calculated.
      */
     int nInputBytes;
 
     /** Whether we have the private keys to spend this output */
     bool fSpendable;
 
     /** Whether we know how to spend this output, ignoring the lack of keys */
     bool fSolvable;
 
     /**
      * Whether to use the maximum sized, 72 byte signature when calculating the
      * size of the input spend. This should only be set when watch-only outputs
      * are allowed.
      */
     bool use_max_sig;
 
     /**
      * Whether this output is considered safe to spend. Unconfirmed transactions
      * from outside keys are considered unsafe and will not be used to fund new
      * spending transactions.
      */
     bool fSafe;
 
     COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn,
             bool fSolvableIn, bool fSafeIn, bool use_max_sig_in = false) {
         tx = txIn;
         i = iIn;
         nDepth = nDepthIn;
         fSpendable = fSpendableIn;
         fSolvable = fSolvableIn;
         fSafe = fSafeIn;
         nInputBytes = -1;
         use_max_sig = use_max_sig_in;
         // If known and signable by the given wallet, compute nInputBytes
         // Failure will keep this value -1
         if (fSpendable && tx) {
             nInputBytes = tx->GetSpendSize(i, use_max_sig);
         }
     }
 
     std::string ToString() const;
 
     inline CInputCoin GetInputCoin() const {
         return CInputCoin(tx->tx, i, nInputBytes);
     }
 };
 
 struct CoinSelectionParams {
     bool use_bnb = true;
     size_t change_output_size = 0;
     size_t change_spend_size = 0;
     CFeeRate effective_fee = CFeeRate(Amount::zero());
     size_t tx_noinputs_size = 0;
 
     CoinSelectionParams(bool use_bnb_, size_t change_output_size_,
                         size_t change_spend_size_, CFeeRate effective_fee_,
                         size_t tx_noinputs_size_)
         : use_bnb(use_bnb_), change_output_size(change_output_size_),
           change_spend_size(change_spend_size_), effective_fee(effective_fee_),
           tx_noinputs_size(tx_noinputs_size_) {}
     CoinSelectionParams() {}
 };
 
 // forward declarations for ScanForWalletTransactions/RescanFromTime
 class WalletRescanReserver;
 
 /**
  * A CWallet is an extension of a keystore, which also maintains a set of
  * transactions and balances, and provides the ability to create new
  * transactions.
  */
 class CWallet final : public FillableSigningProvider,
                       public interfaces::Chain::Notifications {
 private:
     CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
 
     //! if fUseCrypto is true, mapKeys must be empty
     //! if fUseCrypto is false, vMasterKey must be empty
     std::atomic<bool> fUseCrypto;
 
     //! keeps track of whether Unlock has run a thorough check before
     bool fDecryptionThoroughlyChecked;
 
     using CryptedKeyMap =
         std::map<CKeyID, std::pair<CPubKey, std::vector<uint8_t>>>;
     using WatchOnlySet = std::set<CScript>;
     using WatchKeyMap = std::map<CKeyID, CPubKey>;
 
     bool SetCrypted();
 
     //! will encrypt previously unencrypted keys
     bool EncryptKeys(CKeyingMaterial &vMasterKeyIn);
 
     bool Unlock(const CKeyingMaterial &vMasterKeyIn,
                 bool accept_no_keys = false);
     CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
     WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
     WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
 
     bool AddCryptedKeyInner(const CPubKey &vchPubKey,
                             const std::vector<uint8_t> &vchCryptedSecret);
     bool AddKeyPubKeyInner(const CKey &key, const CPubKey &pubkey);
 
     std::atomic<bool> fAbortRescan{false};
     // controlled by WalletRescanReserver
     std::atomic<bool> fScanningWallet{false};
     std::atomic<int64_t> m_scanning_start{0};
     std::atomic<double> m_scanning_progress{0};
     std::mutex mutexScanning;
     friend class WalletRescanReserver;
 
     WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
 
     //! the current wallet version: clients below this version are not able to
     //! load the wallet
     int nWalletVersion GUARDED_BY(cs_wallet) = FEATURE_BASE;
 
     //! the maximum wallet format version: memory-only variable that specifies
     //! to what version this wallet may be upgraded
     int nWalletMaxVersion GUARDED_BY(cs_wallet) = FEATURE_BASE;
 
     int64_t nNextResend = 0;
     int64_t nLastResend = 0;
     bool fBroadcastTransactions = false;
     // Local time that the tip block was received. Used to schedule wallet
     // rebroadcasts.
     std::atomic<int64_t> m_best_block_time{0};
 
     /**
      * Used to keep track of spent outpoints, and detect and report conflicts
      * (double-spends or mutated transactions where the mutant gets mined).
      */
     typedef std::multimap<COutPoint, TxId> TxSpends;
     TxSpends mapTxSpends GUARDED_BY(cs_wallet);
     void AddToSpends(const COutPoint &outpoint, const TxId &wtxid)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void AddToSpends(const TxId &wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Add a transaction to the wallet, or update it. pIndex and posInBlock
      * should be set when the transaction was known to be included in a
      * block. When *pIndex == nullptr, then wallet state is not updated in
      * AddToWallet, but notifications happen and cached balances are marked
      * dirty.
      *
      * If fUpdate is true, existing transactions will be updated.
      * TODO: One exception to this is that the abandoned state is cleared under
      * the assumption that any further notification of a transaction that was
      * considered abandoned is an indication that it is not safe to be
      * considered abandoned. Abandoned state should probably be more carefully
      * tracked via different posInBlock signals or by checking mempool presence
      * when necessary.
      */
     bool AddToWalletIfInvolvingMe(const CTransactionRef &tx,
                                   CWalletTx::Status status,
                                   const BlockHash &block_hash, int posInBlock,
                                   bool fUpdate)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Mark a transaction (and its in-wallet descendants) as conflicting with a
      * particular block.
      */
     void MarkConflicted(const BlockHash &hashBlock, const TxId &txid);
 
     /**
      * Mark a transaction's inputs dirty, thus forcing the outputs to be
      * recomputed
      */
     void MarkInputsDirty(const CTransactionRef &tx)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Used by
      * TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
      * Should be called with non-zero block_hash and posInBlock if this is for a
      * transaction that is included in a block.
      */
     void SyncTransaction(const CTransactionRef &tx, CWalletTx::Status status,
                          const BlockHash &block_hash, int posInBlock = 0,
                          bool update_tx = true)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /* the HD chain data model (external chain counters) */
     CHDChain hdChain;
 
     /* HD derive new child key (on internal or external chain) */
     void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata,
                            CKey &secret, bool internal = false)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
     std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_wallet);
     std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_wallet);
     int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0;
     std::map<CKeyID, int64_t> m_pool_key_to_index;
     std::atomic<uint64_t> m_wallet_flags{0};
 
     int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0;
 
     /**
      * Private version of AddWatchOnly method which does not accept a timestamp,
      * and which will reset the wallet's nTimeFirstKey value to 1 if the watch
      * key did not previously have a timestamp associated with it. Because this
      * is an inherited virtual method, it is accessible despite being marked
      * private, but it is marked private anyway to encourage use of the other
      * AddWatchOnly which accepts a timestamp and sets nTimeFirstKey more
      * intelligently for more efficient rescans.
      */
     bool AddWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool AddWatchOnlyInMem(const CScript &dest);
 
     /** Add a KeyOriginInfo to the wallet */
     bool AddKeyOriginWithDB(WalletBatch &batch, const CPubKey &pubkey,
                             const KeyOriginInfo &info);
 
     //! Adds a key to the store, and saves it to disk.
     bool AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &key,
                             const CPubKey &pubkey)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     //! Adds a watch-only address to the store, and saves it to disk.
     bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest,
                             int64_t create_time)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     void AddKeypoolPubkeyWithDB(const CPubKey &pubkey, const bool internal,
                                 WalletBatch &batch);
 
     bool SetAddressBookWithDB(WalletBatch &batch, const CTxDestination &address,
                               const std::string &strName,
                               const std::string &strPurpose);
 
     //! Adds a script to the store and saves it to disk
     bool AddCScriptWithDB(WalletBatch &batch, const CScript &script);
 
     //! Unsets a wallet flag and saves it to disk
     void UnsetWalletFlagWithDB(WalletBatch &batch, uint64_t flag);
 
     /** Interface for accessing chain state. */
     interfaces::Chain *m_chain;
 
     /**
      * Wallet location which includes wallet name (see WalletLocation).
      */
     WalletLocation m_location;
 
     /** Internal database handle. */
     std::unique_ptr<WalletDatabase> database;
 
     /**
      * The following is used to keep track of how far behind the wallet is
      * from the chain sync, and to allow clients to block on us being caught up.
      *
      * Note that this is *not* how far we've processed, we may need some rescan
      * to have seen all transactions in the chain, but is only used to track
      * live BlockConnected callbacks.
      */
     BlockHash m_last_block_processed GUARDED_BY(cs_wallet);
 
     //! Fetches a key from the keypool
     bool GetKeyFromPool(CPubKey &key, bool internal = false);
 
 public:
     const CChainParams &chainParams;
     /*
      * Main wallet lock.
      * This lock protects all the fields added by CWallet.
      */
     mutable RecursiveMutex cs_wallet;
 
     /**
      * Get database handle used by this wallet. Ideally this function would not
      * be necessary.
      */
     WalletDatabase &GetDBHandle() { return *database; }
 
     /**
      * Select a set of coins such that nValueRet >= nTargetValue and at least
      * all coins from coinControl are selected; Never select unconfirmed coins
      * if they are not ours.
      */
     bool SelectCoins(const std::vector<COutput> &vAvailableCoins,
                      const Amount nTargetValue,
                      std::set<CInputCoin> &setCoinsRet, Amount &nValueRet,
                      const CCoinControl &coin_control,
                      CoinSelectionParams &coin_selection_params,
                      bool &bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     const WalletLocation &GetLocation() const { return m_location; }
 
     /**
      * Get a name for this wallet for logging/debugging purposes.
      */
     const std::string &GetName() const { return m_location.GetName(); }
 
     void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     // Map from Key ID to key metadata.
     std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_wallet);
 
     // Map from Script ID to key metadata (for watch-only keys).
     std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
 
     typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
     MasterKeyMap mapMasterKeys;
     unsigned int nMasterKeyMaxID = 0;
 
     /** Construct wallet with specified name and database implementation. */
     CWallet(const CChainParams &chainParamsIn, interfaces::Chain *chain,
             const WalletLocation &location,
             std::unique_ptr<WalletDatabase> databaseIn)
         : fUseCrypto(false), fDecryptionThoroughlyChecked(false),
           m_chain(chain), m_location(location), database(std::move(databaseIn)),
           chainParams(chainParamsIn) {}
 
     ~CWallet() {
         // Should not have slots connected at this point.
         assert(NotifyUnload.empty());
         delete encrypted_batch;
         encrypted_batch = nullptr;
     }
 
     bool IsCrypted() const { return fUseCrypto; }
     bool IsLocked() const;
     bool Lock();
 
     /** Interface to assert chain access and if successful lock it */
     std::unique_ptr<interfaces::Chain::Lock> LockChain() {
         return m_chain ? m_chain->lock() : nullptr;
     }
 
     std::map<TxId, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
 
     typedef std::multimap<int64_t, CWalletTx *> TxItems;
     TxItems wtxOrdered;
 
     int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
     uint64_t nAccountingEntryNumber = 0;
 
     std::map<CTxDestination, CAddressBookData>
         mapAddressBook GUARDED_BY(cs_wallet);
 
     std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
 
     /** Registered interfaces::Chain::Notifications handler. */
     std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
 
     /** Interface for accessing chain state. */
     interfaces::Chain &chain() const {
         assert(m_chain);
         return *m_chain;
     }
 
     const CWalletTx *GetWalletTx(const TxId &txid) const;
 
     //! check whether we are allowed to upgrade (or already support) to the
     //! named feature
     bool CanSupportFeature(enum WalletFeature wf) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
         AssertLockHeld(cs_wallet);
         return nWalletMaxVersion >= wf;
     }
 
     /**
      * populate vCoins with vector of available COutputs.
      */
     void AvailableCoins(interfaces::Chain::Lock &locked_chain,
                         std::vector<COutput> &vCoins, bool fOnlySafe = true,
                         const CCoinControl *coinControl = nullptr,
                         const Amount nMinimumAmount = SATOSHI,
                         const Amount nMaximumAmount = MAX_MONEY,
                         const Amount nMinimumSumAmount = MAX_MONEY,
                         const uint64_t nMaximumCount = 0) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Return list of available coins and locked coins grouped by non-change
      * output address.
      */
     std::map<CTxDestination, std::vector<COutput>>
     ListCoins(interfaces::Chain::Lock &locked_chain) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Find non-change parent output.
      */
     const CTxOut &FindNonChangeParentOutput(const CTransaction &tx,
                                             int output) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Shuffle and select coins until nTargetValue is reached while avoiding
      * small change; This method is stochastic for some inputs and upon
      * completion the coin set and corresponding actual target value is
      * assembled.
      */
     bool SelectCoinsMinConf(const Amount nTargetValue,
                             const CoinEligibilityFilter &eligibility_filter,
                             std::vector<OutputGroup> groups,
                             std::set<CInputCoin> &setCoinsRet,
                             Amount &nValueRet,
                             const CoinSelectionParams &coin_selection_params,
                             bool &bnb_used) const;
 
     bool IsSpent(interfaces::Chain::Lock &locked_chain,
                  const COutPoint &outpoint) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     // Whether this or any UTXO with the same CTxDestination has been spent.
     bool IsUsedDestination(const CTxDestination &dst) const;
     bool IsUsedDestination(const TxId &txid, unsigned int n) const;
     void SetUsedDestinationState(const TxId &hash, unsigned int n, bool used);
 
     std::vector<OutputGroup> GroupOutputs(const std::vector<COutput> &outputs,
                                           bool single_coin) const;
 
     bool IsLockedCoin(const COutPoint &outpoint) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void LockCoin(const COutPoint &output) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void UnlockCoin(const COutPoint &output)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void UnlockAllCoins() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void ListLockedCoins(std::vector<COutPoint> &vOutpts) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /*
      * Rescan abort properties
      */
     void AbortRescan() { fAbortRescan = true; }
     bool IsAbortingRescan() { return fAbortRescan; }
     bool IsScanning() { return fScanningWallet; }
     int64_t ScanningDuration() const {
         return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0;
     }
     double ScanningProgress() const {
         return fScanningWallet ? double(m_scanning_progress) : 0;
     }
 
     /**
      * keystore implementation
      * Generate a new key
      */
     CPubKey GenerateNewKey(WalletBatch &batch, bool internal = false)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Adds a key to the store, and saves it to disk.
     bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Adds a key to the store, without saving it to disk (used by LoadWallet)
     bool LoadKey(const CKey &key, const CPubKey &pubkey) {
         return AddKeyPubKeyInner(key, pubkey);
     }
     //! Load metadata (used by LoadWallet)
     void LoadKeyMetadata(const CKeyID &keyID, const CKeyMetadata &metadata)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void LoadScriptMetadata(const CScriptID &script_id,
                             const CKeyMetadata &metadata)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Upgrade stored CKeyMetadata objects to store key origin info as
     //! KeyOriginInfo
     void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
         AssertLockHeld(cs_wallet);
         nWalletVersion = nVersion;
         nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion);
         return true;
     }
     void UpdateTimeFirstKey(int64_t nCreateTime)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     //! Adds an encrypted key to the store, and saves it to disk.
     bool AddCryptedKey(const CPubKey &vchPubKey,
                        const std::vector<uint8_t> &vchCryptedSecret);
     //! Adds an encrypted key to the store, without saving it to disk (used by
     //! LoadWallet)
     bool LoadCryptedKey(const CPubKey &vchPubKey,
                         const std::vector<uint8_t> &vchCryptedSecret);
     bool GetKey(const CKeyID &address, CKey &keyOut) const override;
     bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override;
     bool HaveKey(const CKeyID &address) const override;
     std::set<CKeyID> GetKeys() const override;
     bool AddCScript(const CScript &redeemScript) override;
     bool LoadCScript(const CScript &redeemScript);
 
     //! Adds a destination data tuple to the store, and saves it to disk
     bool AddDestData(const CTxDestination &dest, const std::string &key,
                      const std::string &value)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Erases a destination data tuple in the store and on disk
     bool EraseDestData(const CTxDestination &dest, const std::string &key)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Adds a destination data tuple to the store, without saving it to disk
     void LoadDestData(const CTxDestination &dest, const std::string &key,
                       const std::string &value)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! 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
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Get all destination values matching a prefix.
     std::vector<std::string> GetDestValues(const std::string &prefix) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     //! Adds a watch-only address to the store, and saves it to disk.
     bool AddWatchOnly(const CScript &dest, int64_t nCreateTime)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool RemoveWatchOnly(const CScript &dest)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     //! Adds a watch-only address to the store, without saving it to disk (used
     //! by LoadWallet)
     bool LoadWatchOnly(const CScript &dest);
     //! Returns whether the watch-only script is in the wallet
     bool HaveWatchOnly(const CScript &dest) const;
     //! Returns whether there are any watch-only things in the wallet
     bool HaveWatchOnly() const;
     //! Fetches a pubkey from mapWatchKeys if it exists there
     bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
 
     //! Holds a timestamp at which point the wallet is scheduled (externally) to
     //! be relocked. Caller must arrange for actual relocking to occur via
     //! Lock().
     int64_t nRelockTime = 0;
 
     bool Unlock(const SecureString &strWalletPassphrase,
                 bool accept_no_keys = false);
     bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase,
                                 const SecureString &strNewWalletPassphrase);
     bool EncryptWallet(const SecureString &strWalletPassphrase);
 
     void GetKeyBirthTimes(interfaces::Chain::Lock &locked_chain,
                           std::map<CKeyID, int64_t> &mapKeyBirth) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     unsigned int ComputeTimeSmart(const CWalletTx &wtx) const;
 
     /**
      * Increment the next transaction order id
      * @return next transaction order id
      */
     int64_t IncOrderPosNext(WalletBatch *batch = nullptr)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     DBErrors ReorderTransactions();
 
     void MarkDirty();
     bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose = true);
     void LoadToWallet(CWalletTx &wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void TransactionAddedToMempool(const CTransactionRef &tx) override;
     void
     BlockConnected(const CBlock &block,
                    const std::vector<CTransactionRef> &vtxConflicted) override;
     void BlockDisconnected(const CBlock &block) override;
     void UpdatedBlockTip() override;
     int64_t RescanFromTime(int64_t startTime,
                            const WalletRescanReserver &reserver, bool update);
 
     struct ScanResult {
         enum { SUCCESS, FAILURE, USER_ABORT } status = SUCCESS;
 
         //! Hash and height of most recent block that was successfully scanned.
         //! Unset if no blocks were scanned due to read errors or the chain
         //! being empty.
         BlockHash last_scanned_block;
         Optional<int> last_scanned_height;
 
         //! Hash of the most recent block that could not be scanned due to
         //! read errors or pruning. Will be set if status is FAILURE, unset if
         //! status is SUCCESS, and may or may not be set if status is
         //! USER_ABORT.
         BlockHash last_failed_block;
     };
     ScanResult ScanForWalletTransactions(const BlockHash &first_block,
                                          const BlockHash &last_block,
                                          const WalletRescanReserver &reserver,
                                          bool fUpdate);
     void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
     void ReacceptWalletTransactions(interfaces::Chain::Lock &locked_chain)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     void ResendWalletTransactions();
     struct Balance {
         //! Trusted, at depth=GetBalance.min_depth or more
         Amount m_mine_trusted{Amount::zero()};
         //! Untrusted, but in mempool (pending)
         Amount m_mine_untrusted_pending{Amount::zero()};
         //! Immature coinbases in the main chain
         Amount m_mine_immature{Amount::zero()};
         Amount m_watchonly_trusted{Amount::zero()};
         Amount m_watchonly_untrusted_pending{Amount::zero()};
         Amount m_watchonly_immature{Amount::zero()};
     };
     Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const;
     Amount GetAvailableBalance(const CCoinControl *coinControl = nullptr) const;
 
     OutputType TransactionChangeType(OutputType change_type,
                                      const std::vector<CRecipient> &vecSend);
 
     /**
      * Insert additional inputs into the transaction by calling
      * CreateTransaction();
      */
     bool FundTransaction(CMutableTransaction &tx, Amount &nFeeRet,
                          int &nChangePosInOut, std::string &strFailReason,
                          bool lockUnspents,
                          const std::set<int> &setSubtractFeeFromOutputs,
                          CCoinControl coinControl);
     bool SignTransaction(CMutableTransaction &tx)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     /**
      * Create a new transaction paying the recipients with a set of coins
      * selected by SelectCoins(); Also create the change output, when needed
      * @note passing nChangePosInOut as -1 will result in setting a random
      * position
      */
     bool CreateTransaction(interfaces::Chain::Lock &locked_chain,
                            const std::vector<CRecipient> &vecSend,
                            CTransactionRef &tx, Amount &nFeeRet,
                            int &nChangePosInOut, std::string &strFailReason,
                            const CCoinControl &coin_control, bool sign = true);
     bool CommitTransaction(
         CTransactionRef tx, mapValue_t mapValue,
         std::vector<std::pair<std::string, std::string>> orderForm,
         TxValidationState &state);
 
     bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts,
                      bool use_max_sig = false) const {
         std::vector<CTxOut> v_txouts(txouts.size());
         std::copy(txouts.begin(), txouts.end(), v_txouts.begin());
         return DummySignTx(txNew, v_txouts, use_max_sig);
     }
     bool DummySignTx(CMutableTransaction &txNew,
                      const std::vector<CTxOut> &txouts,
                      bool use_max_sig = false) const;
     bool DummySignInput(CTxIn &tx_in, const CTxOut &txout,
                         bool use_max_sig = false) const;
 
     bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool ImportPrivKeys(const std::map<CKeyID, CKey> &privkey_map,
                         const int64_t timestamp)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool ImportPubKeys(
         const std::vector<CKeyID> &ordered_pubkeys,
         const std::map<CKeyID, CPubKey> &pubkey_map,
         const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> &key_origins,
         const bool add_keypool, const bool internal, const int64_t timestamp)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool ImportScriptPubKeys(const std::string &label,
                              const std::set<CScript> &script_pub_keys,
                              const bool have_solving_data,
                              const bool apply_label, const int64_t timestamp)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
     bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
-    // will be defined via chainparams
+    //! will be defined via chainparams
     bool m_allow_fallback_fee{true};
     // Override with -mintxfee
     CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE_PER_KB};
     /**
      * If fee estimation does not have enough data to provide estimates, use
      * this fee instead. Has no effect if not using fee estimation Override with
      * -fallbackfee
      */
     CFeeRate m_fallback_fee{DEFAULT_FALLBACK_FEE};
     OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE};
     OutputType m_default_change_type{DEFAULT_CHANGE_TYPE};
     /**
      * Absolute maximum transaction fee (in satoshis) used by default for the
      * wallet.
      */
     Amount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
 
     bool NewKeyPool();
     size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     bool TopUpKeyPool(unsigned int kpSize = 0);
 
     /**
      * Reserves a key from the keypool and sets nIndex to its index
      *
      * @param[out] nIndex the index of the key in keypool
      * @param[out] keypool the keypool the key was drawn from, which could be
      * the the pre-split pool if present, or the internal or external pool
      * @param fRequestedInternal true if the caller would like the key drawn
      *     from the internal keypool, false if external is preferred
      *
      * @return true if succeeded, false if failed due to empty keypool
      * @throws std::runtime_error if keypool read failed, key was invalid,
      *     was not found in the wallet, or was misclassified in the internal
      *     or external keypool
      */
     bool ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool,
                                bool fRequestedInternal);
     void KeepKey(int64_t nIndex);
     void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey);
     int64_t GetOldestKeyPoolTime();
     /**
      * Marks all keys in the keypool up to and including reserve_key as used.
      */
     void MarkReserveKeysAsUsed(int64_t keypool_id)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     const std::map<CKeyID, int64_t> &GetAllReserveKeys() const {
         return m_pool_key_to_index;
     }
 
     std::set<std::set<CTxDestination>> GetAddressGroupings()
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     std::map<CTxDestination, Amount>
     GetAddressBalances(interfaces::Chain::Lock &locked_chain);
 
     std::set<CTxDestination> GetLabelAddresses(const std::string &label) const;
 
     bool GetNewDestination(const OutputType type, const std::string label,
                            CTxDestination &dest, std::string &error);
     bool GetNewChangeDestination(const OutputType type, CTxDestination &dest,
                                  std::string &error);
 
     isminetype IsMine(const CTxIn &txin) const;
     /**
      * Returns amount of debit if the input matches the filter, otherwise
      * returns 0
      */
     Amount GetDebit(const CTxIn &txin, const isminefilter &filter) const;
     isminetype IsMine(const CTxOut &txout) const;
     Amount GetCredit(const CTxOut &txout, const isminefilter &filter) const;
     bool IsChange(const CTxOut &txout) const;
     bool IsChange(const CScript &script) const;
     Amount GetChange(const CTxOut &txout) const;
     bool IsMine(const CTransaction &tx) const;
     /** should probably be renamed to IsRelevantToMe */
     bool IsFromMe(const CTransaction &tx) const;
     Amount GetDebit(const CTransaction &tx, const isminefilter &filter) const;
     /** Returns whether all of the inputs match the filter */
     bool IsAllFromMe(const CTransaction &tx, const isminefilter &filter) const;
     Amount GetCredit(const CTransaction &tx, const isminefilter &filter) const;
     Amount GetChange(const CTransaction &tx) const;
     void ChainStateFlushed(const CBlockLocator &loc) override;
 
     DBErrors LoadWallet(bool &fFirstRunRet);
     DBErrors ZapWalletTx(std::vector<CWalletTx> &vWtx);
     DBErrors ZapSelectTx(std::vector<TxId> &txIdsIn,
                          std::vector<TxId> &txIdsOut)
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     bool SetAddressBook(const CTxDestination &address,
                         const std::string &strName, const std::string &purpose);
 
     bool DelAddressBook(const CTxDestination &address);
 
     const std::string &GetLabelName(const CScript &scriptPubKey) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     unsigned int GetKeyPoolSize() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
         AssertLockHeld(cs_wallet);
         return setInternalKeyPool.size() + setExternalKeyPool.size();
     }
 
     //! signify that a particular wallet feature is now used. this may change
     //! nWalletVersion and nWalletMaxVersion if those are lower
     void SetMinVersion(enum WalletFeature, WalletBatch *batch_in = nullptr,
                        bool fExplicit = false);
 
     //! change which version we're allowed to upgrade to (note that this does
     //! not immediately imply upgrading to that format)
     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;
     }
 
     //! Get wallet transactions that conflict with given transaction (spend same
     //! outputs)
     std::set<TxId> GetConflicts(const TxId &txid) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     //! Check if a given transaction has any of its outputs spent by another
     //! transaction in the wallet
     bool HasWalletSpend(const TxId &txid) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
 
     //! Flush wallet (bitdb flush)
     void Flush(bool shutdown = false);
 
     /** Wallet is about to be unloaded */
     boost::signals2::signal<void()> NotifyUnload;
 
     /**
      * Address book entry changed.
      * @note called with lock cs_wallet held.
      */
     boost::signals2::signal<void(CWallet *wallet, const CTxDestination &address,
                                  const std::string &label, bool isMine,
                                  const std::string &purpose, ChangeType status)>
         NotifyAddressBookChanged;
 
     /**
      * Wallet transaction added, removed or updated.
      * @note called with lock cs_wallet held.
      */
     boost::signals2::signal<void(CWallet *wallet, const TxId &txid,
                                  ChangeType status)>
         NotifyTransactionChanged;
 
     /** Show progress e.g. for rescan */
     boost::signals2::signal<void(const std::string &title, int nProgress)>
         ShowProgress;
 
     /** Watch-only address added */
     boost::signals2::signal<void(bool fHaveWatchOnly)> NotifyWatchonlyChanged;
 
     /** Keypool has new keys */
     boost::signals2::signal<void()> NotifyCanGetAddressesChanged;
 
     /**
      * Wallet status (encrypted, locked) changed.
      * Note: Called without locks held.
      */
     boost::signals2::signal<void(CWallet *wallet)> NotifyStatusChanged;
 
     /** Inquire whether this wallet broadcasts transactions. */
     bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
     /** Set whether this wallet broadcasts transactions. */
     void SetBroadcastTransactions(bool broadcast) {
         fBroadcastTransactions = broadcast;
     }
 
     /** Return whether transaction can be abandoned */
     bool TransactionCanBeAbandoned(const TxId &txid) const;
 
     /**
      * Mark a transaction (and it in-wallet descendants) as abandoned so its
      * inputs may be respent.
      */
     bool AbandonTransaction(interfaces::Chain::Lock &locked_chain,
                             const TxId &txid);
 
     //! Verify wallet naming and perform salvage on the wallet if required
     static bool Verify(const CChainParams &chainParams,
                        interfaces::Chain &chain, const WalletLocation &location,
                        bool salvage_wallet, std::string &error_string,
                        std::string &warning_string);
 
     /**
      * Initializes the wallet, returns a new CWallet instance or a null pointer
      * in case of an error.
      */
     static std::shared_ptr<CWallet> CreateWalletFromFile(
         const CChainParams &chainParams, interfaces::Chain &chain,
         const WalletLocation &location, uint64_t wallet_creation_flags = 0);
 
     /**
      * Wallet post-init setup
      * Gives the wallet a chance to register repetitive tasks and complete
      * post-init tasks
      */
     void postInitProcess();
 
     bool BackupWallet(const std::string &strDest);
 
     /* Set the HD chain model (chain child index counters) */
     void SetHDChain(const CHDChain &chain, bool memonly);
     const CHDChain &GetHDChain() const { return hdChain; }
 
     /* Returns true if HD is enabled */
     bool IsHDEnabled() const;
 
     /* Returns true if the wallet can generate new keys */
     bool CanGenerateKeys();
 
     /**
      * Returns true if the wallet can give out new addresses. This means it has
      * keys in the keypool or can generate new keys.
      */
     bool CanGetAddresses(bool internal = false);
 
     /* Generates a new HD seed (will not be activated) */
     CPubKey GenerateNewSeed();
 
     /**
      * Derives a new HD seed (will not be activated)
      */
     CPubKey DeriveNewSeed(const CKey &key);
 
     /**
      * Set the current HD seed (will reset the chain child index counters)
      * Sets the seed's version based on the current wallet version (so the
      * caller must ensure the current wallet version is correct before calling
      * this function).
      */
     void SetHDSeed(const CPubKey &key);
 
     /**
      * Blocks until the wallet state is up-to-date to /at least/ the current
      * chain at the time this function is entered.
      * Obviously holding cs_main/cs_wallet when going into this call may cause
      * deadlock
      */
     void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet);
 
     /**
      * Explicitly make the wallet learn the related scripts for outputs to the
      * given key. This is purely to make the wallet file compatible with older
      * software, as FillableSigningProvider automatically does this implicitly
      * for all keys now.
      */
     void LearnRelatedScripts(const CPubKey &key, OutputType);
 
     /**
      * Same as LearnRelatedScripts, but when the OutputType is not known (and
      * could be anything).
      */
     void LearnAllRelatedScripts(const CPubKey &key);
 
     /**
      * Set a single wallet flag.
      */
     void SetWalletFlag(uint64_t flags);
 
     /**
      * Unsets a single wallet flag.
      */
     void UnsetWalletFlag(uint64_t flag);
 
     /**
      * Check if a certain wallet flag is set.
      */
     bool IsWalletFlagSet(uint64_t flag) const;
 
     /**
      * Overwrite all flags by the given uint64_t.
      * Returns false if unknown, non-tolerable flags are present.
      */
     bool SetWalletFlags(uint64_t overwriteFlags, bool memOnly);
 
     /**
      * Returns a bracketed wallet name for displaying in logs, will return
      * [default wallet] if the wallet has no name.
      */
     const std::string GetDisplayName() const {
         std::string wallet_name =
             GetName().length() == 0 ? "default wallet" : GetName();
         return strprintf("[%s]", wallet_name);
     };
 
     /**
      * Prepends the wallet name in logging output to ease debugging in
      * multi-wallet use cases.
      */
     template <typename... Params>
     void WalletLogPrintf(std::string fmt, Params... parameters) const {
         LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
     };
 
     template <typename... Params>
     void WalletLogPrintfToBeContinued(std::string fmt,
                                       Params... parameters) const {
         LogPrintfToBeContinued(("%s " + fmt).c_str(), GetDisplayName(),
                                parameters...);
     };
 
     /**
      * Implement lookup of key origin information through wallet key metadata.
      */
     bool GetKeyOrigin(const CKeyID &keyid, KeyOriginInfo &info) const override;
 };
 
 /**
  * Called periodically by the schedule thread. Prompts individual wallets to
  * resend their transactions. Actual rebroadcast schedule is managed by the
  * wallets themselves.
  */
 void MaybeResendWalletTxs();
 
 /** RAII object to check and reserve a wallet rescan */
 class WalletRescanReserver {
 private:
     CWallet *m_wallet;
     bool m_could_reserve;
 
 public:
     explicit WalletRescanReserver(CWallet *w)
         : m_wallet(w), m_could_reserve(false) {}
 
     bool reserve() {
         assert(!m_could_reserve);
         std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
         if (m_wallet->fScanningWallet) {
             return false;
         }
         m_wallet->m_scanning_start = GetTimeMillis();
         m_wallet->m_scanning_progress = 0;
         m_wallet->fScanningWallet = true;
         m_could_reserve = true;
         return true;
     }
 
     bool isReserved() const {
         return (m_could_reserve && m_wallet->fScanningWallet);
     }
 
     ~WalletRescanReserver() {
         std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
         if (m_could_reserve) {
             m_wallet->fScanningWallet = false;
         }
     }
 };
 
 // Calculate the size of the transaction assuming all signatures are max size
 // Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
 // NOTE: this requires that all inputs must be in mapWallet (eg the tx should
 // be IsAllFromMe).
 int64_t CalculateMaximumSignedTxSize(const CTransaction &tx,
                                      const CWallet *wallet,
                                      bool use_max_sig = false)
     EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
 int64_t CalculateMaximumSignedTxSize(const CTransaction &tx,
                                      const CWallet *wallet,
                                      const std::vector<CTxOut> &txouts,
                                      bool use_max_sig = false);
 
 #endif // BITCOIN_WALLET_WALLET_H