From c32ca07407bc66cc7b71a70a7b045204c9244e74 Mon Sep 17 00:00:00 2001
From: mxaddict <mxaddict@codedmaster.com>
Date: Wed, 31 Jul 2024 23:04:03 +0800
Subject: [PATCH] Updated staker to reload unloaded wallet while running

---
 src/navio-staker.cpp | 222 +++++++++++++++++++++++--------------------
 1 file changed, 120 insertions(+), 102 deletions(-)

diff --git a/src/navio-staker.cpp b/src/navio-staker.cpp
index 7055e5a96d751..45b49032001bf 100644
--- a/src/navio-staker.cpp
+++ b/src/navio-staker.cpp
@@ -350,18 +350,35 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
         }
     } else if (response.status == HTTP_SERVICE_UNAVAILABLE) {
         throw std::runtime_error(strprintf("Server response: %s", response.body));
-    } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
+    } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) {
         throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
-    else if (response.body.empty())
+    } else if (response.body.empty()) {
         throw std::runtime_error("no response from server");
+    }
 
-    // Parse reply
     UniValue valReply(UniValue::VSTR);
-    if (!valReply.read(response.body))
+    if (!valReply.read(response.body)) {
         throw std::runtime_error("couldn't parse reply from server");
-    const UniValue& reply = rh->ProcessReply(valReply);
-    if (reply.empty())
+    }
+
+    UniValue reply = rh->ProcessReply(valReply);
+    if (reply.empty()) {
         throw std::runtime_error("expected reply to have result, error and id properties");
+    }
+
+    if (strMethod != "loadwallet") {
+        const UniValue& error = reply.find_value("error");
+        if (!error.isNull() && error["code"].getInt<int>() == RPC_WALLET_NOT_FOUND) {
+            auto loadwallet_reply = CallRPC(rh, "loadwallet", /* args=*/{rpcwallet->data()}, rpcwallet);
+            const UniValue& error = loadwallet_reply.find_value("error");
+
+            if (!error.isNull() && error["code"].getInt<int>() != RPC_WALLET_ALREADY_LOADED) {
+                return loadwallet_reply;
+            }
+
+            reply = CallRPC(rh, strMethod, args, rpcwallet);
+        }
+    }
 
     return reply;
 }
@@ -377,17 +394,17 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
  */
 static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& strMethod, const std::vector<std::string>& args, const std::optional<std::string>& rpcwallet = {})
 {
-    UniValue response(UniValue::VOBJ);
+    UniValue reply(UniValue::VOBJ);
     // Execute and handle connection failures with -rpcwait.
-    const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
+    const bool fWait = gArgs.GetBoolArg("-rpcwait", true);
     const int timeout = gArgs.GetIntArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT);
     const auto deadline{std::chrono::steady_clock::now() + 1s * timeout};
 
     do {
         try {
-            response = CallRPC(rh, strMethod, args, rpcwallet);
+            reply = CallRPC(rh, strMethod, args, rpcwallet);
             if (fWait) {
-                const UniValue& error = response.find_value("error");
+                const UniValue& error = reply.find_value("error");
                 if (!error.isNull() && error["code"].getInt<int>() == RPC_IN_WARMUP) {
                     throw CConnectionFailed("server in warmup");
                 }
@@ -401,7 +418,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str
             }
         }
     } while (fWait);
-    return response;
+    return reply;
 }
 
 /** Parse UniValue error to update the message to print to std::cerr and the code to return. */
@@ -425,7 +442,7 @@ static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)
     } else {
         strPrint = "error: " + error.write();
     }
-    nRet = abs(error["code"].getInt<int>());
+    nRet = error["code"].getInt<int>();
 }
 
 static std::string rpcPass;
@@ -522,128 +539,122 @@ bool TestSetup()
 
     try {
         UniValue reply = ConnectAndCallRPC(rh.get(), "listwallets", /* args=*/{});
-
-        // Parse reply
-        const UniValue& error = reply.find_value("error");
+        UniValue error = reply.find_value("error");
 
         std::string strError;
         int nRet;
 
-        if (error.isNull()) {
-            LogPrintf("%s: [%s] Test connection to RPC: OK\n", __func__, walletName);
+        if (!error.isNull()) {
+            ParseError(error, strError, nRet);
+            LogPrintf("%s: [%s] Could not connect to RPC node: (%s)\n", __func__, walletName, strError);
+            return false;
+        }
 
-            reply = ConnectAndCallRPC(rh.get(), "loadwallet", /* args=*/{walletName});
+        LogPrintf("%s: [%s] Test connection to RPC: OK\n", __func__, walletName);
 
-            const UniValue& error = reply.find_value("error");
+        reply = ConnectAndCallRPC(rh.get(), "loadwallet", /* args=*/{walletName});
+        error = reply.find_value("error");
 
-            strError.clear();
-            nRet = 0;
+        strError.clear();
+        nRet = 0;
 
-            if (!error.isNull()) {
-                ParseError(error, strError, nRet);
-            }
+        if (!error.isNull()) {
+            ParseError(error, strError, nRet);
+        }
 
-            if (error.isNull() || nRet == 35) {
-                LogPrintf("%s: [%s] Test load wallet: OK\n", __func__, walletName);
+        if (nRet != RPC_WALLET_ALREADY_LOADED) {
+            LogPrintf("%s: [%s] Could not load wallet (%s)\n", __func__, walletName, strError);
+            return false;
+        }
 
-                reply = ConnectAndCallRPC(rh.get(), "getwalletinfo", /* args=*/{}, walletName);
+        LogPrintf("%s: [%s] Test load wallet: OK\n", __func__, walletName);
 
-                const UniValue& result = reply.find_value("result");
-                const UniValue& error = reply.find_value("error");
+        reply = ConnectAndCallRPC(rh.get(), "getwalletinfo", /* args=*/{}, walletName);
+        UniValue result = reply.find_value("result");
+        error = reply.find_value("error");
 
-                strError.clear();
-                nRet = 0;
+        strError.clear();
+        nRet = 0;
 
-                if (!error.isNull()) {
-                    ParseError(error, strError, nRet);
-                }
+        if (!error.isNull()) {
+            ParseError(error, strError, nRet);
+            LogPrintf("%s: [%s] Could not get wallet info (%s)\n", __func__, walletName, strError);
+            return false;
+        }
 
-                if (error.isNull()) {
-                    if (!result["blsct"].get_bool()) {
-                        LogPrintf("%s: [%s] Wallet is not of type blsct\n", __func__, walletName);
-                        return false;
-                    }
+        if (!result["blsct"].get_bool()) {
+            LogPrintf("%s: [%s] Wallet is not of type blsct\n", __func__, walletName);
+            return false;
+        }
 
-                    if (!result["unlocked_until"].isNull() && result["unlocked_until"].get_real() == 0) {
-                        LogPrintf("%s: [%s] Wallet is locked. Testing password.\n", __func__, walletName);
+        if (!result["unlocked_until"].isNull() && result["unlocked_until"].get_real() == 0) {
+            LogPrintf("%s: [%s] Wallet is locked. Testing password.\n", __func__, walletName);
 
-                        mustUnlockWallet = true;
+            mustUnlockWallet = true;
 
-                        reply = ConnectAndCallRPC(rh.get(), "walletpassphrase", /* args=*/{walletPassphrase, "1"}, walletName);
+            reply = ConnectAndCallRPC(rh.get(), "walletpassphrase", /* args=*/{walletPassphrase, "1"}, walletName);
 
-                        const UniValue& error = reply.find_value("error");
+            const UniValue& error = reply.find_value("error");
 
-                        strError.clear();
-                        nRet = 0;
+            strError.clear();
+            nRet = 0;
 
-                        if (error.isNull()) {
-                            LogPrintf("%s: [%s] Wallet passphrase test: OK\n", __func__, walletName);
-                        } else {
-                            ParseError(error, strError, nRet);
-                            LogPrintf("%s: [%s] Could not unlock wallet (%s)\n", __func__, walletName, strError);
+            if (error.isNull()) {
+                LogPrintf("%s: [%s] Wallet passphrase test: OK\n", __func__, walletName);
+            } else {
+                ParseError(error, strError, nRet);
+                LogPrintf("%s: [%s] Could not unlock wallet (%s)\n", __func__, walletName, strError);
 
-                            return false;
-                        }
-                    }
+                return false;
+            }
+        }
 
-                    if (coinbase_dest == "") {
-                        reply = ConnectAndCallRPC(rh.get(), "getaddressesbylabel", /* args=*/{"Staking"}, walletName);
+        if (coinbase_dest == "") {
+            reply = ConnectAndCallRPC(rh.get(), "getaddressesbylabel", /* args=*/{"Staking"}, walletName);
 
-                        const UniValue& result = reply.find_value("result");
-                        const UniValue& error = reply.find_value("error");
+            const UniValue& result = reply.find_value("result");
+            const UniValue& error = reply.find_value("error");
 
-                        if (error.isNull() && result.isObject()) {
-                            const UniValue& array = result.get_obj();
+            if (error.isNull() && result.isObject()) {
+                const UniValue& array = result.get_obj();
 
-                            for (auto& it : array.getKeys()) {
-                                const UniValue& obj = array.find_value(it);
+                for (auto& it : array.getKeys()) {
+                    const UniValue& obj = array.find_value(it);
 
-                                if (obj.isObject()) {
-                                    if (obj.get_obj().find_value("purpose").get_str() == "receive") {
-                                        coinbase_dest = it;
-                                        break;
-                                    }
-                                }
-                            }
+                    if (obj.isObject()) {
+                        if (obj.get_obj().find_value("purpose").get_str() == "receive") {
+                            coinbase_dest = it;
+                            break;
                         }
+                    }
+                }
+            }
 
-                        if (coinbase_dest == "") {
-                            reply = ConnectAndCallRPC(rh.get(), "getnewaddress", /* args=*/{"Staking", "blsct"}, walletName);
-
-                            const UniValue& result = reply.find_value("result");
-                            const UniValue& error = reply.find_value("error");
-
-                            strError.clear();
-                            nRet = 0;
-
-                            if (error.isNull() || !result.isStr()) {
-                                coinbase_dest = result.get_str();
-                            } else {
-                                ParseError(error, strError, nRet);
-                                LogPrintf("%s: [%s] Could not get an address for rewards from wallet (%s)\n", __func__, walletName, strError);
+            if (coinbase_dest == "") {
+                reply = ConnectAndCallRPC(rh.get(), "getnewaddress", /* args=*/{"Staking", "blsct"}, walletName);
 
-                                return false;
-                            }
-                        }
-                    }
+                const UniValue& result = reply.find_value("result");
+                const UniValue& error = reply.find_value("error");
 
-                    LogPrintf("%s: [%s] Rewards address: %s\n", __func__, walletName, coinbase_dest);
+                strError.clear();
+                nRet = 0;
 
-                    return true;
+                if (error.isNull() || !result.isStr()) {
+                    coinbase_dest = result.get_str();
                 } else {
-                    LogPrintf("%s: [%s] Could not get wallet info (%s)\n", __func__, walletName, strError);
+                    ParseError(error, strError, nRet);
+                    LogPrintf("%s: [%s] Could not get an address for rewards from wallet (%s)\n", __func__, walletName, strError);
+
                     return false;
                 }
-            } else {
-                LogPrintf("%s: [%s] Could not load wallet (%s)\n", __func__, walletName, strError);
-                return false;
             }
-        } else {
-            LogPrintf("%s: [%s] Could not connect to RPC node: %s\n", __func__, walletName, error.getValStr());
-            return false;
         }
+
+        LogPrintf("%s: [%s] Rewards address: (%s)\n", __func__, walletName, coinbase_dest);
+
+        return true;
     } catch (const std::exception& e) {
-        LogPrintf("%s: [%s] error: %s\n", __func__, walletName, e.what());
+        LogPrintf("%s: [%s] error: (%s)\n", __func__, walletName, e.what());
         return false;
     }
 
@@ -715,9 +726,18 @@ std::string EncodeHexBlock(const CBlock& block)
 
 std::vector<StakedCommitment> GetStakedCommitments(const std::unique_ptr<BaseRequestHandler>& rh)
 {
-    const UniValue& reply_staked = ConnectAndCallRPC(rh.get(), "liststakedcommitments", /* args=*/{}, walletName);
+    const UniValue& response = ConnectAndCallRPC(rh.get(), "liststakedcommitments", /* args=*/{}, walletName);
+    const UniValue& error = response.find_value("error");
+    const UniValue& result = response.find_value("result");
 
-    const UniValue& result = reply_staked.find_value("result");
+    std::string strError;
+    auto nRet = 0;
+
+    if (!error.isNull()) {
+        ParseError(error, strError, nRet);
+        LogPrintf("%s: [%s] Could not load stake commitments (%s)\n", __func__, walletName, strError);
+        return std::vector<StakedCommitment> {};
+    }
 
     return UniValueArrayToStakedCommitmentsMine(result.get_array());
 }
@@ -859,11 +879,9 @@ MAIN_FUNCTION
         return EXIT_FAILURE;
     }
 
-    int ret = EXIT_FAILURE;
-
     Setup();
     if (!TestSetup())
-        return ret;
+        return EXIT_FAILURE;
 
     Loop();