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)
{
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;
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
- fMiningRequiresPeers = true;
+ //fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
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
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);
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; }
*/
const CChainParams &Params();
bool AreParamsInitialized();
+void DisableCoinbaseMustBeProtected();
+void EnableCoinbaseMustBeProtected();
/** Return parameters for the given network. */
CChainParams &Params(CBaseChainParams::Network network);
*/
__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;
_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);
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]))
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;
\r
// get the final hash with a mutated dynamic key for each hash result\r
(*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate));\r
-\r
- /*\r
- // TEST BEGIN\r
- // test against the portable version\r
- uint256 testHash1 = *(uint256 *)hash, testHash2;\r
- FillExtra((u128 *)curBuf);\r
- u128 *hashKey = ((u128 *)vclh.gethashkey());\r
- uint64_t temp = verusclhash_port(key, curBuf, vclh.keyMask);\r
- FillExtra(&temp);\r
- haraka512_keyed((unsigned char *)&testHash2, curBuf, hashKey + IntermediateTo128Offset(intermediate));\r
- if (testHash1 != testHash2)\r
- {\r
- printf("Portable version failed! intermediate1: %lx, intermediate2: %lx\n", intermediate, temp);\r
- }\r
- // END TEST\r
- */\r
}\r
\r
inline unsigned char *CurBuffer()\r
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
#include <algorithm>
extern uint160 VERUS_CHAINID;
+extern std::string VERUS_CHAINNAME;
namespace
{
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<std::string> 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::string>();
}
+
std::vector<std::string> retNames;
boost::split(retNames, nameCopy, boost::is_any_of("@"));
if (!retNames.size() || retNames.size() > 2)
{
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<std::string>();
+ }
}
// if no chain is specified, default to chain of the ID
if (retNames.size() == 1)
{
// by default, we assume the Verus chain for no suffix
- ChainOut = "";
+ ChainOut = VERUS_CHAINNAME;
}
else
{
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))) {
}
}
-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
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 )
{
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);
// 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();
assert(nThreadsServicingQueue == 0);
}
-
void CScheduler::serviceQueue()
{
boost::unique_lock<boost::mutex> lock(newTaskMutex);
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;
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_) {
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.");
}
}
}
return true;
}
-bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false)
+bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptProtectedCoinbase=false)
{
std::set<CTxDestination> destinations;
destinations.insert(fromtaddr_);
vector<COutput> 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;
}
}
- // 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);
}
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<unsigned char, ZC_MEMO_SIZE> get_memo_from_hex_string(std::string s);
bool main_impl();
// Get available utxos
vector<COutput> 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) {
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."
if (useAnyUTXO || taddrs.size() > 0) {
// Get available utxos
vector<COutput> 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) {
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)
{
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);
}
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) &&
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);
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<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const
+void CWallet::AvailableCoins(vector<COutput>& 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<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
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]);
return true;
}
-bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl* coinControl) const
+bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& 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 )
//{
// *interestp = 0;
//}
vector<COutput> 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<COutput> 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) {
if ( KOMODO_EXCHANGEWALLET == 0 )
valueWithCoinbase += out.tx->vout[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)
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > 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");
}
//! 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<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const;
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true, bool fIncludeProtectedCoinbase=true) const;
void AvailableReserveCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeCoinBase) const;
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
bool SelectReserveCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;