From: miketout <23489320+miketout@users.noreply.github.com> Date: Sun, 24 Nov 2019 22:23:26 +0000 (-0800) Subject: Prepare for new hash algorithm changes and removing coinbase shielding requirements X-Git-Url: https://repo.jachan.dev/VerusCoin.git/commitdiff_plain/1e435b54955467bfe7b755f6a34fd01f31827d93 Prepare for new hash algorithm changes and removing coinbase shielding requirements --- diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index fa3c8df01..86aee339f 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -324,7 +324,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 const CKeyStore& keystore = *pwalletMain; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, false); utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos)); BOOST_FOREACH(const COutput& out, vecOutputs) { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c73e80e5d..711c093ee 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -93,7 +93,7 @@ public: strNetworkID = "main"; strCurrencyUnits = "KMD"; bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md (ZCASH, should be VRSC) - consensus.fCoinbaseMustBeProtected = false; // true this is only true wuth Verus and enforced after block 12800 + consensus.fCoinbaseMustBeProtected = false; // true this is only true wuth Verus and enforced after block 12800 (enforcement ending at solution V3) consensus.nSubsidySlowStartInterval = 20000; consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL; consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL; @@ -201,7 +201,7 @@ public: vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); - fMiningRequiresPeers = true; + //fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = true; fMineBlocksOnDemand = false; @@ -271,12 +271,17 @@ void *chainparams_commandline(void *ptr) mainParams.consensus.nLwmaPOSAjustedWeight = 46531; } + // this includes VRSCTEST, unlike the checkpoints and changes below + if (_IsVerusActive()) + { + mainParams.consensus.fCoinbaseMustBeProtected = true; + } + // only require coinbase protection on Verus from the Komodo family of coins if (strcmp(ASSETCHAINS_SYMBOL,"VRSC") == 0) { mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520; mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520; - mainParams.consensus.fCoinbaseMustBeProtected = true; checkpointData = //(Checkpoints::CCheckpointData) { boost::assign::map_list_of @@ -749,6 +754,18 @@ const CChainParams &Params() { return *pCurrentParams; } +void DisableCoinbaseMustBeProtected() +{ + CChainParams &curParams = pCurrentParams ? *pCurrentParams : mainParams; + curParams.DisableCoinbaseMustBeProtected(); +} + +void EnableCoinbaseMustBeProtected() +{ + CChainParams &curParams = pCurrentParams ? *pCurrentParams : mainParams; + curParams.EnableCoinbaseMustBeProtected(); +} + bool AreParamsInitialized() { return (pCurrentParams != NULL); diff --git a/src/chainparams.h b/src/chainparams.h index 9d5fad1ff..a1a667917 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -103,6 +103,10 @@ public: std::string GetFoundersRewardAddressAtHeight(int height) const; CScript GetFoundersRewardScriptAtHeight(int height) const; std::string GetFoundersRewardAddressAtIndex(int i) const; + /** Enable disable coinbase protection on mainnet */ + void DisableCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = false; } + void EnableCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; } + /** Enforce coinbase consensus rule in regtest mode */ void SetRegTestCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; } @@ -153,6 +157,8 @@ protected: */ const CChainParams &Params(); bool AreParamsInitialized(); +void DisableCoinbaseMustBeProtected(); +void EnableCoinbaseMustBeProtected(); /** Return parameters for the given network. */ CChainParams &Params(CBaseChainParams::Network network); diff --git a/src/crypto/verus_clhash.cpp b/src/crypto/verus_clhash.cpp index 69d26b982..3b1cb8501 100644 --- a/src/crypto/verus_clhash.cpp +++ b/src/crypto/verus_clhash.cpp @@ -224,7 +224,7 @@ inline void fixupkey(__m128i **pMoveScratch, verusclhash_descr *pdesc) */ __m128i __verusclmulwithoutreduction64alignedrepeat(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); -bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count) +bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint32_t solutionVersion, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count) { CVerusHashV2 &vh = vhw.GetState(); verusclhasher &vclh = vh.vclh; @@ -288,45 +288,6 @@ bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHas _mm_store_si128((u128 *)(&curBuf[32 + 16]), fill1); curBuf[32 + 15] = ch; - /* - if (!i) - { - std::cout << "pre-buffer = "; - std::cout << HexBytes(curBuf, 64); - - std::cout << std::endl; - std::cout << "test_buf = ["; - for (int k = 0; k < 64; k++) - { - if (k == 63) - { - std::cout << strprintf("0x%02x]", *(curBuf + k)); - } - else - { - std::cout << strprintf("0x%02x, ", *(curBuf + k)); - } - } - std::cout << std::endl; - - std::cout << "test_key = ["; - for (int k = 0; k < (((u128 *)hasherrefresh) - hashKey); k++) - { - std::cout << "0x"; - std::cout << LEToHex(*(hashKey + k)); - if (k == (((u128 *)hasherrefresh) - hashKey) - 1) - { - std::cout << "]"; - } - else - { - std::cout << ", "; - } - } - std::cout << std::endl; - } - */ - // run verusclhash on the buffer //const uint64_t intermediate = vclh(curBuf, hashKey, pMoveScratch); __m128i acc = __verusclmulwithoutreduction64alignedrepeat(hashKey, (const __m128i *)curBuf, vclh.keyMask, pMoveScratch); @@ -340,18 +301,6 @@ bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHas haraka512_keyed_local((unsigned char *)&curHash, curBuf, hashKey + vh.IntermediateTo128Offset(intermediate)); - /* - if (!i) - { - std::cout << "intermediate: "; - std::cout << LEToHex(intermediate); - std::cout << std::endl; - std::cout << "hashBytes: "; - std::cout << HexBytes((unsigned char *)&curHash, 32); - std::cout << std::endl; - } - */ - if (compResult[3] > compTarget[3] || (compResult[3] == compTarget[3] && compResult[2] > compTarget[2]) || (compResult[3] == compTarget[3] && compResult[2] == compTarget[2] && compResult[1] > compTarget[1]) || (compResult[3] == compTarget[3] && compResult[2] == compTarget[2] && compResult[1] == compTarget[1] && compResult[0] > compTarget[0])) diff --git a/src/crypto/verus_clhash_portable.cpp b/src/crypto/verus_clhash_portable.cpp index 2a0322f9e..a14b71182 100644 --- a/src/crypto/verus_clhash_portable.cpp +++ b/src/crypto/verus_clhash_portable.cpp @@ -650,7 +650,7 @@ uint64_t verusclhash_port(void * random, const unsigned char buf[64], uint64_t k return precompReduction64_port(acc); } -bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count) +bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint32_t solutionVersion, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count) { CVerusHashV2 &vh = vhw.GetState(); verusclhasher &vclh = vh.vclh; diff --git a/src/crypto/verus_hash.h b/src/crypto/verus_hash.h index 727f1f80a..fb502e97d 100644 --- a/src/crypto/verus_hash.h +++ b/src/crypto/verus_hash.h @@ -218,22 +218,6 @@ class CVerusHashV2 // get the final hash with a mutated dynamic key for each hash result (*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate)); - - /* - // TEST BEGIN - // test against the portable version - uint256 testHash1 = *(uint256 *)hash, testHash2; - FillExtra((u128 *)curBuf); - u128 *hashKey = ((u128 *)vclh.gethashkey()); - uint64_t temp = verusclhash_port(key, curBuf, vclh.keyMask); - FillExtra(&temp); - haraka512_keyed((unsigned char *)&testHash2, curBuf, hashKey + IntermediateTo128Offset(intermediate)); - if (testHash1 != testHash2) - { - printf("Portable version failed! intermediate1: %lx, intermediate2: %lx\n", intermediate, temp); - } - // END TEST - */ } inline unsigned char *CurBuffer() diff --git a/src/init.cpp b/src/init.cpp index 751ea5941..7402c9fd8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1218,12 +1218,18 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV2, 310000); CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV3, 780000); } - else + else if (strcmp(ASSETCHAINS_SYMBOL,"VRSCTEST") == 0) { CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV2, 1); CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV3, 110); //CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV4, 1); } + else + { + CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV2, 1); + CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV3, 1); + CConstVerusSolutionVector::activationHeight.SetActivationHeight(CActivationHeight::SOLUTION_VERUSV4, 1); + } } // Sanity check diff --git a/src/key_io.cpp b/src/key_io.cpp index 7e76171a0..8388d8fde 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -22,6 +22,7 @@ #include extern uint160 VERUS_CHAINID; +extern std::string VERUS_CHAINNAME; namespace { @@ -494,17 +495,48 @@ uint160 CCrossChainRPCData::GetConditionID(std::string name, int32_t condition) return Hash160(chainHash.begin(), chainHash.end()); } +std::string TrimLeading(const std::string &Name, unsigned char ch) +{ + std::string nameCopy = Name; + int removeSpaces; + for (removeSpaces = 0; removeSpaces < nameCopy.size(); removeSpaces++) + { + if (nameCopy[removeSpaces] != ch) + { + break; + } + } + if (removeSpaces) + { + nameCopy.erase(nameCopy.begin(), nameCopy.begin() + removeSpaces); + } + return nameCopy; +} + +std::string TrimTrailing(const std::string &Name, unsigned char ch) +{ + std::string nameCopy = Name; + int removeSpaces; + for (removeSpaces = nameCopy.size() - 1; removeSpaces >= 0; removeSpaces--) + { + if (nameCopy[removeSpaces] != ch) + { + break; + } + } + nameCopy.resize(nameCopy.size() - removeSpaces); + return nameCopy; +} + std::vector ParseSubNames(const std::string &Name, std::string &ChainOut) { std::string nameCopy = Name; std::string invalidChars = "\\/:*?\"<>|"; for (int i = 0; i < nameCopy.size(); i++) { - if (invalidChars.find(nameCopy[i]) != std::string::npos) - { - nameCopy[i] = '_'; - } + return std::vector(); } + std::vector retNames; boost::split(retNames, nameCopy, boost::is_any_of("@")); if (!retNames.size() || retNames.size() > 2) @@ -528,6 +560,11 @@ std::vector ParseSubNames(const std::string &Name, std::string &Cha { retNames[i] = std::string(retNames[i], 0, (KOMODO_ASSETCHAIN_MAXLEN - 1)); } + // spaces are allowed, but no sub-name can have leading or trailing spaces + if (!retNames[i].size() || retNames[i] != TrimTrailing(TrimLeading(retNames[i], ' '), ' ')) + { + return std::vector(); + } } // if no chain is specified, default to chain of the ID @@ -536,7 +573,7 @@ std::vector ParseSubNames(const std::string &Name, std::string &Cha if (retNames.size() == 1) { // by default, we assume the Verus chain for no suffix - ChainOut = ""; + ChainOut = VERUS_CHAINNAME; } else { diff --git a/src/main.cpp b/src/main.cpp index 831cb9cff..701ba3804 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2671,9 +2671,12 @@ namespace Consensus { REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); } - // Ensure that coinbases cannot be spent to transparent outputs - // Disabled on regtest - if (fCoinbaseEnforcedProtectionEnabled && + // As of solution version 3, we're done with the Zcash coinbase protection. + // After careful consideration, it seems that while there is no real privacy benefit to the + // coinbase protection beyond forcing the private address pool to be used at least a little by everyone, it does increase the size of the blockchain + // and often reduces privacy by mixing multiple coinbase payment addresses + if (CConstVerusSolutionVector::GetVersionByHeight(coins->nHeight) < CActivationHeight::SOLUTION_VERUSV3 && + fCoinbaseEnforcedProtectionEnabled && consensusParams.fCoinbaseMustBeProtected && !(tx.vout.size() == 0 || (tx.vout.size() == 1 && tx.vout[0].nValue == 0)) && (strcmp(ASSETCHAINS_SYMBOL, "VRSC") != 0 || (nSpendHeight >= 12800 && coins->nHeight >= 12800))) { diff --git a/src/miner.cpp b/src/miner.cpp index 1bf90b6c9..eadd9dfeb 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -2294,9 +2294,9 @@ void static VerusStaker(CWallet *pwallet) } } -typedef bool (*minefunction)(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); -bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); -bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); +typedef bool (*minefunction)(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint32_t solutionVersion, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); +bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint32_t solutionVersion, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); +bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint32_t solutionVersion, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count); void static BitcoinMiner_noeq(CWallet *pwallet) #else @@ -2429,8 +2429,10 @@ void static BitcoinMiner_noeq() bool mergeMining = false; savebits = pblock->nBits; + uint32_t solutionVersion = CConstVerusSolutionVector::Version(pblock->nSolution); bool verusHashV2 = pblock->nVersion == CBlockHeader::VERUS_V2; - bool verusSolutionV4 = CConstVerusSolutionVector::Version(pblock->nSolution) >= CActivationHeight::SOLUTION_VERUSV4; + bool verusSolutionGTEV3 = solutionVersion >= CActivationHeight::SOLUTION_VERUSV3; + bool verusSolutionV4 = solutionVersion >= CActivationHeight::SOLUTION_VERUSV4; if ( ASSETCHAINS_SYMBOL[0] != 0 ) { @@ -2627,12 +2629,12 @@ void static BitcoinMiner_noeq() CPBaaSPreHeader savedHeader(*pblock); pblock->ClearNonCanonicalData(); - blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo); + blockFound = (*mine_verus)(*pblock, ss2, solutionVersion, hashResult, uintTarget, start, &hashesToGo); savedHeader.SetBlockData(*pblock); } else { - blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo); + blockFound = (*mine_verus)(*pblock, ss2, solutionVersion, hashResult, uintTarget, start, &hashesToGo); } arithHash = UintToArith256(hashResult); diff --git a/src/rpc/pbaasrpc.cpp b/src/rpc/pbaasrpc.cpp index 75a0ff55e..53d1f9a0d 100644 --- a/src/rpc/pbaasrpc.cpp +++ b/src/rpc/pbaasrpc.cpp @@ -4183,7 +4183,7 @@ UniValue registernamecommitment(const UniValue& params, bool fHelp) // if either we have an invalid name or an implied parent, that is not valid if (name == "" || !parent.IsNull()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid name for commitment"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid name for commitment. Names must not have leading or trailing spaces and must not include any of the following characters between parentheses (\\/:*?\"<>|)"); } parent = ConnectedChains.ThisChain().GetChainID(); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index ecd904cde..20532045d 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -19,7 +19,6 @@ CScheduler::~CScheduler() assert(nThreadsServicingQueue == 0); } - void CScheduler::serviceQueue() { boost::unique_lock lock(newTaskMutex); diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp index 8430b0103..0089321b9 100644 --- a/src/wallet-utility.cpp +++ b/src/wallet-utility.cpp @@ -13,6 +13,7 @@ char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; bool PBAAS_TESTMODE; uint160 ASSETCHAINS_CHAINID; uint160 VERUS_CHAINID; +std::string VERUS_CHAINNAME; int64_t MAX_MONEY = 200000000 * 100000000LL; uint64_t ASSETCHAINS_SUPPLY; uint16_t BITCOIND_RPCPORT = 7771; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 6f34a236a..58beb3b8e 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -222,6 +222,8 @@ bool AsyncRPCOperation_sendmany::main_impl() { bool isPureTaddrOnlyTx = (isfromtaddr_ && z_outputs_.size() == 0); CAmount minersFee = fee_; + uint solutionVersion = CConstVerusSolutionVector::GetVersionByHeight(chainActive.Height() + 1); + // When spending coinbase utxos, you can only specify a single zaddr as the change must go somewhere // and if there are multiple zaddrs, we don't know where to send it. if (isfromtaddr_) { @@ -235,9 +237,9 @@ bool AsyncRPCOperation_sendmany::main_impl() { bool b = find_utxos(false); if (!b) { if (isMultipleZaddrOutput) { - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend. Coinbase UTXOs can only be sent to a single zaddr recipient."); + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase UTXOs without shielding requirements to spend. Protected coinbase UTXOs can only be sent to a single zaddr recipient."); } else { - throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend."); + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase UTXOs without shielding requirements to spend."); } } } @@ -938,7 +940,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { return true; } -bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) +bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptProtectedCoinbase=false) { std::set destinations; destinations.insert(fromtaddr_); @@ -948,7 +950,7 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) vector vecOutputs; LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, fAcceptCoinbase); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, false, true, fAcceptProtectedCoinbase); BOOST_FOREACH(const COutput& out, vecOutputs) { CTxDestination dest; @@ -979,16 +981,9 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) } } - // By default we ignore coinbase outputs if coinbase shielding is required - // TODO: audit use of fAcceptCoinbase to ensure that in all cases when coinbase is not required to be shielded that this is skipped - bool isCoinbase = out.tx->IsCoinBase(); - if (isCoinbase && fAcceptCoinbase==false) { - continue; - } - CAmount nValue = out.tx->vout[out.i].nValue; - SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase, scriptPubKey); + SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, out.tx->IsCoinBase(), scriptPubKey); t_inputs_.push_back(utxo); } diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index a9e904421..4fa929d28 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -111,7 +111,7 @@ private: void add_taddr_change_output_to_tx(CReserveKey& keyChange, CAmount amount); void add_taddr_outputs_to_tx(); bool find_unspent_notes(); - bool find_utxos(bool fAcceptCoinbase); + bool find_utxos(bool fAcceptProtectedCoinbase); std::array get_memo_from_hex_string(std::string s); bool main_impl(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a60495bc9..07ffd9db8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4590,7 +4590,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Get available utxos vector vecOutputs; - pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true); + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, true); // Find unspent coinbase utxos and update estimated size BOOST_FOREACH(const COutput& out, vecOutputs) { @@ -4720,7 +4720,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) throw runtime_error( "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" + strDisabledMsg + - "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" + "\nMerge multiple UTXOs and notes into a single UTXO or note. Protected coinbase UTXOs are ignored, use `z_shieldcoinbase`" "\nto combine those into a single note." "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." @@ -4929,7 +4929,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (useAnyUTXO || taddrs.size() > 0) { // Get available utxos vector vecOutputs; - pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false); // Find unspent utxos and update estimated size for (const COutput& out : vecOutputs) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5674808b4..8e9824cbf 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1496,13 +1496,14 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, auto consensusParams = Params().GetConsensus(); CValidationState state; - pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, !consensusParams.fCoinbaseMustBeProtected); + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false); if (pastBlockIndex = komodo_chainactive(nHeight - 100)) { uint256 pastHash = pastBlockIndex->GetVerusEntropyHash(); CPOSNonce curNonce; uint32_t srcIndex; + uint32_t solutionVersion = CConstVerusSolutionVector::activationHeight.ActiveVersion(nHeight); BOOST_FOREACH(COutput &txout, vecOutputs) { @@ -1512,7 +1513,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, int32_t txSize = GetSerializeSize(s, *(CTransaction *)txout.tx); //printf("Serialized size of transaction %s is %lu\n", txout.tx->GetHash().GetHex().c_str(), txSize); - if (txSize > MAX_TX_SIZE_FOR_STAKING) + if (solutionVersion >= CActivationHeight::SOLUTION_VERUSV4 && txSize > MAX_TX_SIZE_FOR_STAKING) { LogPrintf("Transaction %s is too large to stake. Serialized size == %lu\n", txout.tx->GetHash().GetHex().c_str(), txSize); } @@ -1522,8 +1523,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, uint256 txHash = txout.tx->GetHash(); checkStakeTx.vin.push_back(CTxIn(COutPoint(txHash, txout.i))); - if (txSize <= MAX_TX_SIZE_FOR_STAKING && - (!pwinner || UintToArith256(curNonce) > UintToArith256(pBlock->nNonce)) && + if ((!pwinner || UintToArith256(curNonce) > UintToArith256(pBlock->nNonce)) && (Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH)) && !cheatList.IsUTXOInList(COutPoint(txHash, txout.i), nHeight <= 100 ? 1 : nHeight-100) && view.AccessCoins(txHash) && @@ -1542,7 +1542,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, voutNum = pwinner->i; pBlock->nNonce = curNonce; - if (CConstVerusSolutionVector::activationHeight.ActiveVersion(nHeight) == CActivationHeight::SOLUTION_VERUSV4) + if (solutionVersion >= CActivationHeight::SOLUTION_VERUSV4) { CDataStream txStream = CDataStream(SER_NETWORK, PROTOCOL_VERSION); @@ -4357,13 +4357,14 @@ CAmount CWallet::GetImmatureWatchOnlyReserveBalance() const uint64_t komodo_interestnew(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); -void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const +void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase, bool fIncludeProtectedCoinbase) const { uint64_t interest,*ptr; vCoins.clear(); { LOCK2(cs_main, cs_wallet); + uint32_t nHeight = chainActive.Height() + 1; for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; @@ -4375,16 +4376,22 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const if (fOnlyConfirmed && !pcoin->IsTrusted()) continue; - if (pcoin->IsCoinBase() && !fIncludeCoinBase) + bool isCoinbase = pcoin->IsCoinBase(); + if (isCoinbase && !fIncludeCoinBase) continue; - - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + + if (isCoinbase && pcoin->GetBlocksToMaturity() > 0) continue; int nDepth = pcoin->GetDepthInMainChain(); if (nDepth < 0) continue; + uint32_t coinHeight = nHeight - nDepth; + // even if we should include coinbases, we may opt to exclude protected coinbases, which must only be included when shielding + if (isCoinbase && !fIncludeProtectedCoinbase && Params().GetConsensus().fCoinbaseMustBeProtected && (CConstVerusSolutionVector::GetVersionByHeight(coinHeight) < CActivationHeight::SOLUTION_VERUSV3)) + continue; + for (int i = 0; i < pcoin->vout.size(); i++) { isminetype mine = IsMine(pcoin->vout[i]); @@ -4659,9 +4666,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int return true; } -bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, bool& fOnlyProtectedCoinbaseCoinsRet, bool& fNeedProtectedCoinbaseCoinsRet, const CCoinControl* coinControl) const { - // Output parameter fOnlyCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos. + // Output parameter fOnlyProtectedCoinbaseCoinsRet is set to true when the only available coins are coinbase utxos. uint64_t tmp; int32_t retval; //if ( interestp == 0 ) //{ @@ -4669,15 +4676,15 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set vCoinsNoCoinbase, vCoinsWithCoinbase; - AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, false); - AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true); - fOnlyCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0; + AvailableCoins(vCoinsNoCoinbase, true, coinControl, false, true, false); + AvailableCoins(vCoinsWithCoinbase, true, coinControl, false, true, true); + fOnlyProtectedCoinbaseCoinsRet = vCoinsNoCoinbase.size() == 0 && vCoinsWithCoinbase.size() > 0; // If coinbase utxos can only be sent to zaddrs, exclude any coinbase utxos from coin selection. bool fProtectCoinbase = Params().GetConsensus().fCoinbaseMustBeProtected; vector vCoins = (fProtectCoinbase) ? vCoinsNoCoinbase : vCoinsWithCoinbase; - // Output parameter fNeedCoinbaseCoinsRet is set to true if coinbase utxos need to be spent to meet target amount + // Output parameter fNeedProtectedCoinbaseCoinsRet is set to true if coinbase utxos that must be shielded need to be spent to meet target amount if (fProtectCoinbase && vCoinsWithCoinbase.size() > vCoinsNoCoinbase.size()) { CAmount value = 0; for (const COutput& out : vCoinsNoCoinbase) { @@ -4698,7 +4705,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, setvout[out.i].interest; } - fNeedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue); + fNeedProtectedCoinbaseCoinsRet = (valueWithCoinbase >= nTargetValue); } } // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) @@ -5130,15 +5137,15 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // Choose coins to use set > setCoins; CAmount nValueIn = 0; - bool fOnlyCoinbaseCoins = false; - bool fNeedCoinbaseCoins = false; + bool fOnlyProtectedCoinbaseCoins = false; + bool fNeedProtectedCoinbaseCoins = false; interest2 = 0; - if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyCoinbaseCoins, fNeedCoinbaseCoins, coinControl)) + if (!SelectCoins(nTotalValue, setCoins, nValueIn, fOnlyProtectedCoinbaseCoins, fNeedProtectedCoinbaseCoins, coinControl)) { - if (fOnlyCoinbaseCoins && Params().GetConsensus().fCoinbaseMustBeProtected) { - strFailReason = _("Coinbase funds can only be sent to a zaddr"); - } else if (fNeedCoinbaseCoins) { - strFailReason = _("Insufficient funds, coinbase funds can only be spent after they have been sent to a zaddr"); + if (fOnlyProtectedCoinbaseCoins) { + strFailReason = _("Coinbase funds earned while shielding protection is active can only be sent to a zaddr"); + } else if (fNeedProtectedCoinbaseCoins) { + strFailReason = _("Insufficient funds, protected coinbase funds can only be spent after they have been sent to a zaddr"); } else { strFailReason = _("Insufficient funds"); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 441729ce0..a761b300a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1035,7 +1035,7 @@ public: //! check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } - void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const; + void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true, bool fIncludeProtectedCoinbase=true) const; void AvailableReserveCoins(std::vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeCoinBase) const; bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; bool SelectReserveCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const;