From 5f63373eb96780294c82380309093a3ea080dc07 Mon Sep 17 00:00:00 2001
From: miketout <michaeltoutonghi@gmail.com>
Date: Mon, 8 Oct 2018 21:15:21 -0700
Subject: [PATCH] Selectively reject Sapling transactions while synced below
 activation height. Add separate control of staking.

---
 src/gtest/test_keys.cpp  |  3 ++-
 src/init.cpp             |  5 +++--
 src/key_io.cpp           |  4 ++--
 src/key_io.h             |  2 +-
 src/komodo_globals.h     |  3 ++-
 src/komodo_utils.h       |  3 ++-
 src/miner.cpp            |  5 +++--
 src/rpc/mining.cpp       | 32 +++++++++++++++++++++++---------
 src/wallet/rpcwallet.cpp | 17 ++++++++++++-----
 src/wallet/wallet.h      |  5 +----
 src/zcash/Address.cpp    | 28 ++++++++++++++++++++++++++--
 src/zcash/Address.hpp    |  3 ++-
 12 files changed, 79 insertions(+), 31 deletions(-)

diff --git a/src/gtest/test_keys.cpp b/src/gtest/test_keys.cpp
index 4b4ff8817..bd9599421 100644
--- a/src/gtest/test_keys.cpp
+++ b/src/gtest/test_keys.cpp
@@ -2,6 +2,7 @@
 #include <key_io.h>
 #include <zcash/Address.hpp>
 #include <zcash/zip32.h>
+#include "consensus/upgrades.h"
 
 #include <gtest/gtest.h>
 
@@ -37,7 +38,7 @@ TEST(Keys, EncodeAndDecodeSapling)
                 Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS));
 
             auto paymentaddr2 = DecodePaymentAddress(addr_string);
-            EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2));
+            EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2, SAPLING_BRANCH_ID));
 
             ASSERT_TRUE(boost::get<libzcash::SaplingPaymentAddress>(&paymentaddr2) != nullptr);
             auto addr2 = boost::get<libzcash::SaplingPaymentAddress>(paymentaddr2);
diff --git a/src/init.cpp b/src/init.cpp
index 0c4bdedc8..9d22a1b63 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -504,8 +504,9 @@ std::string HelpMessage(HelpMessageMode mode)
 
 #ifdef ENABLE_MINING
     strUsage += HelpMessageGroup(_("Mining options:"));
-    strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
-    strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 0));
+    strUsage += HelpMessageOpt("-mint", strprintf(_("Mint/stake coins automatically (default: %u)"), 0));
+    strUsage += HelpMessageOpt("-gen", strprintf(_("Mine/generate coins (default: %u)"), 0));
+    strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin mining if enabled (-1 = all cores, default: %d)"), 0));
     strUsage += HelpMessageOpt("-equihashsolver=<name>", _("Specify the Equihash solver to be used if enabled (default: \"default\")"));
     strUsage += HelpMessageOpt("-mineraddress=<addr>", _("Send mined coins to a specific single address"));
     strUsage += HelpMessageOpt("-minetolocalwallet", strprintf(
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 72e8f7537..f04c4da04 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -308,8 +308,8 @@ libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
     return libzcash::InvalidEncoding();
 }
 
-bool IsValidPaymentAddressString(const std::string& str) {
-    return IsValidPaymentAddress(DecodePaymentAddress(str));
+bool IsValidPaymentAddressString(const std::string& str, uint32_t consensusBranchId) {
+    return IsValidPaymentAddress(DecodePaymentAddress(str), consensusBranchId);
 }
 
 std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
diff --git a/src/key_io.h b/src/key_io.h
index 47ca84fb8..3606ad09f 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -31,7 +31,7 @@ bool IsValidDestinationString(const std::string& str, const CChainParams& params
 
 std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
 libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
-bool IsValidPaymentAddressString(const std::string& str);
+bool IsValidPaymentAddressString(const std::string& str, uint32_t consensusBranchId);
 
 std::string EncodeViewingKey(const libzcash::ViewingKey& vk);
 libzcash::ViewingKey DecodeViewingKey(const std::string& str);
diff --git a/src/komodo_globals.h b/src/komodo_globals.h
index 4059daae5..41b668182 100644
--- a/src/komodo_globals.h
+++ b/src/komodo_globals.h
@@ -44,10 +44,11 @@ struct komodo_state KOMODO_STATES[34];
 #define _COINBASE_MATURITY 100
 int COINBASE_MATURITY = _COINBASE_MATURITY;//100;
 
-int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1;
+int32_t KOMODO_MININGTHREADS = 0,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1;
 int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
 std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY;
 uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE;
+bool VERUS_MINTBLOCKS;
 
 char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
 uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
diff --git a/src/komodo_utils.h b/src/komodo_utils.h
index c80c6d4ba..0db25e0f1 100644
--- a/src/komodo_utils.h
+++ b/src/komodo_utils.h
@@ -1652,7 +1652,8 @@ void komodo_args(char *argv0)
     IS_KOMODO_NOTARY = GetBoolArg("-notary", false);
     if ( GetBoolArg("-gen", false) != 0 )
         KOMODO_MININGTHREADS = GetArg("-genproclimit",-1);
-    else KOMODO_MININGTHREADS = -1;
+    else KOMODO_MININGTHREADS = 0;
+    VERUS_MINTBLOCKS = GetBoolArg("-mint", false);
     if ( (KOMODO_EXCHANGEWALLET= GetBoolArg("-exchange", false)) != 0 )
         fprintf(stderr,"KOMODO_EXCHANGEWALLET mode active\n");
     DONATION_PUBKEY = GetArg("-donation", "");
diff --git a/src/miner.cpp b/src/miner.cpp
index 0251e5e0e..7d27f1f1a 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -116,6 +116,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
 extern CCriticalSection cs_metrics;
 extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
 extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
+extern bool VERUS_MINTBLOCKS;
 extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
 extern const char *ASSETCHAINS_ALGORITHMS[];
 extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
@@ -1795,13 +1796,13 @@ void static BitcoinMiner()
         if ( nThreads == 0 && ASSETCHAINS_STAKED )
             nThreads = 1;
 
-        if ((nThreads == 0 && ASSETCHAINS_LWMAPOS == 0) || !fGenerate)
+        if ((nThreads == 0 || !fGenerate) && VERUS_MINTBLOCKS == 0)
             return;
 
         minerThreads = new boost::thread_group();
 
 #ifdef ENABLE_WALLET
-        if (ASSETCHAINS_LWMAPOS != 0)
+        if (ASSETCHAINS_LWMAPOS != 0 && VERUS_MINTBLOCKS)
         {
             minerThreads->create_thread(boost::bind(&VerusStaker, pwallet));
         }
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 51d29b5ea..a49ddac76 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -36,6 +36,7 @@ using namespace std;
 extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LWMAPOS;
 extern uint64_t ASSETCHAINS_STAKED;
 extern int32_t KOMODO_MININGTHREADS;
+extern bool VERUS_MINTBLOCKS;
 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
 
 /**
@@ -287,18 +288,20 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
     if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
             "setgenerate generate ( genproclimit )\n"
-            "\nSet 'generate' true or false to turn generation on or off.\n"
-            "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n"
+            "\nSet 'generate' true to turn either mining/generation or minting/staking on and false to turn both off.\n"
+            "Mining is limited to 'genproclimit' processors, -1 is unlimited, setgenerate true with 0 genproclimit turns on staking\n"
             "See the getgenerate call for the current setting.\n"
             "\nArguments:\n"
             "1. generate         (boolean, required) Set to true to turn on generation, off to turn off.\n"
-            "2. genproclimit     (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n"
+            "2. genproclimit     (numeric, optional) Set processor limit when generation is on. Can be -1 for unlimited, 0 to turn on staking.\n"
             "\nExamples:\n"
             "\nSet the generation on with a limit of one processor\n"
             + HelpExampleCli("setgenerate", "true 1") +
+            "\nTurn minting/staking on\n"
+            + HelpExampleCli("setgenerate", "true 0") +
             "\nCheck the setting\n"
             + HelpExampleCli("getgenerate", "") +
-            "\nTurn off generation\n"
+            "\nTurn off generation and minting\n"
             + HelpExampleCli("setgenerate", "false") +
             "\nUsing json rpc\n"
             + HelpExampleRpc("setgenerate", "true, 1")
@@ -320,7 +323,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
     if (params.size() > 0)
         fGenerate = params[0].get_bool();
 
-    int nGenProcLimit = -1;
+    int nGenProcLimit = GetArg("-genproclimit", -1);;
     if (params.size() > 1)
     {
         nGenProcLimit = params[1].get_int();
@@ -328,11 +331,22 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
         //    fGenerate = false;
     }
 
-    mapArgs["-gen"] = (fGenerate ? "1" : "0");
-    mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
-    if ( fGenerate == 0 )
-        KOMODO_MININGTHREADS = -1;
+    if (fGenerate && !nGenProcLimit)
+    {
+        VERUS_MINTBLOCKS = 1;
+        fGenerate = GetBoolArg("-gen", false);
+        nGenProcLimit = KOMODO_MININGTHREADS;
+    }
+    else if (!fGenerate)
+    {
+        VERUS_MINTBLOCKS = 0;
+        KOMODO_MININGTHREADS = 0;
+    }
     else KOMODO_MININGTHREADS = (int32_t)nGenProcLimit;
+
+    mapArgs["-gen"] = (fGenerate ? "1" : "0");
+    mapArgs ["-genproclimit"] = itostr(KOMODO_MININGTHREADS);
+
 #ifdef ENABLE_WALLET
     GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
 #else
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 7773f8694..9e3e3cf7d 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -30,6 +30,8 @@
 #include "wallet/asyncrpcoperation_sendmany.h"
 #include "wallet/asyncrpcoperation_shieldcoinbase.h"
 
+#include "consensus/upgrades.h"
+
 #include "sodium.h"
 
 #include <stdint.h>
@@ -3996,11 +3998,14 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
     auto fromaddress = params[0].get_str();
     bool fromTaddr = false;
     bool fromSapling = false;
+
+    uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
+
     CTxDestination taddr = DecodeDestination(fromaddress);
     fromTaddr = IsValidDestination(taddr);
     if (!fromTaddr) {
         auto res = DecodePaymentAddress(fromaddress);
-        if (!IsValidPaymentAddress(res)) {
+        if (!IsValidPaymentAddress(res, branchId)) {
             // invalid
             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
         }
@@ -4048,7 +4053,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
         CTxDestination taddr = DecodeDestination(address);
         if (!IsValidDestination(taddr)) {
             auto res = DecodePaymentAddress(address);
-            if (IsValidPaymentAddress(res)) {
+            if (IsValidPaymentAddress(res, branchId)) {
                 isZaddr = true;
 
                 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
@@ -4289,7 +4294,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
 
     // Validate the destination address
     auto destaddress = params[1].get_str();
-    if (!IsValidPaymentAddressString(destaddress)) {
+    if (!IsValidPaymentAddressString(destaddress, CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus()))) {
         throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
     }
 
@@ -4524,6 +4529,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
     std::set<CTxDestination> taddrs = {};
     std::set<libzcash::PaymentAddress> zaddrs = {};
 
+    uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
+
     UniValue addresses = params[0].get_array();
     if (addresses.size()==0)
         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
@@ -4552,7 +4559,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
                 }
             } else {
                 auto zaddr = DecodePaymentAddress(address);
-                if (IsValidPaymentAddress(zaddr)) {
+                if (IsValidPaymentAddress(zaddr, branchId)) {
                     // Ignore listed z-addrs if we are using all of them
                     if (!(useAny || useAnyNote)) {
                         zaddrs.insert(zaddr);
@@ -4575,7 +4582,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
     bool isToZaddr = false;
     CTxDestination taddr = DecodeDestination(destaddress);
     if (!IsValidDestination(taddr)) {
-        if (IsValidPaymentAddressString(destaddress)) {
+        if (IsValidPaymentAddressString(destaddress, branchId)) {
             isToZaddr = true;
         } else {
             throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 36bdb5ce2..e7f25f2bd 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1420,11 +1420,8 @@ public:
 };
 
 class GetPubKeyForPubKey : public boost::static_visitor<CPubKey> {
-private:
-    const CKeyStore &keystore;
-
 public:
-    GetPubKeyForPubKey(const CKeyStore &keystoreIn) : keystore(keystoreIn) {}
+    GetPubKeyForPubKey() {}
 
     CPubKey operator()(const CKeyID &id) const {
         return CPubKey();
diff --git a/src/zcash/Address.cpp b/src/zcash/Address.cpp
index dd436ad6d..148cd321c 100644
--- a/src/zcash/Address.cpp
+++ b/src/zcash/Address.cpp
@@ -9,6 +9,8 @@
 const unsigned char ZCASH_SAPLING_FVFP_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
     {'Z', 'c', 'a', 's', 'h', 'S', 'a', 'p', 'l', 'i', 'n', 'g', 'F', 'V', 'F', 'P'};
 
+const uint32_t SAPLING_BRANCH_ID = 0x76b809bb;
+
 namespace libzcash {
 
 uint256 SproutPaymentAddress::GetHash() const {
@@ -111,8 +113,30 @@ SaplingPaymentAddress SaplingSpendingKey::default_address() const {
 
 }
 
-bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr) {
-    return zaddr.which() != 0;
+class IsValidAddressForNetwork : public boost::static_visitor<bool> {
+    private:
+        uint32_t branchId;
+    public:
+        IsValidAddressForNetwork(uint32_t consensusBranchId) : branchId(consensusBranchId) {}
+
+        bool operator()(const libzcash::SproutPaymentAddress &addr) const {
+            return true;
+        }
+
+        bool operator()(const libzcash::InvalidEncoding &addr) const {
+            return false;
+        }
+
+        bool operator()(const libzcash::SaplingPaymentAddress &addr) const {
+            if (SAPLING_BRANCH_ID == branchId)
+                return true;
+            else
+                return false;
+        }
+};
+
+bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr, uint32_t consensusBranchId) {
+    return boost::apply_visitor(IsValidAddressForNetwork(consensusBranchId), zaddr);
 }
 
 bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp
index dd2a75cff..42f01b57b 100644
--- a/src/zcash/Address.hpp
+++ b/src/zcash/Address.hpp
@@ -224,7 +224,8 @@ typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
 }
 
 /** Check whether a PaymentAddress is not an InvalidEncoding. */
-bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr);
+extern const uint32_t SAPLING_BRANCH_ID;
+bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr, uint32_t consensusBranchId = SAPLING_BRANCH_ID);
 
 /** Check whether a ViewingKey is not an InvalidEncoding. */
 bool IsValidViewingKey(const libzcash::ViewingKey& vk);
-- 
2.42.0