From 6a6537be2e944ea1a9e287ed9408db5c086aa2c8 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 11 Sep 2019 15:20:26 +0200 Subject: [PATCH 001/126] smartrewards: Removed DB locking stuff --- src/init.cpp | 4 ---- src/smartrewards/rewards.cpp | 12 ------------ src/smartrewards/rewardsdb.cpp | 23 ----------------------- src/smartrewards/rewardsdb.h | 7 +------ 4 files changed, 1 insertion(+), 45 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 0f5b3468..f4b7579b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1799,16 +1799,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) prewards = new CSmartRewards(prewardsdb); } - if( prewards->IsLocked() ) throw std::runtime_error(_("SmartRewards database is incomplete.")); - if( !(fLoaded = prewards->Verify()) ) throw std::runtime_error(_("Failed to verify SmartRewards database.")); if( pLastIndex != NULL && !(fLoaded = (prewards->GetLastHeight() <= pLastIndex->nHeight)) ) throw std::runtime_error(_("SmartRewards database exceeds current chain height.")); if (fRequestShutdown) break; - prewards->Lock(); - } catch (const std::runtime_error &e) { if (fDebug) LogPrintf("%s\n", e.what()); strLoadError = e.what(); diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index caeb527e..4fa7dd73 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -323,18 +323,6 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) pdb->ReadCurrentRound(currentRound); } -void CSmartRewards::Lock() -{ - LOCK(cs_rewardsdb); - pdb->Lock(); -} - -bool CSmartRewards::IsLocked() -{ - LOCK(cs_rewardsdb); - return pdb->IsLocked(); -} - bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) { LOCK(cs_rewardsdb); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index bb015438..58c26cca 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -29,12 +29,9 @@ static const char DB_BLOCK_LAST = 'b'; static const char DB_TX_HASH = 't'; static const char DB_VERSION = 'V'; -static const char DB_LOCK = 'L'; CSmartRewardsDB::CSmartRewardsDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "rewards", nCacheSize, fMemory, fWipe) { - locked = false; - if( !Exists(DB_VERSION) ){ Write(DB_VERSION, REWARDS_DB_VERSION); } @@ -99,26 +96,6 @@ bool CSmartRewardsDB::Verify(int& lastBlockHeight) return true; } -void CSmartRewardsDB::Lock() -{ - locked = true; - Write(DB_LOCK, 1, true); - Sync(); -} - -void CSmartRewardsDB::Unlock() -{ - if(locked){ - Erase(DB_LOCK,true); - Sync(); - } -} - -bool CSmartRewardsDB::IsLocked() -{ - return Exists(DB_LOCK); -} - bool CSmartRewardsDB::ReadBlock(const int nHeight, CSmartRewardBlock &block) { return Read(make_pair(DB_BLOCK,nHeight), block); diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index 7d2dd2ab..ca9b8095 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -270,20 +270,15 @@ class CSmartRewardsDB : public CDBWrapper { public: CSmartRewardsDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - ~CSmartRewardsDB() { Unlock(); } + ~CSmartRewardsDB() {Sync();} private: CSmartRewardsDB(const CSmartRewardsDB&); void operator=(const CSmartRewardsDB&); - bool locked; - void Unlock(); public: bool Verify(int& lastBlockHeight); - void Lock(); - bool IsLocked(); - bool ReadBlock(const int nHeight, CSmartRewardBlock &block); bool ReadLastBlock(CSmartRewardBlock &block); From de29b6078ae1bbcb89bc5a3cac68dcb472e743f3 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 11 Sep 2019 20:24:33 +0200 Subject: [PATCH 002/126] smartrewards: Seperated in/output processing --- src/smartrewards/rewards.cpp | 736 ++++++++++++++++++----------------- src/smartrewards/rewards.h | 9 +- 2 files changed, 385 insertions(+), 360 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 4fa7dd73..96094820 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -370,295 +370,235 @@ void CSmartRewards::StartBlock() transactionEntries.clear(); } -void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) +void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) { - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - %s", tx.GetHash().ToString()); - + uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardEntry *rEntry = nullptr; - int nFirst_1_3_Round = chainparams.GetConsensus().nRewardsFirst_1_3_Round; + std::vector ids; - int nCurrentRound; + int required = ParseScript(in.scriptPubKey ,ids); - { - LOCK(cs_rewardrounds); - nCurrentRound = currentRound.number; - } - - int nHeight = pIndex->nHeight; - - if(nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + if( !required || required > 1 || ids.size() > 1 ){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Inputs: Could't parse CSmartAddress: %s\n",in.ToString()); return; } - int nTime1 = GetTimeMicros(); - - CSmartRewardTransaction testTx; + if(!GetCachedRewardEntry(ids.at(0), rEntry)){ - // First check if the transaction hash did already come up in the past. - if( GetTransaction(tx.GetHash(), testTx) ){ + rEntry = new CSmartRewardEntry(ids.at(0)); - // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - [%s] Double appearance! First in %d - Now in %d\n", testTx.hash.ToString(), testTx.blockHeight, pIndex->nHeight); - return; + if(!ReadRewardEntry(rEntry->id, *rEntry)){ + delete rEntry; + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Spend without previous receive - %s", tx.ToString()); + return; + } - }else{ - // If not save add it to the database. - AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); + rewardEntries.insert(make_pair(ids.at(0), rEntry)); } - CSmartAddress *voteProofCheck = nullptr; - CAmount nVoteProofIn = 0; - unsigned char cProofOption = 0; + // If its a voteproof transaction not instantly make the + // balance ineligible. First check if the change is sent back + // to the address or not to avoid exploiting fund sending + // with voteproof transactions + if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() && *voteProofCheck == nullptr ){ + *voteProofCheck = new CSmartAddress(rEntry->id); + nVoteProofIn += in.nValue; + } - // No reason to check the input here for new coins. - if( !tx.IsCoinBase() ){ + rEntry->balance -= in.nValue; - BOOST_FOREACH(const CTxIn &in, tx.vin) { + // If its a voteproof transaction not instantly make the + // balance ineligible. First check if the change is sent back + // to the address or not to avoid exploiting fund sending + // with voteproof transactions + if( nCurrentRound >= nFirst_1_3_Round && *voteProofCheck == nullptr && rEntry->disqualifyingTx.IsNull() ){ - if( in.scriptSig.IsZerocoinSpend() ) continue; + if( rEntry->IsEligible() ){ + result.disqualifiedEntries++; + result.disqualifiedSmart += rEntry->balanceEligible; + } - const Coin &coin = coins.AccessCoin(in.prevout); - const CTxOut &rOut = coin.out; + rEntry->disqualifyingTx = tx.GetHash(); - std::vector ids; + }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx.IsNull() ){ - int required = ParseScript(rOut.scriptPubKey ,ids); + rEntry->disqualifyingTx = tx.GetHash(); - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Inputs: Could't parse CSmartAddress: %s\n",rOut.ToString()); - continue; - } + if( rEntry->balanceEligible ){ + result.disqualifiedEntries++; + result.disqualifiedSmart += rEntry->balanceEligible; + } - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ + } - rEntry = new CSmartRewardEntry(ids.at(0)); + if(rEntry->balance < 0 ){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Negative amount?! - %s", rEntry->ToString()); + rEntry->balance = 0; + } - if(!ReadRewardEntry(rEntry->id, *rEntry)){ - delete rEntry; - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Spend without previous receive - %s", tx.ToString()); - continue; - } +} - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } +void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result) +{ + uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardEntry *rEntry = nullptr; + std::vector ids; + int required = ParseScript(out.scriptPubKey ,ids); - // If its a voteproof transaction not instantly make the - // balance ineligible. First check if the change is sent back - // to the address or not to avoid exploiting fund sending - // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() && voteProofCheck == nullptr ){ - voteProofCheck = new CSmartAddress(rEntry->id); - nVoteProofIn += rOut.nValue; - } + if( !required || required > 1 || ids.size() > 1 ){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); + return; + }else{ - rEntry->balance -= rOut.nValue; + if(!GetCachedRewardEntry(ids.at(0),rEntry)){ + rEntry = new CSmartRewardEntry(ids.at(0)); + ReadRewardEntry(rEntry->id, *rEntry); + rewardEntries.insert(make_pair(ids.at(0), rEntry)); + } - // If its a voteproof transaction not instantly make the - // balance ineligible. First check if the change is sent back - // to the address or not to avoid exploiting fund sending - // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && voteProofCheck == nullptr && rEntry->disqualifyingTx.IsNull() ){ + if( voteProofCheck ){ - if( rEntry->IsEligible() ){ - result.disqualifiedEntries++; - result.disqualifiedSmart += rEntry->balanceEligible; - } + unsigned char cProofOption = 0; - rEntry->disqualifyingTx = tx.GetHash(); + if( !out.IsVoteProofData() && + !(*voteProofCheck == rEntry->id) ){ - }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx.IsNull() ){ + CSmartRewardEntry *vkEntry = nullptr; - rEntry->disqualifyingTx = tx.GetHash(); + if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ + vkEntry = new CSmartRewardEntry(*voteProofCheck); + ReadRewardEntry(vkEntry->id, *vkEntry); + rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); + } - if( rEntry->balanceEligible ){ + if( vkEntry->IsEligible() ){ result.disqualifiedEntries++; - result.disqualifiedSmart += rEntry->balanceEligible; + result.disqualifiedSmart += vkEntry->balanceEligible; } - } + // Finally invalidate the balance since the change was not sent + // back to the sender! We don't want to allow + // a exploit to send around funds withouht breaking smartrewards. + vkEntry->disqualifyingTx = tx.GetHash(); - if(rEntry->balance < 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Negative amount?! - %s", rEntry->ToString()); - rEntry->balance = 0; - } + }else if( !out.IsVoteProofData() && + (*voteProofCheck == rEntry->id) ){ - } - } + CSmartRewardEntry *proofEntry = nullptr; + unsigned char cAddressType = 0; + uint32_t nProofRound; + uint160 addressHash; + uint256 nProposalHash; // Placeholder only for now + CSmartAddress proofAddress; - int nTime2 = GetTimeMicros(); + BOOST_FOREACH(const CTxOut &outData, tx.vout) { - BOOST_FOREACH(const CTxOut &out, tx.vout) { + if( outData.IsVoteProofData() ){ - if(out.scriptPubKey.IsZerocoinMint() ) continue; + std::vector scriptData; + scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); + CDataStream ss(scriptData, SER_NETWORK, 0); - std::vector ids; - int required = ParseScript(out.scriptPubKey ,ids); - - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); - continue; - }else{ + ss >> cProofOption; + ss >> nProofRound; + ss >> nProposalHash; - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ - rEntry = new CSmartRewardEntry(ids.at(0)); - ReadRewardEntry(rEntry->id, *rEntry); - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } + if( cProofOption == 0x01 && + voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ + proofAddress = *voteProofCheck; + proofEntry = rEntry; + }else if( cProofOption == 0x02 && + voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ - if( voteProofCheck ){ + ss >> cAddressType; + ss >> addressHash; - if( !out.IsVoteProofData() && - !(*voteProofCheck == rEntry->id) ){ + if( cAddressType == 0x01 ){ + proofAddress = CSmartAddress(CKeyID(addressHash)); + }else if( cAddressType == 0x02){ + proofAddress = CSmartAddress(CScriptID(addressHash)); + }else{ + proofAddress = CSmartAddress(); // Invalid address type + } - CSmartRewardEntry *vkEntry = nullptr; + if(!GetCachedRewardEntry(proofAddress, proofEntry)){ + proofEntry = new CSmartRewardEntry(proofAddress); + ReadRewardEntry(proofEntry->id, *proofEntry); + rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); + } - if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ - vkEntry = new CSmartRewardEntry(*voteProofCheck); - ReadRewardEntry(vkEntry->id, *vkEntry); - rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); + }else{ + proofAddress = CSmartAddress(); // Invalid option + } } + } - if( vkEntry->IsEligible() ){ - result.disqualifiedEntries++; - result.disqualifiedSmart += vkEntry->balanceEligible; - } + if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - // Finally invalidate the balance since the change was not sent - // back to the sender! We don't want to allow - // a exploit to send around funds withouht breaking smartrewards. - vkEntry->disqualifyingTx = tx.GetHash(); - - }else if( !out.IsVoteProofData() && - (*voteProofCheck == rEntry->id) ){ - - CSmartRewardEntry *proofEntry = nullptr; - unsigned char cAddressType = 0; - uint32_t nProofRound; - uint160 addressHash; - uint256 nProposalHash; // Placeholder only for now - CSmartAddress proofAddress; - - BOOST_FOREACH(const CTxOut &outData, tx.vout) { - - if( outData.IsVoteProofData() ){ - - std::vector scriptData; - scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); - CDataStream ss(scriptData, SER_NETWORK, 0); - - ss >> cProofOption; - ss >> nProofRound; - ss >> nProposalHash; - - if( cProofOption == 0x01 && - voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ - proofAddress = *voteProofCheck; - proofEntry = rEntry; - }else if( cProofOption == 0x02 && - voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ - - ss >> cAddressType; - ss >> addressHash; - - if( cAddressType == 0x01 ){ - proofAddress = CSmartAddress(CKeyID(addressHash)); - }else if( cAddressType == 0x02){ - proofAddress = CSmartAddress(CScriptID(addressHash)); - }else{ - proofAddress = CSmartAddress(); // Invalid address type - } - - if(!GetCachedRewardEntry(proofAddress, proofEntry)){ - proofEntry = new CSmartRewardEntry(proofAddress); - ReadRewardEntry(proofEntry->id, *proofEntry); - rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); - } + if( cProofOption == 0x01 && proofEntry->balanceEligible ){ + proofEntry->balanceEligible -= nVoteProofIn - tx.GetValueOut(); - }else{ - proofAddress = CSmartAddress(); // Invalid option - } + if( proofEntry->balanceEligible < 0 ){ + proofEntry->balanceEligible = 0; } } - if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - - if( cProofOption == 0x01 && proofEntry->balanceEligible ){ - proofEntry->balanceEligible -= nVoteProofIn - tx.GetValueOut(); + if( proofEntry->voteProof.IsNull() ){ - if( proofEntry->balanceEligible < 0 ){ - proofEntry->balanceEligible = 0; - } + if( nProofRound == nCurrentRound ){ + proofEntry->voteProof = tx.GetHash(); } - if( proofEntry->voteProof.IsNull() ){ - - if( nProofRound == currentRound.number ){ - proofEntry->voteProof = tx.GetHash(); - } - - // If the entry is eligible now after the vote proof update the results - if( proofEntry->IsEligible() ){ - result.qualifiedEntries++; - result.qualifiedSmart += proofEntry->balanceEligible; - } - + // If the entry is eligible now after the vote proof update the results + if( proofEntry->IsEligible() ){ + result.qualifiedEntries++; + result.qualifiedSmart += proofEntry->balanceEligible; } + } } - - delete voteProofCheck; } - rEntry->balance += out.nValue; + delete voteProofCheck; + } - // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists - if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ + rEntry->balance += out.nValue; - int nInterval = SmartNodePayments::PayoutInterval(nHeight); - int nPayoutsPerBlock = SmartNodePayments::PayoutsPerBlock(nHeight); - // Just to avoid potential zero divisions - nPayoutsPerBlock = std::max(1,nPayoutsPerBlock); + // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists + if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ - CAmount nNodeReward = SmartNodePayments::Payment(nHeight) / nPayoutsPerBlock; + int nInterval = SmartNodePayments::PayoutInterval(nHeight); + int nPayoutsPerBlock = SmartNodePayments::PayoutsPerBlock(nHeight); + // Just to avoid potential zero divisions + nPayoutsPerBlock = std::max(1, nPayoutsPerBlock); - // If we have an interval check if this is a node payout block - if( nInterval && !(nHeight % nInterval) ){ + CAmount nNodeReward = SmartNodePayments::Payment(nHeight) / nPayoutsPerBlock; - // If the amount matches and the entry is not yet marked as node do it - if( abs(out.nValue - nNodeReward ) < 2 ){ + // If we have an interval check if this is a node payout block + if( nInterval && !(nHeight % nInterval) ){ - if( rEntry->smartnodePaymentTx.IsNull() ){ + // If the amount matches and the entry is not yet marked as node do it + if( abs(out.nValue - nNodeReward ) < 2 ){ - // If it is currently eligible adjust the round's results - if( rEntry->IsEligible() ){ - ++result.disqualifiedEntries; - result.disqualifiedSmart += rEntry->balanceEligible; - } + if( rEntry->smartnodePaymentTx.IsNull() ){ - rEntry->smartnodePaymentTx = tx.GetHash(); + // If it is currently eligible adjust the round's results + if( rEntry->IsEligible() ){ + ++result.disqualifiedEntries; + result.disqualifiedSmart += rEntry->balanceEligible; } + + rEntry->smartnodePaymentTx = tx.GetHash(); } } } } } - - int nTime3 = GetTimeMicros(); - int nTimeTx = nTime3 - nTime1; - - if( LogAcceptCategory("smartrewards-tx") ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), nTimeTx * 0.001); - LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime2 - nTime1) * 0.001); - LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime3 - nTime2) * 0.001); - } } -void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) +void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) { - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - %s", tx.GetHash().ToString()); - - CSmartRewardEntry *rEntry = nullptr; - int nFirst_1_3_Round = chainparams.GetConsensus().nRewardsFirst_1_3_Round; + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - %s", tx.GetHash().ToString()); int nCurrentRound; @@ -678,233 +618,313 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CSmartRewardTransaction testTx; // First check if the transaction hash did already come up in the past. - if( GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight ){ - AddTransaction(testTx); - }else{ + if( GetTransaction(tx.GetHash(), testTx) ){ + + // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - [%s] Double appearance! First in %d - Now in %d\n", testTx.hash.ToString(), testTx.blockHeight, pIndex->nHeight); return; + + }else{ + // If not save add it to the database. + AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); } CSmartAddress *voteProofCheck = nullptr; - unsigned char cProofOption = 0; - CAmount nVoteProofIn = 0, nVoteProofOut = 0; + CAmount nVoteProofIn = 0; - if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() ){ + // No reason to check the input here for new coins. + if( !tx.IsCoinBase() ){ - const Coin &coin = coins.AccessCoin(tx.vin[0].prevout); - const CTxOut &rOut = coin.out; + BOOST_FOREACH(const CTxIn &in, tx.vin) { - std::vector ids; + if( in.scriptSig.IsZerocoinSpend() ) continue; - int required = ParseScript(rOut.scriptPubKey ,ids); + const Coin &coin = coins.AccessCoin(in.prevout); + const CTxOut &rOut = coin.out; - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process VoteProof: Could't parse CSmartAddress: %s\n",rOut.ToString()); + ProcessInput(tx, rOut, &voteProofCheck, nVoteProofIn, nCurrentRound, result); + } + } + + int nTime2 = GetTimeMicros(); + + BOOST_FOREACH(const CTxOut &out, tx.vout) { + + if(out.scriptPubKey.IsZerocoinMint() ) continue; + + ProcessOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRound, nHeight, result); + } + + int nTime3 = GetTimeMicros(); + int nTimeTx = nTime3 - nTime1; + + if( LogAcceptCategory("smartrewards-tx") ){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), nTimeTx * 0.001); + LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime2 - nTime1) * 0.001); + LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime3 - nTime2) * 0.001); + } +} + +void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) +{ + uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardEntry *rEntry; + std::vector ids; + + int required = ParseScript(in.scriptPubKey ,ids); + + if( !required || required > 1 || ids.size() > 1 ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Inputs: Could't parse CSmartAddress: %s\n", in.ToString()); + return; + } + + if(!GetCachedRewardEntry(ids.at(0),rEntry)){ + + rEntry = new CSmartRewardEntry(ids.at(0)); + + if(!ReadRewardEntry(rEntry->id, *rEntry)){ + delete rEntry; + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); return; } - nVoteProofIn = rOut.nValue; - voteProofCheck = new CSmartAddress(ids[0]); + rewardEntries.insert(make_pair(ids.at(0), rEntry)); } - BOOST_REVERSE_FOREACH(const CTxOut &out, tx.vout) { + rEntry->balance += in.nValue; - if(out.scriptPubKey.IsZerocoinMint() ) continue; + if( nCurrentRound >= nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ - std::vector ids; - int required = ParseScript(out.scriptPubKey ,ids); + rEntry->disqualifyingTx.SetNull(); - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); - continue; - }else{ + if( rEntry->IsEligible() ){ + --result.disqualifiedEntries; + result.disqualifiedSmart -= rEntry->balanceEligible; + } - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ - rEntry = new CSmartRewardEntry(ids.at(0)); - ReadRewardEntry(rEntry->id, *rEntry); - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } + }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ - if( voteProofCheck ){ + rEntry->disqualifyingTx.SetNull(); - nVoteProofOut += out.nValue; + if( rEntry->balanceEligible ){ + --result.disqualifiedEntries; + result.disqualifiedSmart -= rEntry->balanceEligible; + } - if( !out.IsVoteProofData() && - !(*voteProofCheck == rEntry->id) ){ + } - CSmartRewardEntry *vkEntry = nullptr; + if(rEntry->balance < 0 ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Negative amount?! - %s", rEntry->ToString()); + rEntry->balance = 0; + } - if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ - vkEntry = new CSmartRewardEntry(*voteProofCheck); - ReadRewardEntry(vkEntry->id, *vkEntry); - rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); - } +} - if( vkEntry->disqualifyingTx == tx.GetHash() ){ +void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) +{ + uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardEntry *rEntry; + std::vector ids; + int required = ParseScript(out.scriptPubKey ,ids); - vkEntry->disqualifyingTx.SetNull(); + if( !required || required > 1 || ids.size() > 1 ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); + return; + }else{ - if( vkEntry->IsEligible() ){ - --result.disqualifiedEntries; - result.disqualifiedSmart -= vkEntry->balanceEligible; - } - } + if(!GetCachedRewardEntry(ids.at(0),rEntry)){ + rEntry = new CSmartRewardEntry(ids.at(0)); + ReadRewardEntry(rEntry->id, *rEntry); + rewardEntries.insert(make_pair(ids.at(0), rEntry)); + } + + if( voteProofCheck ){ + + unsigned char cProofOption = 0; - }else if( !out.IsVoteProofData() && - (*voteProofCheck == rEntry->id) ){ + if( !out.IsVoteProofData() && + !(*voteProofCheck == rEntry->id) ){ - CSmartRewardEntry *proofEntry = nullptr; - unsigned char cAddressType = 0; - uint32_t nProofRound; - uint160 addressHash; - uint256 nProposalHash; // Placeholder only for now - CSmartAddress proofAddress; + CSmartRewardEntry *vkEntry = nullptr; + + if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ + vkEntry = new CSmartRewardEntry(*voteProofCheck); + ReadRewardEntry(vkEntry->id, *vkEntry); + rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); + } + + if( vkEntry->disqualifyingTx == tx.GetHash() ){ + + vkEntry->disqualifyingTx.SetNull(); + + if( vkEntry->IsEligible() ){ + --result.disqualifiedEntries; + result.disqualifiedSmart -= vkEntry->balanceEligible; + } + } - BOOST_FOREACH(const CTxOut &outData, tx.vout) { + }else if( !out.IsVoteProofData() && + (*voteProofCheck == rEntry->id) ){ - if( outData.IsVoteProofData() ){ + CSmartRewardEntry *proofEntry = nullptr; + unsigned char cAddressType = 0; + uint32_t nProofRound; + uint160 addressHash; + uint256 nProposalHash; // Placeholder only for now + CSmartAddress proofAddress; - std::vector scriptData; - scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); - CDataStream ss(scriptData, SER_NETWORK, 0); + BOOST_FOREACH(const CTxOut &outData, tx.vout) { - ss >> cProofOption; - ss >> nProofRound; - ss >> nProposalHash; + if( outData.IsVoteProofData() ){ - if( cProofOption == 0x01 && - voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ - proofAddress = *voteProofCheck; - proofEntry = rEntry; - }else if( cProofOption == 0x02 && - voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ + std::vector scriptData; + scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); + CDataStream ss(scriptData, SER_NETWORK, 0); - ss >> cAddressType; - ss >> addressHash; + ss >> cProofOption; + ss >> nProofRound; + ss >> nProposalHash; - if( cAddressType == 0x01 ){ - proofAddress = CSmartAddress(CKeyID(addressHash)); - }else if( cAddressType == 0x02){ - proofAddress = CSmartAddress(CScriptID(addressHash)); - }else{ - proofAddress = CSmartAddress(); // Invalid address type - } + if( cProofOption == 0x01 && + voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ + proofAddress = *voteProofCheck; + proofEntry = rEntry; + }else if( cProofOption == 0x02 && + voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ - if(!GetCachedRewardEntry(proofAddress, proofEntry)){ - proofEntry = new CSmartRewardEntry(proofAddress); - ReadRewardEntry(proofEntry->id, *proofEntry); - rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); - } + ss >> cAddressType; + ss >> addressHash; + if( cAddressType == 0x01 ){ + proofAddress = CSmartAddress(CKeyID(addressHash)); + }else if( cAddressType == 0x02){ + proofAddress = CSmartAddress(CScriptID(addressHash)); }else{ - proofAddress = CSmartAddress(); // Invalid option + proofAddress = CSmartAddress(); // Invalid address type + } + + if(!GetCachedRewardEntry(proofAddress, proofEntry)){ + proofEntry = new CSmartRewardEntry(proofAddress); + ReadRewardEntry(proofEntry->id, *proofEntry); + rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); } + + }else{ + proofAddress = CSmartAddress(); // Invalid option } } + } - if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - - if( proofEntry->voteProof == tx.GetHash() ){ + if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - proofEntry->voteProof.SetNull(); + if( proofEntry->voteProof == tx.GetHash() ){ - --result.qualifiedEntries; - result.qualifiedSmart -= proofEntry->balanceEligible; + proofEntry->voteProof.SetNull(); - if( cProofOption == 0x01 ){ - proofEntry->balanceEligible += nVoteProofIn - nVoteProofOut; - } + --result.qualifiedEntries; + result.qualifiedSmart -= proofEntry->balanceEligible; + if( cProofOption == 0x01 ){ + proofEntry->balanceEligible += nVoteProofIn - tx.GetValueOut(); } + } } - - delete voteProofCheck; } - rEntry->balance -= out.nValue; + delete voteProofCheck; + } - // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists - if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ + rEntry->balance -= out.nValue; - if( rEntry->smartnodePaymentTx == tx.GetHash() ){ + // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists + if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ - rEntry->smartnodePaymentTx.SetNull(); + if( rEntry->smartnodePaymentTx == tx.GetHash() ){ - // If it is eligible now adjust the round's results - if( rEntry->IsEligible() ){ - --result.disqualifiedEntries; - result.disqualifiedSmart -= rEntry->balanceEligible; - } + rEntry->smartnodePaymentTx.SetNull(); + + // If it is eligible now adjust the round's results + if( rEntry->IsEligible() ){ + --result.disqualifiedEntries; + result.disqualifiedSmart -= rEntry->balanceEligible; } } } } +} - int nTime2 = GetTimeMicros(); +void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) +{ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - %s", tx.GetHash().ToString()); - // No reason to check the input here for new coins. - if( !tx.IsCoinBase() ){ + int nFirst_1_3_Round = chainparams.GetConsensus().nRewardsFirst_1_3_Round; - BOOST_REVERSE_FOREACH(const CTxIn &in, tx.vin) { + int nCurrentRound; - if( in.scriptSig.IsZerocoinSpend() ) continue; + { + LOCK(cs_rewardrounds); + nCurrentRound = currentRound.number; + } - const Coin &coin = coins.AccessCoin(in.prevout); - const CTxOut &rOut = coin.out; + int nHeight = pIndex->nHeight; - std::vector ids; + if(nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + return; + } - int required = ParseScript(rOut.scriptPubKey ,ids); + int nTime1 = GetTimeMicros(); - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Inputs: Could't parse CSmartAddress: %s\n",rOut.ToString()); - continue; - } + CSmartRewardTransaction testTx; - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ + // First check if the transaction hash did already come up in the past. + if( GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight ){ + AddTransaction(testTx); + }else{ + return; + } - rEntry = new CSmartRewardEntry(ids.at(0)); + CSmartAddress *voteProofCheck = nullptr; + CAmount nVoteProofIn = 0; - if(!ReadRewardEntry(rEntry->id, *rEntry)){ - delete rEntry; - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); - continue; - } + if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() ){ - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } + const Coin &coin = coins.AccessCoin(tx.vin[0].prevout); + const CTxOut &rOut = coin.out; - rEntry->balance += rOut.nValue; + std::vector ids; - // If its a voteproof transaction not instantly make the - // balance ineligible. First check if the change is sent back - // to the address or not to avoid exploiting fund sending - // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && voteProofCheck == nullptr && rEntry->disqualifyingTx == tx.GetHash() ){ + int required = ParseScript(rOut.scriptPubKey ,ids); - rEntry->disqualifyingTx.SetNull(); + if( !required || required > 1 || ids.size() > 1 ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process VoteProof: Could't parse CSmartAddress: %s\n",rOut.ToString()); + return; + } - if( rEntry->IsEligible() ){ - --result.disqualifiedEntries; - result.disqualifiedSmart -= rEntry->balanceEligible; - } + nVoteProofIn = rOut.nValue; + voteProofCheck = new CSmartAddress(ids[0]); + } - }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ + BOOST_REVERSE_FOREACH(const CTxOut &out, tx.vout) { - rEntry->disqualifyingTx.SetNull(); + if(out.scriptPubKey.IsZerocoinMint() ) continue; - if( rEntry->balanceEligible ){ - --result.disqualifiedEntries; - result.disqualifiedSmart -= rEntry->balanceEligible; - } + UndoOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRound, result); + } - } + int nTime2 = GetTimeMicros(); - if(rEntry->balance < 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Negative amount?! - %s", rEntry->ToString()); - rEntry->balance = 0; - } + // No reason to check the input here for new coins. + if( !tx.IsCoinBase() ){ + + BOOST_REVERSE_FOREACH(const CTxIn &in, tx.vin) { + + if( in.scriptSig.IsZerocoinSpend() ) continue; + + const Coin &coin = coins.AccessCoin(in.prevout); + const CTxOut &rOut = coin.out; + UndoInput(tx, rOut, nCurrentRound, result); } } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 218dcfd5..50ecaa71 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -13,8 +13,7 @@ using namespace std; static const CAmount SMART_REWARDS_MIN_BALANCE = 1000 * COIN; -// Cache max. n prepared entries before the sync (leveldb batch write). -const int64_t nCacheEntires = 8000; + // Minimum distance of the last processed block compared to the current chain // height to assume the rewards are synced. const int64_t nRewardsSyncDistance = 150; @@ -118,6 +117,12 @@ class CSmartRewards bool GetRewardRoundResults(const int16_t round, CSmartRewardRoundResultList &results); bool GetRewardPayouts(const int16_t round, CSmartRewardRoundResultList &payouts); bool GetRewardPayouts(const int16_t round, CSmartRewardRoundResultPtrList &payouts); +private: + void ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + void ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result); + + void UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + void UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); }; /** Global variable that points to the active rewards object (protected by cs_main) */ From 10ed08ff1c8750ad3039a0273acb6bceccc692a1 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 19 Sep 2019 15:52:22 +0200 Subject: [PATCH 003/126] smartrewards: WIP, Use cache and bind disk writes to index/block writes --- src/init.cpp | 7 +- src/qt/smartrewardslist.cpp | 48 +- src/qt/smartvoting.cpp | 4 +- src/qt/specialtransactiondialog.cpp | 23 +- src/rpc/smartrewards.cpp | 132 ++--- src/sapi/sapi_smartrewards.cpp | 100 ++-- src/smartrewards/rewards.cpp | 751 +++++++++++++++------------ src/smartrewards/rewards.h | 100 +++- src/smartrewards/rewardsdb.cpp | 115 ++-- src/smartrewards/rewardsdb.h | 54 +- src/smartrewards/rewardspayments.cpp | 136 +---- src/smartrewards/rewardspayments.h | 6 +- src/validation.cpp | 11 +- 13 files changed, 754 insertions(+), 733 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f4b7579b..2cc6d746 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1801,7 +1801,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if( !(fLoaded = prewards->Verify()) ) throw std::runtime_error(_("Failed to verify SmartRewards database.")); - if( pLastIndex != NULL && !(fLoaded = (prewards->GetLastHeight() <= pLastIndex->nHeight)) ) throw std::runtime_error(_("SmartRewards database exceeds current chain height.")); +// if( pLastIndex && prewards->GetLastHeight() <= pLastIndex->nHeight){ +// prewards->RollBack(pLastIndex); +// }else if( pLastIndex && prewards->GetLastHeight() > pLastIndex->nHeight ){ +// prewards->CatchUp(pLastIndex); +// } +// if( pLastIndex != NULL && !(fLoaded = (prewards->GetLastHeight() <= pLastIndex->nHeight)) ) throw std::runtime_error(_("SmartRewards database exceeds current chain height.")); if (fRequestShutdown) break; diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 3304b72b..0137e472 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -257,27 +257,27 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if (!(sAddress == sWalletAddress)){ // change address QSmartRewardField change; - CSmartRewardEntry reward; + CSmartRewardEntry *reward = nullptr; change.address = sAddress; change.label = tr("(change)"); change.balance = out.tx->vout[out.i].nValue; - if( prewards->GetRewardEntry(CSmartAddress(sAddress.toStdString()),reward) ){ - change.balance = reward.balance; - change.fIsSmartNode = !reward.smartnodePaymentTx.IsNull(); - change.balanceAtStart = reward.balanceAtStart; - change.disqualifyingTx = reward.disqualifyingTx; + if( prewards->GetRewardEntry(CSmartAddress(sAddress.toStdString()),reward, false) ){ + change.balance = reward->balance; + change.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); + change.balanceAtStart = reward->balanceAtStart; + change.disqualifyingTx = reward->disqualifyingTx; if( currentRound.number < nFirst_1_3_Round ){ - change.eligible = reward.balanceEligible && reward.disqualifyingTx.IsNull() ? reward.balanceEligible : 0; + change.eligible = reward->balanceEligible && reward->disqualifyingTx.IsNull() ? reward->balanceEligible : 0; }else{ - change.eligible = reward.IsEligible() ? reward.balanceEligible : 0; + change.eligible = reward->IsEligible() ? reward->balanceEligible : 0; } change.reward = currentRound.percent * change.eligible; - if( reward.id.GetKeyID(keyId) ){ + if( reward->id.GetKeyID(keyId) ){ LOCK2(cs_main, pwalletMain->cs_wallet); @@ -290,7 +290,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c CTransaction tx; uint256 nBlockHash; - if( !reward.voteProof.IsNull() ){ + if( !reward->voteProof.IsNull() ){ change.nVoteProofConfirmations = Params().GetConsensus().nRewardsConfirmationsRequired; }else if(!GetTransaction(proofHash, tx, Params().GetConsensus(), nBlockHash, true)){ change.nVoteProofConfirmations = -1; @@ -312,7 +312,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end() && pwalletMain->mapVoteProofs[keyId].find(currentRound.number) == pwalletMain->mapVoteProofs[keyId].end() && - reward.balanceEligible && reward.disqualifyingTx.IsNull() && reward.smartnodePaymentTx.IsNull() ){ + reward->balanceEligible && reward->disqualifyingTx.IsNull() && reward->smartnodePaymentTx.IsNull() ){ ++nAvailableForProof; } @@ -337,23 +337,23 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( !rewardField.address.isEmpty() ){ - CSmartRewardEntry reward; + CSmartRewardEntry *reward = nullptr; - if( prewards->GetRewardEntry(CSmartAddress(rewardField.address.toStdString()),reward) ){ - rewardField.balance = reward.balance; - rewardField.fIsSmartNode = !reward.smartnodePaymentTx.IsNull(); - rewardField.balanceAtStart = reward.balanceAtStart; - rewardField.disqualifyingTx = reward.disqualifyingTx; + if( prewards->GetRewardEntry(CSmartAddress(rewardField.address.toStdString()),reward, false) ){ + rewardField.balance = reward->balance; + rewardField.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); + rewardField.balanceAtStart = reward->balanceAtStart; + rewardField.disqualifyingTx = reward->disqualifyingTx; if( currentRound.number < nFirst_1_3_Round ){ - rewardField.eligible = reward.balanceEligible && reward.disqualifyingTx.IsNull() ? reward.balanceEligible : 0; + rewardField.eligible = reward->balanceEligible && reward->disqualifyingTx.IsNull() ? reward->balanceEligible : 0; }else{ - rewardField.eligible = reward.IsEligible() ? reward.balanceEligible : 0; + rewardField.eligible = reward->IsEligible() ? reward->balanceEligible : 0; } rewardField.reward = currentRound.percent * rewardField.eligible; - if( reward.id.GetKeyID(keyId) ){ + if( reward->id.GetKeyID(keyId) ){ LOCK2(cs_main, pwalletMain->cs_wallet); @@ -366,7 +366,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c CTransaction tx; uint256 nBlockHash; - if( !reward.voteProof.IsNull() ){ + if( !reward->voteProof.IsNull() ){ rewardField.nVoteProofConfirmations = Params().GetConsensus().nRewardsConfirmationsRequired; }else if(!GetTransaction(proofHash, tx, Params().GetConsensus(), nBlockHash, true)){ rewardField.nVoteProofConfirmations = -1; @@ -388,7 +388,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end() && pwalletMain->mapVoteProofs[keyId].find(currentRound.number) == pwalletMain->mapVoteProofs[keyId].end() && - reward.balanceEligible && reward.disqualifyingTx.IsNull() && reward.smartnodePaymentTx.IsNull() ){ + reward->balanceEligible && reward->disqualifyingTx.IsNull() && reward->smartnodePaymentTx.IsNull() ){ ++nAvailableForProof; } @@ -533,8 +533,8 @@ void SmartrewardsList::updateUI() CSmartRewardRound currentRound; CBlockIndex* tip = nullptr; { - LOCK(cs_rewardrounds); - currentRound = prewards->GetCurrentRound(); + LOCK(cs_rewardscache); + currentRound = *prewards->GetCurrentRound(); tip = chainActive.Tip(); } diff --git a/src/qt/smartvoting.cpp b/src/qt/smartvoting.cpp index 202ffd57..e429846d 100755 --- a/src/qt/smartvoting.cpp +++ b/src/qt/smartvoting.cpp @@ -259,7 +259,9 @@ void SmartVotingPage::voteDone(QString &address, int nProposalId, bool successfu if(CSmartAddress(address.toStdString()).GetKeyID(keyId)){ - int nCurrentRound = prewards->GetCurrentRound().number; + LOCK(cs_rewardscache); + + int nCurrentRound = prewards->GetCurrentRound()->number; if( !pwalletMain->mapVoted[keyId].count(nCurrentRound) ){ pwalletMain->mapVoted[keyId].insert(std::make_pair(nCurrentRound, nProposalHash)); diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index ddfab79e..090266aa 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -380,9 +380,13 @@ void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) case REGISTRATION_TRANSACTIONS: fSuccess = SendRegistration(it.first, it.second, strError); break; - case VOTE_PROOF_TRANSACTIONS: - fSuccess = SendVoteProof(it.first, it.second, prewards->GetCurrentRound().number, strError); - break; + case VOTE_PROOF_TRANSACTIONS:{ + + LOCK(cs_rewardscache); + int nCurrentRound = prewards->GetCurrentRound()->number; + + fSuccess = SendVoteProof(it.first, it.second, nCurrentRound, strError); + }break; } if( !fSuccess ){ @@ -848,17 +852,22 @@ void SpecialTransactionDialog::updateView() if( type == VOTE_PROOF_TRANSACTIONS ){ CKeyID keyId; CSmartAddress voteAddress(sWalletAddress.toStdString()); - int nCurrentRound = prewards->GetCurrentRound().number; + int nCurrentRound = 0; + + { + LOCK(cs_rewardscache); + nCurrentRound = prewards->GetCurrentRound()->number; + } - CSmartRewardEntry reward; + CSmartRewardEntry *reward = nullptr; - if( voteAddress.GetKeyID(keyId) && prewards->GetRewardEntry(voteAddress, reward) ){ + if( voteAddress.GetKeyID(keyId) && prewards->GetRewardEntry(voteAddress, reward, false) ){ LOCK(pwalletMain->cs_wallet); if( pwalletMain->mapVoted[keyId].find(nCurrentRound) == pwalletMain->mapVoted[keyId].end() || pwalletMain->mapVoteProofs[keyId].find(nCurrentRound) != pwalletMain->mapVoteProofs[keyId].end() || - reward.balanceEligible == 0 || !reward.disqualifyingTx.IsNull() || !reward.smartnodePaymentTx.IsNull() ){ + reward->balanceEligible == 0 || !reward->disqualifyingTx.IsNull() || !reward->smartnodePaymentTx.IsNull() ){ // If not yet voted, no eligible balance or already vote proven skip it. continue; } diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index ba656bd6..aa16b32d 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -59,25 +59,25 @@ UniValue smartrewards(const UniValue& params, bool fHelp) { UniValue obj(UniValue::VOBJ); - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache, cacheLocked); - if(!roundsLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); + if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRound& current = prewards->GetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); - if( !current.number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); + if( !current->number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); - obj.pushKV("rewards_cycle",current.number); - obj.pushKV("start_blockheight",current.startBlockHeight); - obj.pushKV("start_blocktime",current.startBlockTime); - obj.pushKV("end_blockheight",current.endBlockHeight); - obj.pushKV("end_blocktime",current.endBlockTime); - obj.pushKV("eligible_addresses",current.eligibleEntries - current.disqualifiedEntries); - obj.pushKV("eligible_smart",format(current.eligibleSmart - current.disqualifiedSmart)); - obj.pushKV("disqualified_addresses",current.disqualifiedEntries); - obj.pushKV("disqualified_smart",format(current.disqualifiedSmart)); - obj.pushKV("estimated_rewards",format(current.rewards)); - obj.pushKV("estimated_percent",current.percent); + obj.pushKV("rewards_cycle",current->number); + obj.pushKV("start_blockheight",current->startBlockHeight); + obj.pushKV("start_blocktime",current->startBlockTime); + obj.pushKV("end_blockheight",current->endBlockHeight); + obj.pushKV("end_blocktime",current->endBlockTime); + obj.pushKV("eligible_addresses",current->eligibleEntries - current->disqualifiedEntries); + obj.pushKV("eligible_smart",format(current->eligibleSmart - current->disqualifiedSmart)); + obj.pushKV("disqualified_addresses",current->disqualifiedEntries); + obj.pushKV("disqualified_smart",format(current->disqualifiedSmart)); + obj.pushKV("estimated_rewards",format(current->rewards)); + obj.pushKV("estimated_percent",current->percent); return obj; } @@ -86,51 +86,53 @@ UniValue smartrewards(const UniValue& params, bool fHelp) { UniValue obj(UniValue::VARR); - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache, cacheLocked); - if(!roundsLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); + if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRoundList& history = prewards->GetRewardRounds(); + const CSmartRewardRoundList* history = prewards->GetRewardRounds(); int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; - if(!history.size()) throw JSONRPCError(RPC_DATABASE_ERROR, "No finished reward round available yet."); + if(!history->size()) throw JSONRPCError(RPC_DATABASE_ERROR, "No finished reward round available yet."); - BOOST_FOREACH(CSmartRewardRound round, history) { + auto round = history->begin(); + + while( round != history->end() ){ UniValue roundObj(UniValue::VOBJ); - roundObj.pushKV("rewards_cycle",round.number); - roundObj.pushKV("start_blockheight",round.startBlockHeight); - roundObj.pushKV("start_blocktime",round.startBlockTime); - roundObj.pushKV("end_blockheight",round.endBlockHeight); - roundObj.pushKV("end_blocktime",round.endBlockTime); - roundObj.pushKV("eligible_addresses",round.eligibleEntries - round.disqualifiedEntries); - roundObj.pushKV("eligible_smart",format(round.eligibleSmart - round.disqualifiedSmart)); - roundObj.pushKV("disqualified_addresses",round.disqualifiedEntries); - roundObj.pushKV("disqualified_smart",format(round.disqualifiedSmart)); - roundObj.pushKV("rewards",format(round.rewards)); - roundObj.pushKV("percent",round.percent); + roundObj.pushKV("rewards_cycle",round->number); + roundObj.pushKV("start_blockheight",round->startBlockHeight); + roundObj.pushKV("start_blocktime",round->startBlockTime); + roundObj.pushKV("end_blockheight",round->endBlockHeight); + roundObj.pushKV("end_blocktime",round->endBlockTime); + roundObj.pushKV("eligible_addresses",round->eligibleEntries - round->disqualifiedEntries); + roundObj.pushKV("eligible_smart",format(round->eligibleSmart - round->disqualifiedSmart)); + roundObj.pushKV("disqualified_addresses",round->disqualifiedEntries); + roundObj.pushKV("disqualified_smart",format(round->disqualifiedSmart)); + roundObj.pushKV("rewards",format(round->rewards)); + roundObj.pushKV("percent",round->percent); UniValue payObj(UniValue::VOBJ); - int nPayeeCount = round.eligibleEntries - round.disqualifiedEntries; + int nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; if( nPayeeCount ){ - int nBlockPayees = round.nBlockPayees; - int nPayoutInterval = round.nBlockInterval; + int nBlockPayees = round->nBlockPayees; + int nPayoutInterval = round->nBlockInterval; int nRewardBlocks = nPayeeCount / nBlockPayees; if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; - int nLastRoundBlock = round.endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); + int nLastRoundBlock = round->endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); - payObj.pushKV("firstBlock", round.endBlockHeight + nPayoutDelay ); + payObj.pushKV("firstBlock", round->endBlockHeight + nPayoutDelay ); payObj.pushKV("totalBlocks", nRewardBlocks ); payObj.pushKV("lastBlock", nLastRoundBlock ); payObj.pushKV("totalPayees", nPayeeCount); - payObj.pushKV("blockPayees", round.nBlockPayees); + payObj.pushKV("blockPayees", round->nBlockPayees); payObj.pushKV("lastBlockPayees", nPayeeCount % nBlockPayees ); - payObj.pushKV("blockInterval",round.nBlockInterval); + payObj.pushKV("blockInterval",round->nBlockInterval); }else{ payObj.pushKV("error", "No payees were eligible for this round"); } @@ -138,6 +140,8 @@ UniValue smartrewards(const UniValue& params, bool fHelp) roundObj.pushKV("payouts", payObj); obj.push_back(roundObj); + + ++round; } return obj; @@ -145,16 +149,16 @@ UniValue smartrewards(const UniValue& params, bool fHelp) if(strCommand == "payouts") { - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache, cacheLocked); - if(!roundsLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); + if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRound& current = prewards->GetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); - if( !current.number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); + if( !current->number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); int round = 0; - std::string err = strprintf("Past SmartReward round required: 1 - %d ",current.number - 1 ); + std::string err = strprintf("Past SmartReward round required: 1 - %d ",current->number - 1 ); if (params.size() != 2) throw JSONRPCError(RPC_INVALID_PARAMETER, err); @@ -170,16 +174,16 @@ UniValue smartrewards(const UniValue& params, bool fHelp) } catch (...) {} - if(round < 1 || round >= current.number) throw JSONRPCError(RPC_INVALID_PARAMETER, err); + if(round < 1 || round >= current->number) throw JSONRPCError(RPC_INVALID_PARAMETER, err); - CSmartRewardRoundResultList payouts; + CSmartRewardResultEntryList payouts; if( !prewards->GetRewardPayouts(round,payouts) ) throw JSONRPCError(RPC_DATABASE_ERROR, "Couldn't fetch the list from the database."); UniValue obj(UniValue::VARR); - BOOST_FOREACH(CSmartRewardRoundResult payout, payouts) { + BOOST_FOREACH(CSmartRewardResultEntry payout, payouts) { UniValue addrObj(UniValue::VOBJ); addrObj.pushKV("address", payout.entry.id.ToString()); @@ -193,16 +197,16 @@ UniValue smartrewards(const UniValue& params, bool fHelp) if(strCommand == "snapshot") { - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache, cacheLocked); - if(!roundsLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); + if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRound& current = prewards->GetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); - if( !current.number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); + if( !current->number ) throw JSONRPCError(RPC_DATABASE_ERROR, "No active reward round available yet."); int round = 0; - std::string err = strprintf("Past SmartReward round required: 1 - %d ",current.number - 1 ); + std::string err = strprintf("Past SmartReward round required: 1 - %d ",current->number - 1 ); if (params.size() != 2) throw JSONRPCError(RPC_INVALID_PARAMETER, err); @@ -218,16 +222,16 @@ UniValue smartrewards(const UniValue& params, bool fHelp) } catch (...) {} - if(round < 1 || round >= current.number) throw JSONRPCError(RPC_INVALID_PARAMETER, err); + if(round < 1 || round >= current->number) throw JSONRPCError(RPC_INVALID_PARAMETER, err); - CSmartRewardRoundResultList results; + CSmartRewardResultEntryList results; if( !prewards->GetRewardRoundResults(round, results) ) throw JSONRPCError(RPC_DATABASE_ERROR, "Couldn't fetch the list from the database."); UniValue obj(UniValue::VARR); - BOOST_FOREACH(CSmartRewardRoundResult s, results) { + BOOST_FOREACH(CSmartRewardResultEntry s, results) { UniValue addrObj(UniValue::VOBJ); addrObj.pushKV("address", s.entry.id.ToString()); @@ -243,11 +247,11 @@ UniValue smartrewards(const UniValue& params, bool fHelp) { if (params.size() != 2) throw JSONRPCError(RPC_INVALID_PARAMETER, "SmartCash address required."); - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache, cacheLocked); - if(!roundsLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); + if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRound& current = prewards->GetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; @@ -256,18 +260,18 @@ UniValue smartrewards(const UniValue& params, bool fHelp) if( !id.IsValid() ) throw JSONRPCError(RPC_DATABASE_ERROR, strprintf("Invalid SmartCash address provided: %s",addressString)); - CSmartRewardEntry entry; + CSmartRewardEntry *entry = nullptr; - if( !prewards->GetRewardEntry(id, entry) ) throw JSONRPCError(RPC_DATABASE_ERROR, "Couldn't find this SmartCash address in the database."); + if( !prewards->GetRewardEntry(id, entry, false) ) throw JSONRPCError(RPC_DATABASE_ERROR, "Couldn't find this SmartCash address in the database."); UniValue obj(UniValue::VOBJ); obj.pushKV("address",id.ToString()); - obj.pushKV("balance",format(entry.balance)); - obj.pushKV("balance_eligible", format(entry.balanceEligible)); - obj.pushKV("is_smartnode", !entry.smartnodePaymentTx.IsNull()); - obj.pushKV("voted", !entry.voteProof.IsNull()); - obj.pushKV("eligible", current.number < nFirst_1_3_Round ? entry.balanceEligible > 0 : entry.IsEligible()); + obj.pushKV("balance",format(entry->balance)); + obj.pushKV("balance_eligible", format(entry->balanceEligible)); + obj.pushKV("is_smartnode", !entry->smartnodePaymentTx.IsNull()); + obj.pushKV("voted", !entry->voteProof.IsNull()); + obj.pushKV("eligible", current->number < nFirst_1_3_Round ? entry->balanceEligible > 0 : entry->IsEligible()); return obj; } diff --git a/src/sapi/sapi_smartrewards.cpp b/src/sapi/sapi_smartrewards.cpp index 03cd3497..2c674ec8 100644 --- a/src/sapi/sapi_smartrewards.cpp +++ b/src/sapi/sapi_smartrewards.cpp @@ -57,11 +57,11 @@ static bool CheckAddresses(HTTPRequest* req, std::vector vecAddr, s vecResults.clear(); - TRY_LOCK(cs_rewardrounds,roundsLocked); + TRY_LOCK(cs_rewardscache,cacheLocked); - if(!roundsLocked) return SAPI::Error(req, SAPI::RewardsDatabaseBusy, "Rewards database is busy..Try it again!"); + if(!cacheLocked) return SAPI::Error(req, SAPI::RewardsDatabaseBusy, "Rewards database is busy..Try it again!"); - const CSmartRewardRound& current = prewards->GetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; @@ -76,9 +76,9 @@ static bool CheckAddresses(HTTPRequest* req, std::vector vecAddr, s continue; } - CSmartRewardEntry entry; + CSmartRewardEntry *entry = nullptr; - if( !prewards->GetRewardEntry(id, entry) ){ + if( !prewards->GetRewardEntry(id, entry, false) ){ code = SAPI::AddressNotFound; std::string message = "Couldn't find this SmartCash address in the database."; errors.push_back(SAPI::Result(code, message)); @@ -88,11 +88,11 @@ static bool CheckAddresses(HTTPRequest* req, std::vector vecAddr, s UniValue obj(UniValue::VOBJ); obj.pushKV("address",id.ToString()); - obj.pushKV("balance",UniValueFromAmount(entry.balance)); - obj.pushKV("balance_eligible", UniValueFromAmount(entry.balanceEligible)); - obj.pushKV("is_smartnode", !entry.smartnodePaymentTx.IsNull()); - obj.pushKV("voted", !entry.voteProof.IsNull()); - obj.pushKV("eligible", current.number < nFirst_1_3_Round ? entry.balanceEligible > 0 : entry.IsEligible()); + obj.pushKV("balance",UniValueFromAmount(entry->balance)); + obj.pushKV("balance_eligible", UniValueFromAmount(entry->balanceEligible)); + obj.pushKV("is_smartnode", !entry->smartnodePaymentTx.IsNull()); + obj.pushKV("voted", !entry->voteProof.IsNull()); + obj.pushKV("eligible", current->number < nFirst_1_3_Round ? entry->balanceEligible > 0 : entry->IsEligible()); vecResults.push_back(obj); } @@ -112,25 +112,25 @@ static bool smartrewards_current(HTTPRequest* req, const std::mapGetCurrentRound(); + const CSmartRewardRound *current = prewards->GetCurrentRound(); - if( !current.number ) return SAPI::Error(req, SAPI::NoActiveRewardRound, "No active reward round available yet."); + if( !current->number ) return SAPI::Error(req, SAPI::NoActiveRewardRound, "No active reward round available yet."); - obj.pushKV("rewards_cycle",current.number); - obj.pushKV("start_blockheight",current.startBlockHeight); - obj.pushKV("start_blocktime",current.startBlockTime); - obj.pushKV("end_blockheight",current.endBlockHeight); - obj.pushKV("end_blocktime",current.endBlockTime); - obj.pushKV("eligible_addresses",current.eligibleEntries - current.disqualifiedEntries); - obj.pushKV("eligible_smart",UniValueFromAmount(current.eligibleSmart - current.disqualifiedSmart)); - obj.pushKV("disqualified_addresses",current.disqualifiedEntries); - obj.pushKV("disqualified_smart",UniValueFromAmount(current.disqualifiedSmart)); - obj.pushKV("estimated_rewards",UniValueFromAmount(current.rewards)); - obj.pushKV("estimated_percent",current.percent); + obj.pushKV("rewards_cycle",current->number); + obj.pushKV("start_blockheight",current->startBlockHeight); + obj.pushKV("start_blocktime",current->startBlockTime); + obj.pushKV("end_blockheight",current->endBlockHeight); + obj.pushKV("end_blocktime",current->endBlockTime); + obj.pushKV("eligible_addresses",current->eligibleEntries - current->disqualifiedEntries); + obj.pushKV("eligible_smart",UniValueFromAmount(current->eligibleSmart - current->disqualifiedSmart)); + obj.pushKV("disqualified_addresses",current->disqualifiedEntries); + obj.pushKV("disqualified_smart",UniValueFromAmount(current->disqualifiedSmart)); + obj.pushKV("estimated_rewards",UniValueFromAmount(current->rewards)); + obj.pushKV("estimated_percent",current->percent); SAPI::WriteReply(req, obj); @@ -142,52 +142,56 @@ static bool smartrewards_history(HTTPRequest* req, const std::mapGetRewardRounds(); + const CSmartRewardRoundList* history = prewards->GetRewardRounds(); int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; - if(!history.size()) return SAPI::Error(req, SAPI::NoFinishedRewardRound, "No finished reward round available yet."); + if(!history->size()) return SAPI::Error(req, SAPI::NoFinishedRewardRound, "No finished reward round available yet."); - BOOST_FOREACH(CSmartRewardRound round, history) { + auto round = history->begin(); + + while( round != history->end() ){ UniValue roundObj(UniValue::VOBJ); - roundObj.pushKV("rewards_cycle",round.number); - roundObj.pushKV("start_blockheight",round.startBlockHeight); - roundObj.pushKV("start_blocktime",round.startBlockTime); - roundObj.pushKV("end_blockheight",round.endBlockHeight); - roundObj.pushKV("end_blocktime",round.endBlockTime); - roundObj.pushKV("eligible_addresses",round.eligibleEntries - round.disqualifiedEntries); - roundObj.pushKV("eligible_smart",UniValueFromAmount(round.eligibleSmart - round.disqualifiedSmart)); - roundObj.pushKV("disqualified_addresses",round.disqualifiedEntries); - roundObj.pushKV("disqualified_smart",UniValueFromAmount(round.disqualifiedSmart)); - roundObj.pushKV("rewards",UniValueFromAmount(round.rewards)); - roundObj.pushKV("percent",round.percent); + roundObj.pushKV("rewards_cycle",round->number); + roundObj.pushKV("start_blockheight",round->startBlockHeight); + roundObj.pushKV("start_blocktime",round->startBlockTime); + roundObj.pushKV("end_blockheight",round->endBlockHeight); + roundObj.pushKV("end_blocktime",round->endBlockTime); + roundObj.pushKV("eligible_addresses",round->eligibleEntries - round->disqualifiedEntries); + roundObj.pushKV("eligible_smart",UniValueFromAmount(round->eligibleSmart - round->disqualifiedSmart)); + roundObj.pushKV("disqualified_addresses",round->disqualifiedEntries); + roundObj.pushKV("disqualified_smart",UniValueFromAmount(round->disqualifiedSmart)); + roundObj.pushKV("rewards",UniValueFromAmount(round->rewards)); + roundObj.pushKV("percent",round->percent); UniValue payObj(UniValue::VOBJ); - int nPayeeCount = round.eligibleEntries - round.disqualifiedEntries; - int nBlockPayees = round.nBlockPayees; - int nPayoutInterval = round.nBlockInterval; + int nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; + int nBlockPayees = round->nBlockPayees; + int nPayoutInterval = round->nBlockInterval; int nRewardBlocks = nPayeeCount / nBlockPayees; if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; - int nLastRoundBlock = round.endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); + int nLastRoundBlock = round->endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); - payObj.pushKV("firstBlock", round.endBlockHeight + nPayoutDelay ); + payObj.pushKV("firstBlock", round->endBlockHeight + nPayoutDelay ); payObj.pushKV("totalBlocks", nRewardBlocks ); payObj.pushKV("lastBlock", nLastRoundBlock ); payObj.pushKV("totalPayees", nPayeeCount); - payObj.pushKV("blockPayees", round.nBlockPayees); + payObj.pushKV("blockPayees", round->nBlockPayees); payObj.pushKV("lastBlockPayees", nPayeeCount % nBlockPayees ); - payObj.pushKV("blockInterval",round.nBlockInterval); + payObj.pushKV("blockInterval",round->nBlockInterval); roundObj.pushKV("payouts", payObj); obj.push_back(roundObj); + + ++round; } SAPI::WriteReply(req, obj); diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 96094820..f7ebead3 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -9,6 +9,7 @@ #include "smarthive/hive.h" #include "smartnode/spork.h" #include "smartnode/smartnodepayments.h" +#include "rewards.h" #include "ui_interface.h" #include "validation.h" @@ -16,14 +17,34 @@ #include #include +#define REWARDS_MAX_CACHE 400000000UL // 400MB + CSmartRewards *prewards = NULL; CCriticalSection cs_rewardsdb; -CCriticalSection cs_rewardrounds; +CCriticalSection cs_rewardscache; // Used for time conversions. boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); +struct CompareRewardScore +{ + bool operator()(const std::pair& s1, + const std::pair& s2) const + { + return (s1.first != s2.first) ? (s1.first < s2.first) : (s1.second->entry.balance < s2.second->entry.balance); + } +}; + +struct ComparePaymentPrtList +{ + bool operator()(const CSmartRewardResultEntry* p1, + const CSmartRewardResultEntry* p2) const + { + return *p1 < *p2; + } +}; + // Estimate or return the current block height. int GetBlockHeight(const CBlockIndex *index) { @@ -52,115 +73,176 @@ int ParseScript(const CScript &script, std::vector &ids){ return nRequired; } -void CalculateRewardRatio(CSmartRewardRound &round) +void CalculateRewardRatio() { - int64_t time = GetTime(); - int64_t start = round.startBlockHeight; - round.rewards = 0; - - while( start <= round.endBlockHeight) round.rewards += GetBlockValue(start++,0,time) * 0.15; - - CAmount nCalcSmart = round.eligibleSmart - round.disqualifiedSmart; - if( nCalcSmart ){ - round.percent = double(round.rewards) / nCalcSmart; - }else{ - round.percent = 0; - } } bool CSmartRewards::Verify() { LOCK(cs_rewardsdb); - return pdb->Verify(rewardHeight); + int nHeight = cache.GetCurrentBlock()->nHeight; + return pdb->Verify(nHeight); } +bool CSmartRewards::NeedsCacheWrite() +{ + return cache.NeedsSync(); +} -void CSmartRewards::UpdatePayoutParameter(CSmartRewardRound &round) +void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result) { + AssertLockHeld(cs_rewardscache); - int64_t nPayeeCount = round.eligibleEntries - round.disqualifiedEntries; + const CSmartRewardRound *round = cache.GetCurrentRound(); + int64_t nBlockPayees = round->nBlockPayees, nBlockInterval = nBlockInterval; + + int64_t nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - if( round.number < nFirst_1_3_Round ){ - round.nBlockPayees = Params().GetConsensus().nRewardsPayouts_1_2_BlockPayees; - round.nBlockInterval = Params().GetConsensus().nRewardsPayouts_1_2_BlockInterval; + if( round->number < nFirst_1_3_Round ){ + nBlockPayees = Params().GetConsensus().nRewardsPayouts_1_2_BlockPayees; + nBlockInterval = Params().GetConsensus().nRewardsPayouts_1_2_BlockInterval; }else if( nPayeeCount ){ int64_t nBlockStretch = Params().GetConsensus().nRewardsPayouts_1_3_BlockStretch; int64_t nBlocksPerRound = Params().GetConsensus().nRewardsBlocksPerRound_1_3; - int64_t nBlockPayees = Params().GetConsensus().nRewardsPayouts_1_3_BlockPayees; + int64_t nTempBlockPayees = Params().GetConsensus().nRewardsPayouts_1_3_BlockPayees; - round.nBlockPayees = std::max(nBlockPayees, (nPayeeCount / nBlockStretch * nBlockPayees) + 1); + nBlockPayees = std::max(nTempBlockPayees, (nPayeeCount / nBlockStretch * nTempBlockPayees) + 1); - if( nPayeeCount > round.nBlockPayees ){ + if( nPayeeCount > nBlockPayees ){ int64_t nStartDelayBlocks = Params().GetConsensus().nRewardsPayoutStartDelay; int64_t nBlocksTarget = nStartDelayBlocks + nBlocksPerRound; - round.nBlockInterval = ((nBlockStretch * round.nBlockPayees) / nPayeeCount) + 1; - int64_t nStretchedLength = nPayeeCount / round.nBlockPayees * (round.nBlockInterval); + nBlockInterval = ((nBlockStretch * nBlockPayees) / nPayeeCount) + 1; + int64_t nStretchedLength = nPayeeCount / nBlockPayees * (nBlockInterval); if( nStretchedLength > nBlocksTarget ){ - round.nBlockInterval--; + nBlockInterval--; }else if( nStretchedLength < nBlockStretch ){ - round.nBlockInterval++; + nBlockInterval++; } }else{ // If its only one block to pay - round.nBlockInterval = 1; + nBlockInterval = 1; } }else{ // If there are no eligible smartreward entries - round.nBlockPayees = 0; - round.nBlockInterval = 0; + nBlockPayees = 0; + nBlockInterval = 0; + } + + // Calculate the current rewards percentage + int64_t nTime = GetTime(); + int64_t nStartHeight = round->startBlockHeight; + CAmount nRewards = 0; + double nPercent = 0.0; + + while( nStartHeight <= round->endBlockHeight) nRewards += GetBlockValue(nStartHeight++,0,nTime) * 0.15; + + CAmount nCalcSmart = round->eligibleSmart - round->disqualifiedSmart; + + if( nCalcSmart ){ + nPercent = double(nRewards) / nCalcSmart; + }else{ + nPercent = 0; } + cache.UpdateRoundParameter(result, nBlockPayees, nBlockInterval, nRewards, nPercent); } -void CSmartRewards::EvaluateRound(CSmartRewardRound ¤t, CSmartRewardRound &next, CSmartRewardEntryList &entries, CSmartRewardRoundResultList &results) +void CSmartRewards::EvaluateRound(CSmartRewardRound &next) { - LOCK(cs_rewardsdb); - results.clear(); - - UpdatePayoutParameter(current); + LOCK(cs_rewardscache); int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); + CAmount nReward; + const CSmartRewardRound *round = cache.GetCurrentRound(); + pResult->round = *round; + + auto entry = cache.GetEntries()->begin(); - BOOST_FOREACH(CSmartRewardEntry &entry, entries) { + while(entry != cache.GetEntries()->end() ) { - if( current.number ){ + if( cache.GetCurrentRound()->number ){ - if( current.number < nFirst_1_3_Round ){ - nReward = entry.balanceEligible > 0 && entry.disqualifyingTx.IsNull() ? CAmount(entry.balanceEligible * current.percent) : 0; + if( cache.GetCurrentRound()->number < nFirst_1_3_Round ){ + nReward = entry->second->balanceEligible > 0 && entry->second->disqualifyingTx.IsNull() ? CAmount(entry->second->balanceEligible * round->percent) : 0; }else{ - nReward = entry.IsEligible() ? CAmount(entry.balanceEligible * current.percent) : 0; + nReward = entry->second->IsEligible() ? CAmount(entry->second->balanceEligible * round->percent) : 0; } - results.push_back(CSmartRewardRoundResult(entry, nReward)); + pResult->results.push_back(new CSmartRewardResultEntry(entry->second, nReward)); + + if( nReward ){ + pResult->payouts.push_back(pResult->results.back()); + } } - entry.balanceAtStart = entry.balance; + entry->second->balanceAtStart = entry->second->balance; - if( entry.balance >= SMART_REWARDS_MIN_BALANCE && !SmartHive::IsHive(entry.id) ){ - entry.balanceEligible = entry.balance; + if( entry->second->balance >= SMART_REWARDS_MIN_BALANCE && !SmartHive::IsHive(entry->second->id) ){ + entry->second->balanceEligible = entry->second->balance; + }else{ + entry->second->balanceEligible = 0; } // Reset outgoing transaction with every cycle. - entry.disqualifyingTx.SetNull(); + entry->second->disqualifyingTx.SetNull(); // Reset SmartNode payment tx with every cycle in case a node was shut down during the cycle. - entry.smartnodePaymentTx.SetNull(); + entry->second->smartnodePaymentTx.SetNull(); // Reset the vote proof tx with every cycle to force a new vote for eligibility - entry.voteProof.SetNull(); + entry->second->voteProof.SetNull(); - if( next.number < nFirst_1_3_Round && entry.balanceEligible ){ + if( next.number < nFirst_1_3_Round && entry->second->balanceEligible ){ ++next.eligibleEntries; - next.eligibleSmart += entry.balanceEligible; + next.eligibleSmart += entry->second->balanceEligible; } + + ++entry; } + + if( !pResult->payouts.size() ){ + + if( round->number < nFirst_1_3_Round ){ + // Sort it to make sure the slices are the same network wide. + std::sort(pResult->payouts.begin(), pResult->payouts.end(), ComparePaymentPrtList() ); + }else{ + + uint256 blockHash; + if(!GetBlockHash(blockHash, pResult->round.startBlockHeight)) { + throw std::runtime_error(strprintf("CSmartRewards::EvaluateRound -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", round->startBlockHeight)); + } + + std::vector> vecScores; + // Since we use payouts stretched out over a week better to have some "random" sort here + // based on a score calculated with the round start's blockhash. + CSmartRewardResultEntryPtrList::iterator it = pResult->payouts.begin(); + + while( it != pResult->payouts.end() ){ + arith_uint256 nScore = (*it)->CalculateScore(blockHash); + vecScores.push_back(std::make_pair(nScore,*it)); + ++it; + } + + std::sort(vecScores.begin(), vecScores.end(), CompareRewardScore()); + + pResult->payouts.clear(); + + for(auto s : vecScores) + pResult->payouts.push_back(s.second); + } + } + + cache.AddFinishedRound(pResult->round); + cache.SetCurrentRound(next); + cache.SetResult(pResult); } bool CSmartRewards::StartFirstRound(const CSmartRewardRound &first, const CSmartRewardEntryList &entries) @@ -169,94 +251,75 @@ bool CSmartRewards::StartFirstRound(const CSmartRewardRound &first, const CSmart return pdb->StartFirstRound(first,entries); } -bool CSmartRewards::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardRoundResultList &results) +bool CSmartRewards::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results) { LOCK(cs_rewardsdb); return pdb->FinalizeRound(current, next, entries, results); } -bool CSmartRewards::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRoundResultList &results) +bool CSmartRewards::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results) { LOCK(cs_rewardsdb); return pdb->UndoFinalizeRound(current, results); } -bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardRoundResultList &results) +bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results) { LOCK(cs_rewardsdb); return pdb->ReadRewardRoundResults(round, results); } -bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardRoundResultList &payouts) +const CSmartRewardsRoundResult *CSmartRewards::GetLastRoundResult() { - LOCK(cs_rewardsdb); - return pdb->ReadRewardPayouts(round, payouts); + return cache.GetLastRoundResult(); } -bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardRoundResultPtrList &payouts) +bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts) { LOCK(cs_rewardsdb); return pdb->ReadRewardPayouts(round, payouts); } -bool CSmartRewards::GetCachedRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry) +bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts) { LOCK(cs_rewardsdb); - - // Return the entry if its already in cache. - auto findResult = rewardEntries.find(id); - - if( findResult != rewardEntries.end() ){ - entry = findResult->second; - return true; - } - - return false; + return pdb->ReadRewardPayouts(round, payouts); } -bool CSmartRewards::ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry) +bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry, bool fCreate) { - LOCK(cs_rewardsdb); - return pdb->ReadRewardEntry(id,entry); -} + LOCK(cs_rewardscache); -bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry) -{ - LOCK(cs_rewardsdb); + // Return the entry if its already in cache. + auto it = cache.GetEntries()->find(id); - CSmartRewardEntry * pReadEntry; + if( it != cache.GetEntries()->end() ){ + entry = it->second; + return entry->balance > 0; + } - if( GetCachedRewardEntry(id,pReadEntry) ){ - entry = *pReadEntry; + if( fCreate ){ + entry = new CSmartRewardEntry(id); + cache.AddEntry(entry); return true; } - return ReadRewardEntry(id,entry); + return false; } -bool CSmartRewards::GetRewardEntries(CSmartRewardEntryList &entries) +bool CSmartRewards::GetRewardEntries(CSmartRewardEntryMap &entries) { LOCK(cs_rewardsdb); return pdb->ReadRewardEntries(entries); } -bool CSmartRewards::SyncCached(bool fUndo) -{ - return SyncCached(CSmartRewardBlock(), fUndo); -} - -bool CSmartRewards::SyncCached(const CSmartRewardBlock &block, bool fUndo) +bool CSmartRewards::SyncCached() { - LOCK2(cs_rewardsdb, cs_rewardrounds); + LOCK2(cs_rewardsdb, cs_rewardscache); - bool ret = pdb->SyncCached(block, currentRound, rewardEntries, transactionEntries, fUndo); - - for( std::pair it : rewardEntries ){ - delete it.second; - } + bool ret = pdb->SyncCached(cache); - rewardEntries.clear(); - transactionEntries.clear(); + cache.Clear(); return ret; } @@ -264,25 +327,18 @@ bool CSmartRewards::SyncCached(const CSmartRewardBlock &block, bool fUndo) bool CSmartRewards::IsSynced() { int nSyncDistance = MainNet() ? nRewardsSyncDistance : nRewardsSyncDistance_Testnet; - return (chainHeight - rewardHeight) <= nSyncDistance - 1; + return (pindexBestHeader->nHeight - cache.GetCurrentBlock()->nHeight ) <= nSyncDistance - 1; } double CSmartRewards::GetProgress() { int nSyncDistance = MainNet() ? nRewardsSyncDistance : nRewardsSyncDistance_Testnet; - double progress = chainHeight > nSyncDistance ? double(rewardHeight) / double(chainHeight - nSyncDistance) : 0.0; + double progress = pindexBestHeader->nHeight > nSyncDistance ? double(cache.GetCurrentBlock()->nHeight) / double(pindexBestHeader->nHeight - nSyncDistance) : 0.0; return progress > 1 ? 1 : progress; } -int CSmartRewards::GetLastHeight() -{ - return rewardHeight; -} - int CSmartRewards::GetBlocksPerRound(const int nRound) { - LOCK(cs_rewardrounds); - const CChainParams& chainparams = Params(); if( nRound < chainparams.GetConsensus().nRewardsFirst_1_3_Round ){ @@ -293,34 +349,24 @@ int CSmartRewards::GetBlocksPerRound(const int nRound) } -void CSmartRewards::AddTransaction(const CSmartRewardTransaction &transaction) -{ - LOCK(cs_rewardsdb); - transactionEntries.push_back(transaction); -} - CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) { - LOCK(cs_rewardsdb); + LOCK2(cs_rewardsdb, cs_rewardscache); - // Get the last written block of the rewards database. - if(!pdb->ReadLastBlock(currentBlock)){ - // If there is no one available yet - // Use 0 to get 1 as start below. - currentBlock.nHeight = 0; - currentBlock.blockHash = uint256(); - currentBlock.blockTime = 0; - } + CSmartRewardBlock block; + CSmartRewardRound round; + CSmartRewardRoundList rounds; + CSmartRewardEntryMap entries; + CSmartRewardResultEntryList results; - pdb->ReadRounds(finishedRounds); + pdb->ReadLastBlock(block); + pdb->ReadCurrentRound(round); + pdb->ReadRounds(rounds); + pdb->ReadRewardEntries(entries); - std::sort(finishedRounds.begin(), finishedRounds.end()); + std::sort(rounds.begin(), rounds.end()); - if( finishedRounds.size() ){ - lastRound = finishedRounds.back(); - } - - pdb->ReadCurrentRound(currentRound); + cache.Load(block, round, rounds, entries); } bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) @@ -330,44 +376,28 @@ bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) return pdb->ReadLastBlock(block); } -bool CSmartRewards::GetTransaction(const uint256 hash, CSmartRewardTransaction &transaction) +bool CSmartRewards::GetTransaction(const uint256 nHash, CSmartRewardTransaction &transaction) { + LOCK2(cs_rewardsdb, cs_rewardscache); // If the transaction is already in the cache use this one. - BOOST_FOREACH(CSmartRewardTransaction t, transactionEntries) { - if(t.hash == hash){ - transaction = t; - return true; - } - } + auto it = cache.GetAddedTransactions()->find(nHash); - return pdb->ReadTransaction(hash, transaction); -} - -const CSmartRewardRound& CSmartRewards::GetCurrentRound() -{ - return currentRound; -} - -const CSmartRewardRound& CSmartRewards::GetLastRound() -{ - return lastRound; -} + if( it != cache.GetAddedTransactions()->end() ){ + transaction = it->second; + return true; + } -const CSmartRewardRoundList& CSmartRewards::GetRewardRounds() -{ - return finishedRounds; + return pdb->ReadTransaction(nHash, transaction); } -void CSmartRewards::UpdateHeights(const int nHeight, const int nRewardHeight) +const CSmartRewardRound* CSmartRewards::GetCurrentRound() { - chainHeight = nHeight; - rewardHeight = nRewardHeight; + return cache.GetCurrentRound(); } -void CSmartRewards::StartBlock() +const CSmartRewardRoundList* CSmartRewards::GetRewardRounds() { - rewardEntries.clear(); - transactionEntries.clear(); + return cache.GetRounds(); } void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) @@ -383,17 +413,9 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar return; } - if(!GetCachedRewardEntry(ids.at(0), rEntry)){ - - rEntry = new CSmartRewardEntry(ids.at(0)); - - if(!ReadRewardEntry(rEntry->id, *rEntry)){ - delete rEntry; - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Spend without previous receive - %s", tx.ToString()); - return; - } - - rewardEntries.insert(make_pair(ids.at(0), rEntry)); + if(!GetRewardEntry(ids.at(0), rEntry, false)){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Spend without previous receive - %s", tx.ToString()); + return; } // If its a voteproof transaction not instantly make the @@ -431,7 +453,7 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar } - if(rEntry->balance < 0 ){ + if(rEntry->balance <= 0 ){ LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Negative amount?! - %s", rEntry->ToString()); rEntry->balance = 0; } @@ -450,11 +472,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm return; }else{ - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ - rEntry = new CSmartRewardEntry(ids.at(0)); - ReadRewardEntry(rEntry->id, *rEntry); - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } + GetRewardEntry(ids.at(0),rEntry, true); if( voteProofCheck ){ @@ -465,11 +483,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm CSmartRewardEntry *vkEntry = nullptr; - if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ - vkEntry = new CSmartRewardEntry(*voteProofCheck); - ReadRewardEntry(vkEntry->id, *vkEntry); - rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); - } + GetRewardEntry(*voteProofCheck,vkEntry, true); if( vkEntry->IsEligible() ){ result.disqualifiedEntries++; @@ -521,11 +535,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm proofAddress = CSmartAddress(); // Invalid address type } - if(!GetCachedRewardEntry(proofAddress, proofEntry)){ - proofEntry = new CSmartRewardEntry(proofAddress); - ReadRewardEntry(proofEntry->id, *proofEntry); - rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); - } + GetRewardEntry(proofAddress, proofEntry, true); }else{ proofAddress = CSmartAddress(); // Invalid option @@ -603,8 +613,8 @@ void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& int nCurrentRound; { - LOCK(cs_rewardrounds); - nCurrentRound = currentRound.number; + LOCK(cs_rewardscache); + nCurrentRound = cache.GetCurrentRound()->number; } int nHeight = pIndex->nHeight; @@ -625,8 +635,8 @@ void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& return; }else{ - // If not save add it to the database. - AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); + // If not save add it to the cache. + cache.AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); } CSmartAddress *voteProofCheck = nullptr; @@ -668,7 +678,7 @@ void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry; + CSmartRewardEntry *rEntry = nullptr; std::vector ids; int required = ParseScript(in.scriptPubKey ,ids); @@ -678,17 +688,9 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t return; } - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ - - rEntry = new CSmartRewardEntry(ids.at(0)); - - if(!ReadRewardEntry(rEntry->id, *rEntry)){ - delete rEntry; - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); - return; - } - - rewardEntries.insert(make_pair(ids.at(0), rEntry)); + if( !GetRewardEntry(ids.at(0), rEntry, false) ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); + return; } rEntry->balance += in.nValue; @@ -723,7 +725,7 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry; + CSmartRewardEntry *rEntry = nullptr; std::vector ids; int required = ParseScript(out.scriptPubKey ,ids); @@ -732,11 +734,7 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart return; }else{ - if(!GetCachedRewardEntry(ids.at(0),rEntry)){ - rEntry = new CSmartRewardEntry(ids.at(0)); - ReadRewardEntry(rEntry->id, *rEntry); - rewardEntries.insert(make_pair(ids.at(0), rEntry)); - } + GetRewardEntry(ids.at(0),rEntry, true); if( voteProofCheck ){ @@ -747,11 +745,7 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart CSmartRewardEntry *vkEntry = nullptr; - if(!GetCachedRewardEntry(*voteProofCheck,vkEntry)){ - vkEntry = new CSmartRewardEntry(*voteProofCheck); - ReadRewardEntry(vkEntry->id, *vkEntry); - rewardEntries.insert(make_pair(vkEntry->id, vkEntry)); - } + GetRewardEntry(*voteProofCheck, vkEntry, true); if( vkEntry->disqualifyingTx == tx.GetHash() ){ @@ -803,11 +797,7 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart proofAddress = CSmartAddress(); // Invalid address type } - if(!GetCachedRewardEntry(proofAddress, proofEntry)){ - proofEntry = new CSmartRewardEntry(proofAddress); - ReadRewardEntry(proofEntry->id, *proofEntry); - rewardEntries.insert(make_pair(proofEntry->id, proofEntry)); - } + GetRewardEntry(proofAddress, proofEntry, true); }else{ proofAddress = CSmartAddress(); // Invalid option @@ -863,8 +853,8 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nCurrentRound; { - LOCK(cs_rewardrounds); - nCurrentRound = currentRound.number; + LOCK(cs_rewardscache); + nCurrentRound = cache.GetCurrentRound()->number; } int nHeight = pIndex->nHeight; @@ -877,9 +867,8 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CSmartRewardTransaction testTx; - // First check if the transaction hash did already come up in the past. if( GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight ){ - AddTransaction(testTx); + cache.RemoveTransaction(testTx); }else{ return; } @@ -946,21 +935,19 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe return true; } - if(!pIndex || pIndex->nHeight != currentBlock.nHeight + 1 ){ - LogPrintf("CSmartRewards::CommitBlock - Invalid next block!"); - return false; - } + LOCK(cs_rewardscache); + + const CSmartRewardRound *round = cache.GetCurrentRound(); - if(!SyncCached(result.block, false)){ - LogPrintf("CSmartRewards::CommitBlock - Failed to sync cache - Initial!"); + if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight + 1 ){ + LogPrintf("CSmartRewards::CommitBlock - Invalid next block!"); return false; } - // Update the current block to the processed one - currentBlock = result.block; + UpdateRoundParameter(result); // For the first round we have special parameter.. - if( !currentRound.number ){ + if( !round->number ){ if( (MainNet() && pIndex->GetBlockTime() > nFirstRoundStartTime) || (TestNet() && pIndex->nHeight >= nFirstRoundStartBlock_Testnet) ){ @@ -974,59 +961,23 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe // Estimate the block, gets updated on the end of the round to the real one. first.endBlockHeight = MainNet() ? nFirstRoundEndBlock : nFirstRoundEndBlock_Testnet; - CSmartRewardEntryList entries; - CSmartRewardRoundResultList results; - - // Get the current entries - if( !GetRewardEntries(entries) ){ - LogPrintf("CSmartRewards::CommitBlock - Failed to read all reward entries!"); - return false; - } - // Evaluate the round and update the next rounds parameter. - EvaluateRound(currentRound, first, entries, results ); - - CalculateRewardRatio(first); - - if( !StartFirstRound(first, entries) ){ - LogPrintf("CSmartRewards::CommitBlock - Failed to finalize round!"); - return false; - } - - currentRound = first; + EvaluateRound(first); } - }else if( result.disqualifiedEntries || result.disqualifiedSmart || - result.qualifiedEntries || result.qualifiedSmart ){ - - // If there were disqualification during the last block processing - // update the current round stats. - - currentRound.disqualifiedEntries += result.disqualifiedEntries; - currentRound.disqualifiedSmart += result.disqualifiedSmart; - - currentRound.eligibleEntries += result.qualifiedEntries; - currentRound.eligibleSmart += result.qualifiedSmart; - - CalculateRewardRatio(currentRound); } // If just hit the next round threshold - if( ( MainNet() && currentRound.number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() > currentRound.endBlockTime ) || - ( ( TestNet() || currentRound.number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == currentRound.endBlockHeight ) ){ + if( ( MainNet() && round->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() > round->endBlockTime ) || + ( ( TestNet() || round->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == round->endBlockHeight ) ){ - // Write the round to the history - currentRound.endBlockHeight = pIndex->nHeight; - currentRound.endBlockTime = pIndex->GetBlockTime(); - - CSmartRewardEntryList entries; - CSmartRewardRoundResultList results; + cache.UpdateRoundEnd(pIndex->nHeight, pIndex->GetBlockTime()); // Create the next round. CSmartRewardRound next; - next.number = currentRound.number + 1; - next.startBlockTime = currentRound.endBlockTime; - next.startBlockHeight = currentRound.endBlockHeight + 1; + next.number = round->number + 1; + next.startBlockTime = round->endBlockTime; + next.startBlockHeight = round->endBlockHeight + 1; int nBlocksPerRound = GetBlocksPerRound(next.number); time_t startTime = (time_t)next.startBlockTime; @@ -1055,49 +1006,26 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe next.endBlockTime = startTime + nBlocksPerRound * 55; } - // Get the current entries - if( !GetRewardEntries(entries) ){ - LogPrintf("CSmartRewards::CommitBlock - Failed to read all reward entries!"); - return false; - } - - CalculateRewardRatio(currentRound); - // Evaluate the round and update the next rounds parameter. - EvaluateRound(currentRound, next, entries, results); - - CalculateRewardRatio(next); + EvaluateRound(next); - if( !FinalizeRound(currentRound, next, entries, results) ){ - LogPrintf("CSmartRewards::CommitBlock - Failed to finalize round!"); - return false; - } - - LOCK(cs_rewardrounds); - - finishedRounds.push_back(currentRound); - lastRound = currentRound; - currentRound = next; } - if(!SyncCached()){ - LogPrintf("CSmartRewards::CommitBlock - Failed to sync cached - Processed!"); - return false; - } + UpdateRoundParameter(CSmartRewardsUpdateResult()); - prewards->UpdateHeights(GetBlockHeight(pIndex), currentBlock.nHeight); + cache.UpdateHeights(GetBlockHeight(pIndex), cache.GetCurrentBlock()->nHeight); int nTime2 = GetTimeMicros(); if( LogAcceptCategory("smartrewards-block") ){ - LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",currentRound.number, currentBlock.nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); LogPrint("smartrewards-block", " Commit block: %.2fms\n", (nTime2 - nTime1) * 0.001); } // If we are synced notify the UI on each new block. // If not notify the UI every nRewardsUISyncUpdateRate blocks to let it update the // loading screen. - if( IsSynced() || !(currentBlock.nHeight % nRewardsUISyncUpdateRate) ) + if( IsSynced() || !(cache.GetCurrentBlock()->nHeight % nRewardsUISyncUpdateRate) ) uiInterface.NotifySmartRewardUpdate(); return true; @@ -1111,82 +1039,217 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda return true; } - if(!pIndex || pIndex->nHeight != currentBlock.nHeight ){ + LOCK(cs_rewardscache); + + const CSmartRewardRound *round = cache.GetCurrentRound(); + + if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight ){ LogPrintf("CSmartRewards::CommitUndoBlock - Invalid next block!"); return false; } - if(!SyncCached(result.block, true)){ - LogPrintf("CSmartRewards::CommitUndoBlock - Failed to sync cache - Initial!"); - return false; - } + CSmartRewardsUpdateResult undoResult(pIndex->pprev->nHeight, pIndex->pprev->phashBlock, pIndex->pprev->GetBlockTime()); - currentBlock = CSmartRewardBlock(pIndex->pprev->nHeight, pIndex->pprev->GetBlockHash(), pIndex->pprev->GetBlockTime() ); + undoResult.disqualifiedEntries = result.disqualifiedEntries; + undoResult.disqualifiedSmart = result.disqualifiedSmart; + undoResult.qualifiedEntries = result.qualifiedEntries; + undoResult.qualifiedSmart = result.qualifiedSmart; - if( result.disqualifiedEntries || result.disqualifiedSmart || - result.qualifiedEntries || result.qualifiedSmart ){ + UpdateRoundParameter(undoResult); - // If there were disqualification during the last block processing - // update the current round stats. +// // If just hit the last round's threshold +// if( ( MainNet() && currentRound.number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < currentRound.endBlockTime ) || +// ( ( TestNet() || currentRound.number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == currentRound.startBlockHeight ) ){ - currentRound.disqualifiedEntries += result.disqualifiedEntries; - currentRound.disqualifiedSmart += result.disqualifiedSmart; +// LOCK2(cs_rewardsdb, cs_rewardrounds); - currentRound.eligibleEntries += result.qualifiedEntries; - currentRound.eligibleSmart += result.qualifiedSmart; +// // Recover the last round from the history as current round +// currentRound = finishedRounds.back(); +// finishedRounds.pop_back(); - CalculateRewardRatio(currentRound); - } +// lastRound = finishedRounds.back(); - // If just hit the last round's threshold - if( ( MainNet() && currentRound.number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < currentRound.endBlockTime ) || - ( ( TestNet() || currentRound.number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == currentRound.startBlockHeight ) ){ +// CSmartRewardEntryList entries; +// CSmartRewardResultEntryList results; - LOCK2(cs_rewardsdb, cs_rewardrounds); +// // Get the current entries +// if( !GetRewardRoundResults(currentRound.number, results) ){ +// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to read last round's results!"); +// return false; +// } - // Recover the last round from the history as current round - currentRound = finishedRounds.back(); - finishedRounds.pop_back(); +// CalculateRewardRatio(currentRound); - lastRound = finishedRounds.back(); +// if( !UndoFinalizeRound(currentRound, results) ){ +// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to finalize round!"); +// return false; +// } - CSmartRewardEntryList entries; - CSmartRewardRoundResultList results; +// } - // Get the current entries - if( !GetRewardRoundResults(currentRound.number, results) ){ - LogPrintf("CSmartRewards::CommitUndoBlock - Failed to read last round's results!"); - return false; - } +// if(!SyncCached(true)){ +// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to sync cached - Processed!"); +// return false; +// } + +// cache.UpdateHeights(GetBlockHeight(pIndex), currentBlock.nHeight); + +// int nTime2 = GetTimeMicros(); + +// if( LogAcceptCategory("smartrewards-block") ){ +// LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",currentRound.number, currentBlock.nHeight, int(prewards->GetProgress() * 100)); +// LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); +// } - CalculateRewardRatio(currentRound); +// // If we are synced notify the UI on each new block. +// // If not notify the UI every nRewardsUISyncUpdateRate blocks to let it update the +// // loading screen. +// if( IsSynced() || !(currentBlock.nHeight % nRewardsUISyncUpdateRate) ) +// uiInterface.NotifySmartRewardUpdate(); - if( !UndoFinalizeRound(currentRound, results) ){ - LogPrintf("CSmartRewards::CommitUndoBlock - Failed to finalize round!"); - return false; + return true; +} + +CSmartRewardsCache::~CSmartRewardsCache() +{ + LOCK(cs_rewardscache); + + for( std::pair it : entries ){ + delete it.second; + } + + if( result ){ + for( CSmartRewardResultEntry *resultEntry : result->results ){ + delete resultEntry; } + result->results.clear(); + delete result; } - if(!SyncCached(true)){ - LogPrintf("CSmartRewards::CommitUndoBlock - Failed to sync cached - Processed!"); - return false; + block = CSmartRewardBlock(); + round = CSmartRewardRound(); + rounds.clear(); + addTransactions.clear(); + removeTransactions.clear(); + entries.clear(); +} + +unsigned long CSmartRewardsCache::EstimatedSize() +{ + return sizeof *this; +} + +void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds, const CSmartRewardEntryMap &entries) +{ + this->block = block; + this->round = round; + this->rounds = rounds; + this->entries = entries; +// this->payouts = payouts; +} + +bool CSmartRewardsCache::NeedsSync() +{ + LOCK(cs_rewardscache); + return (result != nullptr && !result->fSynced) || EstimatedSize() > REWARDS_MAX_CACHE; +} + +void CSmartRewardsCache::Clear() +{ + LOCK(cs_rewardscache); + + if( result ){ + result->fSynced = true; } - prewards->UpdateHeights(GetBlockHeight(pIndex), currentBlock.nHeight); + addTransactions.clear(); + removeTransactions.clear(); +} - int nTime2 = GetTimeMicros(); +void CSmartRewardsCache::SetCurrentBlock(const CSmartRewardBlock ¤tBlock) +{ + AssertLockHeld(cs_rewardscache); + block = currentBlock; +} - if( LogAcceptCategory("smartrewards-block") ){ - LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",currentRound.number, currentBlock.nHeight, int(prewards->GetProgress() * 100)); - LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); +void CSmartRewardsCache::SetCurrentRound(const CSmartRewardRound ¤tRound) +{ + AssertLockHeld(cs_rewardscache); + round = currentRound; +} + +void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) +{ + AssertLockHeld(cs_rewardscache); + result = pResult; +} + +void CSmartRewardsCache::UpdateRoundParameter(const CSmartRewardsUpdateResult &result, int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent) +{ + AssertLockHeld(cs_rewardscache); + + if( result.IsValid() ){ + SetCurrentBlock(result.block); + + round.disqualifiedEntries += result.disqualifiedEntries; + round.disqualifiedSmart += result.disqualifiedSmart; + + round.eligibleEntries += result.qualifiedEntries; + round.eligibleSmart += result.qualifiedSmart; } - // If we are synced notify the UI on each new block. - // If not notify the UI every nRewardsUISyncUpdateRate blocks to let it update the - // loading screen. - if( IsSynced() || !(currentBlock.nHeight % nRewardsUISyncUpdateRate) ) - uiInterface.NotifySmartRewardUpdate(); + round.nBlockPayees = nBlockPayees; + round.nBlockInterval = nBlockInterval; + round.rewards = nRewards; + round.percent = dPercent; +} - return true; +void CSmartRewardsCache::UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime) +{ + round.endBlockHeight = nBlockHeight; + round.endBlockTime = nBlockTime; +} + +void CSmartRewardsCache::UpdateHeights(const int nHeight, const int nRewardHeight) +{ + AssertLockHeld(cs_rewardscache); + chainHeight = nHeight; + rewardHeight = nRewardHeight; +} + +void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound &round) +{ + AssertLockHeld(cs_rewardscache); + rounds.push_back(round); +} + +void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction &transaction) +{ + LOCK(cs_rewardscache); + auto it = removeTransactions.find(transaction.hash); + + if( it != removeTransactions.end() ){ + removeTransactions.erase(it); + }else{ + addTransactions.insert(std::make_pair(transaction.hash, transaction)); + } +} + +void CSmartRewardsCache::RemoveTransaction(const CSmartRewardTransaction &transaction) +{ + LOCK(cs_rewardscache); + auto it = addTransactions.find(transaction.hash); + + if( it != addTransactions.end() ){ + addTransactions.erase(it); + }else{ + removeTransactions.insert(std::make_pair(transaction.hash, transaction)); + } +} + +void CSmartRewardsCache::AddEntry(CSmartRewardEntry *entry) +{ + LOCK(cs_rewardscache); + entries.insert(std::make_pair(entry->id, entry)); } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 50ecaa71..07210fdc 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -40,8 +40,8 @@ const int64_t nFirstRoundEndBlock_Testnet = nFirstRoundStartBlock_Testnet + 1000 void ThreadSmartRewards(bool fRecreate = false); CAmount CalculateRewardsForBlockRange(int64_t start, int64_t end); +extern CCriticalSection cs_rewardscache; extern CCriticalSection cs_rewardsdb; -extern CCriticalSection cs_rewardrounds; struct CSmartRewardsUpdateResult { @@ -50,31 +50,79 @@ struct CSmartRewardsUpdateResult int64_t qualifiedEntries; int64_t qualifiedSmart; CSmartRewardBlock block; + CSmartRewardsUpdateResult() : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() {} CSmartRewardsUpdateResult(const int nHeight, const uint256* pBlockHash, const int64_t nBlockTime) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block(nHeight, pBlockHash, nBlockTime) { } + + bool IsValid() const { return block.IsValid(); } }; -class CSmartRewards +struct CSmartRewardsRoundResult { - CSmartRewardsDB * pdb; - CSmartRewardRoundList finishedRounds; - CSmartRewardRound currentRound; - CSmartRewardRound lastRound; - CSmartRewardBlock currentBlock; + CSmartRewardRound round; + CSmartRewardResultEntryPtrList results; + CSmartRewardResultEntryPtrList payouts; + bool fSynced; + CSmartRewardsRoundResult(){fSynced = false;} +}; +class CSmartRewardsCache +{ int chainHeight; int rewardHeight; - CSmartRewardTransactionList transactionEntries; - CSmartRewardEntryMap rewardEntries; + CSmartRewardBlock block; + CSmartRewardRound round; + CSmartRewardRoundList rounds; + CSmartRewardTransactionMap addTransactions; + CSmartRewardTransactionMap removeTransactions; + CSmartRewardEntryMap entries; + CSmartRewardsRoundResult *result; + +public: + + CSmartRewardsCache() : block(), round(), rounds(), addTransactions(), removeTransactions(), entries(), result(nullptr) { } + ~CSmartRewardsCache(); + + unsigned long EstimatedSize(); + + void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds, const CSmartRewardEntryMap &entries); + + bool NeedsSync(); + void Clear(); + + void SetCurrentBlock(const CSmartRewardBlock ¤tBlock); + void SetCurrentRound(const CSmartRewardRound ¤tRound); + void SetResult(CSmartRewardsRoundResult *pResult); + + void UpdateRoundParameter(const CSmartRewardsUpdateResult &result, int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent); + void UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime); + void UpdateHeights(const int nHeight, const int nRewardHeight); + + const CSmartRewardBlock* GetCurrentBlock() const { return █ } + const CSmartRewardRound* GetCurrentRound() const { return &round; } + const CSmartRewardRoundList* GetRounds() const { return &rounds; } + const CSmartRewardTransactionMap* GetAddedTransactions() const { return &addTransactions; } + const CSmartRewardTransactionMap* GetRemovedTransactions() const { return &removeTransactions; } + const CSmartRewardEntryMap* GetEntries() const { return &entries; } + const CSmartRewardsRoundResult* GetLastRoundResult() const { return result; } + + void AddFinishedRound(const CSmartRewardRound &round); + void AddTransaction(const CSmartRewardTransaction &transaction); + void RemoveTransaction(const CSmartRewardTransaction &transaction); + void AddEntry(CSmartRewardEntry *entry); +}; + +class CSmartRewards +{ + CSmartRewardsDB * pdb; + CSmartRewardsCache cache; mutable CCriticalSection csRounds; - void UpdatePayoutParameter(CSmartRewardRound &round); + void UpdateRoundParameter(const CSmartRewardsUpdateResult &result); - bool GetCachedRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry); bool ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry); - bool GetRewardEntries(CSmartRewardEntryList &entries); - void AddTransaction(const CSmartRewardTransaction &transaction); + bool GetRewardEntries(CSmartRewardEntryMap &entries); public: CSmartRewards(CSmartRewardsDB *prewardsdb); @@ -84,39 +132,37 @@ class CSmartRewards bool GetLastBlock(CSmartRewardBlock &block); bool GetTransaction(const uint256 hash, CSmartRewardTransaction &transaction); - const CSmartRewardRound& GetCurrentRound(); - const CSmartRewardRound &GetLastRound(); - const CSmartRewardRoundList& GetRewardRounds(); + const CSmartRewardRound* GetCurrentRound(); + const CSmartRewardRoundList* GetRewardRounds(); void UpdateHeights(const int nHeight, const int nRewardHeight); bool Verify(); - bool SyncCached(bool fUndo = false); - bool SyncCached(const CSmartRewardBlock &block, bool fUndo = false); + bool NeedsCacheWrite(); + bool SyncCached(); bool IsSynced(); double GetProgress(); - int GetLastHeight(); int GetBlocksPerRound(const int nRound); bool Update(CBlockIndex *pindexNew, const CChainParams& chainparams, const int nCurrentRound, CSmartRewardsUpdateResult &result); bool UpdateRound(const CSmartRewardRound &round); - void StartBlock(); void ProcessTransaction(CBlockIndex* pLastIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result); void UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result); bool CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); bool CommitUndoBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); - bool GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry); + bool GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry, bool fCreate); - void EvaluateRound(CSmartRewardRound ¤t, CSmartRewardRound &next, CSmartRewardEntryList &entries, CSmartRewardRoundResultList &results); + void EvaluateRound(CSmartRewardRound &next); bool StartFirstRound(const CSmartRewardRound &next, const CSmartRewardEntryList &entries); - bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardRoundResultList &results); - bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRoundResultList &results); + bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results); + bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results); - bool GetRewardRoundResults(const int16_t round, CSmartRewardRoundResultList &results); - bool GetRewardPayouts(const int16_t round, CSmartRewardRoundResultList &payouts); - bool GetRewardPayouts(const int16_t round, CSmartRewardRoundResultPtrList &payouts); + bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results); + const CSmartRewardsRoundResult* GetLastRoundResult(); + bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); + bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); private: void ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); void ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 58c26cca..33bf635a 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -10,6 +10,7 @@ #include "uint256.h" #include "ui_interface.h" #include "init.h" +#include "rewards.h" #include "rewardsdb.h" #include @@ -63,36 +64,6 @@ bool CSmartRewardsDB::Verify(int& lastBlockHeight) lastBlockHeight = last.nHeight; - LogPrintf("CSmartRewards::Verify() Verify blocks 1 - %d\n", last.nHeight); - - std::vector testBlocks; - - pcursor->Seek(DB_BLOCK); - - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - if (pcursor->GetKey(key) && key.first == DB_BLOCK) { - CSmartRewardBlock nValue; - if (pcursor->GetValue(nValue)) { - if( nValue.nHeight != key.second ) return error("Block value %d contains wrong height: %s",key.second, nValue.ToString()); - pcursor->Next(); - testBlocks.push_back(nValue); - } else { - return error("failed to get block entry %d", key.second); - } - } else { - if( testBlocks.size() < size_t(last.nHeight) ) return error("Odd block count %d <> %d", testBlocks.size(), last.nHeight); - break; - } - } - - std::sort(testBlocks.begin(), testBlocks.end()); - vector::iterator it; - for(it = testBlocks.begin() + 1; it != testBlocks.end(); it++ ) { - if( (it-1)->nHeight + 1 != it->nHeight) return error("Block %d missing", it->nHeight); - } - return true; } @@ -151,37 +122,39 @@ bool CSmartRewardsDB::ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry return Read(make_pair(DB_REWARD_ENTRY,id), entry); } -bool CSmartRewardsDB::SyncCached(const CSmartRewardRound& current, const CSmartRewardEntryMap &rewards, const CSmartRewardTransactionList &transactions, bool fUndo) -{ - return SyncCached(CSmartRewardBlock(), current, rewards, transactions, fUndo); -} -bool CSmartRewardsDB::SyncCached(const CSmartRewardBlock &block, const CSmartRewardRound& current, const CSmartRewardEntryMap &rewards, const CSmartRewardTransactionList &transactions, bool fUndo) +bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) { CDBBatch batch(*this); - BOOST_FOREACH(const PAIRTYPE(CSmartAddress, CSmartRewardEntry*)& r, rewards) { - if( r.second->balance <= 0 ){ - batch.Erase(make_pair(DB_REWARD_ENTRY,r.first)); + auto entry = cache.GetEntries()->begin(); + + while( entry != cache.GetEntries()->end() ){ + + if( entry->second->balance <= 0 ){ + batch.Erase(make_pair(DB_REWARD_ENTRY,entry->first)); }else{ - batch.Write(make_pair(DB_REWARD_ENTRY,r.first), *r.second); + batch.Write(make_pair(DB_REWARD_ENTRY,entry->first), *entry->second); } + + ++entry; } - BOOST_FOREACH(const CSmartRewardTransaction &t, transactions) { + auto addTx = cache.GetAddedTransactions()->begin(); - if( fUndo ){ - batch.Erase(make_pair(DB_TX_HASH, t.hash)); - }else{ - batch.Write(make_pair(DB_TX_HASH,t.hash), t); - } + while( addTx != cache.GetAddedTransactions()->end() ){ + batch.Write(make_pair(DB_TX_HASH, addTx->first), addTx->second); + ++addTx; } - if( block.IsValid() ){ - batch.Write(make_pair(DB_BLOCK,block.nHeight), block); - batch.Write(DB_BLOCK_LAST, block); + auto removeTx = cache.GetRemovedTransactions()->begin(); + + while( removeTx != cache.GetRemovedTransactions()->end() ){ + batch.Erase(make_pair(DB_TX_HASH, removeTx->first)); + ++removeTx; } - batch.Write(DB_ROUND_CURRENT, current); + batch.Write(DB_BLOCK_LAST, *cache.GetCurrentBlock()); + batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); return WriteBatch(batch); } @@ -199,11 +172,11 @@ bool CSmartRewardsDB::StartFirstRound(const CSmartRewardRound &start, const CSma return WriteBatch(batch); } -bool CSmartRewardsDB::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardRoundResultList &results) +bool CSmartRewardsDB::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results) { CDBBatch batch(*this); - BOOST_FOREACH(const CSmartRewardRoundResult &s, results) { + BOOST_FOREACH(const CSmartRewardResultEntry &s, results) { batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(current.number, s.entry.id)), s); } @@ -217,11 +190,11 @@ bool CSmartRewardsDB::FinalizeRound(const CSmartRewardRound ¤t, const CSma return WriteBatch(batch); } -bool CSmartRewardsDB::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRoundResultList &results) +bool CSmartRewardsDB::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results) { CDBBatch batch(*this); - BOOST_FOREACH(const CSmartRewardRoundResult &s, results) { + BOOST_FOREACH(const CSmartRewardResultEntry &s, results) { batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(current.number, s.entry.id))); batch.Write(make_pair(DB_REWARD_ENTRY,s.entry.id), s.entry); } @@ -232,7 +205,7 @@ bool CSmartRewardsDB::UndoFinalizeRound(const CSmartRewardRound ¤t, const return WriteBatch(batch); } -bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryList &entries) { +bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryMap &entries) { boost::scoped_ptr pcursor(NewIterator()); @@ -242,9 +215,9 @@ bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryList &entries) { boost::this_thread::interruption_point(); std::pair key; if (pcursor->GetKey(key) && key.first == DB_REWARD_ENTRY) { - CSmartRewardEntry nValue; - if (pcursor->GetValue(nValue)) { - entries.push_back(nValue); + CSmartRewardEntry entry; + if (pcursor->GetValue(entry)) { + entries.insert(std::make_pair(entry.id, new CSmartRewardEntry(entry) )); pcursor->Next(); } else { return error("failed to get reward entry"); @@ -257,7 +230,7 @@ bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryList &entries) { return true; } -bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRoundResultList &results) { +bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results) { boost::scoped_ptr pcursor(NewIterator()); @@ -270,7 +243,7 @@ bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRo if( key.second.first != round ) break; - CSmartRewardRoundResult nValue; + CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { results.push_back(nValue); pcursor->Next(); @@ -285,7 +258,7 @@ bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRo return true; } -bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardRoundResultList &payouts) { +bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts) { boost::scoped_ptr pcursor(NewIterator()); @@ -298,7 +271,7 @@ bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardRoundRe if( key.second.first != round ) break; - CSmartRewardRoundResult nValue; + CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { if( nValue.reward ) payouts.push_back(nValue); pcursor->Next(); @@ -313,7 +286,7 @@ bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardRoundRe return true; } -bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardRoundResultPtrList &payouts) { +bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts) { boost::scoped_ptr pcursor(NewIterator()); @@ -326,9 +299,9 @@ bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardRoundRe if( key.second.first != round ) break; - CSmartRewardRoundResult nValue; + CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { - if( nValue.reward ) payouts.push_back(new CSmartRewardRoundResult(nValue)); + if( nValue.reward ) payouts.push_back(new CSmartRewardResultEntry(nValue)); pcursor->Next(); } else { // Delete everything if something fails @@ -380,8 +353,8 @@ string CSmartRewardBlock::ToString() const std::stringstream s; s << strprintf("CSmartRewardBlock(height=%d, hash=%s, time=%d)\n", nHeight, - blockHash.ToString(), - blockTime); + nHash.ToString(), + nTime); return s.str(); } @@ -401,24 +374,24 @@ string CSmartRewardRound::ToString() const return s.str(); } -string CSmartRewardRoundResult::GetAddress() const +string CSmartRewardResultEntry::GetAddress() const { return entry.id.ToString(); } -string CSmartRewardRoundResult::ToString() const +string CSmartRewardResultEntry::ToString() const { std::stringstream s; - s << strprintf("CSmartRewardRoundResult(id=%d, balance=%d, reward=%d\n", + s << strprintf("CSmartRewardResultEntry(id=%d, balance=%d, reward=%d\n", GetAddress(), entry.balance, reward); return s.str(); } -arith_uint256 CSmartRewardRoundResult::CalculateScore(const uint256& blockHash) +arith_uint256 CSmartRewardResultEntry::CalculateScore(const uint256& blockHash) { - // Deterministically calculate a "score" for a CSmartRewardRoundResult based on any given (block)hash + // Deterministically calculate a "score" for a CSmartRewardResultEntry based on any given (block)hash // Used to sort the payout list for 1.3 smartreward payouts CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); ss << reward << entry.id << blockHash; diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index ca9b8095..c3de4db2 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -24,16 +24,17 @@ static const int64_t nRewardsMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; class CSmartRewardBlock; class CSmartRewardEntry; class CSmartRewardRound; -class CSmartRewardRoundResult; +class CSmartRewardResultEntry; class CSmartRewardTransaction; +class CSmartRewardsCache; typedef std::vector CSmartRewardBlockList; typedef std::vector CSmartRewardEntryList; typedef std::vector CSmartRewardRoundList; -typedef std::vector CSmartRewardRoundResultList; -typedef std::vector CSmartRewardRoundResultPtrList; -typedef std::vector CSmartRewardTransactionList; +typedef std::vector CSmartRewardResultEntryList; +typedef std::vector CSmartRewardResultEntryPtrList; +typedef std::map CSmartRewardTransactionMap; typedef std::map CSmartRewardEntryMap; class CSmartRewardTransaction @@ -70,19 +71,19 @@ class CSmartRewardBlock public: int nHeight; - uint256 blockHash; - int64_t blockTime; - CSmartRewardBlock(){nHeight = 0; blockHash = uint256(); blockTime = 0;} - CSmartRewardBlock(int height, const uint256* pHash, int64_t time) : nHeight(height), blockHash(*pHash), blockTime(time) {} - CSmartRewardBlock(int height, const uint256 nHash, int64_t time) : nHeight(height), blockHash(nHash), blockTime(time) {} + uint256 nHash; + int64_t nTime; + CSmartRewardBlock() : nHeight(0), nHash(uint256()), nTime(0) {} + CSmartRewardBlock(int nHeight, const uint256* pHash, int64_t nTime) : nHeight(nHeight), nHash(*pHash), nTime(nTime) {} + CSmartRewardBlock(int nHeight, const uint256 nHash, int64_t nTime) : nHeight(nHeight), nHash(nHash), nTime(nTime) {} ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(nHeight); - READWRITE(blockHash); - READWRITE(blockTime); + READWRITE(nHash); + READWRITE(nTime); } friend bool operator==(const CSmartRewardBlock& a, const CSmartRewardBlock& b) @@ -102,7 +103,7 @@ class CSmartRewardBlock std::string ToString() const; - bool IsValid() const { return !blockHash.IsNull(); } + bool IsValid() const { return !nHash.IsNull(); } }; class CSmartRewardRound @@ -220,7 +221,7 @@ class CSmartRewardEntry bool IsEligible(); }; -class CSmartRewardRoundResult +class CSmartRewardResultEntry { public: @@ -236,22 +237,22 @@ class CSmartRewardRoundResult READWRITE(reward); } - CSmartRewardRoundResult(){} + CSmartRewardResultEntry(){} - CSmartRewardRoundResult(CSmartRewardEntry &entry, CAmount nReward) : - entry(entry), reward(nReward){} + CSmartRewardResultEntry(CSmartRewardEntry *entry, CAmount nReward) : + entry(*entry), reward(nReward){} - friend bool operator==(const CSmartRewardRoundResult& a, const CSmartRewardRoundResult& b) + friend bool operator==(const CSmartRewardResultEntry& a, const CSmartRewardResultEntry& b) { return (a.entry.id == b.entry.id); } - friend bool operator!=(const CSmartRewardRoundResult& a, const CSmartRewardRoundResult& b) + friend bool operator!=(const CSmartRewardResultEntry& a, const CSmartRewardResultEntry& b) { return !(a == b); } - friend bool operator<(const CSmartRewardRoundResult& a, const CSmartRewardRoundResult& b) + friend bool operator<(const CSmartRewardResultEntry& a, const CSmartRewardResultEntry& b) { // TBD, verify this sort is fast/unique int cmp = a.entry.id.Compare(b.entry.id); @@ -290,17 +291,16 @@ class CSmartRewardsDB : public CDBWrapper bool ReadCurrentRound(CSmartRewardRound &round); bool ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry); - bool ReadRewardEntries(CSmartRewardEntryList &vect); + bool ReadRewardEntries(CSmartRewardEntryMap &entries); - bool ReadRewardRoundResults(const int16_t round, CSmartRewardRoundResultList &results); - bool ReadRewardPayouts(const int16_t round, CSmartRewardRoundResultList &payouts); - bool ReadRewardPayouts(const int16_t round, CSmartRewardRoundResultPtrList &payouts); + bool ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results); + bool ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); + bool ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); - bool SyncCached(const CSmartRewardRound& current, const CSmartRewardEntryMap &rewards, const CSmartRewardTransactionList &transactions, bool fUndo = false); - bool SyncCached(const CSmartRewardBlock &block, const CSmartRewardRound& current, const CSmartRewardEntryMap &rewards, const CSmartRewardTransactionList &transactions, bool fUndo = false); + bool SyncCached(const CSmartRewardsCache &cache); bool StartFirstRound(const CSmartRewardRound &start, const CSmartRewardEntryList &entries); - bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardRoundResultList &results); - bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRoundResultList &results); + bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results); + bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results); }; diff --git a/src/smartrewards/rewardspayments.cpp b/src/smartrewards/rewardspayments.cpp index cd6e9052..84ac4322 100644 --- a/src/smartrewards/rewardspayments.cpp +++ b/src/smartrewards/rewardspayments.cpp @@ -16,114 +16,28 @@ #include -static std::pair *paymentData = nullptr; - -static void ResetPaymentData() -{ - if( paymentData ){ - - for( CSmartRewardRoundResult* s : paymentData->second ){ - delete s; - } - - delete paymentData; - } - - paymentData = new std::pair(); - paymentData->second.clear(); -} - -struct CompareRewardScore +CSmartRewardResultEntryPtrList SmartRewardPayments::GetPayments(const CSmartRewardsRoundResult *pResult, const int64_t nPayoutDelay, const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result) { - bool operator()(const std::pair& s1, - const std::pair& s2) const - { - return (s1.first != s2.first) ? (s1.first < s2.first) : (s1.second->entry.balance < s2.second->entry.balance); - } -}; - -struct ComparePaymentPrtList -{ - bool operator()(const CSmartRewardRoundResult* p1, - const CSmartRewardRoundResult* p2) const - { - return *p1 < *p2; - } -}; - -CSmartRewardRoundResultPtrList SmartRewardPayments::GetPayments(const CSmartRewardRound &round, const int64_t nPayoutDelay, const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result) -{ - int64_t nPayeeCount = round.eligibleEntries - round.disqualifiedEntries; + int64_t nPayeeCount = pResult->round.eligibleEntries - pResult->round.disqualifiedEntries; // If we have no eligible addresses. Just to make sure...wont happen. if( nPayeeCount <= 0 ){ result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } - int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - - int64_t nBlockPayees = round.nBlockPayees; - int64_t nPayoutInterval = round.nBlockInterval; + int64_t nBlockPayees = pResult->round.nBlockPayees; + int64_t nPayoutInterval = pResult->round.nBlockInterval; int64_t nRewardBlocks = nPayeeCount / nBlockPayees; // If we dont match nRewardsPayoutsPerBlock add one more block for the remaining payments. if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; - int64_t nLastRoundBlock = round.endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); + int64_t nLastRoundBlock = pResult->round.endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); if( nHeight <= nLastRoundBlock && !(( nLastRoundBlock - nHeight ) % nPayoutInterval) ){ // We have a reward block! Now try to create the payments vector. - // Do this stuff only one time and leave it in memory until all blocks are paid - if( !paymentData || paymentData->first != round.number ){ - - ResetPaymentData(); - - if( round.number < nFirst_1_3_Round ){ - - if( !prewards->GetRewardPayouts( round.number, paymentData->second ) || - paymentData->second.size() != static_cast(nPayeeCount) ){ - result = SmartRewardPayments::DatabaseError; - return CSmartRewardRoundResultPtrList(); - } - - // Sort it to make sure the slices are the same network wide. - std::sort(paymentData->second.begin(), paymentData->second.end(), ComparePaymentPrtList() ); - - }else{ - - CSmartRewardRoundResultPtrList roundPayments; - if( !prewards->GetRewardPayouts( round.number, roundPayments ) || - roundPayments.size() != static_cast(nPayeeCount) ){ - result = SmartRewardPayments::DatabaseError; - return CSmartRewardRoundResultPtrList(); - } - - uint256 blockHash; - if(!GetBlockHash(blockHash, round.startBlockHeight)) { - LogPrintf("SmartRewardPayments::GetPayments_1_3 -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", round.startBlockHeight); - result = SmartRewardPayments::CoreError; - return CSmartRewardRoundResultPtrList(); - } - - std::vector> vecScores; - // Since we use payouts stretched out over a week better to have some "random" sort here - // based on a score calculated with the round start's blockhash. - for (auto s : roundPayments) { - arith_uint256 nScore = s->CalculateScore(blockHash); - vecScores.push_back(std::make_pair(nScore,s)); - } - - std::sort(vecScores.begin(), vecScores.end(), CompareRewardScore()); - - for(auto s : vecScores) - paymentData->second.push_back(s.second); - } - // And set the round number the payment data belongs to - paymentData->first = round.number; - } - // Index of the current payout block for this round. int64_t nRewardBlock = nRewardBlocks - ( (nLastRoundBlock - nHeight) / nPayoutInterval ); int64_t nFinalBlockPayees = nBlockPayees; @@ -140,71 +54,67 @@ CSmartRewardRoundResultPtrList SmartRewardPayments::GetPayments(const CSmartRewa // As ennd index we use the startIndex + number of payees for this round. size_t nEndIndex = nStartIndex + nFinalBlockPayees; // If for any reason the calculations end up in an overflow of the vector return an error. - if( nEndIndex > paymentData->second.size() ){ + if( nEndIndex > pResult->payouts.size() ){ // Should not happen! result = SmartRewardPayments::DatabaseError; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } // Finally return the subvector with the payees of this blockHeight! - return CSmartRewardRoundResultPtrList(paymentData->second.begin() + nStartIndex, paymentData->second.begin() + nEndIndex); + return CSmartRewardResultEntryPtrList(pResult->payouts.begin() + nStartIndex, pResult->payouts.begin() + nEndIndex); } // If we arent in any rounds payout range! result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } -CSmartRewardRoundResultPtrList SmartRewardPayments::GetPaymentsForBlock(const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result) +CSmartRewardResultEntryPtrList SmartRewardPayments::GetPaymentsForBlock(const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result) { result = SmartRewardPayments::Valid; if(nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)) { LogPrint("smartrewards", "SmartRewardPayments::GetPaymentsForBlock -- Disabled"); result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } // If we are not yet at the 1.2 payout block time. if( ( MainNet() && nHeight < HF_V1_2_SMARTREWARD_HEIGHT + Params().GetConsensus().nRewardsBlocksPerRound_1_2 ) || ( TestNet() && nHeight < nFirstRoundEndBlock_Testnet ) ){ result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } - CSmartRewardRound round; - - { - LOCK(cs_rewardrounds); - round = prewards->GetLastRound(); - } + const CSmartRewardsRoundResult *pResult = prewards->GetLastRoundResult(); // If there are no rounds yet or the database has an issue. - if( !round.number ){ + if( !pResult ){ result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } // If the requested height is lower then the rounds end step forward to the // next round. int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; - if( nHeight >= ( round.endBlockHeight + nPayoutDelay ) ){ - return SmartRewardPayments::GetPayments( round, nPayoutDelay, nHeight, blockTime, result ); + if( nHeight >= ( pResult->round.endBlockHeight + nPayoutDelay ) ){ + return SmartRewardPayments::GetPayments( pResult, nPayoutDelay, nHeight, blockTime, result ); } // If we arent in any rounds payout range! result = SmartRewardPayments::NoRewardBlock; - return CSmartRewardRoundResultPtrList(); + return CSmartRewardResultEntryPtrList(); } void SmartRewardPayments::FillPayments(CMutableTransaction &coinbaseTx, int nHeight, int64_t prevBlockTime, std::vector& voutSmartRewards) { + LOCK(cs_rewardscache); SmartRewardPayments::Result result; - CSmartRewardRoundResultPtrList rewards = SmartRewardPayments::GetPaymentsForBlock(nHeight, prevBlockTime, result); + CSmartRewardResultEntryPtrList rewards = SmartRewardPayments::GetPaymentsForBlock(nHeight, prevBlockTime, result); // only create rewardblocks if a rewardblock is actually required at the current height. if( result == SmartRewardPayments::Valid && rewards.size() ) { @@ -224,13 +134,15 @@ void SmartRewardPayments::FillPayments(CMutableTransaction &coinbaseTx, int nHei SmartRewardPayments::Result SmartRewardPayments::Validate(const CBlock& block, int nHeight, CAmount &smartReward) { + LOCK(cs_rewardscache); + SmartRewardPayments::Result result; smartReward = 0; const CTransaction &txCoinbase = block.vtx[0]; - CSmartRewardRoundResultPtrList rewards = SmartRewardPayments::GetPaymentsForBlock(nHeight, block.GetBlockTime(), result); + CSmartRewardResultEntryPtrList rewards = SmartRewardPayments::GetPaymentsForBlock(nHeight, block.GetBlockTime(), result); if( result == SmartRewardPayments::Valid && rewards.size() ) { diff --git a/src/smartrewards/rewardspayments.h b/src/smartrewards/rewardspayments.h index bbbbaeb9..70a6c42b 100644 --- a/src/smartrewards/rewardspayments.h +++ b/src/smartrewards/rewardspayments.h @@ -12,6 +12,8 @@ #include "coins.h" #include "base58.h" +struct CSmartRewardsRoundResult; + namespace SmartRewardPayments{ typedef enum{ @@ -23,8 +25,8 @@ typedef enum{ CoreError } Result; -CSmartRewardRoundResultPtrList GetPayments(const CSmartRewardRound &round, const int64_t nPayoutDelay, const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result); -CSmartRewardRoundResultPtrList GetPaymentsForBlock(const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result); +CSmartRewardResultEntryPtrList GetPayments(const CSmartRewardsRoundResult *pResult, const int64_t nPayoutDelay, const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result); +CSmartRewardResultEntryPtrList GetPaymentsForBlock(const int nHeight, int64_t blockTime, SmartRewardPayments::Result &result); SmartRewardPayments::Result Validate(const CBlock& block, const int nHeight, CAmount& smartReward); void FillPayments(CMutableTransaction& txNew, int nHeight, int64_t prevBlockTime, std::vector& voutSmartRewards); diff --git a/src/validation.cpp b/src/validation.cpp index 5bf475f9..e422f583 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1864,8 +1864,6 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // Result of the smartrewards block processing. CSmartRewardsUpdateResult smartRewardsResult(pindex->nHeight, pindex->phashBlock, pindex->nTime); - prewards->StartBlock(); - // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = block.vtx[i]; @@ -2365,8 +2363,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd //bool fDIP0001Active_context = (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0001, versionbitscache) == THRESHOLD_ACTIVE); - prewards->StartBlock(); - for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; @@ -2755,8 +2751,10 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; + // The cache is over the limit, we have to write now. + bool fRewardsNeedsSync = prewards->NeedsCacheWrite(); // Combine all conditions that result in a full cache flush. - bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; + bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune || fRewardsNeedsSync; // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index @@ -2781,6 +2779,9 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { return AbortNode(state, "Files to write to block index database"); } + if (!prewards->SyncCached()) { + return AbortNode(state, "Files to write to block index database"); + } } // Finally remove any pruned files if (fFlushForPrune) From f26387090f7ba65cf0ccc6ee57d1489f34fa6709 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 19 Sep 2019 15:53:09 +0200 Subject: [PATCH 004/126] smartrewards: Estimate the size of the cache properly --- src/smartrewards/rewards.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index f7ebead3..62b5e5b8 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -367,6 +367,8 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) std::sort(rounds.begin(), rounds.end()); cache.Load(block, round, rounds, entries); + + LogPrintf("CSmartRewards::CSmartRewards - Cache Size %d MB", cache.EstimatedSize() / 1000 / 1000); } bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) @@ -1137,7 +1139,11 @@ CSmartRewardsCache::~CSmartRewardsCache() unsigned long CSmartRewardsCache::EstimatedSize() { - return sizeof *this; + unsigned long nEntriesSize = entries.size() * (sizeof(CSmartAddress) + sizeof(CSmartRewardEntry)); + unsigned long nRoundsSize = (rounds.size() + 1) * sizeof(CSmartRewardRound); + unsigned long nTransactionsSize = (addTransactions.size() + removeTransactions.size()) * (sizeof(uint256) + sizeof(CSmartRewardTransaction)); + unsigned long nBlockSize = sizeof(CSmartRewardBlock); + return nEntriesSize + nRoundsSize + nTransactionsSize + nBlockSize; } void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds, const CSmartRewardEntryMap &entries) From 1bdd32eb013a0206061d0a2106e93822db6ec2a4 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 19 Sep 2019 16:58:26 +0200 Subject: [PATCH 005/126] smartrewards: Delete all results entries if they are not longer needed --- src/smartrewards/rewards.cpp | 22 +++++++++++++++++----- src/smartrewards/rewards.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 62b5e5b8..ecc85736 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -1121,11 +1121,7 @@ CSmartRewardsCache::~CSmartRewardsCache() } if( result ){ - for( CSmartRewardResultEntry *resultEntry : result->results ){ - delete resultEntry; - } - - result->results.clear(); + result->Clear(); delete result; } @@ -1188,6 +1184,12 @@ void CSmartRewardsCache::SetCurrentRound(const CSmartRewardRound ¤tRound) void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) { AssertLockHeld(cs_rewardscache); + + if( result ){ + result->Clear(); + delete result; + } + result = pResult; } @@ -1259,3 +1261,13 @@ void CSmartRewardsCache::AddEntry(CSmartRewardEntry *entry) LOCK(cs_rewardscache); entries.insert(std::make_pair(entry->id, entry)); } + +void CSmartRewardsRoundResult::Clear() +{ + for( CSmartRewardResultEntry *resultEntry : results ){ + delete resultEntry; + } + + results.clear(); + payouts.clear(); +} diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 07210fdc..318f6103 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -63,6 +63,8 @@ struct CSmartRewardsRoundResult CSmartRewardResultEntryPtrList payouts; bool fSynced; CSmartRewardsRoundResult(){fSynced = false;} + + void Clear(); }; class CSmartRewardsCache From aea0d18a983bf8b8d8721932bc82e2b658ec800a Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 19 Sep 2019 23:24:02 +0200 Subject: [PATCH 006/126] smartrewards: Made percent calculation 1.2 compatible --- src/smartrewards/rewards.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index ecc85736..04560a15 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -143,10 +143,8 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result while( nStartHeight <= round->endBlockHeight) nRewards += GetBlockValue(nStartHeight++,0,nTime) * 0.15; - CAmount nCalcSmart = round->eligibleSmart - round->disqualifiedSmart; - - if( nCalcSmart ){ - nPercent = double(nRewards) / nCalcSmart; + if( (round->eligibleSmart - round->disqualifiedSmart) > 0 ){ + nPercent = double(nRewards) / (round->eligibleSmart - round->disqualifiedSmart); }else{ nPercent = 0; } From 91644ad679fbed08119c89fcad0eaf28da8f641f Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 20 Sep 2019 18:38:45 +0200 Subject: [PATCH 007/126] smartrewards: Apply the round's update result before reward calculations --- src/smartrewards/rewards.cpp | 13 ++++++++++--- src/smartrewards/rewards.h | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 04560a15..caf96abe 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -135,13 +135,15 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result nBlockInterval = 0; } + cache.ApplyRoundUpdateResult(result); + // Calculate the current rewards percentage int64_t nTime = GetTime(); int64_t nStartHeight = round->startBlockHeight; CAmount nRewards = 0; double nPercent = 0.0; - while( nStartHeight <= round->endBlockHeight) nRewards += GetBlockValue(nStartHeight++,0,nTime) * 0.15; + while( nStartHeight <= round->endBlockHeight) nRewards += GetBlockValue(nStartHeight++, 0, nTime) * 0.15; if( (round->eligibleSmart - round->disqualifiedSmart) > 0 ){ nPercent = double(nRewards) / (round->eligibleSmart - round->disqualifiedSmart); @@ -149,7 +151,7 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result nPercent = 0; } - cache.UpdateRoundParameter(result, nBlockPayees, nBlockInterval, nRewards, nPercent); + cache.UpdateRoundParameter(nBlockPayees, nBlockInterval, nRewards, nPercent); } void CSmartRewards::EvaluateRound(CSmartRewardRound &next) @@ -1191,7 +1193,7 @@ void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) result = pResult; } -void CSmartRewardsCache::UpdateRoundParameter(const CSmartRewardsUpdateResult &result, int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent) +void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result) { AssertLockHeld(cs_rewardscache); @@ -1204,6 +1206,11 @@ void CSmartRewardsCache::UpdateRoundParameter(const CSmartRewardsUpdateResult &r round.eligibleEntries += result.qualifiedEntries; round.eligibleSmart += result.qualifiedSmart; } +} + +void CSmartRewardsCache::UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent) +{ + AssertLockHeld(cs_rewardscache); round.nBlockPayees = nBlockPayees; round.nBlockInterval = nBlockInterval; diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 318f6103..554c7b80 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -96,7 +96,8 @@ class CSmartRewardsCache void SetCurrentRound(const CSmartRewardRound ¤tRound); void SetResult(CSmartRewardsRoundResult *pResult); - void UpdateRoundParameter(const CSmartRewardsUpdateResult &result, int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent); + void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result); + void UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent); void UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime); void UpdateHeights(const int nHeight, const int nRewardHeight); From 767af84b7172b750d9a768b05e3cd7410e534fc5 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 24 Sep 2019 19:35:22 +0200 Subject: [PATCH 008/126] validation: Reduced utxo lookups in ConnectBlock --- src/validation.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index e422f583..6fea1644 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2342,6 +2342,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); std::vector prevheights; + std::vector prevouts; CAmount nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; @@ -2388,8 +2389,11 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd // BIP68 lock checks (as opposed to nLockTime checks) must // be in ConnectBlock because they require the UTXO set prevheights.resize(tx.vin.size()); + prevouts.resize(tx.vin.size()); + for (size_t j = 0; j < tx.vin.size(); j++) { - prevheights[j] = view.AccessCoin(tx.vin[j].prevout).nHeight; + prevouts[j] = view.AccessCoin(tx.vin[j].prevout); + prevheights[j] = prevouts[j].nHeight; } if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { @@ -2401,8 +2405,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd { for (size_t j = 0; j < tx.vin.size(); j++) { const CTxIn input = tx.vin[j]; - const Coin& coin = view.AccessCoin(tx.vin[j].prevout); const CTxOut &prevout = coin.out; + const Coin& coin = prevouts[j]; uint160 hashBytes; int addressType; From 012d60340de6ffbe3d075a0ed32347a04330076c Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 24 Sep 2019 19:37:22 +0200 Subject: [PATCH 009/126] smartrewards: Process transactions in place in ConnectBlock to reduce lookups and only check future transactions in zerocoin part of the chain --- src/smartrewards/rewards.cpp | 106 ++++++++++++++--------------------- src/smartrewards/rewards.h | 14 +++-- src/validation.cpp | 39 +++++++++---- 3 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index caf96abe..fa8ba6d4 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -290,6 +290,7 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *& { LOCK(cs_rewardscache); + int nTime1 = GetTimeMicros(); // Return the entry if its already in cache. auto it = cache.GetEntries()->find(id); @@ -298,12 +299,25 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *& return entry->balance > 0; } + int nTime2 = GetTimeMicros(); + double dFind = (nTime2 - nTime1) * 0.001; + + if(dFind > 10){ + LogPrint("smartrewards-bench", "CSmartRewards::GetRewardEntry - Find: %.2fms", dFind); + } + if( fCreate ){ entry = new CSmartRewardEntry(id); cache.AddEntry(entry); return true; } + int nTime3 = GetTimeMicros(); + double dAdd = (nTime3 - nTime2) * 0.001; + if( dAdd > 10.0 ){ + LogPrint("smartrewards-bench", "CSmartRewards::GetRewardEntry - Add: %.2fsm", dAdd); + } + return false; } @@ -410,13 +424,15 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar int required = ParseScript(in.scriptPubKey ,ids); + int nTime1 = GetTimeMicros(); + if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Inputs: Could't parse CSmartAddress: %s\n",in.ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Could't parse CSmartAddress: %s\n",in.ToString()); return; } if(!GetRewardEntry(ids.at(0), rEntry, false)){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Spend without previous receive - %s", tx.ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Spend without previous receive - %s", tx.ToString()); return; } @@ -456,7 +472,7 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar } if(rEntry->balance <= 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Negative amount?! - %s", rEntry->ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Negative amount?! - %s", rEntry->ToString()); rEntry->balance = 0; } @@ -470,7 +486,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm int required = ParseScript(out.scriptPubKey ,ids); if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::ProcessOutput - Could't parse CSmartAddress: %s\n",out.ToString()); return; }else{ @@ -608,73 +624,32 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm } } -void CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) +bool CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nCurrentRound) { LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - %s", tx.GetHash().ToString()); - int nCurrentRound; - - { - LOCK(cs_rewardscache); - nCurrentRound = cache.GetCurrentRound()->number; - } - int nHeight = pIndex->nHeight; - if(nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ - return; + if(nHeight == 0 || nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + return false; } - int nTime1 = GetTimeMicros(); - CSmartRewardTransaction testTx; - // First check if the transaction hash did already come up in the past. - if( GetTransaction(tx.GetHash(), testTx) ){ - - // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - [%s] Double appearance! First in %d - Now in %d\n", testTx.hash.ToString(), testTx.blockHeight, pIndex->nHeight); - return; - - }else{ - // If not save add it to the cache. - cache.AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); - } - - CSmartAddress *voteProofCheck = nullptr; - CAmount nVoteProofIn = 0; - - // No reason to check the input here for new coins. - if( !tx.IsCoinBase() ){ - - BOOST_FOREACH(const CTxIn &in, tx.vin) { - - if( in.scriptSig.IsZerocoinSpend() ) continue; - - const Coin &coin = coins.AccessCoin(in.prevout); - const CTxOut &rOut = coin.out; - - ProcessInput(tx, rOut, &voteProofCheck, nVoteProofIn, nCurrentRound, result); + // For the first 4 rounds we have zerocoin exploits and we don't want to add them to the rewards db. + if( nCurrentRound < 4 ){ + // First check if the transaction hash did already come up in the past. + if( GetTransaction(tx.GetHash(), testTx) ){ + // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. + LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - [%s] Double appearance! First in %d - Now in %d\n", testTx.hash.ToString(), testTx.blockHeight, pIndex->nHeight); + return false; + }else{ + // If not save add it to the cache. + cache.AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); } } - int nTime2 = GetTimeMicros(); - - BOOST_FOREACH(const CTxOut &out, tx.vout) { - - if(out.scriptPubKey.IsZerocoinMint() ) continue; - - ProcessOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRound, nHeight, result); - } - - int nTime3 = GetTimeMicros(); - int nTimeTx = nTime3 - nTime1; - - if( LogAcceptCategory("smartrewards-tx") ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), nTimeTx * 0.001); - LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime2 - nTime1) * 0.001); - LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime3 - nTime2) * 0.001); - } + return true; } void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) @@ -920,10 +895,10 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, } int nTime3 = GetTimeMicros(); - int nTimeTx = nTime3 - nTime1; + double dProcessingTime = (nTime3 - nTime1) * 0.001; - if( LogAcceptCategory("smartrewards-tx") ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), nTimeTx * 0.001); + if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-tx") ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), dProcessingTime); LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime2 - nTime1) * 0.001); LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime3 - nTime2) * 0.001); } @@ -1018,10 +993,11 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe cache.UpdateHeights(GetBlockHeight(pIndex), cache.GetCurrentBlock()->nHeight); int nTime2 = GetTimeMicros(); + double dProcessingTime = (nTime2 - nTime1) * 0.001; - if( LogAcceptCategory("smartrewards-block") ){ - LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); - LogPrint("smartrewards-block", " Commit block: %.2fms\n", (nTime2 - nTime1) * 0.001); + if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-bench") ){ + LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n",round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-bench", " Commit block: %.2fms\n", dProcessingTime); } // If we are synced notify the UI on each new block. diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 554c7b80..651b259d 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -150,8 +150,15 @@ class CSmartRewards bool Update(CBlockIndex *pindexNew, const CChainParams& chainparams, const int nCurrentRound, CSmartRewardsUpdateResult &result); bool UpdateRound(const CSmartRewardRound &round); - void ProcessTransaction(CBlockIndex* pLastIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result); + void ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + void ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result); + + void UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + void UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + + bool ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nCurrentRound); void UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result); + bool CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); bool CommitUndoBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); @@ -166,12 +173,7 @@ class CSmartRewards const CSmartRewardsRoundResult* GetLastRoundResult(); bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); -private: - void ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); - void ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result); - void UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); - void UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); }; /** Global variable that points to the active rewards object (protected by cs_main) */ diff --git a/src/validation.cpp b/src/validation.cpp index 6fea1644..36109b7b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2371,7 +2371,11 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd std::map, CAmount> vecInputs; std::map, CAmount> vecOutputs; - if( pindex->nHeight > 0 ) prewards->ProcessTransaction(pindex, tx, view, chainparams, smartRewardsResult); + CSmartAddress *voteProofCheck = nullptr; + CAmount nVoteProofIn = 0; + + int nCurrentRewardsRound = prewards->GetCurrentRound()->number; + bool fProcessRewards = prewards->ProcessTransaction(pindex, tx, nCurrentRewardsRound); nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); @@ -2401,12 +2405,18 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd REJECT_INVALID, "bad-txns-nonfinal"); } - if (fAddressIndex || fSpentIndex || fDepositIndex) - { - for (size_t j = 0; j < tx.vin.size(); j++) { - const CTxIn input = tx.vin[j]; - const CTxOut &prevout = coin.out; + for (size_t j = 0; j < tx.vin.size(); j++) { + + const CTxIn input = tx.vin[j]; const Coin& coin = prevouts[j]; + const CTxOut &prevout = coin.out; + + if( fProcessRewards && !input.scriptSig.IsZerocoinSpend() ){ + prewards->ProcessInput(tx, prevout, &voteProofCheck, nVoteProofIn, nCurrentRewardsRound, smartRewardsResult); + } + + if (fAddressIndex || fSpentIndex || fDepositIndex) + { uint160 hashBytes; int addressType; @@ -2478,9 +2488,15 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd control.Add(vChecks); } - if (fAddressIndex || fDepositIndex) { - for (unsigned int k = 0; k < tx.vout.size(); k++) { - const CTxOut &out = tx.vout[k]; + for (unsigned int k = 0; k < tx.vout.size(); k++) { + + const CTxOut &out = tx.vout[k]; + + if( fProcessRewards && !out.scriptPubKey.IsZerocoinMint() ){ + prewards->ProcessOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRewardsRound, pindex->nHeight, smartRewardsResult); + } + + if (fAddressIndex || fDepositIndex) { uint160 hashBytes; int addressType; @@ -2526,7 +2542,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if( fDepositIndex ){ - for( auto const &output : vecOutputs ){ auto input = vecInputs.find(std::make_pair( output.first.first, output.first.second )); @@ -2624,7 +2639,9 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd return false; } - prewards->CommitBlock(pindex, smartRewardsResult); + if( smartRewardsResult.IsValid() ){ + prewards->CommitBlock(pindex, smartRewardsResult); + } // END SMARTCASH From 609ea690c90397c4a71afe25df65e7d12919652e Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 24 Sep 2019 20:31:23 +0200 Subject: [PATCH 010/126] smartrewards: Use synchron levelDB writes when the cache gets synced --- src/smartrewards/rewardsdb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 33bf635a..a5f68e7c 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -156,7 +156,7 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) batch.Write(DB_BLOCK_LAST, *cache.GetCurrentBlock()); batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); - return WriteBatch(batch); + return WriteBatch(batch, true); } bool CSmartRewardsDB::StartFirstRound(const CSmartRewardRound &start, const CSmartRewardEntryList &entries) From 9080a2016be48631bbfab4aca2e5d9b9db53a686 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 25 Sep 2019 10:05:30 +0200 Subject: [PATCH 011/126] smartrewards: Fix the end round for zerocoin exploit transaction checks --- src/smartrewards/rewards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index fa8ba6d4..6a709ec0 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -637,7 +637,7 @@ bool CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& CSmartRewardTransaction testTx; // For the first 4 rounds we have zerocoin exploits and we don't want to add them to the rewards db. - if( nCurrentRound < 4 ){ + if( nCurrentRound <= 4 ){ // First check if the transaction hash did already come up in the past. if( GetTransaction(tx.GetHash(), testTx) ){ // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. From e06b49b56399afe9069144a0028e9c57aa7c3e2b Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 25 Sep 2019 17:14:27 +0200 Subject: [PATCH 012/126] smartrewards: Use flags for the requirements to reduce operations --- src/smartrewards/rewards.cpp | 16 +++++++++++++--- src/smartrewards/rewardsdb.cpp | 14 ++++++++++---- src/smartrewards/rewardsdb.h | 34 ++++++++++++++++++++++++---------- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 6a709ec0..7dc1c078 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -173,7 +173,7 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) if( cache.GetCurrentRound()->number ){ if( cache.GetCurrentRound()->number < nFirst_1_3_Round ){ - nReward = entry->second->balanceEligible > 0 && entry->second->disqualifyingTx.IsNull() ? CAmount(entry->second->balanceEligible * round->percent) : 0; + nReward = entry->second->balanceEligible > 0 && !entry->second->fDisqualifyingTx ? CAmount(entry->second->balanceEligible * round->percent) : 0; }else{ nReward = entry->second->IsEligible() ? CAmount(entry->second->balanceEligible * round->percent) : 0; } @@ -195,10 +195,13 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) // Reset outgoing transaction with every cycle. entry->second->disqualifyingTx.SetNull(); + entry->second->fDisqualifyingTx = false; // Reset SmartNode payment tx with every cycle in case a node was shut down during the cycle. entry->second->smartnodePaymentTx.SetNull(); + entry->second->fSmartnodePaymentTx = false; // Reset the vote proof tx with every cycle to force a new vote for eligibility entry->second->voteProof.SetNull(); + entry->second->fVoteProven = false; if( next.number < nFirst_1_3_Round && entry->second->balanceEligible ){ ++next.eligibleEntries; @@ -451,7 +454,7 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar // balance ineligible. First check if the change is sent back // to the address or not to avoid exploiting fund sending // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && *voteProofCheck == nullptr && rEntry->disqualifyingTx.IsNull() ){ + if( nCurrentRound >= nFirst_1_3_Round && *voteProofCheck == nullptr && !rEntry->fDisqualifyingTx ){ if( rEntry->IsEligible() ){ result.disqualifiedEntries++; @@ -459,10 +462,12 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar } rEntry->disqualifyingTx = tx.GetHash(); + rEntry->fDisqualifyingTx = true; - }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx.IsNull() ){ + }else if( nCurrentRound < nFirst_1_3_Round && !rEntry->fDisqualifyingTx ){ rEntry->disqualifyingTx = tx.GetHash(); + rEntry->fDisqualifyingTx = true; if( rEntry->balanceEligible ){ result.disqualifiedEntries++; @@ -512,6 +517,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm // back to the sender! We don't want to allow // a exploit to send around funds withouht breaking smartrewards. vkEntry->disqualifyingTx = tx.GetHash(); + vkEntry->fDisqualifyingTx = true; }else if( !out.IsVoteProofData() && (*voteProofCheck == rEntry->id) ){ @@ -675,6 +681,7 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t if( nCurrentRound >= nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ rEntry->disqualifyingTx.SetNull(); + rEntry->fDisqualifyingTx = false; if( rEntry->IsEligible() ){ --result.disqualifiedEntries; @@ -684,6 +691,7 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ rEntry->disqualifyingTx.SetNull(); + rEntry->fDisqualifyingTx = false; if( rEntry->balanceEligible ){ --result.disqualifiedEntries; @@ -727,6 +735,8 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart if( vkEntry->disqualifyingTx == tx.GetHash() ){ vkEntry->disqualifyingTx.SetNull(); + vkEntry->fDisqualifyingTx = false; + if( vkEntry->IsEligible() ){ --result.disqualifiedEntries; diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index a5f68e7c..e9703655 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -322,13 +322,19 @@ string CSmartRewardEntry::GetAddress() const return id.ToString(); } -void CSmartRewardEntry::setNull() +void CSmartRewardEntry::SetNull() { + fUpdated = false; id = CSmartAddress(); balance = 0; + balanceAtStart = 0; balanceEligible = 0; + disqualifyingTx.SetNull(); + fDisqualifyingTx = false; smartnodePaymentTx.SetNull(); + fSmartnodePaymentTx = false; voteProof.SetNull(); + fVoteProven = false; } string CSmartRewardEntry::ToString() const @@ -338,14 +344,14 @@ string CSmartRewardEntry::ToString() const GetAddress(), balance, balanceEligible, - !smartnodePaymentTx.IsNull(), - !voteProof.IsNull()); + fSmartnodePaymentTx, + fVoteProven); return s.str(); } bool CSmartRewardEntry::IsEligible() { - return !voteProof.IsNull() && smartnodePaymentTx.IsNull() && balanceEligible > 0 && disqualifyingTx.IsNull(); + return fVoteProven && !fSmartnodePaymentTx && balanceEligible > 0 && !fDisqualifyingTx; } string CSmartRewardBlock::ToString() const diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index c3de4db2..a8784fed 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -172,6 +172,8 @@ class CSmartRewardRound class CSmartRewardEntry { + bool fUpdated; + public: ADD_SERIALIZE_METHODS @@ -183,27 +185,35 @@ class CSmartRewardEntry READWRITE(balanceAtStart); READWRITE(balanceEligible); READWRITE(disqualifyingTx); + READWRITE(fDisqualifyingTx); READWRITE(voteProof); + READWRITE(fVoteProven); READWRITE(smartnodePaymentTx); + READWRITE(fSmartnodePaymentTx); + fUpdated = false; } CSmartAddress id; CAmount balance; CAmount balanceAtStart; CAmount balanceEligible; - CAmount reward; uint256 disqualifyingTx; + bool fDisqualifyingTx; uint256 voteProof; + bool fVoteProven; uint256 smartnodePaymentTx; - - CSmartRewardEntry() : id(CSmartAddress()), - balance(0), balanceAtStart(0), balanceEligible(0), reward(0), - disqualifyingTx(uint256()), voteProof(uint256()), - smartnodePaymentTx(uint256()) {} - CSmartRewardEntry(const CSmartAddress &address) : id(address), - balance(0), balanceAtStart(0), balanceEligible(0), reward(0), - disqualifyingTx(uint256()), voteProof(uint256()), - smartnodePaymentTx(uint256()) {} + bool fSmartnodePaymentTx; + + CSmartRewardEntry() : fUpdated(false), id(CSmartAddress()), + balance(0), balanceAtStart(0), balanceEligible(0), + disqualifyingTx(uint256()), fDisqualifyingTx(false), + voteProof(uint256()), fVoteProven(false), + smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} + CSmartRewardEntry(const CSmartAddress &address) : fUpdated(false), id(address), + balance(0), balanceAtStart(0), balanceEligible(0), + disqualifyingTx(uint256()), fDisqualifyingTx(false), + voteProof(uint256()), fVoteProven(false), + smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} friend bool operator==(const CSmartRewardEntry& a, const CSmartRewardEntry& b) { @@ -215,6 +225,10 @@ class CSmartRewardEntry return !(a == b); } + bool NeedsSync(){ return fUpdated; } + void SetUpdated(){ fUpdated = true; } + void SetSynced(){ fUpdated = false; } + std::string GetAddress() const; void setNull(); std::string ToString() const; From 3ab291a69f4b623dd83ff4656da694abf79aa254 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 26 Sep 2019 09:17:45 +0200 Subject: [PATCH 013/126] smartrewards: Use the smartnode flag instead of tx checks --- src/smartrewards/rewards.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 7dc1c078..c1799f39 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -614,7 +614,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm // If the amount matches and the entry is not yet marked as node do it if( abs(out.nValue - nNodeReward ) < 2 ){ - if( rEntry->smartnodePaymentTx.IsNull() ){ + if( rEntry->fSmartnodePaymentTx ){ // If it is currently eligible adjust the round's results if( rEntry->IsEligible() ){ @@ -623,6 +623,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm } rEntry->smartnodePaymentTx = tx.GetHash(); + rEntry->fSmartnodePaymentTx = true; } } } @@ -820,6 +821,7 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart if( rEntry->smartnodePaymentTx == tx.GetHash() ){ rEntry->smartnodePaymentTx.SetNull(); + rEntry->fSmartnodePaymentTx = false; // If it is eligible now adjust the round's results if( rEntry->IsEligible() ){ From 56a853ff97d2c89c14ffe967fb086a02b7bd0710 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 26 Sep 2019 15:14:11 +0200 Subject: [PATCH 014/126] smartrewards: Caching and performance improved, added -rewardsentrycache --- src/init.cpp | 2 + src/smartrewards/rewards.cpp | 167 +++++++++++++++++++-------------- src/smartrewards/rewards.h | 6 +- src/smartrewards/rewardsdb.cpp | 6 +- src/smartrewards/rewardsdb.h | 15 +-- 5 files changed, 113 insertions(+), 83 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2cc6d746..40e4b52a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1645,6 +1645,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) int64_t nRewardsCache = (GetArg("-rewardsdbcache", nRewardsDefaultDbCache) << 20); LogPrintf("* Using %.1fMiB for smart rewards database\n", nRewardsCache * (1.0 / 1024 / 1024)); + nCacheRewardEntries = GetArg("-rewardsentrycache", REWARDS_CACHE_ENTRIES_DEFAULT); + delete prewards; CSmartRewardsDB *prewardsdb = new CSmartRewardsDB(nRewardsCache, false, false); diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index c1799f39..6f5dec79 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -9,6 +9,7 @@ #include "smarthive/hive.h" #include "smartnode/spork.h" #include "smartnode/smartnodepayments.h" +#include "script/standard.h" #include "rewards.h" #include "ui_interface.h" #include "validation.h" @@ -24,6 +25,8 @@ CSmartRewards *prewards = NULL; CCriticalSection cs_rewardsdb; CCriticalSection cs_rewardscache; +size_t nCacheRewardEntries; + // Used for time conversions. boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); @@ -55,22 +58,34 @@ int GetBlockHeight(const CBlockIndex *index) return syncDiff > 1200 ? firstTxDiff / 55 : index->nHeight; // If we are 20 minutes near now use the current height. } -int ParseScript(const CScript &script, std::vector &ids){ +bool ExtractDestination(const CScript& scriptPubKey, CSmartAddress& idRet) +{ + vector> vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; - std::vector addresses; - txnouttype type; - int nRequired; + if (whichType == TX_PUBKEY) + { + CPubKey pubKey(vSolutions[0]); + if (!pubKey.IsValid()) + return false; - if (!ExtractDestinations(script, type, addresses, nRequired)) { - return 0; + idRet = CSmartAddress(pubKey.GetID()); + return true; } - - BOOST_FOREACH(const CTxDestination &d, addresses) + else if (whichType == TX_PUBKEYHASH) { - ids.push_back(CSmartAddress(d)); + idRet = CSmartAddress(CKeyID(uint160(vSolutions[0]))); + return true; } - - return nRequired; + else if (whichType == TX_SCRIPTHASH) + { + idRet = CSmartAddress(CScriptID(uint160(vSolutions[0]))); + return true; + } + // Multisig txns have more than one address... + return false; } void CalculateRewardRatio() @@ -94,6 +109,8 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result { AssertLockHeld(cs_rewardscache); + cache.ApplyRoundUpdateResult(result); + const CSmartRewardRound *round = cache.GetCurrentRound(); int64_t nBlockPayees = round->nBlockPayees, nBlockInterval = nBlockInterval; @@ -135,23 +152,15 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result nBlockInterval = 0; } - cache.ApplyRoundUpdateResult(result); - - // Calculate the current rewards percentage - int64_t nTime = GetTime(); - int64_t nStartHeight = round->startBlockHeight; - CAmount nRewards = 0; double nPercent = 0.0; - while( nStartHeight <= round->endBlockHeight) nRewards += GetBlockValue(nStartHeight++, 0, nTime) * 0.15; - if( (round->eligibleSmart - round->disqualifiedSmart) > 0 ){ - nPercent = double(nRewards) / (round->eligibleSmart - round->disqualifiedSmart); + nPercent = double(round->rewards) / (round->eligibleSmart - round->disqualifiedSmart); }else{ nPercent = 0; } - cache.UpdateRoundParameter(nBlockPayees, nBlockInterval, nRewards, nPercent); + cache.UpdateRoundParameter(nBlockPayees, nBlockInterval, nPercent); } void CSmartRewards::EvaluateRound(CSmartRewardRound &next) @@ -166,6 +175,20 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) const CSmartRewardRound *round = cache.GetCurrentRound(); pResult->round = *round; + CSmartRewardEntryMap tmpEntries; + pdb->ReadRewardEntries(tmpEntries); + + for( auto itDb = tmpEntries.begin(); itDb != tmpEntries.end(); ++itDb){ + + auto itCache = cache.GetEntries()->find(itDb->first); + + if( itCache == cache.GetEntries()->end() ){ + cache.AddEntry(itDb->second); + }else{ + delete itDb->second; + } + } + auto entry = cache.GetEntries()->begin(); while(entry != cache.GetEntries()->end() ) { @@ -243,6 +266,13 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) } } + // Calculate the current rewards percentage + int64_t nTime = GetTime(); + int64_t nStartHeight = next.startBlockHeight; + next.rewards = 0; + + while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * 0.15; + cache.AddFinishedRound(pResult->round); cache.SetCurrentRound(next); cache.SetResult(pResult); @@ -293,33 +323,28 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *& { LOCK(cs_rewardscache); - int nTime1 = GetTimeMicros(); // Return the entry if its already in cache. auto it = cache.GetEntries()->find(id); if( it != cache.GetEntries()->end() ){ entry = it->second; - return entry->balance > 0; + return true; } - int nTime2 = GetTimeMicros(); - double dFind = (nTime2 - nTime1) * 0.001; + entry = new CSmartRewardEntry(id); - if(dFind > 10){ - LogPrint("smartrewards-bench", "CSmartRewards::GetRewardEntry - Find: %.2fms", dFind); + // Return the entry if its already in db. + if( pdb->ReadRewardEntry(id, *entry) ){ + cache.AddEntry(entry); + return true; } if( fCreate ){ - entry = new CSmartRewardEntry(id); cache.AddEntry(entry); return true; } - int nTime3 = GetTimeMicros(); - double dAdd = (nTime3 - nTime2) * 0.001; - if( dAdd > 10.0 ){ - LogPrint("smartrewards-bench", "CSmartRewards::GetRewardEntry - Add: %.2fsm", dAdd); - } + delete entry; return false; } @@ -334,10 +359,21 @@ bool CSmartRewards::SyncCached() { LOCK2(cs_rewardsdb, cs_rewardscache); + int nTimeStart = GetTimeMicros(); + int nEntriesPre = cache.GetEntries()->size(); + int nSizePre = cache.EstimatedSize(); + bool ret = pdb->SyncCached(cache); cache.Clear(); + int nTimeDone = GetTimeMicros(); + + int nEntriesPost = cache.GetEntries()->size(); + int nSizePost = cache.EstimatedSize(); + + LogPrint("smartrewards-bench", "CSmartRewards::SyncCached size before/after %dMB/%dMB, entries before/after %d/%d, time %.2fms", nSizePre / 1000000, nSizePost / 1000000, nEntriesPre, nEntriesPost, (nTimeDone - nTimeStart) * 0.001); + return ret; } @@ -363,7 +399,6 @@ int CSmartRewards::GetBlocksPerRound(const int nRound) }else{ return chainparams.GetConsensus().nRewardsBlocksPerRound_1_3; } - } CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) @@ -423,18 +458,14 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardEntry *rEntry = nullptr; - std::vector ids; - - int required = ParseScript(in.scriptPubKey ,ids); - - int nTime1 = GetTimeMicros(); + CSmartAddress id; - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Could't parse CSmartAddress: %s\n",in.ToString()); + if(!ExtractDestination(in.scriptPubKey ,id)){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Could't parse CSmartAddress: %s\n", in.ToString()); return; } - if(!GetRewardEntry(ids.at(0), rEntry, false)){ + if(!GetRewardEntry(id, rEntry, false)){ LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Spend without previous receive - %s", tx.ToString()); return; } @@ -476,7 +507,7 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar } - if(rEntry->balance <= 0 ){ + if(rEntry->balance < 0 ){ LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Negative amount?! - %s", rEntry->ToString()); rEntry->balance = 0; } @@ -487,15 +518,14 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardEntry *rEntry = nullptr; - std::vector ids; - int required = ParseScript(out.scriptPubKey ,ids); + CSmartAddress id; - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessOutput - Could't parse CSmartAddress: %s\n",out.ToString()); + if( !ExtractDestination(out.scriptPubKey, id) ){ + LogPrint("smartrewards-tx", "CSmartRewards::ProcessOutput - Could't parse CSmartAddress: %s\n", out.ToString()); return; }else{ - GetRewardEntry(ids.at(0),rEntry, true); + GetRewardEntry(id,rEntry, true); if( voteProofCheck ){ @@ -663,16 +693,14 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardEntry *rEntry = nullptr; - std::vector ids; - - int required = ParseScript(in.scriptPubKey ,ids); + CSmartAddress id; - if( !required || required > 1 || ids.size() > 1 ){ + if( !ExtractDestination(in.scriptPubKey, id) ){ LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Inputs: Could't parse CSmartAddress: %s\n", in.ToString()); return; } - if( !GetRewardEntry(ids.at(0), rEntry, false) ){ + if( !GetRewardEntry(id, rEntry, false) ){ LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); return; } @@ -712,15 +740,14 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart { uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardEntry *rEntry = nullptr; - std::vector ids; - int required = ParseScript(out.scriptPubKey ,ids); + CSmartAddress id; - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Outputs: Could't parse CSmartAddress: %s\n",out.ToString()); + if( !ExtractDestination(out.scriptPubKey, id) ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Outputs: Could't parse CSmartAddress: %s\n", out.ToString()); return; }else{ - GetRewardEntry(ids.at(0),rEntry, true); + GetRewardEntry(id, rEntry, true); if( voteProofCheck ){ @@ -870,17 +897,15 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, const Coin &coin = coins.AccessCoin(tx.vin[0].prevout); const CTxOut &rOut = coin.out; - std::vector ids; - - int required = ParseScript(rOut.scriptPubKey ,ids); + CSmartAddress id; - if( !required || required > 1 || ids.size() > 1 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process VoteProof: Could't parse CSmartAddress: %s\n",rOut.ToString()); + if( !ExtractDestination(rOut.scriptPubKey, id)){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process VoteProof: Could't parse CSmartAddress: %s\n", rOut.ToString()); return; } nVoteProofIn = rOut.nValue; - voteProofCheck = new CSmartAddress(ids[0]); + voteProofCheck = new CSmartAddress(id); } BOOST_REVERSE_FOREACH(const CTxOut &out, tx.vout) { @@ -910,7 +935,7 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, double dProcessingTime = (nTime3 - nTime1) * 0.001; if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-tx") ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - TX %s - %.2fms\n",HexStr(tx.GetHash()), dProcessingTime); + LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - TX %s - %.2fms\n", tx.GetHash().ToString(), dProcessingTime); LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime2 - nTime1) * 0.001); LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime3 - nTime2) * 0.001); } @@ -1008,7 +1033,7 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe double dProcessingTime = (nTime2 - nTime1) * 0.001; if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-bench") ){ - LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n",round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n", round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); LogPrint("smartrewards-bench", " Commit block: %.2fms\n", dProcessingTime); } @@ -1142,7 +1167,7 @@ void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartReward bool CSmartRewardsCache::NeedsSync() { LOCK(cs_rewardscache); - return (result != nullptr && !result->fSynced) || EstimatedSize() > REWARDS_MAX_CACHE; + return (result != nullptr && !result->fSynced) || EstimatedSize() > REWARDS_MAX_CACHE || entries.size() > nCacheRewardEntries; } void CSmartRewardsCache::Clear() @@ -1153,6 +1178,11 @@ void CSmartRewardsCache::Clear() result->fSynced = true; } + for( auto it = entries.cbegin(); it != entries.cend();it++){ + delete it->second; + } + + entries.clear(); addTransactions.clear(); removeTransactions.clear(); } @@ -1196,13 +1226,12 @@ void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult } } -void CSmartRewardsCache::UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent) +void CSmartRewardsCache::UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, double dPercent) { AssertLockHeld(cs_rewardscache); round.nBlockPayees = nBlockPayees; round.nBlockInterval = nBlockInterval; - round.rewards = nRewards; round.percent = dPercent; } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 651b259d..567908a7 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -12,6 +12,8 @@ using namespace std; +#define REWARDS_CACHE_ENTRIES_DEFAULT 50000 + static const CAmount SMART_REWARDS_MIN_BALANCE = 1000 * COIN; // Minimum distance of the last processed block compared to the current chain @@ -43,6 +45,8 @@ CAmount CalculateRewardsForBlockRange(int64_t start, int64_t end); extern CCriticalSection cs_rewardscache; extern CCriticalSection cs_rewardsdb; +extern size_t nCacheRewardEntries; + struct CSmartRewardsUpdateResult { int64_t disqualifiedEntries; @@ -97,7 +101,7 @@ class CSmartRewardsCache void SetResult(CSmartRewardsRoundResult *pResult); void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result); - void UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, CAmount nRewards, double dPercent); + void UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, double dPercent); void UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime); void UpdateHeights(const int nHeight, const int nRewardHeight); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index e9703655..00d8928b 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -154,7 +154,10 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) } batch.Write(DB_BLOCK_LAST, *cache.GetCurrentBlock()); - batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); + + if( cache.GetCurrentRound()->number ){ + batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); + } return WriteBatch(batch, true); } @@ -324,7 +327,6 @@ string CSmartRewardEntry::GetAddress() const void CSmartRewardEntry::SetNull() { - fUpdated = false; id = CSmartAddress(); balance = 0; balanceAtStart = 0; diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index a8784fed..599b3e12 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -103,7 +103,7 @@ class CSmartRewardBlock std::string ToString() const; - bool IsValid() const { return !nHash.IsNull(); } + bool IsValid() const { return nHeight > 0; } }; class CSmartRewardRound @@ -172,8 +172,6 @@ class CSmartRewardRound class CSmartRewardEntry { - bool fUpdated; - public: ADD_SERIALIZE_METHODS @@ -190,7 +188,6 @@ class CSmartRewardEntry READWRITE(fVoteProven); READWRITE(smartnodePaymentTx); READWRITE(fSmartnodePaymentTx); - fUpdated = false; } CSmartAddress id; @@ -204,12 +201,12 @@ class CSmartRewardEntry uint256 smartnodePaymentTx; bool fSmartnodePaymentTx; - CSmartRewardEntry() : fUpdated(false), id(CSmartAddress()), + CSmartRewardEntry() : id(CSmartAddress()), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), voteProof(uint256()), fVoteProven(false), smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} - CSmartRewardEntry(const CSmartAddress &address) : fUpdated(false), id(address), + CSmartRewardEntry(const CSmartAddress &address) : id(address), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), voteProof(uint256()), fVoteProven(false), @@ -225,12 +222,8 @@ class CSmartRewardEntry return !(a == b); } - bool NeedsSync(){ return fUpdated; } - void SetUpdated(){ fUpdated = true; } - void SetSynced(){ fUpdated = false; } - std::string GetAddress() const; - void setNull(); + void SetNull(); std::string ToString() const; bool IsEligible(); }; From abb08850114d0776d7563ae3c41a549017100984 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 26 Sep 2019 16:50:01 +0200 Subject: [PATCH 015/126] consensus: Adjusted 1.3 height --- src/consensus/consensus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index ee5cecc0..920529c3 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT = 1200000; // TBD - set the right height before release +static const int HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT = 1400000; // TBD - set the right height before release /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; From 501415b684697e56c5d0d0a1ce4bf67f35e35494 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 14:09:38 +0200 Subject: [PATCH 016/126] smartrewards: Fixed the vote proof flag check and set the flag properly --- src/smartrewards/rewards.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 6f5dec79..62b079cb 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -607,10 +607,11 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm } } - if( proofEntry->voteProof.IsNull() ){ + if( !proofEntry->fVoteProven ){ if( nProofRound == nCurrentRound ){ proofEntry->voteProof = tx.GetHash(); + proofEntry->fVoteProven = true; } // If the entry is eligible now after the vote proof update the results From bb6e24512ed819bde8a96df5ac40527e98207616 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 14:10:10 +0200 Subject: [PATCH 017/126] smartrewards: Fixed the smartnode payment flag check --- src/smartrewards/rewards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 62b079cb..22238097 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -645,7 +645,7 @@ void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSm // If the amount matches and the entry is not yet marked as node do it if( abs(out.nValue - nNodeReward ) < 2 ){ - if( rEntry->fSmartnodePaymentTx ){ + if( !rEntry->fSmartnodePaymentTx ){ // If it is currently eligible adjust the round's results if( rEntry->IsEligible() ){ From c6a2c266bb38a0cb41df443d304a01c5b315fd65 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 14:12:48 +0200 Subject: [PATCH 018/126] smartrewards: Store the finished rounds in the database --- src/smartrewards/rewardsdb.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 00d8928b..efc69031 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -153,6 +153,13 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) ++removeTx; } + auto round = cache.GetRounds()->begin(); + + while( round != cache.GetRounds()->end() ){ + batch.Write(make_pair(DB_ROUND, round->number), *round); + ++round; + } + batch.Write(DB_BLOCK_LAST, *cache.GetCurrentBlock()); if( cache.GetCurrentRound()->number ){ From 68e8c214ca1aa47fb12ecc29a6177e7a3773a9b3 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 14:14:13 +0200 Subject: [PATCH 019/126] smartrewards: Updated cache loading on startup --- src/smartrewards/rewards.cpp | 9 +++------ src/smartrewards/rewards.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 22238097..f83a70e6 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -408,19 +408,18 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) CSmartRewardBlock block; CSmartRewardRound round; CSmartRewardRoundList rounds; - CSmartRewardEntryMap entries; CSmartRewardResultEntryList results; pdb->ReadLastBlock(block); pdb->ReadCurrentRound(round); pdb->ReadRounds(rounds); - pdb->ReadRewardEntries(entries); std::sort(rounds.begin(), rounds.end()); + cache.Load(block, round, rounds); - cache.Load(block, round, rounds, entries); LogPrintf("CSmartRewards::CSmartRewards - Cache Size %d MB", cache.EstimatedSize() / 1000 / 1000); + LogPrintf("CSmartRewards::CSmartRewards\n Last block %s\n Current Round %s\n Rounds: %d", block.ToString(), round.ToString(), rounds.size()); } bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) @@ -1156,13 +1155,11 @@ unsigned long CSmartRewardsCache::EstimatedSize() return nEntriesSize + nRoundsSize + nTransactionsSize + nBlockSize; } -void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds, const CSmartRewardEntryMap &entries) +void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds) { this->block = block; this->round = round; this->rounds = rounds; - this->entries = entries; -// this->payouts = payouts; } bool CSmartRewardsCache::NeedsSync() diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 567908a7..a4f26814 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -91,7 +91,7 @@ class CSmartRewardsCache unsigned long EstimatedSize(); - void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds, const CSmartRewardEntryMap &entries); + void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds); bool NeedsSync(); void Clear(); From 052d55503d0a1eaec13e722cde6e3da9e0fecd97 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 16:24:26 +0200 Subject: [PATCH 020/126] smartrewards: Store the payout parameter in the rounds object --- src/smartrewards/rewards.cpp | 2 ++ src/smartrewards/rewardsdb.cpp | 14 ++++++++++++++ src/smartrewards/rewardsdb.h | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index f83a70e6..b0ab3472 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -174,6 +174,7 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) CAmount nReward; const CSmartRewardRound *round = cache.GetCurrentRound(); pResult->round = *round; + pResult->round.UpdatePayoutParameter(); CSmartRewardEntryMap tmpEntries; pdb->ReadRewardEntries(tmpEntries); @@ -1250,6 +1251,7 @@ void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound &round) { AssertLockHeld(cs_rewardscache); rounds.push_back(round); + rounds.back().UpdatePayoutParameter(); } void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction &transaction) diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index efc69031..ef5621ea 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -373,6 +373,20 @@ string CSmartRewardBlock::ToString() const return s.str(); } +void CSmartRewardRound::UpdatePayoutParameter() +{ + nPayeeCount = eligibleEntries - disqualifiedEntries; + + if( nPayeeCount > 0 ){ + int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; + + nRewardBlocks = nPayeeCount / nBlockPayees; + if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; + + nLastRoundBlock = endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nBlockInterval ); + } +} + string CSmartRewardRound::ToString() const { std::stringstream s; diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index 599b3e12..53e2c393 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -108,6 +108,12 @@ class CSmartRewardBlock class CSmartRewardRound { + + /* Memory only */ + int nPayeeCount; + int nRewardBlocks; + int nLastRoundBlock; + public: uint16_t number; int64_t startBlockHeight; @@ -140,6 +146,9 @@ class CSmartRewardRound nBlockInterval = 0; rewards = 0; percent = 0; + nPayeeCount = 0; + nRewardBlocks = 0; + nLastRoundBlock = 0; } ADD_SERIALIZE_METHODS @@ -159,6 +168,9 @@ class CSmartRewardRound READWRITE(nBlockInterval); READWRITE(rewards); READWRITE(percent); + + if( ser_action.ForRead()) + UpdatePayoutParameter(); } friend bool operator<(const CSmartRewardRound& a, const CSmartRewardRound& b) @@ -166,6 +178,12 @@ class CSmartRewardRound return a.number < b.number; } + void UpdatePayoutParameter(); + + int GetPayeeCount() const { return nPayeeCount; } + int GetRewardBlocks() const { return nRewardBlocks; } + int GetLastRoundBlock() const { return nLastRoundBlock; } + std::string ToString() const; }; From 6e7b3a07d543cbfced892edd901393ddef66a6bf Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 16:40:26 +0200 Subject: [PATCH 021/126] rpc: Use the payout parameter of the round instead of calculations --- src/rpc/smartrewards.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index aa16b32d..7d46c01a 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -116,22 +116,14 @@ UniValue smartrewards(const UniValue& params, bool fHelp) UniValue payObj(UniValue::VOBJ); - int nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; - - if( nPayeeCount ){ - - int nBlockPayees = round->nBlockPayees; - int nPayoutInterval = round->nBlockInterval; - int nRewardBlocks = nPayeeCount / nBlockPayees; - if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; - int nLastRoundBlock = round->endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); + if( round->GetPayeeCount() ){ payObj.pushKV("firstBlock", round->endBlockHeight + nPayoutDelay ); - payObj.pushKV("totalBlocks", nRewardBlocks ); - payObj.pushKV("lastBlock", nLastRoundBlock ); - payObj.pushKV("totalPayees", nPayeeCount); + payObj.pushKV("totalBlocks", round->GetRewardBlocks() ); + payObj.pushKV("lastBlock", round->GetLastRoundBlock() ); + payObj.pushKV("totalPayees", round->GetPayeeCount() ); payObj.pushKV("blockPayees", round->nBlockPayees); - payObj.pushKV("lastBlockPayees", nPayeeCount % nBlockPayees ); + payObj.pushKV("lastBlockPayees", round->GetPayeeCount() % round->nBlockPayees ); payObj.pushKV("blockInterval",round->nBlockInterval); }else{ payObj.pushKV("error", "No payees were eligible for this round"); From dd538d2b78f7cc4b9402970664f07a73791ed0d2 Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 16:42:03 +0200 Subject: [PATCH 022/126] smartrewards: Clear payout information if all rewardblocks are validated --- src/smartrewards/rewards.cpp | 25 +++++++++++++++++++++++++ src/smartrewards/rewards.h | 1 + 2 files changed, 26 insertions(+) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index b0ab3472..c616c8d0 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -959,6 +959,12 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe return false; } + if( cache.GetLastRoundResult() && + cache.GetLastRoundResult()->fSynced && + pIndex->nHeight > cache.GetLastRoundResult()->round.GetLastRoundBlock() ){ + cache.ClearResult(); + } + UpdateRoundParameter(result); // For the first round we have special parameter.. @@ -1186,6 +1192,25 @@ void CSmartRewardsCache::Clear() removeTransactions.clear(); } +void CSmartRewardsCache::ClearResult() +{ + if( result ){ + + auto it = result->results.begin(); + + while( it != result->results.end() ){ + + delete *it; + ++it; + } + + result->results.clear(); + result->payouts.clear(); + delete result; + result = nullptr; + } +} + void CSmartRewardsCache::SetCurrentBlock(const CSmartRewardBlock ¤tBlock) { AssertLockHeld(cs_rewardscache); diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index a4f26814..3f2076db 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -95,6 +95,7 @@ class CSmartRewardsCache bool NeedsSync(); void Clear(); + void ClearResult(); void SetCurrentBlock(const CSmartRewardBlock ¤tBlock); void SetCurrentRound(const CSmartRewardRound ¤tRound); From 5268f58e78c6cc966311b42b72d17eab425cc05f Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 27 Sep 2019 16:43:23 +0200 Subject: [PATCH 023/126] smartrewards: Sync the round results to the database --- src/smartrewards/rewardsdb.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index ef5621ea..81c90f8f 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -166,6 +166,13 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); } + if( cache.GetLastRoundResult() != nullptr && !cache.GetLastRoundResult()->fSynced ){ + + BOOST_FOREACH(const CSmartRewardResultEntry *s, cache.GetLastRoundResult()->results) { + batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetCurrentRound()->number, s->entry.id)), *s); + } + } + return WriteBatch(batch, true); } From 3cd1454d3bbb2017bb5262ce0257b0630bfabb7b Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 30 Sep 2019 11:12:03 +0200 Subject: [PATCH 024/126] smartrewards: Write the round results with the correct round number --- src/smartrewards/rewardsdb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 81c90f8f..e37e03df 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -169,7 +169,7 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) if( cache.GetLastRoundResult() != nullptr && !cache.GetLastRoundResult()->fSynced ){ BOOST_FOREACH(const CSmartRewardResultEntry *s, cache.GetLastRoundResult()->results) { - batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetCurrentRound()->number, s->entry.id)), *s); + batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetLastRoundResult()->round.number, s->entry.id)), *s); } } From 010338c29105831f7f022d8245a625ba4ea790f1 Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 30 Sep 2019 19:33:37 +0200 Subject: [PATCH 025/126] smartrewards: Store the round history in a map --- src/rpc/smartrewards.cpp | 40 +++++++++++++++++----------------- src/sapi/sapi_smartrewards.cpp | 38 ++++++++++++++++---------------- src/smartrewards/rewards.cpp | 10 ++++----- src/smartrewards/rewards.h | 8 +++---- src/smartrewards/rewardsdb.cpp | 8 +++---- src/smartrewards/rewardsdb.h | 4 ++-- 6 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index 7d46c01a..b0071c3b 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -90,7 +90,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) if(!cacheLocked) throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is busy..Try it again!"); - const CSmartRewardRoundList* history = prewards->GetRewardRounds(); + const CSmartRewardRoundMap* history = prewards->GetRewardRounds(); int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; @@ -102,29 +102,29 @@ UniValue smartrewards(const UniValue& params, bool fHelp) UniValue roundObj(UniValue::VOBJ); - roundObj.pushKV("rewards_cycle",round->number); - roundObj.pushKV("start_blockheight",round->startBlockHeight); - roundObj.pushKV("start_blocktime",round->startBlockTime); - roundObj.pushKV("end_blockheight",round->endBlockHeight); - roundObj.pushKV("end_blocktime",round->endBlockTime); - roundObj.pushKV("eligible_addresses",round->eligibleEntries - round->disqualifiedEntries); - roundObj.pushKV("eligible_smart",format(round->eligibleSmart - round->disqualifiedSmart)); - roundObj.pushKV("disqualified_addresses",round->disqualifiedEntries); - roundObj.pushKV("disqualified_smart",format(round->disqualifiedSmart)); - roundObj.pushKV("rewards",format(round->rewards)); - roundObj.pushKV("percent",round->percent); + roundObj.pushKV("rewards_cycle",round->second.number); + roundObj.pushKV("start_blockheight",round->second.startBlockHeight); + roundObj.pushKV("start_blocktime",round->second.startBlockTime); + roundObj.pushKV("end_blockheight",round->second.endBlockHeight); + roundObj.pushKV("end_blocktime",round->second.endBlockTime); + roundObj.pushKV("eligible_addresses",round->second.eligibleEntries - round->second.disqualifiedEntries); + roundObj.pushKV("eligible_smart",format(round->second.eligibleSmart - round->second.disqualifiedSmart)); + roundObj.pushKV("disqualified_addresses",round->second.disqualifiedEntries); + roundObj.pushKV("disqualified_smart",format(round->second.disqualifiedSmart)); + roundObj.pushKV("rewards",format(round->second.rewards)); + roundObj.pushKV("percent",round->second.percent); UniValue payObj(UniValue::VOBJ); - if( round->GetPayeeCount() ){ + if( round->second.GetPayeeCount() ){ - payObj.pushKV("firstBlock", round->endBlockHeight + nPayoutDelay ); - payObj.pushKV("totalBlocks", round->GetRewardBlocks() ); - payObj.pushKV("lastBlock", round->GetLastRoundBlock() ); - payObj.pushKV("totalPayees", round->GetPayeeCount() ); - payObj.pushKV("blockPayees", round->nBlockPayees); - payObj.pushKV("lastBlockPayees", round->GetPayeeCount() % round->nBlockPayees ); - payObj.pushKV("blockInterval",round->nBlockInterval); + payObj.pushKV("firstBlock", round->second.endBlockHeight + nPayoutDelay ); + payObj.pushKV("totalBlocks", round->second.GetRewardBlocks() ); + payObj.pushKV("lastBlock", round->second.GetLastRoundBlock() ); + payObj.pushKV("totalPayees", round->second.GetPayeeCount() ); + payObj.pushKV("blockPayees", round->second.nBlockPayees); + payObj.pushKV("lastBlockPayees", round->second.GetPayeeCount() % round->second.nBlockPayees ); + payObj.pushKV("blockInterval", round->second.nBlockInterval); }else{ payObj.pushKV("error", "No payees were eligible for this round"); } diff --git a/src/sapi/sapi_smartrewards.cpp b/src/sapi/sapi_smartrewards.cpp index 2c674ec8..f0a20eac 100644 --- a/src/sapi/sapi_smartrewards.cpp +++ b/src/sapi/sapi_smartrewards.cpp @@ -146,7 +146,7 @@ static bool smartrewards_history(HTTPRequest* req, const std::mapGetRewardRounds(); + const CSmartRewardRoundMap* history = prewards->GetRewardRounds(); int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; @@ -158,34 +158,34 @@ static bool smartrewards_history(HTTPRequest* req, const std::mapnumber); - roundObj.pushKV("start_blockheight",round->startBlockHeight); - roundObj.pushKV("start_blocktime",round->startBlockTime); - roundObj.pushKV("end_blockheight",round->endBlockHeight); - roundObj.pushKV("end_blocktime",round->endBlockTime); - roundObj.pushKV("eligible_addresses",round->eligibleEntries - round->disqualifiedEntries); - roundObj.pushKV("eligible_smart",UniValueFromAmount(round->eligibleSmart - round->disqualifiedSmart)); - roundObj.pushKV("disqualified_addresses",round->disqualifiedEntries); - roundObj.pushKV("disqualified_smart",UniValueFromAmount(round->disqualifiedSmart)); - roundObj.pushKV("rewards",UniValueFromAmount(round->rewards)); - roundObj.pushKV("percent",round->percent); + roundObj.pushKV("rewards_cycle",round->second.number); + roundObj.pushKV("start_blockheight",round->second.startBlockHeight); + roundObj.pushKV("start_blocktime",round->second.startBlockTime); + roundObj.pushKV("end_blockheight",round->second.endBlockHeight); + roundObj.pushKV("end_blocktime",round->second.endBlockTime); + roundObj.pushKV("eligible_addresses",round->second.eligibleEntries - round->second.disqualifiedEntries); + roundObj.pushKV("eligible_smart",UniValueFromAmount(round->second.eligibleSmart - round->second.disqualifiedSmart)); + roundObj.pushKV("disqualified_addresses",round->second.disqualifiedEntries); + roundObj.pushKV("disqualified_smart",UniValueFromAmount(round->second.disqualifiedSmart)); + roundObj.pushKV("rewards",UniValueFromAmount(round->second.rewards)); + roundObj.pushKV("percent",round->second.percent); UniValue payObj(UniValue::VOBJ); - int nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; - int nBlockPayees = round->nBlockPayees; - int nPayoutInterval = round->nBlockInterval; + int nPayeeCount = round->second.eligibleEntries - round->second.disqualifiedEntries; + int nBlockPayees = round->second.nBlockPayees; + int nPayoutInterval = round->second.nBlockInterval; int nRewardBlocks = nPayeeCount / nBlockPayees; if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; - int nLastRoundBlock = round->endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); + int nLastRoundBlock = round->second.endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nPayoutInterval ); - payObj.pushKV("firstBlock", round->endBlockHeight + nPayoutDelay ); + payObj.pushKV("firstBlock", round->second.endBlockHeight + nPayoutDelay ); payObj.pushKV("totalBlocks", nRewardBlocks ); payObj.pushKV("lastBlock", nLastRoundBlock ); payObj.pushKV("totalPayees", nPayeeCount); - payObj.pushKV("blockPayees", round->nBlockPayees); + payObj.pushKV("blockPayees", round->second.nBlockPayees); payObj.pushKV("lastBlockPayees", nPayeeCount % nBlockPayees ); - payObj.pushKV("blockInterval",round->nBlockInterval); + payObj.pushKV("blockInterval",round->second.nBlockInterval); roundObj.pushKV("payouts", payObj); diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index c616c8d0..a942720b 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -408,14 +408,13 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) CSmartRewardBlock block; CSmartRewardRound round; - CSmartRewardRoundList rounds; + CSmartRewardRoundMap rounds; CSmartRewardResultEntryList results; pdb->ReadLastBlock(block); pdb->ReadCurrentRound(round); pdb->ReadRounds(rounds); - std::sort(rounds.begin(), rounds.end()); cache.Load(block, round, rounds); @@ -449,7 +448,7 @@ const CSmartRewardRound* CSmartRewards::GetCurrentRound() return cache.GetCurrentRound(); } -const CSmartRewardRoundList* CSmartRewards::GetRewardRounds() +const CSmartRewardRoundMap* CSmartRewards::GetRewardRounds() { return cache.GetRounds(); } @@ -1162,7 +1161,7 @@ unsigned long CSmartRewardsCache::EstimatedSize() return nEntriesSize + nRoundsSize + nTransactionsSize + nBlockSize; } -void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds) +void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundMap &rounds) { this->block = block; this->round = round; @@ -1275,8 +1274,7 @@ void CSmartRewardsCache::UpdateHeights(const int nHeight, const int nRewardHeigh void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound &round) { AssertLockHeld(cs_rewardscache); - rounds.push_back(round); - rounds.back().UpdatePayoutParameter(); + rounds[round.number] = round; } void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction &transaction) diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 3f2076db..ee1e50ae 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -78,7 +78,7 @@ class CSmartRewardsCache CSmartRewardBlock block; CSmartRewardRound round; - CSmartRewardRoundList rounds; + CSmartRewardRoundMap rounds; CSmartRewardTransactionMap addTransactions; CSmartRewardTransactionMap removeTransactions; CSmartRewardEntryMap entries; @@ -91,7 +91,7 @@ class CSmartRewardsCache unsigned long EstimatedSize(); - void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundList &rounds); + void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundMap &rounds); bool NeedsSync(); void Clear(); @@ -108,7 +108,7 @@ class CSmartRewardsCache const CSmartRewardBlock* GetCurrentBlock() const { return █ } const CSmartRewardRound* GetCurrentRound() const { return &round; } - const CSmartRewardRoundList* GetRounds() const { return &rounds; } + const CSmartRewardRoundMap* GetRounds() const { return &rounds; } const CSmartRewardTransactionMap* GetAddedTransactions() const { return &addTransactions; } const CSmartRewardTransactionMap* GetRemovedTransactions() const { return &removeTransactions; } const CSmartRewardEntryMap* GetEntries() const { return &entries; } @@ -141,7 +141,7 @@ class CSmartRewards bool GetLastBlock(CSmartRewardBlock &block); bool GetTransaction(const uint256 hash, CSmartRewardTransaction &transaction); const CSmartRewardRound* GetCurrentRound(); - const CSmartRewardRoundList* GetRewardRounds(); + const CSmartRewardRoundMap* GetRewardRounds(); void UpdateHeights(const int nHeight, const int nRewardHeight); bool Verify(); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index e37e03df..aeb6ba83 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -87,7 +87,7 @@ bool CSmartRewardsDB::ReadRound(const int16_t number, CSmartRewardRound &round) return Read(make_pair(DB_ROUND,number), round); } -bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundList &vect) +bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundMap &rounds) { boost::scoped_ptr pcursor(NewIterator()); @@ -95,11 +95,11 @@ bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundList &vect) while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair key; + std::pair key; if (pcursor->GetKey(key) && key.first == DB_ROUND) { CSmartRewardRound nValue; if (pcursor->GetValue(nValue)) { - vect.push_back(nValue); + rounds.insert(make_pair(nValue.number, nValue)); pcursor->Next(); } else { return error("failed to get reward round"); @@ -156,7 +156,7 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) auto round = cache.GetRounds()->begin(); while( round != cache.GetRounds()->end() ){ - batch.Write(make_pair(DB_ROUND, round->number), *round); + batch.Write(make_pair(DB_ROUND, round->first), round->second); ++round; } diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index 53e2c393..e4ab90bd 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -30,7 +30,7 @@ class CSmartRewardsCache; typedef std::vector CSmartRewardBlockList; typedef std::vector CSmartRewardEntryList; -typedef std::vector CSmartRewardRoundList; +typedef std::map CSmartRewardRoundMap; typedef std::vector CSmartRewardResultEntryList; typedef std::vector CSmartRewardResultEntryPtrList; @@ -311,7 +311,7 @@ class CSmartRewardsDB : public CDBWrapper bool ReadTransaction(const uint256 hash, CSmartRewardTransaction &transaction); bool ReadRound(const int16_t number, CSmartRewardRound &round); - bool ReadRounds(CSmartRewardRoundList &vect); + bool ReadRounds(CSmartRewardRoundMap &rounds); bool ReadCurrentRound(CSmartRewardRound &round); From 4a014ed97e40ced2619c380bbba593eae3f9c92a Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 30 Sep 2019 19:33:47 +0200 Subject: [PATCH 026/126] smartrewards: Fixed undo transaction --- src/smartrewards/rewards.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index a942720b..f3797385 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -881,11 +881,12 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nTime1 = GetTimeMicros(); + CSmartRewardTransaction testTx; if( GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight ){ cache.RemoveTransaction(testTx); - }else{ + }else if( nCurrentRound <= 4 ){ return; } From 218f55de642f742cd75024ad4dd4019c9111247c Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 1 Oct 2019 14:00:16 +0200 Subject: [PATCH 027/126] smartrewards: Improved parameter updates --- src/smartrewards/rewards.cpp | 106 ++++++++++++++++++--------------- src/smartrewards/rewards.h | 6 +- src/smartrewards/rewardsdb.cpp | 74 +++++++++-------------- src/smartrewards/rewardsdb.h | 2 +- 4 files changed, 91 insertions(+), 97 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index f3797385..27d4610e 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -88,11 +88,6 @@ bool ExtractDestination(const CScript& scriptPubKey, CSmartAddress& idRet) return false; } -void CalculateRewardRatio() -{ - -} - bool CSmartRewards::Verify() { LOCK(cs_rewardsdb); @@ -105,14 +100,12 @@ bool CSmartRewards::NeedsCacheWrite() return cache.NeedsSync(); } -void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result) +void CSmartRewards::UpdateRoundPayoutParameter() { AssertLockHeld(cs_rewardscache); - cache.ApplyRoundUpdateResult(result); - const CSmartRewardRound *round = cache.GetCurrentRound(); - int64_t nBlockPayees = round->nBlockPayees, nBlockInterval = nBlockInterval; + int64_t nBlockPayees = round->nBlockPayees, nBlockInterval; int64_t nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; @@ -152,6 +145,15 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result nBlockInterval = 0; } + cache.UpdateRoundPayoutParameter(nBlockPayees, nBlockInterval); +} + +void CSmartRewards::UpdatePercentage() +{ + AssertLockHeld(cs_rewardscache); + + const CSmartRewardRound *round = cache.GetCurrentRound(); + double nPercent = 0.0; if( (round->eligibleSmart - round->disqualifiedSmart) > 0 ){ @@ -160,22 +162,25 @@ void CSmartRewards::UpdateRoundParameter(const CSmartRewardsUpdateResult &result nPercent = 0; } - cache.UpdateRoundParameter(nBlockPayees, nBlockInterval, nPercent); + cache.UpdateRoundPercent(nPercent); } void CSmartRewards::EvaluateRound(CSmartRewardRound &next) { LOCK(cs_rewardscache); + UpdateRoundPayoutParameter(); + + const CSmartRewardRound *round = cache.GetCurrentRound(); + int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); - CAmount nReward; - const CSmartRewardRound *round = cache.GetCurrentRound(); pResult->round = *round; pResult->round.UpdatePayoutParameter(); + CAmount nReward; CSmartRewardEntryMap tmpEntries; pdb->ReadRewardEntries(tmpEntries); @@ -235,7 +240,7 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) ++entry; } - if( !pResult->payouts.size() ){ + if( pResult->payouts.size() ){ if( round->number < nFirst_1_3_Round ){ // Sort it to make sure the slices are the same network wide. @@ -274,27 +279,12 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * 0.15; - cache.AddFinishedRound(pResult->round); - cache.SetCurrentRound(next); - cache.SetResult(pResult); -} - -bool CSmartRewards::StartFirstRound(const CSmartRewardRound &first, const CSmartRewardEntryList &entries) -{ - LOCK(cs_rewardsdb); - return pdb->StartFirstRound(first,entries); -} - -bool CSmartRewards::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results) -{ - LOCK(cs_rewardsdb); - return pdb->FinalizeRound(current, next, entries, results); -} + if( pResult->round.number ){ + cache.AddFinishedRound(pResult->round); + } -bool CSmartRewards::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results) -{ - LOCK(cs_rewardsdb); - return pdb->UndoFinalizeRound(current, results); + cache.SetResult(pResult); + cache.SetCurrentRound(next); } bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results) @@ -417,8 +407,20 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) cache.Load(block, round, rounds); + CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); + + if( round.number > 1 ){ + pdb->ReadRewardRoundResults(round.number - 1, pResult->results); + + for( auto it : pResult->results ){ + if( it->reward ){ + pResult->payouts.push_back(it); + } + } + } + + cache.SetResult(pResult); - LogPrintf("CSmartRewards::CSmartRewards - Cache Size %d MB", cache.EstimatedSize() / 1000 / 1000); LogPrintf("CSmartRewards::CSmartRewards\n Last block %s\n Current Round %s\n Rounds: %d", block.ToString(), round.ToString(), rounds.size()); } @@ -965,7 +967,7 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe cache.ClearResult(); } - UpdateRoundParameter(result); + cache.ApplyRoundUpdateResult(result); // For the first round we have special parameter.. if( !round->number ){ @@ -992,6 +994,8 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe if( ( MainNet() && round->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() > round->endBlockTime ) || ( ( TestNet() || round->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == round->endBlockHeight ) ){ + UpdatePercentage(); + cache.UpdateRoundEnd(pIndex->nHeight, pIndex->GetBlockTime()); // Create the next round. @@ -1029,19 +1033,17 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe // Evaluate the round and update the next rounds parameter. EvaluateRound(next); - } - UpdateRoundParameter(CSmartRewardsUpdateResult()); + UpdatePercentage(); cache.UpdateHeights(GetBlockHeight(pIndex), cache.GetCurrentBlock()->nHeight); - int nTime2 = GetTimeMicros(); - double dProcessingTime = (nTime2 - nTime1) * 0.001; - - if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-bench") ){ - LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n", round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); - LogPrint("smartrewards-bench", " Commit block: %.2fms\n", dProcessingTime); + if( LogAcceptCategory("smartrewards-bench") ){ + int nTime2 = GetTimeMicros(); + double dProcessingTime = (nTime2 - nTime1) * 0.001; + LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n", round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-bench", " Commit block: %.2fms\n", dProcessingTime); } // If we are synced notify the UI on each new block. @@ -1055,7 +1057,6 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpdateResult &result) { - int nTime1 = GetTimeMicros(); if(pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ return true; @@ -1063,13 +1064,13 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda LOCK(cs_rewardscache); - const CSmartRewardRound *round = cache.GetCurrentRound(); - if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight ){ LogPrintf("CSmartRewards::CommitUndoBlock - Invalid next block!"); return false; } + const CSmartRewardRound *pRound = cache.GetCurrentRound(); + CSmartRewardsUpdateResult undoResult(pIndex->pprev->nHeight, pIndex->pprev->phashBlock, pIndex->pprev->GetBlockTime()); undoResult.disqualifiedEntries = result.disqualifiedEntries; @@ -1250,24 +1251,33 @@ void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult } } -void CSmartRewardsCache::UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, double dPercent) +void CSmartRewardsCache::UpdateRoundPayoutParameter(int64_t nBlockPayees, int64_t nBlockInterval) { AssertLockHeld(cs_rewardscache); round.nBlockPayees = nBlockPayees; round.nBlockInterval = nBlockInterval; - round.percent = dPercent; } void CSmartRewardsCache::UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime) { + AssertLockHeld(cs_rewardscache); + round.endBlockHeight = nBlockHeight; round.endBlockTime = nBlockTime; } +void CSmartRewardsCache::UpdateRoundPercent(double dPercent) +{ + AssertLockHeld(cs_rewardscache); + + round.percent = dPercent; +} + void CSmartRewardsCache::UpdateHeights(const int nHeight, const int nRewardHeight) { AssertLockHeld(cs_rewardscache); + chainHeight = nHeight; rewardHeight = nRewardHeight; } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index ee1e50ae..dc1e1600 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -102,8 +102,9 @@ class CSmartRewardsCache void SetResult(CSmartRewardsRoundResult *pResult); void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result); - void UpdateRoundParameter(int64_t nBlockPayees, int64_t nBlockInterval, double dPercent); + void UpdateRoundPayoutParameter(int64_t nBlockPayees, int64_t nBlockInterval); void UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime); + void UpdateRoundPercent(double dPercent); void UpdateHeights(const int nHeight, const int nRewardHeight); const CSmartRewardBlock* GetCurrentBlock() const { return █ } @@ -127,7 +128,8 @@ class CSmartRewards mutable CCriticalSection csRounds; - void UpdateRoundParameter(const CSmartRewardsUpdateResult &result); + void UpdateRoundPayoutParameter(); + void UpdatePercentage(); bool ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry); bool GetRewardEntries(CSmartRewardEntryMap &entries); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index aeb6ba83..2702e3d6 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -176,52 +176,6 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) return WriteBatch(batch, true); } -bool CSmartRewardsDB::StartFirstRound(const CSmartRewardRound &start, const CSmartRewardEntryList &entries) -{ - CDBBatch batch(*this); - - BOOST_FOREACH(const CSmartRewardEntry &e, entries) { - batch.Write(make_pair(DB_REWARD_ENTRY,e.id), e); - } - - batch.Write(DB_ROUND_CURRENT, start); - - return WriteBatch(batch); -} - -bool CSmartRewardsDB::FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results) -{ - CDBBatch batch(*this); - - BOOST_FOREACH(const CSmartRewardResultEntry &s, results) { - batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(current.number, s.entry.id)), s); - } - - BOOST_FOREACH(const CSmartRewardEntry &e, entries) { - batch.Write(make_pair(DB_REWARD_ENTRY,e.id), e); - } - - batch.Write(make_pair(DB_ROUND,current.number), current); - batch.Write(DB_ROUND_CURRENT, next); - - return WriteBatch(batch); -} - -bool CSmartRewardsDB::UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results) -{ - CDBBatch batch(*this); - - BOOST_FOREACH(const CSmartRewardResultEntry &s, results) { - batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(current.number, s.entry.id))); - batch.Write(make_pair(DB_REWARD_ENTRY,s.entry.id), s.entry); - } - - batch.Erase(make_pair(DB_ROUND, current.number)); - batch.Write(DB_ROUND_CURRENT, current); - - return WriteBatch(batch); -} - bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryMap &entries) { boost::scoped_ptr pcursor(NewIterator()); @@ -275,6 +229,34 @@ bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRe return true; } +bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results) { + + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT,round)); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair> key; + if (pcursor->GetKey(key) && key.first == DB_ROUND_SNAPSHOT) { + + if( key.second.first != round ) break; + + CSmartRewardResultEntry nValue; + if (pcursor->GetValue(nValue)) { + results.push_back(new CSmartRewardResultEntry(nValue)); + pcursor->Next(); + } else { + return error("failed to get reward entry"); + } + } else { + break; + } + } + + return true; +} + bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts) { boost::scoped_ptr pcursor(NewIterator()); diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index e4ab90bd..4e6885d5 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -319,11 +319,11 @@ class CSmartRewardsDB : public CDBWrapper bool ReadRewardEntries(CSmartRewardEntryMap &entries); bool ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results); + bool ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results); bool ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); bool ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); bool SyncCached(const CSmartRewardsCache &cache); - bool StartFirstRound(const CSmartRewardRound &start, const CSmartRewardEntryList &entries); bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results); bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results); }; From 8297bd3e305cf23414c020646f6b1bc876bd3f0f Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 1 Oct 2019 23:01:56 +0200 Subject: [PATCH 028/126] smartrewards: Fixed block undo --- src/smartrewards/rewards.cpp | 157 ++++++++++++++++++++++----------- src/smartrewards/rewards.h | 7 +- src/smartrewards/rewardsdb.cpp | 56 ++++++++++-- 3 files changed, 158 insertions(+), 62 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 27d4610e..6d4a6bcc 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -293,6 +293,12 @@ bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResul return pdb->ReadRewardRoundResults(round, results); } +bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results) +{ + LOCK(cs_rewardsdb); + return pdb->ReadRewardRoundResults(round, results); +} + const CSmartRewardsRoundResult *CSmartRewards::GetLastRoundResult() { return cache.GetLastRoundResult(); @@ -348,7 +354,7 @@ bool CSmartRewards::GetRewardEntries(CSmartRewardEntryMap &entries) bool CSmartRewards::SyncCached() { - LOCK2(cs_rewardsdb, cs_rewardscache); + LOCK2(cs_rewardscache, cs_rewardsdb); int nTimeStart = GetTimeMicros(); int nEntriesPre = cache.GetEntries()->size(); @@ -394,7 +400,7 @@ int CSmartRewards::GetBlocksPerRound(const int nRound) CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) { - LOCK2(cs_rewardsdb, cs_rewardscache); + LOCK2(cs_rewardscache, cs_rewardsdb); CSmartRewardBlock block; CSmartRewardRound round; @@ -433,7 +439,7 @@ bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) bool CSmartRewards::GetTransaction(const uint256 nHash, CSmartRewardTransaction &transaction) { - LOCK2(cs_rewardsdb, cs_rewardscache); + LOCK2(cs_rewardscache, cs_rewardsdb); // If the transaction is already in the cache use this one. auto it = cache.GetAddedTransactions()->find(nHash); @@ -698,12 +704,12 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t CSmartAddress id; if( !ExtractDestination(in.scriptPubKey, id) ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Inputs: Could't parse CSmartAddress: %s\n", in.ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Process Inputs: Could't parse CSmartAddress: %s\n", in.ToString()); return; } - if( !GetRewardEntry(id, rEntry, false) ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Spend without previous receive - %s", tx.ToString()); + if( !GetRewardEntry(id, rEntry, true) ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Spend without previous receive - %s", tx.ToString()); return; } @@ -732,7 +738,7 @@ void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t } if(rEntry->balance < 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Negative amount?! - %s", rEntry->ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Negative amount?! - %s", rEntry->ToString()); rEntry->balance = 0; } @@ -745,7 +751,7 @@ void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmart CSmartAddress id; if( !ExtractDestination(out.scriptPubKey, id) ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process Outputs: Could't parse CSmartAddress: %s\n", out.ToString()); + LogPrint("smartrewards-tx", "CSmartRewards::UndoOutput - Process Outputs: Could't parse CSmartAddress: %s\n", out.ToString()); return; }else{ @@ -1057,12 +1063,13 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpdateResult &result) { + int nTime1 = GetTimeMicros(); if(pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ return true; } - LOCK(cs_rewardscache); + LOCK2(cs_rewardscache, cs_rewardsdb); if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight ){ LogPrintf("CSmartRewards::CommitUndoBlock - Invalid next block!"); @@ -1071,64 +1078,62 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda const CSmartRewardRound *pRound = cache.GetCurrentRound(); - CSmartRewardsUpdateResult undoResult(pIndex->pprev->nHeight, pIndex->pprev->phashBlock, pIndex->pprev->GetBlockTime()); + CSmartRewardsUpdateResult undoUpdate(pIndex->pprev->nHeight, pIndex->pprev->phashBlock, pIndex->pprev->GetBlockTime()); - undoResult.disqualifiedEntries = result.disqualifiedEntries; - undoResult.disqualifiedSmart = result.disqualifiedSmart; - undoResult.qualifiedEntries = result.qualifiedEntries; - undoResult.qualifiedSmart = result.qualifiedSmart; + undoUpdate.disqualifiedEntries = result.disqualifiedEntries; + undoUpdate.disqualifiedSmart = result.disqualifiedSmart; + undoUpdate.qualifiedEntries = result.qualifiedEntries; + undoUpdate.qualifiedSmart = result.qualifiedSmart; - UpdateRoundParameter(undoResult); + cache.ApplyRoundUpdateResult(undoUpdate); -// // If just hit the last round's threshold -// if( ( MainNet() && currentRound.number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < currentRound.endBlockTime ) || -// ( ( TestNet() || currentRound.number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == currentRound.startBlockHeight ) ){ + // If just hit the last round's threshold + if( ( MainNet() && pRound->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < pRound->endBlockTime ) || + ( ( TestNet() || pRound->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == pRound->startBlockHeight ) ){ -// LOCK2(cs_rewardsdb, cs_rewardrounds); + // Recover the last round from the history as current round + CSmartRewardRound prevRound = cache.GetRounds()->at(pRound->number - 1); -// // Recover the last round from the history as current round -// currentRound = finishedRounds.back(); -// finishedRounds.pop_back(); + cache.SetCurrentRound(prevRound); + cache.RemoveFinishedRound(prevRound.number); -// lastRound = finishedRounds.back(); + CSmartRewardsRoundResult *undoResult = new CSmartRewardsRoundResult(); -// CSmartRewardEntryList entries; -// CSmartRewardResultEntryList results; + undoResult->round = prevRound; -// // Get the current entries -// if( !GetRewardRoundResults(currentRound.number, results) ){ -// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to read last round's results!"); -// return false; -// } + if( !GetRewardRoundResults(prevRound.number, undoResult->results) ){ + LogPrintf("CSmartRewards::CommitUndoBlock - Failed to read last round's results!"); + return false; + } -// CalculateRewardRatio(currentRound); + cache.SetUndoResult(undoResult); -// if( !UndoFinalizeRound(currentRound, results) ){ -// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to finalize round!"); -// return false; -// } + // Load all entries into the cache + CSmartRewardEntryMap tmpEntries; + pdb->ReadRewardEntries(tmpEntries); -// } + for( auto itDb = tmpEntries.begin(); itDb != tmpEntries.end(); ++itDb){ -// if(!SyncCached(true)){ -// LogPrintf("CSmartRewards::CommitUndoBlock - Failed to sync cached - Processed!"); -// return false; -// } + auto itCache = cache.GetEntries()->find(itDb->first); + + if( itCache == cache.GetEntries()->end() ){ + cache.AddEntry(itDb->second); + }else{ + delete itDb->second; + } + } + } -// cache.UpdateHeights(GetBlockHeight(pIndex), currentBlock.nHeight); + UpdatePercentage(); -// int nTime2 = GetTimeMicros(); + cache.UpdateHeights(GetBlockHeight(pIndex), cache.GetCurrentBlock()->nHeight); -// if( LogAcceptCategory("smartrewards-block") ){ -// LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",currentRound.number, currentBlock.nHeight, int(prewards->GetProgress() * 100)); -// LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); -// } + int nTime2 = GetTimeMicros(); -// // If we are synced notify the UI on each new block. -// // If not notify the UI every nRewardsUISyncUpdateRate blocks to let it update the -// // loading screen. -// if( IsSynced() || !(currentBlock.nHeight % nRewardsUISyncUpdateRate) ) -// uiInterface.NotifySmartRewardUpdate(); + if( LogAcceptCategory("smartrewards-block") ){ + LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",pRound->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); + } return true; } @@ -1173,7 +1178,9 @@ void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartReward bool CSmartRewardsCache::NeedsSync() { LOCK(cs_rewardscache); - return (result != nullptr && !result->fSynced) || EstimatedSize() > REWARDS_MAX_CACHE || entries.size() > nCacheRewardEntries; + return (result != nullptr && !result->fSynced) || + (undoResults != nullptr && !undoResults->fSynced) || + EstimatedSize() > REWARDS_MAX_CACHE || entries.size() > nCacheRewardEntries; } void CSmartRewardsCache::Clear() @@ -1184,6 +1191,10 @@ void CSmartRewardsCache::Clear() result->fSynced = true; } + if( undoResults ){ + undoResults->fSynced = true; + } + for( auto it = entries.cbegin(); it != entries.cend();it++){ delete it->second; } @@ -1210,6 +1221,22 @@ void CSmartRewardsCache::ClearResult() delete result; result = nullptr; } + + if( undoResults ){ + + auto it = undoResults->results.begin(); + + while( it != undoResults->results.end() ){ + + delete *it; + ++it; + } + + undoResults->results.clear(); + undoResults->payouts.clear(); + delete undoResults; + undoResults = nullptr; + } } void CSmartRewardsCache::SetCurrentBlock(const CSmartRewardBlock ¤tBlock) @@ -1236,6 +1263,18 @@ void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) result = pResult; } +void CSmartRewardsCache::SetUndoResult(CSmartRewardsRoundResult *pResult) +{ + AssertLockHeld(cs_rewardscache); + + if( undoResults ){ + undoResults->Clear(); + delete undoResults; + } + + undoResults = pResult; +} + void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result) { AssertLockHeld(cs_rewardscache); @@ -1285,9 +1324,21 @@ void CSmartRewardsCache::UpdateHeights(const int nHeight, const int nRewardHeigh void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound &round) { AssertLockHeld(cs_rewardscache); + rounds[round.number] = round; } +void CSmartRewardsCache::RemoveFinishedRound(const int &nNumber) +{ + AssertLockHeld(cs_rewardscache); + + auto it = rounds.find(nNumber); + + if( it != rounds.end() ){ + rounds.erase(it); + } +} + void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction &transaction) { LOCK(cs_rewardscache); @@ -1315,7 +1366,7 @@ void CSmartRewardsCache::RemoveTransaction(const CSmartRewardTransaction &transa void CSmartRewardsCache::AddEntry(CSmartRewardEntry *entry) { LOCK(cs_rewardscache); - entries.insert(std::make_pair(entry->id, entry)); + entries[entry->id] = entry; } void CSmartRewardsRoundResult::Clear() diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index dc1e1600..ac2b86d0 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -83,10 +83,11 @@ class CSmartRewardsCache CSmartRewardTransactionMap removeTransactions; CSmartRewardEntryMap entries; CSmartRewardsRoundResult *result; + CSmartRewardsRoundResult *undoResults; public: - CSmartRewardsCache() : block(), round(), rounds(), addTransactions(), removeTransactions(), entries(), result(nullptr) { } + CSmartRewardsCache() : block(), round(), rounds(), addTransactions(), removeTransactions(), entries(), result(nullptr), undoResults(nullptr) { } ~CSmartRewardsCache(); unsigned long EstimatedSize(); @@ -100,6 +101,7 @@ class CSmartRewardsCache void SetCurrentBlock(const CSmartRewardBlock ¤tBlock); void SetCurrentRound(const CSmartRewardRound ¤tRound); void SetResult(CSmartRewardsRoundResult *pResult); + void SetUndoResult(CSmartRewardsRoundResult *pResult); void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result); void UpdateRoundPayoutParameter(int64_t nBlockPayees, int64_t nBlockInterval); @@ -114,8 +116,10 @@ class CSmartRewardsCache const CSmartRewardTransactionMap* GetRemovedTransactions() const { return &removeTransactions; } const CSmartRewardEntryMap* GetEntries() const { return &entries; } const CSmartRewardsRoundResult* GetLastRoundResult() const { return result; } + const CSmartRewardsRoundResult* GetUndoResult() const { return undoResults; } void AddFinishedRound(const CSmartRewardRound &round); + void RemoveFinishedRound(const int &nNumber); void AddTransaction(const CSmartRewardTransaction &transaction); void RemoveTransaction(const CSmartRewardTransaction &transaction); void AddEntry(CSmartRewardEntry *entry); @@ -177,6 +181,7 @@ class CSmartRewards bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results); bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results); + bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results); const CSmartRewardsRoundResult* GetLastRoundResult(); bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 2702e3d6..55e398f0 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -126,17 +126,57 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) { CDBBatch batch(*this); - auto entry = cache.GetEntries()->begin(); + if( cache.GetUndoResult() != nullptr && !cache.GetUndoResult()->fSynced ){ - while( entry != cache.GetEntries()->end() ){ + CSmartRewardResultEntryPtrList tmpResults = cache.GetUndoResult()->results; - if( entry->second->balance <= 0 ){ - batch.Erase(make_pair(DB_REWARD_ENTRY,entry->first)); - }else{ - batch.Write(make_pair(DB_REWARD_ENTRY,entry->first), *entry->second); + auto entry = cache.GetEntries()->begin(); + + while( entry != cache.GetEntries()->end() ){ + + CSmartAddress searchAddress = entry->second->id; + + auto it = std::find_if(tmpResults.begin(), + tmpResults.end(), + [searchAddress](const CSmartRewardResultEntry* rEntry) -> bool { + return rEntry->entry.id == searchAddress; + }); + + if( it == tmpResults.end() ){ + batch.Erase(make_pair(DB_REWARD_ENTRY, entry->first)); + }else{ + CSmartRewardEntry rewardEntry = (*it)->entry; + batch.Write(make_pair(DB_REWARD_ENTRY, rewardEntry.id), rewardEntry); + batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetUndoResult()->round.number, rewardEntry.id))); + tmpResults.erase(it); + } + + ++entry; + } + + auto it = tmpResults.begin(); + + while( it != tmpResults.end() ){ + batch.Write(make_pair(DB_REWARD_ENTRY,(*it)->entry.id), (*it)->entry); + batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetUndoResult()->round.number, (*it)->entry.id))); + + ++it; } - ++entry; + }else{ + + auto entry = cache.GetEntries()->begin(); + + while( entry != cache.GetEntries()->end() ){ + + if( entry->second->balance <= 0 ){ + batch.Erase(make_pair(DB_REWARD_ENTRY,entry->first)); + }else{ + batch.Write(make_pair(DB_REWARD_ENTRY,entry->first), *entry->second); + } + + ++entry; + } } auto addTx = cache.GetAddedTransactions()->begin(); @@ -366,7 +406,7 @@ void CSmartRewardRound::UpdatePayoutParameter() { nPayeeCount = eligibleEntries - disqualifiedEntries; - if( nPayeeCount > 0 ){ + if( nPayeeCount > 0 && nBlockPayees > 0){ int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; nRewardBlocks = nPayeeCount / nBlockPayees; From d2c9f06ab3d0c9b1e4f5b59b18413a8619ce0919 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 2 Oct 2019 09:34:01 +0200 Subject: [PATCH 029/126] smartrewards: Properly set the last rounds result on startup --- src/smartrewards/rewards.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 6d4a6bcc..576805a2 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -416,6 +416,8 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); if( round.number > 1 ){ + pResult->fSynced = true; + pResult->round = rounds[round.number - 1]; pdb->ReadRewardRoundResults(round.number - 1, pResult->results); for( auto it : pResult->results ){ From e5af94862af3ca8fd5b5806564944dba506fe70d Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 2 Oct 2019 09:37:23 +0200 Subject: [PATCH 030/126] validation: Ignore index/smartrewards during db verification on startup --- src/validation.cpp | 50 ++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 36109b7b..de93b7a5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1829,7 +1829,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out) /** Undo the effects of this block (with given index) on the UTXO set represented by coins. * When UNCLEAN or FAILED is returned, view is left in an indeterminate state. */ -static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view) +static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool fIsVerifyDB = false) { assert(pindex->GetBlockHash() == view.GetBestBlock()); @@ -2066,14 +2066,16 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // At this point, all of txundo.vprevout should have been moved out. } - prewards->UndoTransaction((CBlockIndex*) pindex, tx, view, params, smartRewardsResult); + if( !fIsVerifyDB ){ + prewards->UndoTransaction((CBlockIndex*) pindex, tx, view, params, smartRewardsResult); + } } // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); - if (fDepositIndex) { + if (!fIsVerifyDB && fDepositIndex) { if( !pblocktree->EraseDepositIndex(depositIndex) ){ AbortNode(state, "Failed to write deposit index"); @@ -2081,7 +2083,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s } } - if (fAddressIndex) { + if (!fIsVerifyDB && fAddressIndex) { if (!pblocktree->EraseAddressIndex(addressIndex)) { AbortNode(state, "Failed to delete address index"); return DISCONNECT_FAILED; @@ -2092,7 +2094,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s } } - if( !prewards->CommitUndoBlock( (CBlockIndex*) pindex, smartRewardsResult) ){ + if( !fIsVerifyDB && !prewards->CommitUndoBlock( (CBlockIndex*) pindex, smartRewardsResult) ){ AbortNode(state, "Failed to commit smartrewards block undo"); return DISCONNECT_FAILED; } @@ -2109,7 +2111,6 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s } */ - return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; } @@ -2220,7 +2221,7 @@ static int64_t nTimeTotal = 0; /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() * can fail if those validity checks fail (among other reasons). */ -static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck = false) +static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck = false, bool fIsVerifyDB = false) { const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); @@ -2375,7 +2376,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd CAmount nVoteProofIn = 0; int nCurrentRewardsRound = prewards->GetCurrentRound()->number; - bool fProcessRewards = prewards->ProcessTransaction(pindex, tx, nCurrentRewardsRound); + bool fProcessRewards = !fIsVerifyDB && prewards->ProcessTransaction(pindex, tx, nCurrentRewardsRound); nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); @@ -2639,10 +2640,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd return false; } - if( smartRewardsResult.IsValid() ){ - prewards->CommitBlock(pindex, smartRewardsResult); - } - // END SMARTCASH if (!control.Wait()) @@ -2653,6 +2650,10 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd if (fJustCheck) return true; + if( !fIsVerifyDB && smartRewardsResult.IsValid() ){ + prewards->CommitBlock(pindex, smartRewardsResult); + } + // Write undo information to disk if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) { @@ -2672,11 +2673,11 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd setDirtyBlockIndex.insert(pindex); } - if (fTxIndex) + if (!fIsVerifyDB && fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); - if (fAddressIndex) { + if (!fIsVerifyDB && fAddressIndex) { if (!pblocktree->WriteAddressIndex(addressIndex)) { return AbortNode(state, "Failed to write address index"); } @@ -2686,15 +2687,15 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd } } - if (fSpentIndex) + if (!fIsVerifyDB && fSpentIndex) if (!pblocktree->UpdateSpentIndex(spentIndex)) - return AbortNode(state, "Failed to write transaction index"); + return AbortNode(state, "Failed to write spent index"); - if (fTimestampIndex) + if (!fIsVerifyDB && fTimestampIndex) if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(pindex->nTime, pindex->GetBlockHash()))) return AbortNode(state, "Failed to write timestamp index"); - if (fDepositIndex) { + if (!fIsVerifyDB && fDepositIndex) { if( !pblocktree->WriteDepositIndex(depositIndex) ){ return AbortNode(state, "Failed to write deposit index"); @@ -2988,7 +2989,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - bool rv = ConnectBlock(*pblock, state, pindexNew, view); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, false); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) @@ -3969,7 +3970,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha int nHeight = pindex->nHeight; if(!newHash && ((nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT && Params().NetworkIDString() == CBaseChainParams::MAIN) || (nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT_TESTNET && Params().NetworkIDString() == CBaseChainParams::TESTNET))){ - newHash = true; +// newHash = true; } // Write block to history file @@ -4053,7 +4054,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, return false; if (!ContextualCheckBlock(block, state, pindexPrev)) return false; - if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) + if (!ConnectBlock(block, state, &indexDummy, viewNew, true, true)) return false; assert(state.IsValid()); @@ -4386,7 +4387,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nHeight = pindex->nHeight; if(!newHash && ((nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT && Params().NetworkIDString() == CBaseChainParams::MAIN) || (nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT_TESTNET && Params().NetworkIDString() == CBaseChainParams::TESTNET))){ - newHash = true; +// newHash = true; } if (pindex->nHeight < chainActive.Height()-nCheckDepth) @@ -4409,10 +4410,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, } // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { - DisconnectResult res = DisconnectBlock(block, state, pindex, coins); + DisconnectResult res = DisconnectBlock(block, state, pindex, coins, true); if (res == DISCONNECT_FAILED) { return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } + pindexState = pindex->pprev; if (res == DISCONNECT_UNCLEAN) { nGoodTransactions = 0; @@ -4437,7 +4439,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins, false, true)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } From 5a16e7c8fa13a3f4a1d15b02b0b0d276248ab486 Mon Sep 17 00:00:00 2001 From: dustinface Date: Sat, 12 Oct 2019 16:09:42 +0200 Subject: [PATCH 031/126] smartrewards/validation: Fixed null pointer crash when generating blocks --- src/smartrewards/rewards.h | 5 +++++ src/validation.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index ac2b86d0..35e177f2 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -56,6 +56,11 @@ struct CSmartRewardsUpdateResult CSmartRewardBlock block; CSmartRewardsUpdateResult() : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() {} CSmartRewardsUpdateResult(const int nHeight, const uint256* pBlockHash, const int64_t nBlockTime) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block(nHeight, pBlockHash, nBlockTime) { } + CSmartRewardsUpdateResult(const CBlockIndex* pIndex) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() { + if( pIndex && pIndex->phashBlock ){ + block = CSmartRewardBlock(pIndex->nHeight, pIndex->phashBlock, pIndex->nTime); + } + } bool IsValid() const { return block.IsValid(); } }; diff --git a/src/validation.cpp b/src/validation.cpp index de93b7a5..548380b7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1862,7 +1862,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s */ // Result of the smartrewards block processing. - CSmartRewardsUpdateResult smartRewardsResult(pindex->nHeight, pindex->phashBlock, pindex->nTime); + CSmartRewardsUpdateResult smartRewardsResult(pindex); // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { @@ -2361,7 +2361,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd */ // Result of the smartrewards block processing. - CSmartRewardsUpdateResult smartRewardsResult(pindex->nHeight, pindex->phashBlock, pindex->nTime); + CSmartRewardsUpdateResult smartRewardsResult(pindex); //bool fDIP0001Active_context = (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0001, versionbitscache) == THRESHOLD_ACTIVE); From 7784644e48536363a4957ee29c1e0b6ac0ac6158 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 15 Oct 2019 11:33:47 +0200 Subject: [PATCH 032/126] validation: Removed newhash checks --- src/validation.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 548380b7..2d0bc7bb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3969,9 +3969,6 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha } int nHeight = pindex->nHeight; - if(!newHash && ((nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT && Params().NetworkIDString() == CBaseChainParams::MAIN) || (nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT_TESTNET && Params().NetworkIDString() == CBaseChainParams::TESTNET))){ -// newHash = true; - } // Write block to history file try { @@ -4385,11 +4382,6 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, boost::this_thread::interruption_point(); uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); - int nHeight = pindex->nHeight; - if(!newHash && ((nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT && Params().NetworkIDString() == CBaseChainParams::MAIN) || (nHeight > HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT_TESTNET && Params().NetworkIDString() == CBaseChainParams::TESTNET))){ -// newHash = true; - } - if (pindex->nHeight < chainActive.Height()-nCheckDepth) break; CBlock block; From aefd0eb9a0b5fd5c0a6f45c61f36e59e6f2f6c3c Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 15 Oct 2019 11:33:56 +0200 Subject: [PATCH 033/126] hash: Removed new hash format --- src/hash.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/hash.h b/src/hash.h index ad363ca3..9d617176 100644 --- a/src/hash.h +++ b/src/hash.h @@ -19,7 +19,6 @@ #include typedef uint256 ChainCode; -static bool newHash = false; /** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */ class CHash256 { @@ -163,7 +162,6 @@ class CHashWriter { private: SHA256_CTX ctx; - CHash256 ctxNew; public: int nType; @@ -184,15 +182,9 @@ class CHashWriter // invalidates the object uint256 GetHash() { - if(newHash){ - uint256 result; - ctxNew.Finalize((unsigned char*)&result); - return result; - }else{ uint256 hash1; SHA256_Final((unsigned char*)&hash1, &ctx); return hash1; - } } arith_uint256 GetArith256Hash() { From 3fd18fdc4d02f8f0b8a01a231f62b0cd06b2663d Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 15 Oct 2019 11:34:04 +0200 Subject: [PATCH 034/126] consensus: Removed 1.3 fork constant --- src/consensus/consensus.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 920529c3..0e6042ea 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,6 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT = 1400000; // TBD - set the right height before release /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; @@ -45,7 +44,6 @@ static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 = 1001; // 28500; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 = 1002; // 30300; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3 = 1003; // 75000; static const int TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 1004; // 415000; -static const int HF_V1_3_SMARTREWARD_WITHOUT_NODE_HEIGHT_TESTNET = 35000; /** Testnet payment intervals*/ static const int TESTNET_V1_2_NODES_PER_BLOCK_1 = 3; From 69306cb5fc9e9db6f30b3d5b0bf4cca5150a968f Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 16 Oct 2019 14:18:46 +0200 Subject: [PATCH 035/126] Removed some zerocoin checks --- src/script/ismine.cpp | 1 - src/script/sign.cpp | 2 -- src/script/standard.cpp | 10 ---------- src/script/standard.h | 3 +-- 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index bf1b48cc..535c56b5 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -51,7 +51,6 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) case TX_NONSTANDARD: case TX_NULL_DATA: break; - case TX_ZEROCOINMINT: case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if (keystore.HaveKey(keyID)) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index b9c61f6c..2f4111f7 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -77,7 +77,6 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP case TX_NONSTANDARD: case TX_NULL_DATA: return false; - case TX_ZEROCOINMINT: case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, scriptSigRet); @@ -223,7 +222,6 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatur if (sigs1.size() >= sigs2.size()) return PushAll(sigs1); return PushAll(sigs2); - case TX_ZEROCOINMINT: case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: diff --git a/src/script/standard.cpp b/src/script/standard.cpp index ca2d71bf..183f82b5 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -31,7 +31,6 @@ const char* GetTxnOutputType(txnouttype t) case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; - case TX_ZEROCOINMINT: return "zerocoinmint"; } return NULL; } @@ -67,15 +66,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 150) return false; - vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); - vSolutionsRet.push_back(hashBytes); - return true; - } - // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first diff --git a/src/script/standard.h b/src/script/standard.h index 385ab73d..237ef0c6 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -50,8 +50,7 @@ enum txnouttype TX_PUBKEYHASH, TX_SCRIPTHASH, TX_MULTISIG, - TX_NULL_DATA, - TX_ZEROCOINMINT + TX_NULL_DATA }; class CNoDestination { From 5fd9ac4e0417c0dd8d26c4f7158193d039bc348e Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 16:11:17 +0200 Subject: [PATCH 036/126] wallet: Fixed inputs nSequence value to activate nLockTime --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 551023c1..b9a989fc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3254,7 +3254,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // Note how the sequence number is set to max()-1 so that the // nLockTime set above actually works. BOOST_FOREACH(const PAIRTYPE(const CWalletTx *, unsigned int) &coin, setCoins) - txNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second, CScript(), std::numeric_limits < unsigned int > ::max())); + txNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second, CScript(), std::numeric_limits < unsigned int > ::max() - 1)); // Sign int nIn = 0; From 9ed1115617ad9404efe122e07192bb178bf02587 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 17:02:44 +0200 Subject: [PATCH 037/126] block: Increased block version --- src/primitives/block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/block.h b/src/primitives/block.h index c85cd4f7..fb999649 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -23,7 +23,7 @@ class CBlockHeader { public: // header - static const int CURRENT_VERSION = 2; + static const int CURRENT_VERSION = 4; int nVersion; uint256 hashPrevBlock; From 59de38362daef829d5ab60a6410ba87d15ed2b92 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 17:05:09 +0200 Subject: [PATCH 038/126] miner: Use latest block version for blocktemplate and generated blocks --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 86d5fa4d..c1e1249b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -208,7 +208,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, co pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); - pblock->nVersion = 2;//ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); + pblock->nVersion = CBlockHeader::CURRENT_VERSION; // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) From 29b371c9a09a0d00461438ecdb1617946e75fd08 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 17:22:41 +0200 Subject: [PATCH 039/126] standard: Added new template for outputs with CHECKLOCKTIMEVERIFY lock --- src/script/standard.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/script/standard.h | 1 + 2 files changed, 39 insertions(+) diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 183f82b5..c765434d 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -259,6 +259,36 @@ class CScriptVisitor : public boost::static_visitor }; } + +namespace +{ +class CLockedScriptVisitor : public boost::static_visitor +{ +private: + CScript *script; + int nLockTime; +public: + CLockedScriptVisitor(CScript *scriptin, int nLockTime) : script(scriptin), nLockTime(nLockTime) { } + + bool operator()(const CNoDestination &dest) const { + script->clear(); + return false; + } + + bool operator()(const CKeyID &keyID) const { + script->clear(); + *script << nLockTime << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; + return true; + } + + bool operator()(const CScriptID &scriptID) const { + script->clear(); + *script << nLockTime << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; + return true; + } +}; +} + CScript GetScriptForDestination(const CTxDestination& dest) { CScript script; @@ -267,6 +297,14 @@ CScript GetScriptForDestination(const CTxDestination& dest) return script; } +CScript GetLockedScriptForDestination(const CTxDestination& dest, int nLockTime) +{ + CScript script; + + boost::apply_visitor(CLockedScriptVisitor(&script, nLockTime), dest); + return script; +} + CScript GetScriptForRawPubKey(const CPubKey& pubKey) { return CScript() << std::vector(pubKey.begin(), pubKey.end()) << OP_CHECKSIG; diff --git a/src/script/standard.h b/src/script/standard.h index 237ef0c6..c6ba0f96 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -75,6 +75,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); CScript GetScriptForDestination(const CTxDestination& dest); +CScript GetLockedScriptForDestination(const CTxDestination& dest, int nLockTime); CScript GetScriptForRawPubKey(const CPubKey& pubkey); CScript GetScriptForMultisig(int nRequired, const std::vector& keys); CScript GetScriptForWitness(const CScript& redeemscript); From 7d3518123a331f2fa4ea594249d6e42842c36e37 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 17:31:53 +0200 Subject: [PATCH 040/126] policy/script: Made locked script/pubkeyhash outputs/inputs standard --- src/policy/policy.cpp | 2 +- src/script/interpreter.cpp | 2 +- src/script/ismine.cpp | 2 ++ src/script/script.cpp | 40 ++++++++++++++++++++++++++++++++++++++ src/script/script.h | 2 ++ src/script/sign.cpp | 8 ++++++-- src/script/standard.cpp | 28 ++++++++++++++++++++++++-- src/script/standard.h | 2 ++ 8 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 92ffbea6..6b66de88 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -133,7 +133,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (!Solver(prevScript, whichType, vSolutions)) return false; - if (whichType == TX_SCRIPTHASH) + if (whichType == TX_SCRIPTHASH || whichType == TX_SCRIPTHASHLOCKED) { std::vector > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9f29ee78..6ae998f9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1262,7 +1262,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne return set_error(serror, SCRIPT_ERR_EVAL_FALSE); // Additional validation for spend-to-script-hash transactions: - if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) + if ((flags & SCRIPT_VERIFY_P2SH) && ( scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToScriptHashLocked() ) ) { // scriptSig must be literals-only or validation fails if (!scriptSig.IsPushOnly()) diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 535c56b5..d8fba06e 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -57,11 +57,13 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) return ISMINE_SPENDABLE; break; case TX_PUBKEYHASH: + case TX_PUBKEYHASHLOCKED: keyID = CKeyID(uint160(vSolutions[0])); if (keystore.HaveKey(keyID)) return ISMINE_SPENDABLE; break; case TX_SCRIPTHASH: + case TX_SCRIPTHASHLOCKED: { CScriptID scriptID = CScriptID(uint160(vSolutions[0])); CScript subscript; diff --git a/src/script/script.cpp b/src/script/script.cpp index c7a754e0..1ba53e44 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -218,6 +218,27 @@ bool CScript::IsPayToPublicKeyHash() const (*this)[24] == OP_CHECKSIG); } +bool CScript::IsPayToPublicKeyHashLocked() const +{ + // Extra-fast test for pay-to-pubkey-hash CScripts with OP_CHECKLOCKTIMEVERIFY: + + if( this->size() < 29 || this->size() > 33){ + return false; + } + + int nLockTimeLength = (*this)[0]; + int nOffset = nLockTimeLength + 1; + + return (nLockTimeLength >= 1 && nLockTimeLength <= 5 && + (*this)[nOffset + 0] == OP_CHECKLOCKTIMEVERIFY && + (*this)[nOffset + 1] == OP_DROP && + (*this)[nOffset + 2] == OP_DUP && + (*this)[nOffset + 3] == OP_HASH160 && + (*this)[nOffset + 4] == 0x14 && + (*this)[nOffset + 25] == OP_EQUALVERIFY && + (*this)[nOffset + 26] == OP_CHECKSIG); +} + bool CScript::IsPayToPublicKey() const { // Extra-fast test for pay-to-pubkey CScripts: @@ -259,6 +280,25 @@ bool CScript::IsPayToScriptHash() const (*this)[22] == OP_EQUAL); } +bool CScript::IsPayToScriptHashLocked() const +{ + // Extra-fast test for pay-to-script-hash CScripts with OP_CHECKLOCKTIMEVERIFY: + + if( this->size() < 26 || this->size() > 31){ + return false; + } + + int nLockTimeLength = (*this)[0]; + int nOffset = nLockTimeLength + 1; + + return (nLockTimeLength >= 1 && nLockTimeLength <= 5 && + (*this)[nOffset + 0] == OP_CHECKLOCKTIMEVERIFY && + (*this)[nOffset + 1] == OP_DROP && + (*this)[nOffset + 2] == OP_HASH160 && + (*this)[nOffset + 3] == 0x14 && + (*this)[nOffset + 24] == OP_EQUAL); +} + bool CScript::IsPayToWitnessScriptHash() const { // Extra-fast test for pay-to-witness-script-hash CScripts: diff --git a/src/script/script.h b/src/script/script.h index eaaf23e2..759c38dc 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -631,11 +631,13 @@ class CScript : public CScriptBase unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsPayToPublicKeyHash() const; + bool IsPayToPublicKeyHashLocked() const; bool IsPayToPublicKey() const; bool IsNormalPaymentScript() const; bool IsPayToScriptHash() const; + bool IsPayToScriptHashLocked() const; bool IsPayToWitnessScriptHash() const; bool IsWitnessProgram(int& version, std::vector& program) const; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 2f4111f7..e87d0ebc 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -59,7 +59,7 @@ static bool SignN(const vector& multisigdata, const BaseSignatureCreato /** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), - * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. + * unless whichTypeRet is TX_SCRIPTHASH or TX_SCRIPTHASHLOCKED, in which case scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, @@ -81,6 +81,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, scriptSigRet); case TX_PUBKEYHASH: + case TX_PUBKEYHASHLOCKED: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet)) return false; @@ -92,6 +93,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP } return true; case TX_SCRIPTHASH: + case TX_SCRIPTHASHLOCKED: return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet); case TX_MULTISIG: @@ -107,7 +109,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu if (!SignStep(creator, fromPubKey, scriptSig, whichType)) return false; - if (whichType == TX_SCRIPTHASH) + if (whichType == TX_SCRIPTHASH || whichType == TX_SCRIPTHASHLOCKED) { // Solver returns the subscript that need to be evaluated; // the final scriptSig is the signatures from that @@ -224,11 +226,13 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatur return PushAll(sigs2); case TX_PUBKEY: case TX_PUBKEYHASH: + case TX_PUBKEYHASHLOCKED: // Signatures are bigger than placeholders or empty scripts: if (sigs1.empty() || sigs1[0].empty()) return PushAll(sigs2); return PushAll(sigs1); case TX_SCRIPTHASH: + case TX_SCRIPTHASHLOCKED: if (sigs1.empty() || sigs1.back().empty()) return PushAll(sigs2); else if (sigs2.empty() || sigs2.back().empty()) diff --git a/src/script/standard.cpp b/src/script/standard.cpp index c765434d..7a41636c 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -28,7 +28,9 @@ const char* GetTxnOutputType(txnouttype t) case TX_NONSTANDARD: return "nonstandard"; case TX_PUBKEY: return "pubkey"; case TX_PUBKEYHASH: return "pubkeyhash"; + case TX_PUBKEYHASHLOCKED: return "pubkeyhashlocked"; case TX_SCRIPTHASH: return "scripthash"; + case TX_SCRIPTHASHLOCKED: return "scripthashlocked"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; } @@ -56,6 +58,17 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector hashBytes(scriptPubKey.begin() + nOffset, scriptPubKey.begin() + nOffset + 20); + vSolutionsRet.push_back(hashBytes); + return true; + } + // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) @@ -66,6 +79,17 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector hashBytes(scriptPubKey.begin() + nOffset, scriptPubKey.begin() + nOffset + 20); + vSolutionsRet.push_back(hashBytes); + return true; + } + // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first @@ -177,12 +201,12 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) addressRet = pubKey.GetID(); return true; } - else if (whichType == TX_PUBKEYHASH) + else if (whichType == TX_PUBKEYHASH || whichType == TX_PUBKEYHASHLOCKED) { addressRet = CKeyID(uint160(vSolutions[0])); return true; } - else if (whichType == TX_SCRIPTHASH) + else if (whichType == TX_SCRIPTHASH || whichType == TX_SCRIPTHASHLOCKED) { addressRet = CScriptID(uint160(vSolutions[0])); return true; diff --git a/src/script/standard.h b/src/script/standard.h index c6ba0f96..4374baa0 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -48,7 +48,9 @@ enum txnouttype // 'standard' transaction types: TX_PUBKEY, TX_PUBKEYHASH, + TX_PUBKEYHASHLOCKED, TX_SCRIPTHASH, + TX_SCRIPTHASHLOCKED, TX_MULTISIG, TX_NULL_DATA }; From c6ec2289140ba41673098699ff286daf159f8d05 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 17 Oct 2019 17:35:00 +0200 Subject: [PATCH 041/126] rpc: Added "sendtoaddresslocked" as wrapper to send locked outputs --- src/rpc/client.cpp | 2 + src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + src/wallet/rpcwallet.cpp | 87 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 8cd8429c..3874a546 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -39,6 +39,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendtoaddress", 4 }, { "sendtoaddress", 5 }, { "sendtoaddress", 6 }, + { "sendtoaddresslocked", 1 }, + { "sendtoaddresslocked", 2 }, { "instantsendtoaddress", 1 }, { "instantsendtoaddress", 4 }, { "settxfee", 0 }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index a10b987f..7a473d29 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -415,6 +415,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "sendfrom", &sendfrom, false }, { "wallet", "sendmany", &sendmany, false }, { "wallet", "sendtoaddress", &sendtoaddress, false }, + { "wallet", "sendtoaddresslocked", &sendtoaddresslocked, false }, { "wallet", "setaccount", &setaccount, true }, { "wallet", "settxfee", &settxfee, true }, { "wallet", "signmessage", &signmessage, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 5103f287..420141d4 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -239,6 +239,7 @@ extern UniValue setaccount(const UniValue& params, bool fHelp); extern UniValue getaccount(const UniValue& params, bool fHelp); extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp); extern UniValue sendtoaddress(const UniValue& params, bool fHelp); +extern UniValue sendtoaddresslocked(const UniValue& params, bool fHelp); extern UniValue signmessage(const UniValue& params, bool fHelp); extern UniValue verifymessage(const UniValue& params, bool fHelp); extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9e4bb5e2..52b89fdf 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -561,6 +561,93 @@ UniValue instantsendtoaddress(const UniValue& params, bool fHelp) return wtx.GetHash().GetHex(); } + +UniValue sendtoaddresslocked(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 3 || params.size() > 5) + throw runtime_error( + "sendtoaddresslocked \"smartcashaddress\" amount blockheight( \"comment\" \"comment-to\" subtractfeefromamount )\n" + "\nSend an amount to a given address and lock the output for a given time or number of blocks.\n" + + HelpRequiringPassphrase() + + "\nArguments:\n" + "1. \"smartcashaddress\" (string, required) The SmartCash address to send to.\n" + "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" + "3. \"blockheight\" (numeric, required) The blockheight at which the output becomes spendable/unlocked.\n" + "4. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" + " This is not part of the transaction, just kept in your wallet.\n" + "5. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n" + " to which you're sending the transaction. This is not part of the \n" + " transaction, just kept in your wallet.\n" + "\nResult:\n" + "\"transactionid\" (string) The transaction id.\n" + "\nExamples:\n" + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000") + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000 \"donation\" \"seans outpost\"") + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000 \"\" \"\" true") + + HelpExampleRpc("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\", 0.1, 500000, \"donation\", \"seans outpost\"") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid SmartCash address"); + + // Amount + CAmount nAmount = AmountFromValue(params[1]); + if (nAmount <= 0) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); + + // Locktime + unsigned int nLockTime = params[2].get_int(); + + if( nLockTime >= LOCKTIME_THRESHOLD ){ + throw JSONRPCError(RPC_TYPE_ERROR, strprintf("blockheight needs to be < %d", LOCKTIME_THRESHOLD)); + } + + // Wallet comments + CWalletTx wtx; + if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) + wtx.mapValue["comment"] = params[3].get_str(); + if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty()) + wtx.mapValue["to"] = params[4].get_str(); + + EnsureWalletIsUnlocked(); + + CAmount curBalance = pwalletMain->GetBalance(); + + if (nAmount > curBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + + if (pwalletMain->GetBroadcastTransactions() && !g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + + // Parse SmartCash address + CScript scriptPubKey = GetLockedScriptForDestination(address.Get(), nLockTime); + + // Create and send the transaction + CReserveKey reservekey(pwalletMain); + CAmount nFeeRequired; + std::string strError; + vector vecSend; + int nChangePosRet = -1; + CRecipient recipient = {scriptPubKey, nAmount, false}; + vecSend.push_back(recipient); + if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, + strError, NULL, true, ALL_COINS, false)) { + if (nAmount + nFeeRequired > pwalletMain->GetBalance()) + strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)); + throw JSONRPCError(RPC_WALLET_ERROR, strError); + } + if (!pwalletMain->CommitTransaction(wtx, reservekey, g_connman.get(), NetMsgType::TX)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + + return wtx.GetHash().GetHex(); +} + UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) From 1136fe830de230ac2fe9c42f076d90d3d2812b3e Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 22 Oct 2019 23:48:02 +0200 Subject: [PATCH 042/126] qt: Added new address format flag to the options --- src/qt/forms/optionsdialog.ui | 12 +++++++++++- src/qt/optionsdialog.cpp | 2 ++ src/qt/optionsmodel.cpp | 17 +++++++++++++++-- src/qt/optionsmodel.h | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index ca0ecf77..b9cfc156 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -20,7 +20,7 @@ - 0 + 1 @@ -163,6 +163,16 @@ + + + + If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed. + + + New address format + + + diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 20b53725..5b783806 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -164,6 +164,7 @@ void OptionsDialog::setModel(OptionsModel *model) connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning())); /* Wallet */ connect(ui->spendZeroConfChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); + connect(ui->newAddressFormatChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); /* Network */ connect(ui->allowIncoming, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning())); @@ -183,6 +184,7 @@ void OptionsDialog::setMapper() /* Wallet */ mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange); mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); + mapper->addMapping(ui->newAddressFormatChange, OptionsModel::UseNewAddressFormat); /* Network */ mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 9ac36870..3c7be7c0 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -108,6 +108,11 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("bSpendZeroConfChange", true); if (!SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); + + if (!settings.contains("bUseNewAddressFormat")) + settings.setValue("bUseNewAddressFormat", false); + if (!SoftSetBoolArg("-usenewaddressformat", settings.value("bUseNewAddressFormat").toBool())) + addOverriddenOption("-usenewaddressformat"); #endif // Network @@ -231,6 +236,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const #ifdef ENABLE_WALLET case SpendZeroConfChange: return settings.value("bSpendZeroConfChange"); + case UseNewAddressFormat: + return settings.value("bUseNewAddressFormat"); #endif case DisplayUnit: return nDisplayUnit; @@ -353,7 +360,13 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in settings.setValue("bSpendZeroConfChange", value); setRestartRequired(true); } - break; + break; + case UseNewAddressFormat: + if (settings.value("bUseNewAddressFormat") != value) { + settings.setValue("bUseNewAddressFormat", value); + setRestartRequired(true); + } + break; #endif case DisplayUnit: setDisplayUnit(value); @@ -463,4 +476,4 @@ void OptionsModel::checkAndMigrate() settings.setValue(strSettingsVersionKey, CLIENT_VERSION); } -} \ No newline at end of file +} diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index b23b5f26..4629fcfd 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -46,6 +46,7 @@ class OptionsModel : public QAbstractListModel DatabaseCache, // int SpendZeroConfChange, // bool Listen, // bool + UseNewAddressFormat, // bool OptionIDRowCount, }; From 21392eee935203d8269adb4c0944e042d19f712e Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 22 Oct 2019 23:49:27 +0200 Subject: [PATCH 043/126] chainparams: Added V2 for all available base58 types --- src/chainparams.cpp | 16 ++++++++++++++-- src/chainparams.h | 6 +++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1edaacfe..e46f1aca 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -186,9 +186,15 @@ class CMainParams : public CChainParams { base58Prefixes[SECRET_KEY] = std::vector(1,191); base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + + base58Prefixes[PUBKEY_ADDRESS_V2] = std::vector(1,125); //s + base58Prefixes[SCRIPT_ADDRESS_V2] = std::vector(1,18); + base58Prefixes[SECRET_KEY_V2] = std::vector(1,191); + base58Prefixes[EXT_PUBLIC_KEY_V2] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); + base58Prefixes[EXT_SECRET_KEY_V2] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + base58Prefixes[VOTE_KEY_PUBLIC] = std::vector(1,125); base58Prefixes[VOTE_KEY_SECRET] = std::vector(3,82); - base58Prefixes[NEW_PUBKEY_ADDRESS] = std::vector(1,125); //s // SmartCash BIP44 coin type is '224' nExtCoinType = 224; @@ -322,9 +328,15 @@ class CTestNetParams : public CChainParams { base58Prefixes[SECRET_KEY] = std::vector(1,193); base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); + + base58Prefixes[PUBKEY_ADDRESS_V2] = std::vector(1,127); //t + base58Prefixes[SCRIPT_ADDRESS_V2] = std::vector(1,13); //6 + base58Prefixes[SECRET_KEY_V2] = std::vector(1,130); //u + base58Prefixes[EXT_PUBLIC_KEY_V2] = boost::assign::list_of(0x7F)(0x35)(0x87)(0xCF).convert_to_container >(); + base58Prefixes[EXT_SECRET_KEY_V2] = boost::assign::list_of(0x7F)(0x35)(0x87)(0xCF).convert_to_container >(); + base58Prefixes[VOTE_KEY_PUBLIC] = std::vector(1,112); base58Prefixes[VOTE_KEY_SECRET] = std::vector(3,160); - base58Prefixes[NEW_PUBKEY_ADDRESS] = std::vector(1,127); //t // SmartCash BIP44 coin type is '224' nExtCoinType = 224; diff --git a/src/chainparams.h b/src/chainparams.h index 84dcd8f7..be68a3bb 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -49,9 +49,13 @@ class CChainParams SECRET_KEY, EXT_PUBLIC_KEY, EXT_SECRET_KEY, + PUBKEY_ADDRESS_V2, + SCRIPT_ADDRESS_V2, + SECRET_KEY_V2, + EXT_PUBLIC_KEY_V2, + EXT_SECRET_KEY_V2, VOTE_KEY_PUBLIC, VOTE_KEY_SECRET, - NEW_PUBKEY_ADDRESS, MAX_BASE58_TYPES }; From 6354914397ea7da2a516bd209867073efb36e425 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 22 Oct 2019 23:50:04 +0200 Subject: [PATCH 044/126] base58: Use a global flag to switch between V2 and legacy format --- src/base58.cpp | 108 +++++++++++++++++++++++++++++++++++++++++-------- src/base58.h | 9 ++++- 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 675e8d66..75a7041e 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -18,6 +18,8 @@ /** All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; +bool fUseNewAddressFormat = DEFAULT_USE_NEW_ADDRESS_FORMAT; + bool DecodeBase58(const char* psz, std::vector& vch) { // Skip leading spaces. @@ -230,19 +232,85 @@ bool CBase58Data::SetString(const std::string& str) return SetString(str.c_str()); } -std::string CBase58Data::ToString(bool newFormat) const +std::string CBase58Data::ToString() const +{ + std::vector vch = vchVersion; + if(fUseNewAddressFormat){ + if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)){ + vch = Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)){ + vch = Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY)){ + vch = Params().Base58Prefix(CChainParams::SECRET_KEY_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY)){ + vch = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_SECRET_KEY)){ + vch = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY_V2); + } + vch.insert(vch.end(), vchData.begin(), vchData.end()); + return EncodeBase58CheckNew(vch); + }else{ + if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2)){ + vch = Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2)){ + vch = Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::SECRET_KEY); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_SECRET_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); + } + vch.insert(vch.end(), vchData.begin(), vchData.end()); + return EncodeBase58Check(vch); + } +} + +std::string CBase58Data::ToString(bool fNewFormat) const { std::vector vch = vchVersion; - if(newFormat){ - if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)){ - vch = Params().Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS); - } + if(fNewFormat){ + if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)){ + vch = Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)){ + vch = Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY)){ + vch = Params().Base58Prefix(CChainParams::SECRET_KEY_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY)){ + vch = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY_V2); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_SECRET_KEY)){ + vch = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY_V2); + } vch.insert(vch.end(), vchData.begin(), vchData.end()); return EncodeBase58CheckNew(vch); }else{ - if(vchVersion == Params().Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS)){ - vch = Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS); - } + if(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2)){ + vch = Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2)){ + vch = Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + } + if(vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::SECRET_KEY); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY); + } + if(vchVersion == Params().Base58Prefix(CChainParams::EXT_SECRET_KEY_V2)){ + vch = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY); + } vch.insert(vch.end(), vchData.begin(), vchData.end()); return EncodeBase58Check(vch); } @@ -304,20 +372,26 @@ bool CBitcoinAddress::IsValid(const CChainParams& params) const { bool fCorrectSize = vchData.size() == 20; bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || - vchVersion == params.Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS) || - vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2) || + vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS) || + vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2); return fCorrectSize && fKnownVersion; } +bool CBitcoinAddress::IsValid(const CChainParams::Base58Type& type) const +{ + return vchData.size() == 20 && vchVersion == Params().Base58Prefix(type); +} + CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) return CNoDestination(); uint160 id; memcpy(&id, &vchData[0], 20); - if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS)) + if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2)) return CKeyID(id); - else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) + else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2)) return CScriptID(id); else return CNoDestination(); @@ -327,11 +401,11 @@ bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const { if (!IsValid()) { return false; - } else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS)) { + } else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2)) { memcpy(&hashBytes, &vchData[0], 20); type = 1; return true; - } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { + } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2)) { memcpy(&hashBytes, &vchData[0], 20); type = 2; return true; @@ -342,7 +416,7 @@ bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const { - if (!IsValid() || (vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) && vchVersion != Params().Base58Prefix(CChainParams::NEW_PUBKEY_ADDRESS))) + if (!IsValid() || (vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) && vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_V2))) return false; uint160 id; memcpy(&id, &vchData[0], 20); @@ -352,7 +426,7 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const bool CBitcoinAddress::IsScript() const { - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + return IsValid() && ( vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) || vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS_V2) ); } void CBitcoinSecret::SetKey(const CKey& vchSecret) @@ -374,7 +448,7 @@ CKey CBitcoinSecret::GetKey() bool CBitcoinSecret::IsValid() const { bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); - bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); + bool fCorrectVersion = ( vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY) || vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY_V2) ); return fExpectedFormat && fCorrectVersion; } diff --git a/src/base58.h b/src/base58.h index 9f262bd4..08673e47 100644 --- a/src/base58.h +++ b/src/base58.h @@ -24,6 +24,11 @@ #include #include +//! Default for -usenewaddressformat +static const bool DEFAULT_USE_NEW_ADDRESS_FORMAT = false; + +extern bool fUseNewAddressFormat; + /** * Encode a byte sequence as a base58-encoded string. * pbegin and pend cannot be NULL, unless both are. @@ -88,7 +93,8 @@ class CBase58Data public: bool SetString(const char* psz, unsigned int nVersionBytes = 1); bool SetString(const std::string& str); - std::string ToString(bool newFormat=false) const; + std::string ToString() const; + std::string ToString(bool fNewFormat) const; int CompareTo(const CBase58Data& b58) const; bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } @@ -111,6 +117,7 @@ class CBitcoinAddress : public CBase58Data { bool Set(const CTxDestination &dest); bool IsValid() const; bool IsValid(const CChainParams ¶ms) const; + bool IsValid(const CChainParams::Base58Type& type) const; CBitcoinAddress() {} CBitcoinAddress(const CTxDestination &dest) { Set(dest); } From aed2f8f0670a00c68045f35d0815cb88d36452f6 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:11:20 +0200 Subject: [PATCH 045/126] util: Updated arguments check --- src/util.cpp | 25 +++++++------------------ src/util.h | 2 +- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/util.cpp b/src/util.cpp index 05d5eb95..b64a7ac0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -109,7 +109,7 @@ int nWalletBackups = 10; const char * const BITCOIN_CONF_FILENAME = "smartcash.conf"; const char * const BITCOIN_PID_FILENAME = "smartcashd.pid"; -const std::string args[136] = {"version", "alertnotify", "blocknotify", "blocksonly", "checkblocks", "checklevel", "conf", "daemon", "datadir", "dbcache", "feefilter", "loadblock", "maxorphantx", "maxmempool", "mempoolexpiry", "par", "pid", "prune", "reindex-chainstate", "reindex", "sysperms", "depositindex", "addnode", "banscore", "bantime", "bind", "connect", "discover", "dns", "dnsseed", "externalip", "forcednsseed", "listen", "listenonion", "maxconnections", "maxreceivebuffer", "maxsendbuffer", "maxtimeadjustment", "onion", "onlynet", "permitbaremultisig", "peerbloomfilters", "port", "proxy", "proxyrandomize", "rpcserialversion", "seednode", "timeout", "torcontrol", "torpassword", "upnp", "whitebind", "whitelist", "whitelistrelay", "whitelistforcerelay", "maxuploadtarget", "zmqpubhashblock", "zmqpubhashtx", "zmqpubrawblock", "zmqpubrawtx", "uacomment", "checkblockindex", "checkmempool", "checkpoints", "disablesafemode", "testsafemode", "dropmessagestest", "fuzzmessagestest", "stopafterblockimport", "limitancestorcount", "limitancestorsize", "limitdescendantcount", "limitdescendantsize", "bip9params", "debug", "nodebug", "help-debug", "logips", "logtimestamps", "logtimemicros", "mocktime", "limitfreerelay", "relaypriority", "maxsigcachesize", "maxtipage", "minrelaytxfee", "maxtxfee", "printtoconsole", "printpriority", "shrinkdebugfile", "acceptnonstdtxn", "bytespersigop", "datacarrier", "datacarriersize", "mempoolreplacement", "blockmaxweight", "blockmaxsize", "txmaxcount", "blockprioritysize", "blockversion", "server", "rest", "rpcbind", "rpccookiefile", "rpcuser", "rpcpassword", "rpcauth", "rpcport", "rpcallowip", "rpcthreads", "rpcworkqueue", "rpcservertimeout", "help", "?", "disablewallet", "keypool", "fallbackfee", "mintxfee", "paytxfee", "rescan", "salvagewallet", "sendfreetransactions", "spendzeroconfchange", "txconfirmtarget", "usehd", "upgradewallet", "wallet", "walletbroadcast", "walletnotify", "zapwallettxes", "dblogsize", "flushwallet", "privdb", "walletrejectlongchains", "testnet"}; +const std::vector args = {"version", "alertnotify", "blocknotify", "blocksonly", "checkblocks", "checklevel", "conf", "daemon", "datadir", "dbcache", "feefilter", "loadblock", "maxorphantx", "maxmempool", "mempoolexpiry", "par", "pid", "prune", "reindex-chainstate", "reindex", "sysperms", "depositindex", "addnode", "banscore", "bantime", "bind", "connect", "discover", "dns", "dnsseed", "externalip", "forcednsseed", "listen", "listenonion", "maxconnections", "maxreceivebuffer", "maxsendbuffer", "maxtimeadjustment", "onion", "onlynet", "permitbaremultisig", "peerbloomfilters", "port", "proxy", "proxyrandomize", "rpcserialversion", "seednode", "timeout", "torcontrol", "torpassword", "upnp", "whitebind", "whitelist", "whitelistrelay", "whitelistforcerelay", "maxuploadtarget", "zmqpubhashblock", "zmqpubhashtx", "zmqpubrawblock", "zmqpubrawtx", "uacomment", "checkblockindex", "checkmempool", "checkpoints", "disablesafemode", "testsafemode", "dropmessagestest", "fuzzmessagestest", "stopafterblockimport", "limitancestorcount", "limitancestorsize", "limitdescendantcount", "limitdescendantsize", "bip9params", "debug", "nodebug", "help-debug", "logips", "logtimestamps", "logtimemicros", "mocktime", "limitfreerelay", "relaypriority", "maxsigcachesize", "maxtipage", "minrelaytxfee", "maxtxfee", "printtoconsole", "printpriority", "shrinkdebugfile", "acceptnonstdtxn", "bytespersigop", "datacarrier", "datacarriersize", "mempoolreplacement", "blockmaxweight", "blockmaxsize", "txmaxcount", "blockprioritysize", "blockversion", "server", "rest", "rpcbind", "rpccookiefile", "rpcuser", "rpcpassword", "rpcauth", "rpcport", "rpcallowip", "rpcthreads", "rpcworkqueue", "rpcservertimeout", "help", "?", "disablewallet", "keypool", "fallbackfee", "mintxfee", "paytxfee", "rescan", "salvagewallet", "sendfreetransactions", "spendzeroconfchange", "txconfirmtarget", "usehd", "upgradewallet", "wallet", "walletbroadcast", "walletnotify", "zapwallettxes", "dblogsize", "flushwallet", "privdb", "walletrejectlongchains", "testnet", "usenewaddressformat"}; map mapArgs; map > mapMultiArgs; @@ -364,30 +364,19 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) bool CheckDaemonParameters() { - bool ok = true; - for(map::const_iterator it = mapArgs.begin(); it != mapArgs.end(); ++it) { - bool found = false; - unsigned int j = 0; - while(!found && j < sizeof(args)/sizeof(args[0])) - { - if(it->first.compare("-" + args[j]) == 0) - { - found = true; - } - j++; - } + auto argFind = std::find_if(args.begin(), args.end(), [it](const std::string &arg) -> bool { + return (it->first.substr(1) == arg); + }); - if(!found) - { - ok = false; + if( argFind == args.end() ){ fprintf(stdout, "Invalid parameter %s check the help with -help command\n", it->first.c_str()); - break; + return false; } } - return ok; + return true; } void ParseParameters(int argc, const char* const argv[]) diff --git a/src/util.h b/src/util.h index af90d602..87c006d5 100644 --- a/src/util.h +++ b/src/util.h @@ -56,7 +56,7 @@ extern bool fSmartNode; extern bool fLiteMode; extern int nWalletBackups; -extern const std::string args[136]; +extern const std::vector args; extern std::map mapArgs; extern std::map > mapMultiArgs; extern bool fDebug; From bdbc5c8b0008075e96b25abcdb59d7ca966f58b7 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:11:54 +0200 Subject: [PATCH 046/126] hive: Function to force a legacy address --- src/smarthive/hive.cpp | 26 ++++++++++++++++++++++++++ src/smarthive/hive.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/smarthive/hive.cpp b/src/smarthive/hive.cpp index 20318f5d..815869b4 100644 --- a/src/smarthive/hive.cpp +++ b/src/smarthive/hive.cpp @@ -108,3 +108,29 @@ const CSmartAddress& SmartHive::Address(SmartHive::Payee payee) return *ptr->at(payee); } + +CSmartAddress CSmartAddress::Legacy(const CSmartAddress &address) +{ + if( address.IsValid(CChainParams::PUBKEY_ADDRESS_V2) ){ + return CSmartAddress(address.ToString(false)); + } + if( address.IsValid(CChainParams::SCRIPT_ADDRESS_V2) ){ + return CSmartAddress(address.ToString(false)); + } + + return address; +} + +CSmartAddress CSmartAddress::Legacy(const std::string &strAddress) +{ + CSmartAddress address(strAddress); + + if( address.IsValid(CChainParams::PUBKEY_ADDRESS_V2) ){ + return CSmartAddress(address.ToString(false)); + } + if( address.IsValid(CChainParams::SCRIPT_ADDRESS_V2) ){ + return CSmartAddress(address.ToString(false)); + } + + return address; +} diff --git a/src/smarthive/hive.h b/src/smarthive/hive.h index 684e696e..f0625125 100644 --- a/src/smarthive/hive.h +++ b/src/smarthive/hive.h @@ -37,6 +37,9 @@ struct CSmartAddress : public CBitcoinAddress } CScript GetScript() const { return GetScriptForDestination(Get()); } + + static CSmartAddress Legacy(const CSmartAddress &address); + static CSmartAddress Legacy(const std::string &strAddress); }; namespace SmartHive{ From 8065ef6edbc0d941cf2193f9049aaaf895a59ca0 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:12:09 +0200 Subject: [PATCH 047/126] init: Added -usenewaddressformat --- src/init.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/init.cpp b/src/init.cpp index 40e4b52a..b277a9d6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1259,6 +1259,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); + fUseNewAddressFormat = GetBoolArg("-usenewaddressformat", DEFAULT_USE_NEW_ADDRESS_FORMAT); std::string strWalletFile = GetArg("-wallet", "wallet.dat"); #endif // ENABLE_WALLET From bb9c0c09cb467bfc838c9ad94da5dcd47eaeead8 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:14:25 +0200 Subject: [PATCH 048/126] qt: Added address converter dialog to the help menu --- contrib/bitcoin-qt.pro | 1 + src/Makefile.qt.include | 4 ++ src/qt/addressconverter.cpp | 58 +++++++++++++++++++++ src/qt/addressconverter.h | 30 +++++++++++ src/qt/bitcoingui.cpp | 22 ++++++++ src/qt/bitcoingui.h | 5 ++ src/qt/forms/addressconverter.ui | 86 ++++++++++++++++++++++++++++++++ 7 files changed, 206 insertions(+) create mode 100644 src/qt/addressconverter.cpp create mode 100644 src/qt/addressconverter.h create mode 100644 src/qt/forms/addressconverter.ui diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro index 01393ea7..509cd7f0 100644 --- a/contrib/bitcoin-qt.pro +++ b/contrib/bitcoin-qt.pro @@ -2,6 +2,7 @@ FORMS += \ ../src/qt/forms/aboutdialog.ui \ ../src/qt/forms/addmilestonedialog.ui \ ../src/qt/forms/addressbookpage.ui \ + ../src/qt/forms/addressconverter.ui \ ../src/qt/forms/askpassphrasedialog.ui \ ../src/qt/forms/castvotesdialog.ui \ ../src/qt/forms/coincontroldialog.ui \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 9a2baaa0..5f5a193e 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -96,6 +96,7 @@ QT_TS = \ QT_FORMS_UI = \ qt/forms/addressbookpage.ui \ + qt/forms/addressconverter.ui \ qt/forms/addmilestonedialog.ui \ qt/forms/askpassphrasedialog.ui \ qt/forms/coincontroldialog.ui \ @@ -130,6 +131,7 @@ QT_FORMS_UI = \ QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ + qt/moc_addressconverter.cpp \ qt/moc_addmilestonedialog.cpp \ qt/moc_addresstablemodel.cpp \ qt/moc_askpassphrasedialog.cpp \ @@ -214,6 +216,7 @@ PROTOBUF_PROTO = qt/paymentrequest.proto BITCOIN_QT_H = \ qt/addressbookpage.h \ + qt/addressconverter.h \ qt/addmilestonedialog.h \ qt/addresstablemodel.h \ qt/askpassphrasedialog.h \ @@ -372,6 +375,7 @@ BITCOIN_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp BITCOIN_QT_WALLET_CPP = \ qt/addressbookpage.cpp \ + qt/addressconverter.cpp \ qt/addmilestonedialog.cpp \ qt/addresstablemodel.cpp \ qt/askpassphrasedialog.cpp \ diff --git a/src/qt/addressconverter.cpp b/src/qt/addressconverter.cpp new file mode 100644 index 00000000..c3433563 --- /dev/null +++ b/src/qt/addressconverter.cpp @@ -0,0 +1,58 @@ +// Copyright (c) 2011-2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "addressconverter.h" +#include "ui_addressconverter.h" + +#include "bitcoinunits.h" +#include "coincontroldialog.h" +#include "guiutil.h" +#include "optionsmodel.h" +#include "platformstyle.h" +#include "txmempool.h" +#include "walletmodel.h" +#include "sendcoinsdialog.h" + +#include "wallet/wallet.h" + +#include // for 'map_list_of()' + +#include +#include +#include +#include + + +AddressConverter::AddressConverter(QWidget *parent) : + QDialog(parent), + ui(new Ui::AddressConverter) +{ + ui->setupUi(this); + + connect(ui->input, SIGNAL(textChanged(QString)), this, SLOT(addressInputChanged())); +} + +AddressConverter::~AddressConverter() +{ + delete ui; +} + +void AddressConverter::addressInputChanged() +{ + if( ui->input->text() == "" ){ + ui->output->setText(""); + return; + } + + CSmartAddress address(ui->input->text().toStdString()); + + if(address.IsValid(CChainParams::PUBKEY_ADDRESS) || address.IsValid(CChainParams::SCRIPT_ADDRESS)){ + ui->output->setText(QString::fromStdString(address.ToString(true))); + }else if(address.IsValid(CChainParams::PUBKEY_ADDRESS_V2) || address.IsValid(CChainParams::SCRIPT_ADDRESS_V2)){ + ui->output->setText(QString::fromStdString(address.ToString(false))); + }else{ + ui->output->setText("Invalid SmartCash address"); + } + +} diff --git a/src/qt/addressconverter.h b/src/qt/addressconverter.h new file mode 100644 index 00000000..1ecdfe7f --- /dev/null +++ b/src/qt/addressconverter.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2015 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 SMARTCASH_QT_ADDRESSCONVERTER_H +#define SMARTCASH_QT_ADDRESSCONVERTER_H + +#include + +namespace Ui { + class AddressConverter; +} + +class AddressConverter : public QDialog +{ + Q_OBJECT + +public: + explicit AddressConverter(QWidget *parent = 0); + ~AddressConverter(); + +private: + Ui::AddressConverter *ui; + +private Q_SLOTS: + void addressInputChanged(); + +}; + +#endif // SMARTCASH_QT_ADDRESSCONVERTER_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 9f565a3c..26eaa0ba 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -4,6 +4,7 @@ #include "bitcoingui.h" +#include "addressconverter.h" #include "bitcoinunits.h" #include "clientmodel.h" #include "guiconstants.h" @@ -117,6 +118,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n trayIconMenu(0), notificator(0), rpcConsole(0), + addressConverter(0), helpMessageDialog(0), modalOverlay(0), prevBlocks(0), @@ -154,6 +156,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n #endif rpcConsole = new RPCConsole(platformStyle, 0); + addressConverter = new AddressConverter(0); helpMessageDialog = new HelpMessageDialog(this, HelpMessageDialog::cmdline); #ifdef ENABLE_WALLET if(enableWallet) @@ -273,6 +276,7 @@ BitcoinGUI::~BitcoinGUI() #endif delete rpcConsole; + delete addressConverter; } void BitcoinGUI::createActions() @@ -399,6 +403,9 @@ void BitcoinGUI::createActions() // initially disable the debug window menu item openRPCConsoleAction->setEnabled(false); + openAddressConverterAction = new QAction(tr("&Address converter"), this); + openAddressConverterAction->setStatusTip(tr("Open dialog to convert addresses from/to new address format")); + usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this); usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); @@ -418,6 +425,7 @@ void BitcoinGUI::createActions() connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); connect(openRPCConsoleAction, SIGNAL(triggered()), this, SLOT(showDebugWindow())); + connect(openAddressConverterAction, SIGNAL(triggered()), this, SLOT(showAddressConverter())); // Get restart command-line parameters and handle restart connect(rpcConsole, SIGNAL(handleRestart(QStringList)), this, SLOT(handleRestart(QStringList))); @@ -489,6 +497,7 @@ void BitcoinGUI::createMenuBar() { help->addAction(openRPCConsoleAction); } + help->addAction(openAddressConverterAction); help->addAction(showHelpMessageAction); help->addSeparator(); help->addAction(aboutAction); @@ -712,6 +721,14 @@ void BitcoinGUI::showDebugWindow() rpcConsole->activateWindow(); } +void BitcoinGUI::showAddressConverter() +{ + addressConverter->showNormal(); + addressConverter->show(); + addressConverter->raise(); + addressConverter->activateWindow(); +} + void BitcoinGUI::showPeers() { rpcConsole->setTabFocus(RPCConsole::TAB_PEERS); @@ -1083,6 +1100,7 @@ void BitcoinGUI::closeEvent(QCloseEvent *event) { // close rpcConsole in case it was open to make some space for the shutdown window rpcConsole->close(); + addressConverter->close(); QApplication::quit(); } @@ -1263,6 +1281,10 @@ void BitcoinGUI::detectShutdown() { if(rpcConsole) rpcConsole->hide(); + + if(addressConverter) + addressConverter->hide(); + qApp->quit(); } } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 6f0b9703..5d78249d 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -18,6 +18,7 @@ #include #include +class AddressConverter; class ClientModel; class NetworkStyle; class Notificator; @@ -117,6 +118,7 @@ class BitcoinGUI : public QMainWindow QAction *smartrewardsAction; QAction *smartvotingAction; QAction *openRPCConsoleAction; + QAction *openAddressConverterAction; QAction *openAction; QAction *showHelpMessageAction; @@ -124,6 +126,7 @@ class BitcoinGUI : public QMainWindow QMenu *trayIconMenu; Notificator *notificator; RPCConsole *rpcConsole; + AddressConverter *addressConverter; HelpMessageDialog *helpMessageDialog; ModalOverlay *modalOverlay; @@ -234,6 +237,8 @@ private Q_SLOTS: void aboutClicked(); /** Show debug window */ void showDebugWindow(); + /** Show address converter dialog */ + void showAddressConverter(); /** Show debug window and set focus to the console */ void showDebugWindowActivateConsole(); /** Show help message dialog */ diff --git a/src/qt/forms/addressconverter.ui b/src/qt/forms/addressconverter.ui new file mode 100644 index 00000000..cdce6a13 --- /dev/null +++ b/src/qt/forms/addressconverter.ui @@ -0,0 +1,86 @@ + + + AddressConverter + + + + 0 + 0 + 431 + 153 + + + + Address Converter + + + + + + + 0 + 0 + + + + Helps to convert SmartCash addresses from/to the old/new address format. + + + true + + + + + + + Qt::ClickFocus + + + Qt::AlignCenter + + + Enter a SmartCash address + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::NoFocus + + + Qt::AlignCenter + + + true + + + Converted address + + + + + + + input + output + + + + From f53dad60cb5f519af0ccd472b331aaac5c88e6b7 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:14:34 +0200 Subject: [PATCH 049/126] qt: Force legacy address format for smartreward address checks --- src/qt/smartrewardslist.cpp | 4 ++-- src/qt/specialtransactiondialog.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 0137e472..2ba488a2 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -263,7 +263,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c change.label = tr("(change)"); change.balance = out.tx->vout[out.i].nValue; - if( prewards->GetRewardEntry(CSmartAddress(sAddress.toStdString()),reward, false) ){ + if( prewards->GetRewardEntry(CSmartAddress::Legacy(sAddress.toStdString()), reward, false) ){ change.balance = reward->balance; change.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); change.balanceAtStart = reward->balanceAtStart; @@ -339,7 +339,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c CSmartRewardEntry *reward = nullptr; - if( prewards->GetRewardEntry(CSmartAddress(rewardField.address.toStdString()),reward, false) ){ + if( prewards->GetRewardEntry(CSmartAddress::Legacy(rewardField.address.toStdString()), reward, false) ){ rewardField.balance = reward->balance; rewardField.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); rewardField.balanceAtStart = reward->balanceAtStart; diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 090266aa..8171befb 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -861,7 +861,7 @@ void SpecialTransactionDialog::updateView() CSmartRewardEntry *reward = nullptr; - if( voteAddress.GetKeyID(keyId) && prewards->GetRewardEntry(voteAddress, reward, false) ){ + if( voteAddress.GetKeyID(keyId) && prewards->GetRewardEntry(CSmartAddress::Legacy(voteAddress), reward, false) ){ LOCK(pwalletMain->cs_wallet); From b69a8caed9246e65b6b98503e4ddcf2dd91b0ec8 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:14:41 +0200 Subject: [PATCH 050/126] sapi: Force legacy address format for smartreward address checks --- src/sapi/sapi_smartrewards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sapi/sapi_smartrewards.cpp b/src/sapi/sapi_smartrewards.cpp index f0a20eac..b0ad716d 100644 --- a/src/sapi/sapi_smartrewards.cpp +++ b/src/sapi/sapi_smartrewards.cpp @@ -67,7 +67,7 @@ static bool CheckAddresses(HTTPRequest* req, std::vector vecAddr, s for( auto addrStr : vecAddr ){ - CSmartAddress id = CSmartAddress(addrStr); + CSmartAddress id = CSmartAddress::Legacy(addrStr); if( !id.IsValid() ){ code = SAPI::InvalidSmartCashAddress; From 2515ee6aad60982112c09c87b0f67734c13408c4 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 00:14:49 +0200 Subject: [PATCH 051/126] rpc: Force legacy address format for smartreward address checks --- src/rpc/smartrewards.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index b0071c3b..a2711209 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -248,7 +248,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; std::string addressString = params[1].get_str(); - CSmartAddress id = CSmartAddress(addressString); + CSmartAddress id = CSmartAddress::Legacy(addressString); if( !id.IsValid() ) throw JSONRPCError(RPC_DATABASE_ERROR, strprintf("Invalid SmartCash address provided: %s",addressString)); @@ -258,8 +258,8 @@ UniValue smartrewards(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); - obj.pushKV("address",id.ToString()); - obj.pushKV("balance",format(entry->balance)); + obj.pushKV("address", id.ToString()); + obj.pushKV("balance", format(entry->balance)); obj.pushKV("balance_eligible", format(entry->balanceEligible)); obj.pushKV("is_smartnode", !entry->smartnodePaymentTx.IsNull()); obj.pushKV("voted", !entry->voteProof.IsNull()); From 2fe01691c93c4ce542d665c917fd858fd3fab828 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 01:06:26 +0200 Subject: [PATCH 052/126] qt: Removed legacy address column from addressbook --- src/qt/addressbookpage.cpp | 15 --------------- src/qt/addressbookpage.h | 1 - src/qt/addresstablemodel.cpp | 20 ++++++++------------ src/qt/addresstablemodel.h | 5 ++--- src/qt/forms/addressbookpage.ui | 33 +++++++-------------------------- src/qt/walletmodel.cpp | 4 ++-- src/qt/walletmodel.h | 2 +- 7 files changed, 20 insertions(+), 60 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index b8cdab07..66da06e4 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -33,13 +33,11 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, if (!platformStyle->getImagesOnButtons()) { ui->newAddress->setIcon(QIcon()); ui->copyAddress->setIcon(QIcon()); - ui->copyAddressLegacy->setIcon(QIcon()); ui->deleteAddress->setIcon(QIcon()); ui->exportButton->setIcon(QIcon()); } else { ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add")); ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy")); - ui->copyAddressLegacy->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy")); ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export")); } @@ -79,7 +77,6 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, } // Context menu actions - QAction *copyAddressActionLegacy = new QAction(tr("&Copy Address (Legacy)"), this); QAction *copyAddressAction = new QAction(tr("&Copy Address"), this); QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); QAction *editAction = new QAction(tr("&Edit"), this); @@ -87,7 +84,6 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, // Build context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyAddressActionLegacy); contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(editAction); @@ -96,7 +92,6 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, contextMenu->addSeparator(); // Connect signals for context menu actions - connect(copyAddressActionLegacy, SIGNAL(triggered()), this, SLOT(on_copyAddressLegacy_clicked())); connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); @@ -142,11 +137,9 @@ void AddressBookPage::setModel(AddressTableModel *model) // Set column widths #if QT_VERSION < 0x050000 ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch); - ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::AddressLegacy, QHeaderView::ResizeToContents); ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); #else ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch); - ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::AddressLegacy, QHeaderView::ResizeToContents); ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents); #endif @@ -164,11 +157,6 @@ void AddressBookPage::on_copyAddress_clicked() GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address); } -void AddressBookPage::on_copyAddressLegacy_clicked() -{ - GUIUtil::copyEntryData(ui->tableView, AddressTableModel::AddressLegacy); -} - void AddressBookPage::onCopyLabelAction() { GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label); @@ -249,13 +237,11 @@ void AddressBookPage::selectionChanged() break; } ui->copyAddress->setEnabled(true); - ui->copyAddressLegacy->setEnabled(true); } else { ui->deleteAddress->setEnabled(false); ui->copyAddress->setEnabled(false); - ui->copyAddressLegacy->setEnabled(false); } } @@ -297,7 +283,6 @@ void AddressBookPage::on_exportButton_clicked() // name, column, role writer.setModel(proxyModel); writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole); - writer.addColumn("Address Legacy", AddressTableModel::AddressLegacy, Qt::EditRole); writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole); if(!writer.write()) { diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 29d06ba9..c22566d4 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -67,7 +67,6 @@ private Q_SLOTS: void on_newAddress_clicked(); /** Copy address of currently selected address entry to clipboard */ void on_copyAddress_clicked(); - void on_copyAddressLegacy_clicked(); /** Copy label of currently selected address entry to clipboard (no button) */ void onCopyLabelAction(); /** Edit currently selected address entry (no button) */ diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index c5bbef53..9b0033af 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -32,12 +32,11 @@ struct AddressTableEntry Type type; QString label; QString address; - QString addressNew; QString pubcoin; AddressTableEntry() {} - AddressTableEntry(Type type, const QString &label, const QString &address, const QString &addressNew): - type(type), label(label), address(address), addressNew(addressNew) {} + AddressTableEntry(Type type, const QString &label, const QString &address): + type(type), label(label), address(address) {} AddressTableEntry(Type type, const QString &pubcoin): type(type), pubcoin(pubcoin) {} }; @@ -97,8 +96,7 @@ class AddressTablePriv const std::string& strName = item.second.name; cachedAddressTable.append(AddressTableEntry(addressType, QString::fromStdString(strName), - QString::fromStdString(address.ToString()), - QString::fromStdString(address.ToString(true)) + QString::fromStdString(address.ToString()) )); } } @@ -108,7 +106,7 @@ class AddressTablePriv qSort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); } - void updateEntry(const QString &address,const QString &addressNew, const QString &label, bool isMine, const QString &purpose, int status) + void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { // Find address / label in model QList::iterator lower = qLowerBound( @@ -129,7 +127,7 @@ class AddressTablePriv break; } parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); - cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address, addressNew)); + cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address)); parent->endInsertRows(); break; case CT_UPDATED: @@ -176,7 +174,7 @@ class AddressTablePriv AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) : QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0) { - columns << tr("Label") << tr("Address Legacy") << tr("Address"); + columns << tr("Label") << tr("Address"); priv = new AddressTablePriv(wallet, this); priv->refreshAddressTable(); } @@ -219,8 +217,6 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const return rec->label; } case Address: - return rec->addressNew; - case AddressLegacy: return rec->address; } } @@ -348,11 +344,11 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex &par } } -void AddressTableModel::updateEntry(const QString &address, const QString &addressNew, +void AddressTableModel::updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { // Update address book model from Bitcoin core - priv->updateEntry(address, addressNew, label, isMine, purpose, status); + priv->updateEntry(address, label, isMine, purpose, status); } QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address) diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index baf6ddc6..34bd4b55 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -26,8 +26,7 @@ class AddressTableModel : public QAbstractTableModel enum ColumnIndex { Label = 0, /**< User specified label */ - AddressLegacy = 1, /**< Bitcoin address */ - Address = 2 + Address = 1 /**< Bitcoin address */ }; enum RoleIndex { @@ -90,7 +89,7 @@ class AddressTableModel : public QAbstractTableModel public Q_SLOTS: /* Update address list from core. */ - void updateEntry(const QString &address, const QString &addressNew, const QString &label, bool isMine, const QString &purpose, int status); + void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); friend class AddressTablePriv; }; diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index 9524538e..0c8d1db0 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -6,8 +6,8 @@ 0 0 - 1160 - 480 + 680 + 336 @@ -60,7 +60,7 @@ &New - + :/icons/add:/icons/add @@ -68,23 +68,6 @@ - - - - Copy the currently selected address (legacy) to the system clipboard - - - &Copy (Legacy) - - - - :/icons/editcopy:/icons/editcopy - - - false - - - @@ -94,7 +77,7 @@ &Copy - + :/icons/editcopy:/icons/editcopy @@ -111,7 +94,7 @@ &Delete - + :/icons/remove:/icons/remove @@ -141,7 +124,7 @@ &Export - + :/icons/export:/icons/export @@ -169,8 +152,6 @@ - - - + diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 45d45f62..c1aa84e4 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -174,11 +174,11 @@ void WalletModel::updateTransaction() fForceCheckBalanceChanged = true; } -void WalletModel::updateAddressBook(const QString &address, const QString &addressNew, const QString &label, +void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { if(addressTableModel) - addressTableModel->updateEntry(address, addressNew, label, isMine, purpose, status); + addressTableModel->updateEntry(address, label, isMine, purpose, status); } void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 80cee9de..6d4d80a3 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -321,7 +321,7 @@ public Q_SLOTS: /* New transaction, or transaction changed status */ void updateTransaction(); /* New, updated or removed address book entry */ - void updateAddressBook(const QString &address, const QString &addressNew, const QString &label, bool isMine, const QString &purpose, int status); + void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); /* Watch-only added */ void updateWatchOnlyFlag(bool fHaveWatchonly); /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ From 868b87f185fd271125f61dc2f190e162063272b2 Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 14:23:10 +0200 Subject: [PATCH 053/126] qt: Modified address converter's output field --- src/qt/forms/addressconverter.ui | 54 ++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/qt/forms/addressconverter.ui b/src/qt/forms/addressconverter.ui index cdce6a13..f877d32e 100644 --- a/src/qt/forms/addressconverter.ui +++ b/src/qt/forms/addressconverter.ui @@ -32,9 +32,29 @@ + + + 0 + 25 + + + + + 16777215 + 25 + + Qt::ClickFocus + + QLineEdit{ +color: black; +border: 1px solid; +background-color: white; +border-color: rgb(118, 118, 119); +} + Qt::AlignCenter @@ -60,18 +80,35 @@ - - - Qt::NoFocus + + + + 0 + 25 + + + + + 16777215 + 25 + + + + QLabel{ +color: black; +border: 1px solid; +background-color: white; +border-color: rgb(118, 118, 119); +} + + + Qt::AlignCenter - - true - - - Converted address + + Qt::TextSelectableByMouse @@ -79,7 +116,6 @@ input - output From b018bcbab133effa568a7d8cb1e86ef20741c32f Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 23 Oct 2019 14:23:29 +0200 Subject: [PATCH 054/126] smartnode: Disabled voting maintenance --- src/smartnode/smartnode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smartnode/smartnode.cpp b/src/smartnode/smartnode.cpp index 76b431bd..068ca446 100644 --- a/src/smartnode/smartnode.cpp +++ b/src/smartnode/smartnode.cpp @@ -938,9 +938,11 @@ void ThreadSmartnode(CConnman& connman) mnodeman.DoFullVerificationStep(connman); } + /* WIP-VOTING uncomment if(nTick % (60 * 5) == 0) { smartVoting.DoMaintenance(connman); } + */ } } From cd737d0e203e7dcbbd9ab9a52cb17ed39486b0f0 Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 28 Oct 2019 20:42:41 +0100 Subject: [PATCH 055/126] smartrewards/qt: Increased required balance for smartrewards with 1.3 --- src/qt/smartrewardentry.cpp | 7 ++++++- src/qt/smartrewardentry.h | 2 ++ src/qt/smartrewardslist.cpp | 25 ++++++++++++++++--------- src/smartrewards/rewards.cpp | 3 ++- src/smartrewards/rewards.h | 3 ++- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/qt/smartrewardentry.cpp b/src/qt/smartrewardentry.cpp index 88214399..f856cebc 100755 --- a/src/qt/smartrewardentry.cpp +++ b/src/qt/smartrewardentry.cpp @@ -48,6 +48,11 @@ QSmartRewardEntry::~QSmartRewardEntry() delete ui; } +void QSmartRewardEntry::setMinBalance(CAmount nMinBalance) +{ + this->nMinBalance = nMinBalance; +} + void QSmartRewardEntry::setDisqualifyingTx(const uint256& txHash){ if( disqualifyingTx.IsNull() ){ @@ -104,7 +109,7 @@ QString QSmartRewardEntry::Address() const QSmartRewardEntry::State QSmartRewardEntry::CurrentState() { - if( nBalanceAtStart < SMART_REWARDS_MIN_BALANCE ) return LowBalance; + if( nBalanceAtStart < nMinBalance ) return LowBalance; if( fIsSmartNode ) return IsASmartNode; diff --git a/src/qt/smartrewardentry.h b/src/qt/smartrewardentry.h index 2b1fd755..59f945b9 100755 --- a/src/qt/smartrewardentry.h +++ b/src/qt/smartrewardentry.h @@ -31,6 +31,7 @@ class QSmartRewardEntry : public QFrame IsEligible }; + void setMinBalance(CAmount nMinBalance); void setDisqualifyingTx(const uint256& txHash); void setBalance(CAmount nBalance); void setInfoText(const QString& strText, const QColor& color); @@ -58,6 +59,7 @@ class QSmartRewardEntry : public QFrame QMenu* contextMenu; + CAmount nMinBalance; CAmount nBalanceAtStart; CAmount nBalance; CAmount nEligible; diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 2ba488a2..cc8529c9 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -426,12 +426,14 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( currentRound.number >= nFirst_1_3_Round ){ + entry->setMinBalance(SMART_REWARDS_MIN_BALANCE_1_3); + int nConfirmationsRequired = Params().GetConsensus().nRewardsConfirmationsRequired - field.nVoteProofConfirmations; if( field.fIsSmartNode ){ entry->setInfoText("Address belongs to a SmartNode.", COLOR_NEGATIVE); - }else if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE ){ - entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE/COIN), COLOR_NEGATIVE); + }else if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE_1_3 ){ + entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_3/COIN), COLOR_NEGATIVE); }else if( !field.disqualifyingTx.IsNull() ){ entry->setDisqualifyingTx(field.disqualifyingTx); entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); @@ -449,14 +451,19 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c ++nEligibleAddresses; } - }else if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE ){ - entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE/COIN), COLOR_NEGATIVE); - }else if( !field.disqualifyingTx.IsNull() ){ - entry->setDisqualifyingTx(field.disqualifyingTx); - entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); }else{ - entry->setEligible(field.eligible, field.reward); - ++nEligibleAddresses; + + entry->setMinBalance(SMART_REWARDS_MIN_BALANCE_1_2); + + if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE_1_2 ){ + entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_2/COIN), COLOR_NEGATIVE); + }else if( !field.disqualifyingTx.IsNull() ){ + entry->setDisqualifyingTx(field.disqualifyingTx); + entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); + }else{ + entry->setEligible(field.eligible, field.reward); + ++nEligibleAddresses; + } } rewardSum += field.reward; diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 576805a2..630c61ef 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -174,6 +174,7 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) const CSmartRewardRound *round = cache.GetCurrentRound(); int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CAmount nMinBalance = next.number < nFirst_1_3_Round ? SMART_REWARDS_MIN_BALANCE_1_2 : SMART_REWARDS_MIN_BALANCE_1_3; CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); @@ -216,7 +217,7 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) entry->second->balanceAtStart = entry->second->balance; - if( entry->second->balance >= SMART_REWARDS_MIN_BALANCE && !SmartHive::IsHive(entry->second->id) ){ + if( entry->second->balance >= nMinBalance && !SmartHive::IsHive(entry->second->id) ){ entry->second->balanceEligible = entry->second->balance; }else{ entry->second->balanceEligible = 0; diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 35e177f2..1264e5e8 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -14,7 +14,8 @@ using namespace std; #define REWARDS_CACHE_ENTRIES_DEFAULT 50000 -static const CAmount SMART_REWARDS_MIN_BALANCE = 1000 * COIN; +static const CAmount SMART_REWARDS_MIN_BALANCE_1_2 = 1000 * COIN; +static const CAmount SMART_REWARDS_MIN_BALANCE_1_3 = 10000 * COIN; // Minimum distance of the last processed block compared to the current chain // height to assume the rewards are synced. From 9a5c60c7c0b1206e89745358ff521555e86f2083 Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 28 Oct 2019 20:42:48 +0100 Subject: [PATCH 056/126] smartrewards: Increased blockreward of smartrewards for 1.3 to 30% --- src/smartrewards/rewards.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 630c61ef..140700ed 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -276,9 +276,10 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) // Calculate the current rewards percentage int64_t nTime = GetTime(); int64_t nStartHeight = next.startBlockHeight; + double dBlockReward = next.number < nFirst_1_3_Round ? 0.15 : 0.30; next.rewards = 0; - while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * 0.15; + while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; if( pResult->round.number ){ cache.AddFinishedRound(pResult->round); From 7bc95fb66305b463629472425bd4df3cd2f3585c Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 10:38:28 +0100 Subject: [PATCH 057/126] qt: Fixed addressbook update call --- src/qt/walletmodel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index c1aa84e4..5b4913a1 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -695,14 +695,12 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &purpose, ChangeType status) { QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString()); - QString strAddressNew = QString::fromStdString(CBitcoinAddress(address).ToString(true)); QString strLabel = QString::fromStdString(label); QString strPurpose = QString::fromStdString(purpose); qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status); QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, Q_ARG(QString, strAddress), - Q_ARG(QString, strAddressNew), Q_ARG(QString, strLabel), Q_ARG(bool, isMine), Q_ARG(QString, strPurpose), From d8b33718d06d759e3672dfd654a0604f976fa275 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 13:28:30 +0100 Subject: [PATCH 058/126] consensus: Added 1.3 fork defines --- src/consensus/consensus.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 0e6042ea..bb317344 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,6 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; +static const int HF_V1_3_HEIGHT = 1400000; // TBD, set the correct height /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; @@ -44,6 +45,7 @@ static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 = 1001; // 28500; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 = 1002; // 30300; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3 = 1003; // 75000; static const int TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 1004; // 415000; +static const int TESTNET_V1_3_HEIGHT = 3500; /** Testnet payment intervals*/ static const int TESTNET_V1_2_NODES_PER_BLOCK_1 = 3; From 778675000c306f417e091418387762f3b691be46 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 17:09:05 +0100 Subject: [PATCH 059/126] smarthive: New hive addresses, adjusted payout interval, adjusted split --- src/smarthive/hive.cpp | 96 ++++++++++++++------- src/smarthive/hive.h | 15 +++- src/smarthive/hivepayments.cpp | 149 +++++++++++---------------------- 3 files changed, 125 insertions(+), 135 deletions(-) diff --git a/src/smarthive/hive.cpp b/src/smarthive/hive.cpp index 815869b4..8e6a5968 100644 --- a/src/smarthive/hive.cpp +++ b/src/smarthive/hive.cpp @@ -16,47 +16,79 @@ void SmartHive::Init() if( init ) return; addressesMainnet = { - { SmartHive::ProjectTreasury, new CSmartAddress("SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b") }, - { SmartHive::Support, new CSmartAddress("SW2FbVaBhU1Www855V37auQzGQd8fuLR9x") }, - { SmartHive::Development, new CSmartAddress("SPusYr5tUdUyRXevJg7pnCc9Sm4HEzaYZF") }, - { SmartHive::Outreach, new CSmartAddress("Siim7T5zMH3he8xxtQzhmHs4CQSuMrCV1M") }, - { SmartHive::SmartRewards, new CSmartAddress("SU5bKb35xUV8aHG5dNarWHB3HBVjcCRjYo") }, - { SmartHive::Outreach2, new CSmartAddress("SNxFyszmGEAa2n2kQbzw7gguHa5a4FC7Ay") }, - { SmartHive::Web, new CSmartAddress("Sgq5c4Rznibagv1aopAfPA81jac392scvm") }, - { SmartHive::Quality, new CSmartAddress("Sc61Gc2wivtuGd6recqVDqv4R38TcHqFS8") } + { SmartHive::ProjectTreasury_Legacy, new CSmartAddress("SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b") }, + { SmartHive::Support_Legacy, new CSmartAddress("SW2FbVaBhU1Www855V37auQzGQd8fuLR9x") }, + { SmartHive::Development_Legacy, new CSmartAddress("SPusYr5tUdUyRXevJg7pnCc9Sm4HEzaYZF") }, + { SmartHive::Outreach_Legacy, new CSmartAddress("Siim7T5zMH3he8xxtQzhmHs4CQSuMrCV1M") }, + { SmartHive::SmartRewards_Legacy, new CSmartAddress("SU5bKb35xUV8aHG5dNarWHB3HBVjcCRjYo") }, + { SmartHive::Outreach2_Legacy, new CSmartAddress("SNxFyszmGEAa2n2kQbzw7gguHa5a4FC7Ay") }, + { SmartHive::Web_Legacy, new CSmartAddress("Sgq5c4Rznibagv1aopAfPA81jac392scvm") }, + { SmartHive::Quality_Legacy, new CSmartAddress("Sc61Gc2wivtuGd6recqVDqv4R38TcHqFS8") }, + + { SmartHive::ProjectTreasury, new CSmartAddress("TBD") }, + { SmartHive::Support, new CSmartAddress("TBD") }, + { SmartHive::Development, new CSmartAddress("TBD") }, + { SmartHive::Outreach, new CSmartAddress("TBD") }, + { SmartHive::WebMobileSmartCard, new CSmartAddress("TBD") }, + { SmartHive::Exchanges, new CSmartAddress("TBD") }, + { SmartHive::Merchants, new CSmartAddress("TBD") } }; addressesTestnet = { - { SmartHive::ProjectTreasury, new CSmartAddress("TTpGqTr2PBeVx4vvNRJ9iTq4NwpTCbSSwy") }, - { SmartHive::Support, new CSmartAddress("THypUznpFaDHaE7PS6yAc4pHNjC2BnWzUv") }, - { SmartHive::Development, new CSmartAddress("TDJVZE5oCYYbJQyizU4FgB2KpnKVdebnxg") }, - { SmartHive::Outreach, new CSmartAddress("TSziXCdaBcPk3Dt94BbTH9BZDH18K6sWsc") }, - { SmartHive::SmartRewards, new CSmartAddress("TLn1PGAVccBBjF8JuhQmATCR8vxhmamJg8") }, - { SmartHive::Outreach2, new CSmartAddress("TCi1wcVbkmpUiTcG277o5Y3VeD3zgtsHRD") }, - { SmartHive::Web, new CSmartAddress("TBWBQ1rCXm16huegLWvSz5TCs5KzfoYaNB") }, - { SmartHive::Quality, new CSmartAddress("TVuTV7d5vBKyfg5j45RnnYgdo9G3ET2t2f") } + { SmartHive::ProjectTreasury_Legacy, new CSmartAddress("TTpGqTr2PBeVx4vvNRJ9iTq4NwpTCbSSwy") }, + { SmartHive::Support_Legacy, new CSmartAddress("THypUznpFaDHaE7PS6yAc4pHNjC2BnWzUv") }, + { SmartHive::Development_Legacy, new CSmartAddress("TDJVZE5oCYYbJQyizU4FgB2KpnKVdebnxg") }, + { SmartHive::Outreach_Legacy, new CSmartAddress("TSziXCdaBcPk3Dt94BbTH9BZDH18K6sWsc") }, + { SmartHive::SmartRewards_Legacy, new CSmartAddress("TLn1PGAVccBBjF8JuhQmATCR8vxhmamJg8") }, + { SmartHive::Outreach2_Legacy, new CSmartAddress("TCi1wcVbkmpUiTcG277o5Y3VeD3zgtsHRD") }, + { SmartHive::Web_Legacy, new CSmartAddress("TBWBQ1rCXm16huegLWvSz5TCs5KzfoYaNB") }, + { SmartHive::Quality_Legacy, new CSmartAddress("TVuTV7d5vBKyfg5j45RnnYgdo9G3ET2t2f") }, + + { SmartHive::ProjectTreasury, new CSmartAddress("6HaFiyiFN3SvcXQkE9TrkVvRX2bC4fxhi4") }, + { SmartHive::Support, new CSmartAddress("6Tr3PdsFSm3DfN2b8vQ4Eqo7LzvZ238yXt") }, + { SmartHive::Development, new CSmartAddress("6VE4Qzox3pEXtPLYhroepY9oiMS8YAgmJ9") }, + { SmartHive::Outreach, new CSmartAddress("6WNuCbGoM9ZeMYdW7uXwxNV7u4mgmBKmVY") }, + { SmartHive::WebMobileSmartCard, new CSmartAddress("6bF1bs7A9eth2zuZqNQmCGB2jeap7fZnUE") }, + { SmartHive::Exchanges, new CSmartAddress("6dBFiy4HLZF81Df2FwwcjYjXWWoP3Vqm2b") }, + { SmartHive::Merchants, new CSmartAddress("6HKbGxK7RSoyrpoJj7CCLJ1s56E9B7QNJn") } }; scriptsMainnet = { - { SmartHive::ProjectTreasury, new CScript(std::move(addressesMainnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasure - { SmartHive::Support, new CScript(std::move(addressesMainnet.at(SmartHive::Support)->GetScript())) }, // Support hive - { SmartHive::Development, new CScript(std::move(addressesMainnet.at(SmartHive::Development)->GetScript())) }, // Development hive - { SmartHive::Outreach, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive - { SmartHive::SmartRewards, new CScript(std::move(addressesMainnet.at(SmartHive::SmartRewards)->GetScript())) }, // Legacy smartrewards - { SmartHive::Outreach2, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach2)->GetScript())) }, // New hive 1 - { SmartHive::Web, new CScript(std::move(addressesMainnet.at(SmartHive::Web)->GetScript())) }, // New hive 2 - { SmartHive::Quality, new CScript(std::move(addressesMainnet.at(SmartHive::Quality)->GetScript())) } // New hive 3 + { SmartHive::ProjectTreasury_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::ProjectTreasury_Legacy)->GetScript())) }, // SmartHive treasury + { SmartHive::Support_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Support_Legacy)->GetScript())) }, // Support hive + { SmartHive::Development_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Development_Legacy)->GetScript())) }, // Development hive + { SmartHive::Outreach_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach_Legacy)->GetScript())) }, // Outreach hive + { SmartHive::SmartRewards_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::SmartRewards_Legacy)->GetScript())) }, // Legacy smartrewards + { SmartHive::Outreach2_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach2_Legacy)->GetScript())) }, // New hive 1 + { SmartHive::Web_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Web_Legacy)->GetScript())) }, // New hive 2 + { SmartHive::Quality_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Quality_Legacy)->GetScript())) }, // New hive 3 + + { SmartHive::ProjectTreasury, new CScript(std::move(addressesMainnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasury multisig + { SmartHive::Support, new CScript(std::move(addressesMainnet.at(SmartHive::Support)->GetScript())) }, // Support hive multisig + { SmartHive::Development, new CScript(std::move(addressesMainnet.at(SmartHive::Development)->GetScript())) }, // Development hive multisig + { SmartHive::Outreach, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive multisig + { SmartHive::WebMobileSmartCard, new CScript(std::move(addressesMainnet.at(SmartHive::WebMobileSmartCard)->GetScript())) }, // Outreach hive multisig + { SmartHive::Exchanges, new CScript(std::move(addressesMainnet.at(SmartHive::Exchanges)->GetScript())) }, // Exchange funds multisig + { SmartHive::Merchants, new CScript(std::move(addressesMainnet.at(SmartHive::Merchants)->GetScript())) }, // Merchant funds multisig }; scriptsTestnet = { - { SmartHive::ProjectTreasury, new CScript(std::move(addressesTestnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasure - { SmartHive::Support, new CScript(std::move(addressesTestnet.at(SmartHive::Support)->GetScript())) }, // Support hive - { SmartHive::Development, new CScript(std::move(addressesTestnet.at(SmartHive::Development)->GetScript())) }, // Development hive - { SmartHive::Outreach, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive - { SmartHive::SmartRewards, new CScript(std::move(addressesTestnet.at(SmartHive::SmartRewards)->GetScript())) }, // Legacy smartrewards - { SmartHive::Outreach2, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach2)->GetScript())) }, // New hive 1 - { SmartHive::Web, new CScript(std::move(addressesTestnet.at(SmartHive::Web)->GetScript())) }, // New hive 2 - { SmartHive::Quality, new CScript(std::move(addressesTestnet.at(SmartHive::Quality)->GetScript())) } // New hive 3 + { SmartHive::ProjectTreasury_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::ProjectTreasury_Legacy)->GetScript())) }, // SmartHive treasure + { SmartHive::Support_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Support_Legacy)->GetScript())) }, // Support hive + { SmartHive::Development_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Development_Legacy)->GetScript())) }, // Development hive + { SmartHive::Outreach_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach_Legacy)->GetScript())) }, // Outreach hive + { SmartHive::SmartRewards_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::SmartRewards_Legacy)->GetScript())) }, // Legacy smartrewards + { SmartHive::Outreach2_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach2_Legacy)->GetScript())) }, // New hive 1 + { SmartHive::Web_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Web_Legacy)->GetScript())) }, // New hive 2 + { SmartHive::Quality_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Quality_Legacy)->GetScript())) }, // New hive 3 + + { SmartHive::ProjectTreasury, new CScript(std::move(addressesTestnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasury multisig + { SmartHive::Support, new CScript(std::move(addressesTestnet.at(SmartHive::Support)->GetScript())) }, // Support hive multisig + { SmartHive::Development, new CScript(std::move(addressesTestnet.at(SmartHive::Development)->GetScript())) }, // Development hive multisig + { SmartHive::Outreach, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive multisig + { SmartHive::WebMobileSmartCard, new CScript(std::move(addressesTestnet.at(SmartHive::WebMobileSmartCard)->GetScript())) }, // Outreach hive multisig + { SmartHive::Exchanges, new CScript(std::move(addressesTestnet.at(SmartHive::Exchanges)->GetScript())) }, // Exchange funds multisig + { SmartHive::Merchants, new CScript(std::move(addressesTestnet.at(SmartHive::Merchants)->GetScript())) }, // Merchant funds multisig }; init = true; diff --git a/src/smarthive/hive.h b/src/smarthive/hive.h index f0625125..73807b7d 100644 --- a/src/smarthive/hive.h +++ b/src/smarthive/hive.h @@ -45,14 +45,21 @@ struct CSmartAddress : public CBitcoinAddress namespace SmartHive{ enum Payee{ + Development_Legacy, //Deprecated with 1.3 + Outreach_Legacy, //Deprecated with 1.3 + Support_Legacy, //Deprecated with 1.3 + SmartRewards_Legacy, //Deprecated with 1.2 + ProjectTreasury_Legacy, //Deprecated with 1.3 + Outreach2_Legacy, //Deprecated with 1.3 + Web_Legacy, //Deprecated with 1.3 + Quality_Legacy, //Deprecated with 1.3 Development, Outreach, Support, - SmartRewards, //Deprecated with 1.2 ProjectTreasury, - Outreach2, - Web, - Quality + WebMobileSmartCard, + Exchanges, + Merchants }; const CScript* ScriptPtr(SmartHive::Payee payee); diff --git a/src/smarthive/hivepayments.cpp b/src/smarthive/hivepayments.cpp index 58f90c38..f17b361e 100644 --- a/src/smarthive/hivepayments.cpp +++ b/src/smarthive/hivepayments.cpp @@ -13,10 +13,12 @@ static CSmartHiveSplit *hiveSplitInitial = nullptr; static CSmartHiveSplit *hiveSplit_1_0 = nullptr; static CSmartHiveSplit *hiveSplit_1_1 = nullptr; static CSmartHiveSplit *hiveSplit_1_2 = nullptr; +static CSmartHiveSplit *hiveSplit_1_3 = nullptr; static CSmartHiveSplit *hiveSplitDisabled = nullptr; static CSmartHiveSplit *hiveSplitInvalid_1_0 = nullptr; static int nPayoutInterval_1_2; +static int nPayoutInterval_1_3; void SmartHivePayments::Init() { @@ -26,50 +28,67 @@ void SmartHivePayments::Init() hiveSplitInitial = new CSmartHiveClassicSplit { 95, // Split 95% of the block reward as followed. { - new CSmartHiveClassic(SmartHive::Outreach, 0.08), - new CSmartHiveClassic(SmartHive::Support, 0.08), - new CSmartHiveClassic(SmartHive::Development, 0.08), - new CSmartHiveClassic(SmartHive::SmartRewards, 0.15), - new CSmartHiveClassic(SmartHive::ProjectTreasury, 0.56) + new CSmartHiveClassic(SmartHive::Outreach_Legacy, 0.08), + new CSmartHiveClassic(SmartHive::Support_Legacy, 0.08), + new CSmartHiveClassic(SmartHive::Development_Legacy, 0.08), + new CSmartHiveClassic(SmartHive::SmartRewards_Legacy, 0.15), + new CSmartHiveClassic(SmartHive::ProjectTreasury_Legacy, 0.56) } }; hiveSplit_1_0 = new CSmartHiveRotationSplit( 95, // Split 95% of the block reward as followed. { - new CSmartHiveRotation(SmartHive::Outreach, 0,7), - new CSmartHiveRotation(SmartHive::Support, 8,15), - new CSmartHiveRotation(SmartHive::Development, 16,23), - new CSmartHiveRotation(SmartHive::SmartRewards, 24,38), - new CSmartHiveRotation(SmartHive::ProjectTreasury, 39,94) + new CSmartHiveRotation(SmartHive::Outreach_Legacy, 0,7), + new CSmartHiveRotation(SmartHive::Support_Legacy, 8,15), + new CSmartHiveRotation(SmartHive::Development_Legacy, 16,23), + new CSmartHiveRotation(SmartHive::SmartRewards_Legacy, 24,38), + new CSmartHiveRotation(SmartHive::ProjectTreasury_Legacy, 39,94) } ); hiveSplit_1_1 = new CSmartHiveRotationSplit( 85, // Split 85% of the block reward as followed. { - new CSmartHiveRotation(SmartHive::Outreach, 0,7), - new CSmartHiveRotation(SmartHive::Support, 8,15), - new CSmartHiveRotation(SmartHive::Development, 16,23), - new CSmartHiveRotation(SmartHive::SmartRewards, 24,38), - new CSmartHiveRotation(SmartHive::ProjectTreasury, 39,84) + new CSmartHiveRotation(SmartHive::Outreach_Legacy, 0,7), + new CSmartHiveRotation(SmartHive::Support_Legacy, 8,15), + new CSmartHiveRotation(SmartHive::Development_Legacy, 16,23), + new CSmartHiveRotation(SmartHive::SmartRewards_Legacy, 24,38), + new CSmartHiveRotation(SmartHive::ProjectTreasury_Legacy, 39,84) } ); if(MainNet()) nPayoutInterval_1_2 = 1000; else nPayoutInterval_1_2 = 25; + if(MainNet()) nPayoutInterval_1_3 = 10000; + else nPayoutInterval_1_3 = 50; + hiveSplit_1_2 = new CSmartHiveBatchSplit( 70, // Split 70% of the block reward as followed. nPayoutInterval_1_2, // Trigger the payouts every n blocks { - new CSmartHiveClassic(SmartHive::Outreach, 0.04), - new CSmartHiveClassic(SmartHive::Support, 0.04), - new CSmartHiveClassic(SmartHive::Development, 0.04), - new CSmartHiveClassic(SmartHive::Outreach2, 0.04), - new CSmartHiveClassic(SmartHive::Web, 0.04), - new CSmartHiveClassic(SmartHive::Quality, 0.04), - new CSmartHiveClassic(SmartHive::ProjectTreasury, 0.46), + new CSmartHiveClassic(SmartHive::Outreach_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::Support_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::Development_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::Outreach2_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::Web_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::Quality_Legacy, 0.04), + new CSmartHiveClassic(SmartHive::ProjectTreasury_Legacy, 0.46), + } + ); + + hiveSplit_1_3 = new CSmartHiveBatchSplit( + 55, // Split 55% of the block reward as followed. + nPayoutInterval_1_3, // Trigger the payouts every n blocks + { + new CSmartHiveClassic(SmartHive::Exchanges, 0.05), + new CSmartHiveClassic(SmartHive::Merchants, 0.05), + new CSmartHiveClassic(SmartHive::Outreach, 0.0625), + new CSmartHiveClassic(SmartHive::Support, 0.0625), + new CSmartHiveClassic(SmartHive::Development, 0.0625), + new CSmartHiveClassic(SmartHive::WebMobileSmartCard, 0.0625), + new CSmartHiveClassic(SmartHive::ProjectTreasury, 0.2), } ); @@ -79,78 +98,6 @@ void SmartHivePayments::Init() init = true; } -const CSmartHiveSplit * Get_1_2_Split(int nHeight) -{ - static int64_t nLastPayNewHives = -1; - static CSmartHiveSplit* sporked_Split_1_2 = nullptr; - - int64_t nPayNewHives = 0; - int64_t nPayOutreachSpork = sporkManager.GetSporkValue(SPORK_18_PAY_OUTREACH2); - int64_t nPayWebSpork = sporkManager.GetSporkValue(SPORK_19_PAY_WEB); - int64_t nPayQualitySpork = sporkManager.GetSporkValue(SPORK_20_PAY_QUALITY); - - if( !nPayOutreachSpork || nHeight < nPayOutreachSpork ){ - nPayNewHives |= SmartHivePayments::OUTREACH2_ENABLED; - } - - if( !nPayWebSpork || nHeight < nPayWebSpork ){ - nPayNewHives |= SmartHivePayments::WEB_ENABLED; - } - - if( !nPayQualitySpork || nHeight < nPayQualitySpork ){ - nPayNewHives |= SmartHivePayments::QUALITY_ENABLED; - } - - // If one of the hives is disabled. - if( (nPayNewHives & SmartHivePayments::NEW_HIVES_ENABLED) != SmartHivePayments::NEW_HIVES_ENABLED ){ - - if( nLastPayNewHives == -1 || nLastPayNewHives != nPayNewHives ){ - - nLastPayNewHives = nPayNewHives; - - delete sporked_Split_1_2; - - std::vector sporkedHives_1_2; - - if( nPayNewHives & SmartHivePayments::OUTREACH2_ENABLED ){ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Outreach, 0.04)); - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Outreach2, 0.04)); - }else{ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Outreach, 0.08)); - } - - if( nPayNewHives & SmartHivePayments::WEB_ENABLED ){ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Development, 0.04)); - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Web, 0.04)); - }else{ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Development, 0.08)); - } - - if( nPayNewHives & SmartHivePayments::QUALITY_ENABLED ){ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Support, 0.04)); - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Quality, 0.04)); - }else{ - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::Support, 0.08)); - } - - sporkedHives_1_2.push_back(new CSmartHiveClassic(SmartHive::ProjectTreasury, 0.46)); - - sporked_Split_1_2 = new CSmartHiveBatchSplit( - 70, // Split 70% of the block reward as followed. - nPayoutInterval_1_2, // Trigger the payouts every n blocks - sporkedHives_1_2 - ); - - } - - return sporked_Split_1_2; - } - - // Else us the normal 1.2 split. - return hiveSplit_1_2; -} - - const CSmartHiveSplit * GetHiveSplit(int nHeight, int64_t blockTime) { @@ -165,18 +112,22 @@ const CSmartHiveSplit * GetHiveSplit(int nHeight, int64_t blockTime) return hiveSplit_1_0; }else if ( nHeight >= HF_V1_1_SMARTNODE_HEIGHT && nHeight < HF_V1_2_SMARTREWARD_HEIGHT ) { return hiveSplit_1_1; - }else if ( (nHeight >= HF_V1_2_SMARTREWARD_HEIGHT) && nHeight < HF_CHAIN_REWARD_END_HEIGHT ) { - return Get_1_2_Split(nHeight); + }else if ( (nHeight >= HF_V1_2_SMARTREWARD_HEIGHT) && nHeight < HF_V1_3_HEIGHT ) { + return hiveSplit_1_2; + }else if ( (nHeight >= HF_V1_3_HEIGHT) && nHeight < HF_CHAIN_REWARD_END_HEIGHT ) { + return hiveSplit_1_3; }else if(nHeight <= 1 || nHeight >= HF_CHAIN_REWARD_END_HEIGHT){ return hiveSplitDisabled; } }else{ - if ( nHeight <= TESTNET_V1_2_PAYMENTS_HEIGHT ) { + if ( nHeight < TESTNET_V1_2_PAYMENTS_HEIGHT ) { return hiveSplit_1_1; - }else if ( nHeight > TESTNET_V1_2_PAYMENTS_HEIGHT && nHeight < HF_CHAIN_REWARD_END_HEIGHT ) { - return Get_1_2_Split(nHeight); + }else if ( nHeight >= TESTNET_V1_2_PAYMENTS_HEIGHT && nHeight < TESTNET_V1_3_HEIGHT ) { + return hiveSplit_1_2; + }else if ( nHeight >= TESTNET_V1_3_HEIGHT && nHeight < HF_CHAIN_REWARD_END_HEIGHT ) { + return hiveSplit_1_3; }else if(nHeight >= HF_CHAIN_REWARD_END_HEIGHT){ return hiveSplitDisabled; } From bddfd873d1a9eb082f5b3c31a341764fee4df366 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 19:29:18 +0100 Subject: [PATCH 060/126] chainparams: Adjusted first 1.3 smartrewards round --- src/chainparams.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e46f1aca..67ad54c9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -140,7 +140,7 @@ class CMainParams : public CChainParams { //! 1.3 Parameter consensus.nRewardsBlocksPerRound_1_3 = 142500; - consensus.nRewardsFirst_1_3_Round = 29; + consensus.nRewardsFirst_1_3_Round = 30; consensus.nRewardsPayouts_1_3_BlockStretch = 10990; // 1 week consensus.nRewardsPayouts_1_3_BlockPayees = 10; @@ -292,7 +292,7 @@ class CTestNetParams : public CChainParams { //! 1.3 Parameter consensus.nRewardsBlocksPerRound_1_3 = 1500; - consensus.nRewardsFirst_1_3_Round = 5; + consensus.nRewardsFirst_1_3_Round = 13; consensus.nRewardsPayouts_1_3_BlockStretch = 1000; consensus.nRewardsPayouts_1_3_BlockPayees = 10; From 8f3a897edfe6647dadd0acdbcf7ba1bf90fecdc3 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 19:33:56 +0100 Subject: [PATCH 061/126] consensus: Adjusted 1.3 fork height --- src/consensus/consensus.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index bb317344..a6b73231 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_HEIGHT = 1400000; // TBD, set the correct height +static const int HF_V1_3_HEIGHT = 1380001; /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; @@ -45,7 +45,7 @@ static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 = 1001; // 28500; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 = 1002; // 30300; static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3 = 1003; // 75000; static const int TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 1004; // 415000; -static const int TESTNET_V1_3_HEIGHT = 3500; +static const int TESTNET_V1_3_HEIGHT = 6526; /** Testnet payment intervals*/ static const int TESTNET_V1_2_NODES_PER_BLOCK_1 = 3; From 1ac6a148fa357b45e78bddb5549f55b0e096a575 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 19:43:00 +0100 Subject: [PATCH 062/126] consensus/smartnode: Adjusted some testnet parameter --- src/consensus/consensus.h | 17 ++++-------- src/smarthive/hivepayments.cpp | 4 +-- src/smartnode/smartnodepayments.cpp | 43 ++++++++++------------------- src/smartrewards/rewards.h | 4 +-- 4 files changed, 23 insertions(+), 45 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index a6b73231..0e43a1fc 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -40,21 +40,14 @@ static const int HF_V1_2_8_NODES_PER_BLOCK = 1; static const int HF_CHAIN_REWARD_END_HEIGHT = 717499999; /** Testnet payment start blocks*/ -static const int TESTNET_V1_2_PAYMENTS_HEIGHT = 1000; -static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 = 1001; // 28500; -static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 = 1002; // 30300; -static const int TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3 = 1003; // 75000; -static const int TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 1004; // 415000; +static const int TESTNET_V1_2_8_PAYMENTS_HEIGHT = 101; static const int TESTNET_V1_3_HEIGHT = 6526; /** Testnet payment intervals*/ -static const int TESTNET_V1_2_NODES_PER_BLOCK_1 = 3; -static const int TESTNET_V1_2_NODES_BLOCK_INTERVAL_1 = 6; -static const int TESTNET_V1_2_NODES_PER_BLOCK_2 = 3; -static const int TESTNET_V1_2_NODES_BLOCK_INTERVAL_2 = 3; -static const int TESTNET_V1_2_NODES_PER_BLOCK_3 = 10; -static const int TESTNET_V1_2_NODES_BLOCK_INTERVAL_3 = 2; -static const int TESTNET_V1_2_8_NODES_PER_BLOCK = 1; +static const int TESTNET_V1_2_8_NODES_PER_BLOCK = 1; +static const int TESTNET_V1_2_8_NODES_BLOCK_INTERVAL = 2; +static const int TESTNET_V1_3_NODES_PER_BLOCK = 1; +static const int TESTNET_V1_3_NODES_BLOCK_INTERVAL = 2; inline unsigned int MaxBlockSigOps() { diff --git a/src/smarthive/hivepayments.cpp b/src/smarthive/hivepayments.cpp index f17b361e..e8fc25e9 100644 --- a/src/smarthive/hivepayments.cpp +++ b/src/smarthive/hivepayments.cpp @@ -122,9 +122,9 @@ const CSmartHiveSplit * GetHiveSplit(int nHeight, int64_t blockTime) }else{ - if ( nHeight < TESTNET_V1_2_PAYMENTS_HEIGHT ) { + if ( nHeight < TESTNET_V1_2_8_PAYMENTS_HEIGHT ) { return hiveSplit_1_1; - }else if ( nHeight >= TESTNET_V1_2_PAYMENTS_HEIGHT && nHeight < TESTNET_V1_3_HEIGHT ) { + }else if ( nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT && nHeight < TESTNET_V1_3_HEIGHT ) { return hiveSplit_1_2; }else if ( nHeight >= TESTNET_V1_3_HEIGHT && nHeight < HF_CHAIN_REWARD_END_HEIGHT ) { return hiveSplit_1_3; diff --git a/src/smartnode/smartnodepayments.cpp b/src/smartnode/smartnodepayments.cpp index 1ac1e043..2c61fa02 100644 --- a/src/smartnode/smartnodepayments.cpp +++ b/src/smartnode/smartnodepayments.cpp @@ -48,14 +48,10 @@ int SmartNodePayments::PayoutsPerBlock(int nHeight) }else{ - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 && nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2) - return TESTNET_V1_2_NODES_PER_BLOCK_1; - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 && nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3) - return TESTNET_V1_2_NODES_PER_BLOCK_2; - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3 && nHeight < TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT) - return TESTNET_V1_2_NODES_PER_BLOCK_3; - if(nHeight >= TESTNET_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT) + if(nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT && nHeight < TESTNET_V1_3_HEIGHT) return TESTNET_V1_2_8_NODES_PER_BLOCK; + if(nHeight >= TESTNET_V1_3_HEIGHT) + return TESTNET_V1_3_NODES_PER_BLOCK; } @@ -73,12 +69,11 @@ int SmartNodePayments::PayoutInterval(int nHeight) } }else{ - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 && nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2) - return TESTNET_V1_2_NODES_BLOCK_INTERVAL_1; - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_2 && nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3) - return TESTNET_V1_2_NODES_BLOCK_INTERVAL_2; - if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_3) - return TESTNET_V1_2_NODES_BLOCK_INTERVAL_3; + + if(nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT && nHeight < TESTNET_V1_3_HEIGHT) + return TESTNET_V1_2_8_NODES_BLOCK_INTERVAL; + if(nHeight >= TESTNET_V1_3_HEIGHT) + return TESTNET_V1_3_NODES_BLOCK_INTERVAL; } @@ -110,12 +105,9 @@ CAmount SmartNodePayments::Payment(int nHeight) }else{ - if( nHeight < TESTNET_V1_2_PAYMENTS_HEIGHT ){ + if( nHeight < TESTNET_V1_2_8_PAYMENTS_HEIGHT ){ blockValue = 0; - }else if( nHeight >= TESTNET_V1_2_PAYMENTS_HEIGHT && - nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 ){ - blockValue = GetBlockValue(nHeight,0,INT_MAX); - }else if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1){ + }else if( nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT ){ int interval = SmartNodePayments::PayoutInterval(nHeight); @@ -161,13 +153,9 @@ bool SmartNodePayments::IsPaymentValid(const CTransaction& txNew, int nHeight, C }else{ - if( nHeight < TESTNET_V1_2_PAYMENTS_HEIGHT ){ - return true; - }else if( nHeight >= TESTNET_V1_2_PAYMENTS_HEIGHT && - nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 ){ + if( nHeight < TESTNET_V1_2_8_PAYMENTS_HEIGHT ){ return true; - }else if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1){ - + }else if( nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT ){ if( nHeight % SmartNodePayments::PayoutInterval(nHeight) ) return true; } @@ -277,12 +265,9 @@ void CSmartnodePayments::FillBlockPayee(CMutableTransaction& txNew, int nHeight, }else{ - if( nHeight < TESTNET_V1_2_PAYMENTS_HEIGHT ){ - return; - }else if( nHeight >= TESTNET_V1_2_PAYMENTS_HEIGHT && - nHeight < TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1 ){ + if( nHeight < TESTNET_V1_2_8_PAYMENTS_HEIGHT ){ return; - }else if(nHeight >= TESTNET_V1_2_MULTINODE_PAYMENTS_HEIGHT_1){ + }else if(nHeight >= TESTNET_V1_2_8_PAYMENTS_HEIGHT){ if( nHeight % SmartNodePayments::PayoutInterval(nHeight) ) return; if( !SmartNodePayments::PayoutsPerBlock(nHeight) ) return; } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 1264e5e8..bd8091d3 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -37,8 +37,8 @@ const int64_t nRewardsSyncDistance_Testnet = 60; const int64_t nFirstTxTimestamp_Testnet = 1527192589; const int64_t nFirstRoundStartTime_Testnet = nFirstTxTimestamp_Testnet; const int64_t nFirstRoundEndTime_Testnet = nFirstRoundStartTime_Testnet + (2*60*60); -const int64_t nFirstRoundStartBlock_Testnet = TESTNET_V1_2_PAYMENTS_HEIGHT; -const int64_t nFirstRoundEndBlock_Testnet = nFirstRoundStartBlock_Testnet + 1000; +const int64_t nFirstRoundStartBlock_Testnet = TESTNET_V1_2_8_PAYMENTS_HEIGHT - 1; +const int64_t nFirstRoundEndBlock_Testnet = nFirstRoundStartBlock_Testnet + 500; void ThreadSmartRewards(bool fRecreate = false); CAmount CalculateRewardsForBlockRange(int64_t start, int64_t end); From caf7c76261b7fa890bfc8345110ba1e00f88e0a3 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 29 Oct 2019 20:08:25 +0100 Subject: [PATCH 063/126] chainparams: Adjusted new mainnet base58 prefixes. --- src/chainparams.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 67ad54c9..9c51c789 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -188,10 +188,10 @@ class CMainParams : public CChainParams { base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); base58Prefixes[PUBKEY_ADDRESS_V2] = std::vector(1,125); //s - base58Prefixes[SCRIPT_ADDRESS_V2] = std::vector(1,18); - base58Prefixes[SECRET_KEY_V2] = std::vector(1,191); - base58Prefixes[EXT_PUBLIC_KEY_V2] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); - base58Prefixes[EXT_SECRET_KEY_V2] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + base58Prefixes[SCRIPT_ADDRESS_V2] = std::vector(1,110); + base58Prefixes[SECRET_KEY_V2] = std::vector(1,237); + base58Prefixes[EXT_PUBLIC_KEY_V2] = boost::assign::list_of(0x04)(0x20)(0xBD)(0x3F).convert_to_container >(); + base58Prefixes[EXT_SECRET_KEY_V2] = boost::assign::list_of(0x04)(0x20)(0xB9)(0x03).convert_to_container >(); base58Prefixes[VOTE_KEY_PUBLIC] = std::vector(1,125); base58Prefixes[VOTE_KEY_SECRET] = std::vector(3,82); From 6ff453bc9cf241bec1adf514be5e5072b7ed2401 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 31 Oct 2019 08:39:50 +0100 Subject: [PATCH 064/126] smartrewards: Fixed testnet block undo for the first round --- src/smartrewards/rewards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 140700ed..55a14817 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -1093,7 +1093,7 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda // If just hit the last round's threshold if( ( MainNet() && pRound->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < pRound->endBlockTime ) || - ( ( TestNet() || pRound->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == pRound->startBlockHeight ) ){ + ( ( (TestNet() && pRound->number > 1) || pRound->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == pRound->startBlockHeight ) ){ // Recover the last round from the history as current round CSmartRewardRound prevRound = cache.GetRounds()->at(pRound->number - 1); From 1222a7e586f0fb33bcaeaa8780d86b20c4bdb79f Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 31 Oct 2019 09:42:16 +0100 Subject: [PATCH 065/126] version: Increased protocol version and min protocol --- src/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h b/src/version.h index 1ab5ae0b..a8022617 100644 --- a/src/version.h +++ b/src/version.h @@ -12,7 +12,7 @@ static const int PROTOCOL_BASE_VERSION = 90000; static const int PROTOCOL_MAX_VERSION = 90000 + 0xFF; -static const int PROTOCOL_VERSION = 90030; +static const int PROTOCOL_VERSION = 90032; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 90013; @@ -21,7 +21,7 @@ static const int INIT_PROTO_VERSION = 90013; static const int GETHEADERS_VERSION = 90020; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 90028; +static const int MIN_PEER_PROTO_VERSION = 90031; //! first version with multi node payments static const int MIN_MULTIPAYMENT_PROTO_VERSION = 90026; From 1d13bca5f2382dec7a8e8ff98f84d6e0524a0e69 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 5 Nov 2019 13:01:46 +0100 Subject: [PATCH 066/126] qt: Avoid possible deadlock --- src/qt/specialtransactiondialog.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 8171befb..573cda3b 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -382,8 +382,12 @@ void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) break; case VOTE_PROOF_TRANSACTIONS:{ - LOCK(cs_rewardscache); - int nCurrentRound = prewards->GetCurrentRound()->number; + int nCurrentRound; + + { + LOCK(cs_rewardscache); + nCurrentRound = prewards->GetCurrentRound()->number; + } fSuccess = SendVoteProof(it.first, it.second, nCurrentRound, strError); }break; From fc19521f7a5e1ec5bedec34ae99a3d58c1f8044b Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 5 Nov 2019 13:08:07 +0100 Subject: [PATCH 067/126] qt: Fixed issue with comparison of old/new format addresses --- src/qt/specialtransactiondialog.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 573cda3b..c29e2a43 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -623,23 +623,24 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP strprintf("Address does't refer to a key for TX %s, index %s", out.hash.ToString(), out.n), strError); - std::vector addresses; - txnouttype type; - int nRequired; + CTxDestination addressSolved; - if (!ExtractDestinations(utxo.scriptPubKey, type, addresses, nRequired) || addresses.size() != 1) { + if (!ExtractDestination(utxo.scriptPubKey, addressSolved)) { return Error("GenerateVoteProof", strprintf("Failed to extract address for output with TX %s, index %s", out.hash.ToString(), out.n), strError); } + CKeyID keyIdSolved; + // Force option 1 - verify the vote address with the input of the register tx - if( !(CSmartAddress(addresses[0]) == voteAddress) ) + if( !CSmartAddress(addressSolved).GetKeyID(keyIdSolved) || keyIdSolved != voteAddressKeyID ){ return Error("GenerateVoteProof", strprintf("Failed to force vote proof option one for address %s with TX %s, index %s", voteAddress.ToString(), out.hash.ToString(), out.n), strError); + } // ** // ** Prepare the VoteProof data From c5b0515147403968717cbfdef23dce04ff796ef7 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 11:45:56 +0100 Subject: [PATCH 068/126] qt: Adjusted testnet voting portal URL --- src/qt/smartvotingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/smartvotingmanager.cpp b/src/qt/smartvotingmanager.cpp index 40d956f7..cf9208b4 100755 --- a/src/qt/smartvotingmanager.cpp +++ b/src/qt/smartvotingmanager.cpp @@ -16,7 +16,7 @@ #include const QString urlHiveVotingPortal = "https://vote.smartcash.cc/api/v1/"; -const QString urlHiveVotingPortalTestnet = "https://votesmartcashtest.azurewebsites.net/api/v1/"; +const QString urlHiveVotingPortalTestnet = "https://testnet-vote.smrt.cash/api/v1/"; SmartHiveRequest::SmartHiveRequest(QString endpoint): QNetworkRequest(), From c63d4878e95e5065f91f72b5d970dbbafb5074e6 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 12:33:15 +0100 Subject: [PATCH 069/126] sapi: Fixed smartrewards percentage representation --- src/sapi/sapi_smartrewards.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sapi/sapi_smartrewards.cpp b/src/sapi/sapi_smartrewards.cpp index b0ad716d..950e78a5 100644 --- a/src/sapi/sapi_smartrewards.cpp +++ b/src/sapi/sapi_smartrewards.cpp @@ -130,7 +130,7 @@ static bool smartrewards_current(HTTPRequest* req, const std::mapdisqualifiedEntries); obj.pushKV("disqualified_smart",UniValueFromAmount(current->disqualifiedSmart)); obj.pushKV("estimated_rewards",UniValueFromAmount(current->rewards)); - obj.pushKV("estimated_percent",current->percent); + obj.pushKV("estimated_percent",current->percent * 100.0); SAPI::WriteReply(req, obj); @@ -168,7 +168,7 @@ static bool smartrewards_history(HTTPRequest* req, const std::mapsecond.disqualifiedEntries); roundObj.pushKV("disqualified_smart",UniValueFromAmount(round->second.disqualifiedSmart)); roundObj.pushKV("rewards",UniValueFromAmount(round->second.rewards)); - roundObj.pushKV("percent",round->second.percent); + roundObj.pushKV("percent",round->second.percent * 100.0); UniValue payObj(UniValue::VOBJ); From d7af354e0431720dd94c019b7b7a317727257175 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 12:33:21 +0100 Subject: [PATCH 070/126] rpc: Fixed smartrewards percentage representation --- src/rpc/smartrewards.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index a2711209..71d04acd 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -77,7 +77,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) obj.pushKV("disqualified_addresses",current->disqualifiedEntries); obj.pushKV("disqualified_smart",format(current->disqualifiedSmart)); obj.pushKV("estimated_rewards",format(current->rewards)); - obj.pushKV("estimated_percent",current->percent); + obj.pushKV("estimated_percent",current->percent * 100.0); return obj; } @@ -112,7 +112,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) roundObj.pushKV("disqualified_addresses",round->second.disqualifiedEntries); roundObj.pushKV("disqualified_smart",format(round->second.disqualifiedSmart)); roundObj.pushKV("rewards",format(round->second.rewards)); - roundObj.pushKV("percent",round->second.percent); + roundObj.pushKV("percent",round->second.percent * 100.0); UniValue payObj(UniValue::VOBJ); From 0b583bddffacdf6463b5b278c093ac2a3e2c6550 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 13:29:47 +0100 Subject: [PATCH 071/126] transaction: Added GetLockTime to CtxOut --- src/primitives/transaction.cpp | 12 ++++++++++++ src/primitives/transaction.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 59a96a63..9a2ec7cf 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -72,6 +72,18 @@ uint256 CTxOut::GetHash() const return SerializeHash(*this); } +uint32_t CTxOut::GetLockTime() const +{ + uint32_t nLockTime = 0; + + if( scriptPubKey.IsPayToPublicKeyHashLocked() || scriptPubKey.IsPayToPublicKeyHashLocked() ){ + std::vector vch(scriptPubKey.begin() + 1, scriptPubKey.begin() + 1 + scriptPubKey[0] ); + nLockTime = CScriptNum(vch, false).getint(); + } + + return nLockTime; +} + std::string CTxOut::ToString() const { return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30)); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index cfd2ae9c..ba43724e 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -236,6 +236,8 @@ class CTxOut return scriptPubKey.IsVoteProofData() && nValue == REWARDS_VOTEPROOF_FEE; } + uint32_t GetLockTime() const; + friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && From fe0705642e82c0c6bceda66c88f8ced8697c7662 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 13:30:56 +0100 Subject: [PATCH 072/126] wallet: Added nLockTime to COutput --- src/wallet/wallet.cpp | 34 +++++++++++++++++++++++++++++----- src/wallet/wallet.h | 5 +++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b9a989fc..346e06ad 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2405,11 +2405,19 @@ void CWallet::AvailableCoins(vector &vCoins, bool fOnlyConfirmed, cons if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && (!IsLockedCoin((*it).first, i) || nCoinType == ONLY_10000) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && - (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))) + (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))){ + + uint32_t nLockTime = pcoin->vout[i].GetLockTime(); + + if( nLockTime ){ + LogPrintf("LOCKTIME FOUND: %d\n", nLockTime); + } + vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), - (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); + (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, nLockTime)); + } } } @@ -2452,11 +2460,20 @@ void CWallet::AvailableCoins(vector &vCoins, const CSmartAddress& addr isminetype mine = IsMine(pcoin->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && !IsLockedCoin((*it).first, i) && - pcoin->vout[i].nValue > 0) + pcoin->vout[i].nValue > 0){ + + uint32_t nLockTime = pcoin->vout[i].GetLockTime(); + + if( nLockTime ){ + LogPrintf("LOCKTIME FOUND %d\n", nLockTime); + } + vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || false, - (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); + (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, + nLockTime)); + } } } @@ -2937,7 +2954,14 @@ int CWallet::CountInputsWithAmount(CAmount nInputAmount) int nDepth = pcoin->GetDepthInMainChain(false); for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - COutput out = COutput(pcoin, i, nDepth, true, true); + + uint32_t nLockTime = pcoin->vout[i].GetLockTime(); + + if( nLockTime ){ + LogPrintf("LOGTIME FOUND %d\n", nLockTime); + } + + COutput out = COutput(pcoin, i, nDepth, true, true, nLockTime); //COutPoint outpoint = COutPoint(out.tx->GetHash(), out.i); if(out.tx->vout[out.i].nValue != nInputAmount) continue; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4bc0988e..ee231d96 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -467,10 +467,11 @@ class COutput int nDepth; bool fSpendable; bool fSolvable; + unsigned int nLockTime; - COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn) + COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, unsigned int nLockTimeIn) { - tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; + tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; nLockTime = nLockTimeIn; } std::string ToString() const; From d16eba92471fe5ed16ae8a0331aa352e6dc68cfe Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 13:34:04 +0100 Subject: [PATCH 073/126] qt: Handle outputs locked by OP_CHECKLOCKTIMEVERIFY in coincontrol --- src/qt/coincontroldialog.cpp | 34 ++++++++++++++++++++++++++++------ src/qt/coincontroldialog.h | 1 + src/qt/walletmodel.cpp | 6 +++--- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 719e9aa1..12c04342 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -215,13 +216,14 @@ void CoinControlDialog::showMenu(const QPoint &point) if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) { copyTransactionHashAction->setEnabled(true); - if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) - { + + if( item->data(COLUMN_LOCKED, Qt::UserRole).toBool() ){ + lockAction->setEnabled(false); + unlockAction->setEnabled(false); + }else if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())){ lockAction->setEnabled(false); unlockAction->setEnabled(true); - } - else - { + }else{ lockAction->setEnabled(true); unlockAction->setEnabled(false); } @@ -699,6 +701,9 @@ void CoinControlDialog::updateView() bool treeMode = ui->radioTreeMode->isChecked(); + int nCurrentHeight = chainActive.Height(); + int64_t nCurrentTime = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : GetTime(); + ui->treeWidget->clear(); ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox ui->treeWidget->setAlternatingRowColors(!treeMode); @@ -807,8 +812,25 @@ void CoinControlDialog::updateView() // vout index itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); + bool fOutputLocked = out.nLockTime && ( + ( out.nLockTime < LOCKTIME_THRESHOLD && nCurrentHeight < (int)out.nLockTime ) || + ( out.nLockTime >= LOCKTIME_THRESHOLD && nCurrentTime < out.nLockTime ) ); + + itemOutput->setData(COLUMN_LOCKED, Qt::UserRole, QVariant(fOutputLocked)); + + if( fOutputLocked ){ + + if( out.nLockTime < LOCKTIME_THRESHOLD ){ + itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until block %1").arg(out.nLockTime)); + }else{ + QDateTime timestamp; + timestamp.setTime_t(out.nLockTime); + itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until %1").arg(timestamp.toString(Qt::SystemLocaleShortDate))); + } + } + // disable locked coins - if (model->isLockedCoin(txhash, out.i)) + if (model->isLockedCoin(txhash, out.i) || fOutputLocked) { COutPoint outpt(txhash, out.i); coinControl->UnSelect(outpt); // just to be sure diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 785079b1..3aa3d7b5 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -85,6 +85,7 @@ class CoinControlDialog : public QDialog COLUMN_PRIORITY, COLUMN_TXHASH, COLUMN_VOUT_INDEX, + COLUMN_LOCKED }; friend class CCoinControlWidgetItem; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 5b4913a1..ebe07677 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -843,7 +843,7 @@ void WalletModel::getOutputs(const std::vector& vOutpoints, std::vect if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true); + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true, wallet->mapWallet[outpoint.hash].vout[outpoint.n].GetLockTime()); vOutputs.push_back(out); } } @@ -870,7 +870,7 @@ void WalletModel::listCoins(std::map >& mapCoins, if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true); + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true, wallet->mapWallet[outpoint.hash].vout[outpoint.n].GetLockTime()); if (outpoint.n < out.tx->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE) vCoins.push_back(out); } @@ -883,7 +883,7 @@ void WalletModel::listCoins(std::map >& mapCoins, while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0])) { if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break; - cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true, true); + cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0, true, true, wallet->mapWallet[cout.tx->vin[0].prevout.hash].vout[cout.tx->vin[0].prevout.n].GetLockTime()); } } CTxDestination address; From 63b5d6187f7fb027263d27a2730e54b3c1f71ba0 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 14:40:06 +0100 Subject: [PATCH 074/126] smartrewards/qt: Improved smartrewards UI update process --- src/qt/forms/smartrewardslist.ui | 138 +------------------------------ src/qt/smartrewardslist.cpp | 22 ++--- src/qt/smartrewardslist.h | 1 - src/rpc/smartrewards.cpp | 2 +- src/smartrewards/rewards.cpp | 18 ++-- src/smartrewards/rewards.h | 7 +- 6 files changed, 17 insertions(+), 171 deletions(-) diff --git a/src/qt/forms/smartrewardslist.ui b/src/qt/forms/smartrewardslist.ui index cadbe6c7..32f22e51 100644 --- a/src/qt/forms/smartrewardslist.ui +++ b/src/qt/forms/smartrewardslist.ui @@ -32,7 +32,7 @@ - 2 + 0 @@ -142,142 +142,6 @@ - - - - - - Qt::Vertical - - - - 20 - 142 - - - - - - - - - 29 - 75 - true - - - - - - - Creating SmartRewards database... - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 30 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 80 - 20 - - - - - - - - - 0 - 0 - - - - QProgressBar { - border: 2px solid black; - border-radius: 5px; - text-align: center; - font-weight: bold; -} - -QProgressBar::chunk { - background-color: #FEC60D; -} - - - 100000 - - - 21 - - - Qt::AlignCenter - - - false - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 80 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 142 - - - - - - diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index cc8529c9..71f7933e 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -127,16 +127,9 @@ void SmartrewardsList::setClientModel(ClientModel *model) void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, const CBlockIndex *tip) { + LogPrintf("SmartrewardsList::updateOverviewUI %d\n", tip->nHeight); - static int64_t lastUpdate = 0; int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - int64_t currentTime = QDateTime::currentMSecsSinceEpoch() / 1000; - - if( !lastUpdate || currentTime - lastUpdate > 5 ){ - lastUpdate = currentTime; - }else{ - return; - } if( currentRound.number < nFirst_1_3_Round ){ ui->btnSendProofs->hide(); @@ -144,8 +137,6 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c ui->btnSendProofs->show(); } - ui->spinnerWidget->stop(); - QString percentText; percentText.sprintf("%.2f%%", currentRound.percent * 100); ui->percentLabel->setText(percentText); @@ -194,6 +185,8 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c }else{ + int64_t currentTime = QDateTime::currentMSecsSinceEpoch() / 1000; + roundEndText = roundEnd.toString(Qt::SystemLocaleShortDate); if( currentRound.endBlockTime < currentTime ) { @@ -548,16 +541,11 @@ void SmartrewardsList::updateUI() switch(state){ case STATE_INIT: - setState(STATE_PROCESSING); + if( prewards->IsSynced() && !fReindex ){ - break; - case STATE_PROCESSING: + ui->spinnerWidget->stop(); - if( prewards->IsSynced() && !fReindex ){ setState(STATE_OVERVIEW); - }else{ - double progress = prewards->GetProgress() * ui->loadingProgress->maximum(); - ui->loadingProgress->setValue(progress); } break; diff --git a/src/qt/smartrewardslist.h b/src/qt/smartrewardslist.h index c203e951..bf5e154d 100644 --- a/src/qt/smartrewardslist.h +++ b/src/qt/smartrewardslist.h @@ -59,7 +59,6 @@ class SmartrewardsList : public QWidget enum SmartRewardsListState{ STATE_INIT, - STATE_PROCESSING, STATE_OVERVIEW }; diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index 71d04acd..f276d6d7 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -47,7 +47,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) ); if( !fDebug && !prewards->IsSynced() ) - throw JSONRPCError(RPC_DATABASE_ERROR, strprintf("Rewards database is not up to date. Current progress %d%%",int(prewards->GetProgress() * 100))); + throw JSONRPCError(RPC_DATABASE_ERROR, "Rewards database is not up to date."); TRY_LOCK(cs_rewardsdb, lockRewardsDb); diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 55a14817..9f8c6a26 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -378,15 +378,13 @@ bool CSmartRewards::SyncCached() bool CSmartRewards::IsSynced() { - int nSyncDistance = MainNet() ? nRewardsSyncDistance : nRewardsSyncDistance_Testnet; - return (pindexBestHeader->nHeight - cache.GetCurrentBlock()->nHeight ) <= nSyncDistance - 1; -} + static bool fSynced = false; -double CSmartRewards::GetProgress() -{ - int nSyncDistance = MainNet() ? nRewardsSyncDistance : nRewardsSyncDistance_Testnet; - double progress = pindexBestHeader->nHeight > nSyncDistance ? double(cache.GetCurrentBlock()->nHeight) / double(pindexBestHeader->nHeight - nSyncDistance) : 0.0; - return progress > 1 ? 1 : progress; + if( fSynced ) return true; + + fSynced = (GetTime() - cache.GetCurrentBlock()->nTime ) <= nRewardsSyncDistance; + + return fSynced; } int CSmartRewards::GetBlocksPerRound(const int nRound) @@ -1052,7 +1050,7 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe if( LogAcceptCategory("smartrewards-bench") ){ int nTime2 = GetTimeMicros(); double dProcessingTime = (nTime2 - nTime1) * 0.001; - LogPrint("smartrewards-bench", "Round %d - Block: %d - Progress %d%%\n", round->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-bench", "Round %d - Block: %d\n", round->number, cache.GetCurrentBlock()->nHeight); LogPrint("smartrewards-bench", " Commit block: %.2fms\n", dProcessingTime); } @@ -1135,7 +1133,7 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda int nTime2 = GetTimeMicros(); if( LogAcceptCategory("smartrewards-block") ){ - LogPrint("smartrewards-block", "Round %d - Block: %d - Progress %d%%\n",pRound->number, cache.GetCurrentBlock()->nHeight, int(prewards->GetProgress() * 100)); + LogPrint("smartrewards-block", "Round %d - Block: %d\n",pRound->number, cache.GetCurrentBlock()->nHeight); LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index bd8091d3..71495aae 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -17,9 +17,8 @@ using namespace std; static const CAmount SMART_REWARDS_MIN_BALANCE_1_2 = 1000 * COIN; static const CAmount SMART_REWARDS_MIN_BALANCE_1_3 = 10000 * COIN; -// Minimum distance of the last processed block compared to the current chain -// height to assume the rewards are synced. -const int64_t nRewardsSyncDistance = 150; +// Seconds between current time and last blocktime which must be undershot for the rewards processing to assume its synced +const int64_t nRewardsSyncDistance = 600; // Number of blocks we update the SmartRewards UI when we are in the sync process const int64_t nRewardsUISyncUpdateRate = 500; @@ -33,7 +32,6 @@ const int64_t nFirstRoundStartBlock = 1; const int64_t nFirstRoundEndBlock = 60001; // Timestamps of the first round's start and end on testnet -const int64_t nRewardsSyncDistance_Testnet = 60; const int64_t nFirstTxTimestamp_Testnet = 1527192589; const int64_t nFirstRoundStartTime_Testnet = nFirstTxTimestamp_Testnet; const int64_t nFirstRoundEndTime_Testnet = nFirstRoundStartTime_Testnet + (2*60*60); @@ -160,7 +158,6 @@ class CSmartRewards bool NeedsCacheWrite(); bool SyncCached(); bool IsSynced(); - double GetProgress(); int GetBlocksPerRound(const int nRound); From e5230a2f2407bdfa6eb23599f2d76c7fcad8755e Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 14:44:10 +0100 Subject: [PATCH 075/126] qt: Properly lock/unlock outputs locked with OP_CHECKLOCKTIMEVERIFY --- src/qt/coincontroldialog.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 12c04342..db28f1a1 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -818,8 +818,12 @@ void CoinControlDialog::updateView() itemOutput->setData(COLUMN_LOCKED, Qt::UserRole, QVariant(fOutputLocked)); + COutPoint outpt(txhash, out.i); + if( fOutputLocked ){ + model->lockCoin(outpt); + if( out.nLockTime < LOCKTIME_THRESHOLD ){ itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until block %1").arg(out.nLockTime)); }else{ @@ -827,19 +831,20 @@ void CoinControlDialog::updateView() timestamp.setTime_t(out.nLockTime); itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until %1").arg(timestamp.toString(Qt::SystemLocaleShortDate))); } + }else if( out.nLockTime ){ + model->unlockCoin(outpt); } // disable locked coins - if (model->isLockedCoin(txhash, out.i) || fOutputLocked) + if (model->isLockedCoin(outpt.hash, outpt.n) || fOutputLocked) { - COutPoint outpt(txhash, out.i); coinControl->UnSelect(outpt); // just to be sure itemOutput->setDisabled(true); itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); } // set checkbox - if (coinControl->IsSelected(COutPoint(txhash, out.i))) + if (coinControl->IsSelected(outpt)) itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } From 1d99aa68cc30a6aa06863789a1b35cb39f5fc856 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 15:08:21 +0100 Subject: [PATCH 076/126] wallet: Log cleanup --- src/wallet/wallet.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 346e06ad..321e54e5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2407,16 +2407,10 @@ void CWallet::AvailableCoins(vector &vCoins, bool fOnlyConfirmed, cons (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))){ - uint32_t nLockTime = pcoin->vout[i].GetLockTime(); - - if( nLockTime ){ - LogPrintf("LOCKTIME FOUND: %d\n", nLockTime); - } - vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), - (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, nLockTime)); + (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, pcoin->vout[i].GetLockTime())); } } @@ -2460,19 +2454,12 @@ void CWallet::AvailableCoins(vector &vCoins, const CSmartAddress& addr isminetype mine = IsMine(pcoin->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && !IsLockedCoin((*it).first, i) && - pcoin->vout[i].nValue > 0){ - - uint32_t nLockTime = pcoin->vout[i].GetLockTime(); - - if( nLockTime ){ - LogPrintf("LOCKTIME FOUND %d\n", nLockTime); - } - + pcoin->vout[i].nValue > 0){ vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || false, (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, - nLockTime)); + pcoin->vout[i].GetLockTime())); } } From a668a7be4f869bea724929c57a659e228dd94cde Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 16:25:04 +0100 Subject: [PATCH 077/126] smartrewards: Process locked pub/scripthash outputs --- src/smartrewards/rewards.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 9f8c6a26..8e27f89f 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -84,6 +84,16 @@ bool ExtractDestination(const CScript& scriptPubKey, CSmartAddress& idRet) idRet = CSmartAddress(CScriptID(uint160(vSolutions[0]))); return true; } + else if (whichType == TX_PUBKEYHASHLOCKED) + { + idRet = CSmartAddress(CKeyID(uint160(vSolutions[0]))); + return true; + } + else if (whichType == TX_SCRIPTHASHLOCKED) + { + idRet = CSmartAddress(CScriptID(uint160(vSolutions[0]))); + return true; + } // Multisig txns have more than one address... return false; } From 914679d1fb81ba66504f68050da0cd90b35cc195 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 16:44:54 +0100 Subject: [PATCH 078/126] init: Fixed smartrewards loading --- src/init.cpp | 106 ++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index b277a9d6..0b5d4c1e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1654,7 +1654,56 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) prewards = new CSmartRewards(prewardsdb); + uiInterface.InitMessage(_("Loading SmartRewards...")); + bool fLoaded = false; + + while (!fLoaded) { + + std::string strLoadError; + + nStart = GetTimeMillis(); + do { + try { + + if( fReindex ){ + delete prewards; + + prewardsdb = new CSmartRewardsDB(nRewardsCache, false, true); + prewards = new CSmartRewards(prewardsdb); + } + + if( !(fLoaded = prewards->Verify()) ) throw std::runtime_error(_("Failed to verify SmartRewards database.")); + + if (fRequestShutdown) break; + + } catch (const std::runtime_error &e) { + if (fDebug) LogPrintf("%s\n", e.what()); + strLoadError = e.what(); + break; + } catch (const std::exception &e) { + if (fDebug) LogPrintf("%s\n", e.what()); + strLoadError = _("Error opening rewards database"); + break; + } catch ( ... ){ + if (fDebug) LogPrintf("Unexpected exception\n"); + strLoadError = _("Unexpected error with the rewards database"); + break; + } + + fLoaded = true; + + } while(false); + + if( !fLoaded ){ + InitWarning(strLoadError + _("\n\nReindexing blockchain data now...")); + fReindex = true; + } + + } + + fLoaded = false; + while (!fLoaded && !fRequestShutdown) { bool fReset = fReindex; std::string strLoadError; @@ -1781,63 +1830,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); - uiInterface.InitMessage(_("Verifying SmartRewards...")); - - CBlockIndex *pLastIndex = chainActive.Tip(); - bool fResetRewards = fReindex; - fLoaded = false; - - while (!fLoaded) { - - std::string strLoadError; - - nStart = GetTimeMillis(); - do { - try { - - if( fResetRewards ){ - delete prewards; - - prewardsdb = new CSmartRewardsDB(nRewardsCache, false, true); - prewards = new CSmartRewards(prewardsdb); - } - - if( !(fLoaded = prewards->Verify()) ) throw std::runtime_error(_("Failed to verify SmartRewards database.")); - -// if( pLastIndex && prewards->GetLastHeight() <= pLastIndex->nHeight){ -// prewards->RollBack(pLastIndex); -// }else if( pLastIndex && prewards->GetLastHeight() > pLastIndex->nHeight ){ -// prewards->CatchUp(pLastIndex); -// } -// if( pLastIndex != NULL && !(fLoaded = (prewards->GetLastHeight() <= pLastIndex->nHeight)) ) throw std::runtime_error(_("SmartRewards database exceeds current chain height.")); - - if (fRequestShutdown) break; - - } catch (const std::runtime_error &e) { - if (fDebug) LogPrintf("%s\n", e.what()); - strLoadError = e.what(); - break; - } catch (const std::exception &e) { - if (fDebug) LogPrintf("%s\n", e.what()); - strLoadError = _("Error opening rewards database"); - break; - } catch ( ... ){ - if (fDebug) LogPrintf("Unexpected exception\n"); - strLoadError = _("Unexpected error with the rewards database"); - break; - } - - fLoaded = true; - - } while(false); - - if( !fLoaded ){ - InitWarning(strLoadError + _("\n\nRecreating it now...")); - fResetRewards = true; - } - - } - // As LoadBlockIndex can take several minutes, it's possible the user // requested to kill the GUI during the last operation. If so, exit. // As the program has not fully started yet, Shutdown() is possibly overkill. From 5d4a15c43c5746404df87e7c28dd1d5a8fbf24b5 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 16:45:09 +0100 Subject: [PATCH 079/126] smartrewards: Increased DB version --- src/smartrewards/rewardsdb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index 4e6885d5..6a48e401 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -12,7 +12,7 @@ #include "base58.h" #include "smarthive/hive.h" -static constexpr uint8_t REWARDS_DB_VERSION = 0x09; +static constexpr uint8_t REWARDS_DB_VERSION = 0x0A; //! Compensate for extra memory peak (x1.5-x1.9) at flush time. static constexpr int REWARDS_DB_PEAK_USAGE_FACTOR = 2; From f7e22db7af8b0e4473abac4a76d9c1d02ed962b8 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 7 Nov 2019 17:15:38 +0100 Subject: [PATCH 080/126] qt: Removed obsolete addresses from the smartreward list --- src/qt/smartrewardslist.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 71f7933e..d61f7ca2 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -395,6 +395,24 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c int nEligibleAddresses = 0; CAmount rewardSum = 0; + auto entry = vecEntries.begin(); + + while( entry != vecEntries.end() ){ + + auto it = std::find_if(rewardList.begin(), + rewardList.end(), + [entry](QSmartRewardField& field) -> bool { + return (*entry)->Address() == field.address; + }); + + if( it == rewardList.end() ) { + delete *entry; + entry = vecEntries.erase(entry); + }else{ + ++entry; + } + } + BOOST_FOREACH(const QSmartRewardField& field, rewardList) { QSmartRewardEntry* entry; From dced8a3c15fb9afe31f3e9719c4cb03bc3db1571 Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 11 Nov 2019 14:19:15 +0100 Subject: [PATCH 081/126] mempool: Process locked pubkey/scripthash outputs --- src/txmempool.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index be98da40..383aa4e4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -450,6 +450,26 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(make_pair(key, delta)); inserted.push_back(key); + } else if (prevout.scriptPubKey.IsPayToPublicKeyHashLocked() ) { + + int nOffset = prevout.scriptPubKey[0] + 6; + + vector hashBytes(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20); + + CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(make_pair(key, delta)); + inserted.push_back(key); + } else if (prevout.scriptPubKey.IsPayToScriptHashLocked() ) { + + int nOffset = prevout.scriptPubKey[0] + 5; + + vector hashBytes(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20); + + CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(make_pair(key, delta)); + inserted.push_back(key); } } @@ -477,6 +497,25 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDeltaKey key(1, nPubKeyHash, txhash, k, 0); mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); inserted.push_back(key); + } else if (out.scriptPubKey.IsPayToPublicKeyHashLocked() ) { + + int nOffset = out.scriptPubKey[0] + 6; + + vector hashBytes(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20); + + std::pair ret; + CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0); + mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); + } else if (out.scriptPubKey.IsPayToScriptHashLocked() ) { + + int nOffset = out.scriptPubKey[0] + 5; + + vector hashBytes(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20); + + CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0); + mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); } } @@ -542,6 +581,18 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac } addressType = 1; + } else if (prevout.scriptPubKey.IsPayToPublicKeyHashLocked()) { + + int nOffset = prevout.scriptPubKey[0] + 6; + + addressHash = uint160(vector (prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 1; + } else if (prevout.scriptPubKey.IsPayToScriptHashLocked()) { + + int nOffset = prevout.scriptPubKey[0] + 5; + + addressHash = uint160(vector (prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 2; } else { addressHash.SetNull(); addressType = 0; From 12341daab9eb883fea7a390a17aca3b4225296cb Mon Sep 17 00:00:00 2001 From: dustinface Date: Mon, 11 Nov 2019 14:19:44 +0100 Subject: [PATCH 082/126] validation: Process locked pubkey/scripthash outputs --- src/validation.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 2d0bc7bb..f7474f8b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1894,6 +1894,18 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s CPubKey pubKey(pubKeyBytes); hashBytes = pubKey.GetID(); addressType = 1; + } else if (out.scriptPubKey.IsPayToScriptHashLocked()) { + + int nOffset = out.scriptPubKey[0] + 5; + + hashBytes = uint160(vector(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20)); + addressType = 2; + } else if (out.scriptPubKey.IsPayToPublicKeyHashLocked()) { + + int nOffset = out.scriptPubKey[0] + 6; + + hashBytes = uint160(vector(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20)); + addressType = 1; } else { continue; } @@ -1983,6 +1995,20 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s CPubKey pubKey(pubKeyBytes); hashBytes = pubKey.GetID(); addressType = 1; + } else if (prevout.scriptPubKey.IsPayToScriptHashLocked()) { + + int nOffset = prevout.scriptPubKey[0] + 5; + + hashBytes = uint160(vector(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 2; + + } else if (prevout.scriptPubKey.IsPayToPublicKeyHashLocked()) { + + int nOffset = prevout.scriptPubKey[0] + 6; + + hashBytes = uint160(vector(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 1; + } else { continue; } @@ -2432,6 +2458,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd CPubKey pubKey(pubKeyBytes); hashBytes = pubKey.GetID(); addressType = 1; + } else if (prevout.scriptPubKey.IsPayToScriptHashLocked()) { + int nOffset = prevout.scriptPubKey[0] + 5; + + hashBytes = uint160(vector(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 2; + } else if (prevout.scriptPubKey.IsPayToPublicKeyHashLocked()) { + int nOffset = prevout.scriptPubKey[0] + 6; + + hashBytes = uint160(vector(prevout.scriptPubKey.begin() + nOffset, prevout.scriptPubKey.begin() + nOffset + 20)); + addressType = 1; } else { hashBytes.SetNull(); addressType = 0; @@ -2513,6 +2549,16 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd CPubKey pubKey(pubKeyBytes); hashBytes = pubKey.GetID(); addressType = 1; + } else if (out.scriptPubKey.IsPayToScriptHashLocked()) { + int nOffset = out.scriptPubKey[0] + 5; + + hashBytes = uint160(vector(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20)); + addressType = 2; + } else if (out.scriptPubKey.IsPayToPublicKeyHashLocked()) { + int nOffset = out.scriptPubKey[0] + 6; + + hashBytes = uint160(vector(out.scriptPubKey.begin() + nOffset, out.scriptPubKey.begin() + nOffset + 20)); + addressType = 1; } else { continue; } From 44ed66e8a26ead0548ccac81985f1025af213b06 Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 12 Nov 2019 14:42:14 +0100 Subject: [PATCH 083/126] qt: Text change in SmartRewards tab --- src/qt/smartrewardslist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index d61f7ca2..8bb7fcab 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -451,7 +451,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c }else if( !field.fVoted ){ entry->setInfoText("Voting required. Go to the \"SmartVote\" tab and vote for a proposal with this address.", COLOR_NEGATIVE); }else if( field.fVoted && field.nVoteProofConfirmations == -1){ - entry->setInfoText("VoteProof required. Click the button in the bottom bar to send the VoteProof for this address.", COLOR_WARNING); + entry->setInfoText("VoteProof required. Click the button at the bottom to send the VoteProof for this address.", COLOR_WARNING); }else if( field.fVoted && nConfirmationsRequired > 0){ entry->setInfoText(QString("%1 more block confirmations required for the VoteProof transaction to become processed.").arg(nConfirmationsRequired), COLOR_WARNING); From fc6984a8e8e28711058ec303247fe5ab5fe4ab7c Mon Sep 17 00:00:00 2001 From: dustinface Date: Tue, 12 Nov 2019 16:10:24 +0100 Subject: [PATCH 084/126] qt: Update SmartRewards screen after voting in SmartVoting screen --- src/qt/smartvoting.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/smartvoting.cpp b/src/qt/smartvoting.cpp index e429846d..e6dbe8f2 100755 --- a/src/qt/smartvoting.cpp +++ b/src/qt/smartvoting.cpp @@ -201,6 +201,7 @@ void SmartVotingPage::castVotes(){ dialog.exec(); refreshProposals(true); + uiInterface.NotifySmartRewardUpdate(); } void SmartVotingPage::updateRefreshLock() From 888f00ff97c1babfbf2ac3667c96731c1590ed68 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 14 Nov 2019 00:34:09 +0100 Subject: [PATCH 085/126] qt: Added a description to the VoteProof form --- src/qt/specialtransactiondialog.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qt/specialtransactiondialog.h b/src/qt/specialtransactiondialog.h index 00d7ec8c..64f6059c 100644 --- a/src/qt/specialtransactiondialog.h +++ b/src/qt/specialtransactiondialog.h @@ -105,7 +105,9 @@ static const QString strRegistrationFeeDescription = "Register fee"; static const QString strVoteProofTitle = "Send VoteProofs"; static const QString strVoteProofDescription = ( -"" +"Use this form to send VoteProof transactions to make your addresses eligible for SmartRewards " +"after you cast a vote with them. A small fee of 0.001 SMART will be taken from outputs you choose.\n\n" +"You can either manually select an input for each address or automatically select the smallest input for each address by clicking the checkbox below." ); #endif // SMARTCASH_QT_SPECIALTRANSACTIONDIALOG_H From 322e73317abe717fdca58ce780f6030495319a39 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 14 Nov 2019 00:35:52 +0100 Subject: [PATCH 086/126] qt: Allow to send the VoteProofs from the SmartVoting Tab after voting --- src/qt/smartvoting.cpp | 37 +++++++++++++++++++++++++++++++++++-- src/qt/smartvoting.h | 2 ++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/qt/smartvoting.cpp b/src/qt/smartvoting.cpp index e6dbe8f2..b582a633 100755 --- a/src/qt/smartvoting.cpp +++ b/src/qt/smartvoting.cpp @@ -20,6 +20,7 @@ #include "castvotesdialog.h" #include "validation.h" #include "voteaddressesdialog.h" +#include "specialtransactiondialog.h" #include // for 'map_list_of()' @@ -50,7 +51,8 @@ SmartVotingPage::SmartVotingPage(const PlatformStyle *platformStyle, QWidget *pa QWidget(parent), ui(new Ui::SmartVotingPage), platformStyle(platformStyle), - walletModel(0) + walletModel(0), + nVoteProofRequired(0) { ui->setupUi(this); @@ -198,10 +200,29 @@ void SmartVotingPage::castVotes(){ connect( &dialog, SIGNAL(votedForAddress(QString&, int, bool)), this, SLOT(voteDone(QString&, int, bool))); dialog.setVoting(mapVoteProposals); + nVoteProofRequired = 0; + dialog.exec(); + if( nVoteProofRequired ){ + + // Display message box + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("VoteProof required"), + tr("Do you want to send a VoteProof for %1 address%2 to enable SmartRewards?\n\nThis can also be done later in the SmartRewards Tab.").arg(nVoteProofRequired).arg( nVoteProofRequired > 1 ? "es" : ""), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes); + + if(retval == QMessageBox::Yes){ + SpecialTransactionDialog dlg(VOTE_PROOF_TRANSACTIONS, platformStyle); + dlg.setModel(walletModel); + dlg.exec(); + } + + } + refreshProposals(true); uiInterface.NotifySmartRewardUpdate(); + } void SmartVotingPage::updateRefreshLock() @@ -257,18 +278,30 @@ void SmartVotingPage::voteDone(QString &address, int nProposalId, bool successfu CKeyID keyId; std::string strProposal = strprintf("%d", nProposalId); uint256 nProposalHash = Hash(strProposal.begin(), strProposal.end()); + CSmartAddress id(address.toStdString()); - if(CSmartAddress(address.toStdString()).GetKeyID(keyId)){ + if(id.GetKeyID(keyId)){ LOCK(cs_rewardscache); int nCurrentRound = prewards->GetCurrentRound()->number; if( !pwalletMain->mapVoted[keyId].count(nCurrentRound) ){ + pwalletMain->mapVoted[keyId].insert(std::make_pair(nCurrentRound, nProposalHash)); pwalletMain->UpdateVotedMap(keyId); } + CSmartRewardEntry * entry; + + if( nCurrentRound >= Params().GetConsensus().nRewardsFirst_1_3_Round && + pwalletMain->mapVoteProofs[keyId].find(nCurrentRound) == pwalletMain->mapVoteProofs[keyId].end() && + prewards->GetRewardEntry(CSmartAddress(id.ToString(false)), entry, false) ){ + + if( entry->balanceEligible && !entry->fSmartnodePaymentTx ){ + ++nVoteProofRequired; + } + } } } diff --git a/src/qt/smartvoting.h b/src/qt/smartvoting.h index 2ba6323d..abe55e16 100755 --- a/src/qt/smartvoting.h +++ b/src/qt/smartvoting.h @@ -59,6 +59,8 @@ class SmartVotingPage : public QWidget SmartVotingManager *votingManager; std::vector vecProposalWidgets; std::map mapVoteProposals; + + int nVoteProofRequired; public Q_SLOTS: void updateUI(); From 42713df0b5dc20cc973ff78c8675684a1fe0dfdb Mon Sep 17 00:00:00 2001 From: dustinface Date: Fri, 15 Nov 2019 07:59:16 +0100 Subject: [PATCH 087/126] qt: Text changes in SmartRewards tab and SpecialTransactionDialog --- src/qt/smartrewardslist.cpp | 2 +- src/qt/specialtransactiondialog.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 8bb7fcab..a2ad59d2 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -454,7 +454,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c entry->setInfoText("VoteProof required. Click the button at the bottom to send the VoteProof for this address.", COLOR_WARNING); }else if( field.fVoted && nConfirmationsRequired > 0){ - entry->setInfoText(QString("%1 more block confirmations required for the VoteProof transaction to become processed.").arg(nConfirmationsRequired), COLOR_WARNING); + entry->setInfoText(QString("%1 block confirmation required for the VoteProof transaction to become processed.").arg(nConfirmationsRequired), COLOR_WARNING); }else if( field.fVoted && nConfirmationsRequired <= 0 && field.eligible ){ diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index c29e2a43..c8ed0d06 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -233,7 +233,7 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) "with any earlier backup of your wallet.")); break; case VOTE_PROOF_TRANSACTIONS: - strResult.append(tr("It requires %1 block confirmations for the VoteProof transactions before the address will become eligible in the SmartRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); + strResult.append(tr("It requires %1 block confirmation for the VoteProof transactions before the address will become eligible in the SmartRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); break; } From 88cfcc9a5fe5f04ebe3f2cfb62c0f34223cef33c Mon Sep 17 00:00:00 2001 From: dustinface Date: Wed, 20 Nov 2019 17:13:06 +0100 Subject: [PATCH 088/126] chainparams: Adjusted first 1.3 smartrewards round --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9c51c789..75d36c7d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -140,7 +140,7 @@ class CMainParams : public CChainParams { //! 1.3 Parameter consensus.nRewardsBlocksPerRound_1_3 = 142500; - consensus.nRewardsFirst_1_3_Round = 30; + consensus.nRewardsFirst_1_3_Round = 31; consensus.nRewardsPayouts_1_3_BlockStretch = 10990; // 1 week consensus.nRewardsPayouts_1_3_BlockPayees = 10; From 7be333c7b2d13830c0ae8c4838bde35c20222e7b Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 21 Nov 2019 07:34:34 +0100 Subject: [PATCH 089/126] Disabled Mainnet --- src/init.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 0b5d4c1e..1f48bad6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2289,5 +2289,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman))); + if( MainNet() ){ + InitError("Mainnet is not available in this beta. You can start the client on Testnet with testnet=1 in the smartcash.conf or -testnet=1 as command line argument."); + StartShutdown(); + } + return !fRequestShutdown; } From 4afadb12dcd93e028f7331a073c5edae83ac2971 Mon Sep 17 00:00:00 2001 From: dustinface Date: Thu, 21 Nov 2019 14:36:07 +0100 Subject: [PATCH 090/126] contrib: Added rpi gitian descriptor --- contrib/gitian-descriptors/gitian-rpi.yml | 112 ++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 contrib/gitian-descriptors/gitian-rpi.yml diff --git a/contrib/gitian-descriptors/gitian-rpi.yml b/contrib/gitian-descriptors/gitian-rpi.yml new file mode 100644 index 00000000..1178b89f --- /dev/null +++ b/contrib/gitian-descriptors/gitian-rpi.yml @@ -0,0 +1,112 @@ +--- +name: "smartcash-rpi-1.3" +enable_cache: true +suites: +- "trusty" +architectures: +- "amd64" +packages: +- "g++-multilib" +- "git-core" +- "pkg-config" +- "autoconf2.13" +- "libtool" +- "automake" +- "faketime" +- "bsdmainutils" +- "binutils-gold" +reference_datetime: "2017-01-01 00:00:00" +remotes: +- "url": "https://github.com/smartcash/core-smart.git" + "dir": "core-smart" +files: +- "raspberrypi-tools.tar.gz" +script: | + WRAP_DIR=$HOME/wrapped + HOSTS="arm-linux-gnueabihf" + CONFIGFLAGS="--enable-upnp-default --enable-glibc-back-compat" + FAKETIME_HOST_PROGS="" + FAKETIME_PROGS="date ar ranlib nm strip" + + tar --warning=no-timestamp -xzf raspberrypi-tools.tar.gz + export TOOLCHAIN_BIN=$(pwd)/raspberrypi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin + export PATH=$PATH:$TOOLCHAIN_BIN + + export QT_RCC_TEST=1 + export GZIP="-9n" + export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" + export TZ="UTC" + export BUILD_DIR=`pwd` + mkdir -p ${WRAP_DIR} + if test -n "$GBUILD_CACHE_ENABLED"; then + export SOURCES_PATH=${GBUILD_COMMON_CACHE} + export BASE_CACHE=${GBUILD_PACKAGE_CACHE} + mkdir -p ${BASE_CACHE} ${SOURCES_PATH} + fi + + # Create global faketime wrappers + for prog in ${FAKETIME_PROGS}; do + echo '#!/bin/bash' > ${WRAP_DIR}/${prog} + echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${prog} + chmod +x ${WRAP_DIR}/${prog} + done + + # Create per-host faketime wrappers + for i in $HOSTS; do + for prog in ${FAKETIME_HOST_PROGS}; do + echo '#!/bin/bash' > ${WRAP_DIR}/${i}-${prog} + echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${i}-${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} + chmod +x ${WRAP_DIR}/${i}-${prog} + done + done + export PATH=${WRAP_DIR}:${PATH} + + cd core-smart + BASEPREFIX=`pwd`/depends + # Build dependencies for each host + for i in $HOSTS; do + make ${MAKEOPTS} NO_QT=1 -C ${BASEPREFIX} HOST="${i}" + done + + # Create the release tarball using (arbitrarily) the first host + ./autogen.sh + ./configure --prefix=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'` + make NO_QT=1 dist + SOURCEDIST=`echo smartcash-*.tar.gz` + DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` + # Correct tar file order + mkdir -p temp + pushd temp + tar xf ../$SOURCEDIST + find smartcash-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + popd + + ORIGPATH="$PATH" + # Extract the release tarball into a dir for each host and build + for i in ${HOSTS}; do + export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} + mkdir -p distsrc-${i} + cd distsrc-${i} + INSTALLPATH=`pwd`/installed/${DISTNAME} + mkdir -p ${INSTALLPATH} + tar --strip-components=1 -xf ../$SOURCEDIST + + ./configure --prefix=${BASEPREFIX}/${i} --bindir=${INSTALLPATH}/bin --includedir=${INSTALLPATH}/include --libdir=${INSTALLPATH}/lib --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} + make ${MAKEOPTS} NO_QT=1 + make NO_QT=1 install-strip + cd installed + find . -name "lib*.la" -delete + find . -name "lib*.a" -delete + rm -rf ${DISTNAME}/lib/pkgconfig + find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + cd ../../ + done + mkdir -p $OUTDIR/src + mv $SOURCEDIST $OUTDIR/src + mv ${OUTDIR}/${DISTNAME}-arm-*.tar.gz ${OUTDIR}/${DISTNAME}-arm-rpi.tar.gz From e857aa8425ec85733a913c39b3bf3402137201e7 Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Wed, 4 Dec 2019 13:50:44 -0600 Subject: [PATCH 091/126] Increase Blocksize and Update 1.3 Height --- src/consensus/consensus.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 0e43a1fc..18f61661 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -11,9 +11,9 @@ /** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 8000000; /** The maximum allowed weight for a block, see BIP 141 (network rule) */ -static const unsigned int MAX_BLOCK_WEIGHT = 16000000; +static const unsigned int MAX_BLOCK_WEIGHT = 32000000; /** The maximum allowed size for a block excluding witness data, in bytes (network rule) */ -static const unsigned int MAX_BLOCK_BASE_SIZE = 4000000; +static const unsigned int MAX_BLOCK_BASE_SIZE = 8000000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const int64_t MAX_BLOCK_SIGOPS_COST = 640000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_HEIGHT = 1380001; +static const int HF_V1_3_HEIGHT = 1430001; /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; From 80df8e1d6abd648250950e88be8a345a13265089 Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Sun, 29 Dec 2019 02:34:23 -0600 Subject: [PATCH 092/126] Update Block Buffer --- src/consensus/consensus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 18f61661..b5d153f1 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -9,7 +9,7 @@ #include /** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ -static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 8000000; +static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 16000000; /** The maximum allowed weight for a block, see BIP 141 (network rule) */ static const unsigned int MAX_BLOCK_WEIGHT = 32000000; /** The maximum allowed size for a block excluding witness data, in bytes (network rule) */ From cfa13393e86e3e1e0c5f53951c2aee30564e4240 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Mon, 23 Dec 2019 23:54:06 -0600 Subject: [PATCH 093/126] SAPI updates --- src/consensus/consensus.h | 2 +- src/init.cpp | 16 +++++++++++----- src/qt/bitcoingui.cpp | 4 ++-- src/qt/forms/smartrewardslist.ui | 6 +++--- src/qt/locale/bitcoin_en.ts | 20 ++++++++++---------- src/qt/smartvoting.cpp | 2 +- src/qt/specialtransactiondialog.cpp | 4 ++-- src/sapi/sapi.cpp | 2 +- src/sapi/sapi_smartnodes.cpp | 2 +- src/util.cpp | 2 +- src/wallet/rpcwallet.cpp | 15 +++++++++------ 11 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index b5d153f1..5c59e39f 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_HEIGHT = 1430001; +static const int HF_V1_3_HEIGHT = 1500001; /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; diff --git a/src/init.cpp b/src/init.cpp index 1f48bad6..6fe72a82 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -607,7 +607,13 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpcworkqueue=", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE)); strUsage += HelpMessageOpt("-rpcservertimeout=", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT)); } - + strUsage += HelpMessageGroup(_("SAPI server options:")); + strUsage += HelpMessageOpt("-sapi", _("Enable SmartCash API server and databases. Also enables -addressindex, -spentindex, -depositindex, -instantpayindex.")); + strUsage += HelpMessageOpt("-sapiport=",_("Listen for SAPI requests on (default: 8080)")); + strUsage += HelpMessageOpt("-sapithreads=",_("Set the number of threads for SAPI requests (default: 4)")); + strUsage += HelpMessageOpt("-sapiworkqueue=",_("Set the queue for SAPI requests (default: 16)")); + strUsage += HelpMessageOpt("-sapiservertimeout=",_("Set the seconds before SAPI timeout (default: 30)")); + strUsage += HelpMessageOpt("-sapiwhitelist:",_("Whitelist ip for SAPI")); return strUsage; } @@ -826,8 +832,8 @@ void InitParameterInteraction() if (GetBoolArg("-smartnode", false)) { // smartnodes must accept connections from outside - if (SoftSetBoolArg("-listen", true)) - LogPrintf("%s: parameter interaction: -smartnode=1 -> setting -listen=1\n", __func__); + if (SoftSetBoolArg("-listen", true) && SoftSetBoolArg("-sapi", true)) + LogPrintf("%s: parameter interaction: -smartnode=1 -> setting -listen=1 and -sapi=1\n", __func__); } if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { @@ -2289,10 +2295,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman))); - if( MainNet() ){ +/* if( MainNet() ){ InitError("Mainnet is not available in this beta. You can start the client on Testnet with testnet=1 in the smartcash.conf or -testnet=1 as command line argument."); StartShutdown(); - } + }*/ return !fRequestShutdown; } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 26eaa0ba..4b7eddfc 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -326,8 +326,8 @@ void BitcoinGUI::createActions() smartnodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6)); tabGroup->addAction(smartnodeAction); - smartrewardsAction = new QAction(platformStyle->SingleColorIcon(":/icons/smartrewards"), tr("&SmartRewards"), this); - smartrewardsAction->setStatusTip(tr("Show eligible addresses for SmartRewards")); + smartrewardsAction = new QAction(platformStyle->SingleColorIcon(":/icons/smartrewards"), tr("&VoteRewards"), this); + smartrewardsAction->setStatusTip(tr("Show eligible addresses for VoteRewards")); smartrewardsAction->setToolTip(smartrewardsAction->statusTip()); smartrewardsAction->setCheckable(true); smartrewardsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_7)); diff --git a/src/qt/forms/smartrewardslist.ui b/src/qt/forms/smartrewardslist.ui index 32f22e51..1da08d79 100644 --- a/src/qt/forms/smartrewardslist.ui +++ b/src/qt/forms/smartrewardslist.ui @@ -59,7 +59,7 @@ - Initialize SmartRewards... + Initialize VoteRewards... Qt::AlignCenter @@ -189,7 +189,7 @@ - SmartRewards round + VoteRewards round @@ -336,7 +336,7 @@ - Estimated SmartRewards + Estimated VoteRewards diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 454d602f..496f72e1 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -510,12 +510,12 @@ - &SmartRewards + &VoteRewards - Show eligible addresses for SmartRewards + Show eligible addresses for VoteRewards @@ -4427,7 +4427,7 @@ p, li { white-space: pre-wrap; } - Initialize SmartRewards... + Initialize VoteRewards... @@ -4437,7 +4437,7 @@ p, li { white-space: pre-wrap; } - SmartRewards round + VoteRewards round @@ -4492,7 +4492,7 @@ p, li { white-space: pre-wrap; } - Estimated SmartRewards + Estimated VoteRewards @@ -5851,7 +5851,7 @@ p, li { white-space: pre-wrap; } - Verifying SmartRewards... + Verifying VoteRewards... @@ -6128,7 +6128,7 @@ Recreating it now... - Creating SmartRewards database: + Creating VoteRewards database: @@ -6193,7 +6193,7 @@ Recreating it now... - Failed to verify SmartRewards database. + Failed to verify VoteRewards database. @@ -6383,12 +6383,12 @@ Recreating it now... - SmartRewards database exceeds current chain height. + VoteRewards database exceeds current chain height. - SmartRewards database is incomplete. + VoteRewards database is incomplete. diff --git a/src/qt/smartvoting.cpp b/src/qt/smartvoting.cpp index b582a633..9f7f5b74 100755 --- a/src/qt/smartvoting.cpp +++ b/src/qt/smartvoting.cpp @@ -208,7 +208,7 @@ void SmartVotingPage::castVotes(){ // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("VoteProof required"), - tr("Do you want to send a VoteProof for %1 address%2 to enable SmartRewards?\n\nThis can also be done later in the SmartRewards Tab.").arg(nVoteProofRequired).arg( nVoteProofRequired > 1 ? "es" : ""), + tr("Do you want to send a VoteProof for %1 address%2 to enable VoteRewards?\n\nThis can also be done later in the VoteRewards Tab.").arg(nVoteProofRequired).arg( nVoteProofRequired > 1 ? "es" : ""), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index c8ed0d06..0fc114db 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -233,7 +233,7 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) "with any earlier backup of your wallet.")); break; case VOTE_PROOF_TRANSACTIONS: - strResult.append(tr("It requires %1 block confirmation for the VoteProof transactions before the address will become eligible in the SmartRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); + strResult.append(tr("It requires %1 block confirmation for the VoteProof transactions before the address will become eligible in the VoteRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); break; } @@ -648,7 +648,7 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP if( pwalletMain->mapVoted[voteAddressKeyID].find(nCurrentRound) == pwalletMain->mapVoted[voteAddressKeyID].end() ){ return Error("GenerateVoteProof", - strprintf("Address %s did not yet vote during the SmartRewards round %d", + strprintf("Address %s did not yet vote during the VoteRewards round %d", voteAddress.ToString(), nCurrentRound), strError); } diff --git a/src/sapi/sapi.cpp b/src/sapi/sapi.cpp index 8dba3ba5..862ae4f2 100644 --- a/src/sapi/sapi.cpp +++ b/src/sapi/sapi.cpp @@ -67,7 +67,7 @@ static const int DEFAULT_SAPI_THREADS=4; static const int DEFAULT_SAPI_WORKQUEUE=16; static const int DEFAULT_SAPI_SERVER_TIMEOUT=30; -static const int DEFAULT_SAPI_SERVER_PORT=80; +static const int DEFAULT_SAPI_SERVER_PORT=8080; static const int DEFAULT_SAPI_JSON_INDENT=2; diff --git a/src/sapi/sapi_smartnodes.cpp b/src/sapi/sapi_smartnodes.cpp index 2cd132d5..326d4a86 100644 --- a/src/sapi/sapi_smartnodes.cpp +++ b/src/sapi/sapi_smartnodes.cpp @@ -167,7 +167,7 @@ static bool smartnodes_check_one(HTTPRequest* req, const std::map &mapPathParams, const UniValue &bodyParameter) { if( !bodyParameter.isArray() || bodyParameter.empty() ) - return SAPI::Error(req, HTTPStatus::BAD_REQUEST, "Addresses are expedted to be a JSON array: [ \"address\", ... ]"); + return SAPI::Error(req, HTTPStatus::BAD_REQUEST, "Addresses are expected to be a JSON array: [ \"address\", ... ]"); std::vector vecResults; std::vector vecInfos; diff --git a/src/util.cpp b/src/util.cpp index b64a7ac0..84f5c7db 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -109,7 +109,7 @@ int nWalletBackups = 10; const char * const BITCOIN_CONF_FILENAME = "smartcash.conf"; const char * const BITCOIN_PID_FILENAME = "smartcashd.pid"; -const std::vector args = {"version", "alertnotify", "blocknotify", "blocksonly", "checkblocks", "checklevel", "conf", "daemon", "datadir", "dbcache", "feefilter", "loadblock", "maxorphantx", "maxmempool", "mempoolexpiry", "par", "pid", "prune", "reindex-chainstate", "reindex", "sysperms", "depositindex", "addnode", "banscore", "bantime", "bind", "connect", "discover", "dns", "dnsseed", "externalip", "forcednsseed", "listen", "listenonion", "maxconnections", "maxreceivebuffer", "maxsendbuffer", "maxtimeadjustment", "onion", "onlynet", "permitbaremultisig", "peerbloomfilters", "port", "proxy", "proxyrandomize", "rpcserialversion", "seednode", "timeout", "torcontrol", "torpassword", "upnp", "whitebind", "whitelist", "whitelistrelay", "whitelistforcerelay", "maxuploadtarget", "zmqpubhashblock", "zmqpubhashtx", "zmqpubrawblock", "zmqpubrawtx", "uacomment", "checkblockindex", "checkmempool", "checkpoints", "disablesafemode", "testsafemode", "dropmessagestest", "fuzzmessagestest", "stopafterblockimport", "limitancestorcount", "limitancestorsize", "limitdescendantcount", "limitdescendantsize", "bip9params", "debug", "nodebug", "help-debug", "logips", "logtimestamps", "logtimemicros", "mocktime", "limitfreerelay", "relaypriority", "maxsigcachesize", "maxtipage", "minrelaytxfee", "maxtxfee", "printtoconsole", "printpriority", "shrinkdebugfile", "acceptnonstdtxn", "bytespersigop", "datacarrier", "datacarriersize", "mempoolreplacement", "blockmaxweight", "blockmaxsize", "txmaxcount", "blockprioritysize", "blockversion", "server", "rest", "rpcbind", "rpccookiefile", "rpcuser", "rpcpassword", "rpcauth", "rpcport", "rpcallowip", "rpcthreads", "rpcworkqueue", "rpcservertimeout", "help", "?", "disablewallet", "keypool", "fallbackfee", "mintxfee", "paytxfee", "rescan", "salvagewallet", "sendfreetransactions", "spendzeroconfchange", "txconfirmtarget", "usehd", "upgradewallet", "wallet", "walletbroadcast", "walletnotify", "zapwallettxes", "dblogsize", "flushwallet", "privdb", "walletrejectlongchains", "testnet", "usenewaddressformat"}; +const std::vector args = {"version", "alertnotify", "blocknotify", "blocksonly", "checkblocks", "checklevel", "conf", "daemon", "datadir", "dbcache", "feefilter", "loadblock", "maxorphantx", "maxmempool", "mempoolexpiry", "par", "pid", "prune", "reindex-chainstate", "reindex", "sysperms", "depositindex", "addnode", "banscore", "bantime", "bind", "connect", "discover", "dns", "dnsseed", "externalip", "forcednsseed", "listen", "listenonion", "maxconnections", "maxreceivebuffer", "maxsendbuffer", "maxtimeadjustment", "onion", "onlynet", "permitbaremultisig", "peerbloomfilters", "port", "proxy", "proxyrandomize", "rpcserialversion", "seednode", "timeout", "torcontrol", "torpassword", "upnp", "whitebind", "whitelist", "whitelistrelay", "whitelistforcerelay", "maxuploadtarget", "zmqpubhashblock", "zmqpubhashtx", "zmqpubrawblock", "zmqpubrawtx", "uacomment", "checkblockindex", "checkmempool", "checkpoints", "disablesafemode", "testsafemode", "dropmessagestest", "fuzzmessagestest", "stopafterblockimport", "limitancestorcount", "limitancestorsize", "limitdescendantcount", "limitdescendantsize", "bip9params", "debug", "nodebug", "help-debug", "logips", "logtimestamps", "logtimemicros", "mocktime", "limitfreerelay", "relaypriority", "maxsigcachesize", "maxtipage", "minrelaytxfee", "maxtxfee", "printtoconsole", "printpriority", "shrinkdebugfile", "acceptnonstdtxn", "bytespersigop", "datacarrier", "datacarriersize", "mempoolreplacement", "blockmaxweight", "blockmaxsize", "txmaxcount", "blockprioritysize", "blockversion", "server", "rest", "rpcbind", "rpccookiefile", "rpcuser", "rpcpassword", "rpcauth", "rpcport", "rpcallowip", "rpcthreads", "rpcworkqueue", "rpcservertimeout", "help", "?", "disablewallet", "keypool", "fallbackfee", "mintxfee", "paytxfee", "rescan", "salvagewallet", "sendfreetransactions", "spendzeroconfchange", "txconfirmtarget", "usehd", "upgradewallet", "wallet", "walletbroadcast", "walletnotify", "zapwallettxes", "dblogsize", "flushwallet", "privdb", "walletrejectlongchains", "testnet", "usenewaddressformat", "sapi", "sapiport", "sapithreads", "sapiworkqueue", "sapiservertimeout", "sapiwhitelist"}; map mapArgs; map > mapMultiArgs; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 52b89fdf..bccc80e6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -570,12 +570,15 @@ UniValue sendtoaddresslocked(const UniValue& params, bool fHelp) if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( "sendtoaddresslocked \"smartcashaddress\" amount blockheight( \"comment\" \"comment-to\" subtractfeefromamount )\n" - "\nSend an amount to a given address and lock the output for a given time or number of blocks.\n" + "\nSend an amount to a given address and lock the output until a future blockheight or Unix time.\n" + "This is not an InstantPay lock. Use sendmany or instantsendtoaddress instead.\n" + HelpRequiringPassphrase() + "\nArguments:\n" "1. \"smartcashaddress\" (string, required) The SmartCash address to send to.\n" "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" - "3. \"blockheight\" (numeric, required) The blockheight at which the output becomes spendable/unlocked.\n" + "3. \"blockheight\" (numeric, required) The blockheight at which the output becomes spendable/unlocked. \n" + " Unix time can be used for the time available to spend.\n" + " This is impossible to reverse after sent. Please be careful.\n" "4. \"comment\" (string, optional) A comment used to store what the transaction is for. \n" " This is not part of the transaction, just kept in your wallet.\n" "5. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n" @@ -584,10 +587,10 @@ UniValue sendtoaddresslocked(const UniValue& params, bool fHelp) "\nResult:\n" "\"transactionid\" (string) The transaction id.\n" "\nExamples:\n" - + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000") - + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000 \"donation\" \"seans outpost\"") - + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 500000 \"\" \"\" true") - + HelpExampleRpc("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\", 0.1, 500000, \"donation\", \"seans outpost\"") + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 1400000") + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 1577132833 \"donation\" \"seans outpost\"") + + HelpExampleCli("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\" 0.1 1400000 \"\" \"\" true") + + HelpExampleRpc("sendtoaddresslocked", "\"SXun9XDHLdBhG4Yd1ueZfLfRpC9kZgwT1b\", 0.1, 1400000, \"donation\", \"seans outpost\"") ); LOCK2(cs_main, pwalletMain->cs_wallet); From f187b66ead7d10bcf96561c0709dafb9c862e1e3 Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Tue, 24 Dec 2019 00:23:25 -0600 Subject: [PATCH 094/126] Protocol Version Updates --- src/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h b/src/version.h index a8022617..1ab5ae0b 100644 --- a/src/version.h +++ b/src/version.h @@ -12,7 +12,7 @@ static const int PROTOCOL_BASE_VERSION = 90000; static const int PROTOCOL_MAX_VERSION = 90000 + 0xFF; -static const int PROTOCOL_VERSION = 90032; +static const int PROTOCOL_VERSION = 90030; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 90013; @@ -21,7 +21,7 @@ static const int INIT_PROTO_VERSION = 90013; static const int GETHEADERS_VERSION = 90020; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 90031; +static const int MIN_PEER_PROTO_VERSION = 90028; //! first version with multi node payments static const int MIN_MULTIPAYMENT_PROTO_VERSION = 90026; From f8197a823d9522529a7a99fb04f8e2d24a9213b6 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Sun, 29 Dec 2019 14:33:55 -0600 Subject: [PATCH 095/126] Replace vote proof by activation tx and adapt SmartRewards UI tab --- src/chainparams.cpp | 18 +- src/consensus/consensus.h | 6 +- src/primitives/transaction.cpp | 37 +- src/primitives/transaction.h | 17 +- src/qt/bitcoingui.cpp | 4 +- src/qt/forms/sendcoinsdialog.ui | 1 + src/qt/forms/smartrewardentry.ui | 19 +- src/qt/forms/smartrewardslist.ui | 8 +- src/qt/locale/bitcoin_en.ts | 20 +- src/qt/sendcoinsdialog.cpp | 18 +- src/qt/smartrewardentry.cpp | 15 +- src/qt/smartrewardentry.h | 12 +- src/qt/smartrewardslist.cpp | 145 +---- src/qt/smartvoting.cpp | 62 +- src/qt/smartvoting.h | 3 - src/qt/specialtransactiondialog.cpp | 139 ++--- src/qt/specialtransactiondialog.h | 13 +- src/rpc/rawtransaction.cpp | 2 + src/rpc/smartrewards.cpp | 2 +- src/sapi/sapi_smartrewards.cpp | 2 +- src/script/script.cpp | 23 - src/script/script.h | 3 +- src/smartrewards/rewards.cpp | 887 +++++++++++++--------------- src/smartrewards/rewards.h | 101 ++-- src/smartrewards/rewardsdb.cpp | 181 +++--- src/smartrewards/rewardsdb.h | 13 +- src/smartvoting/proposal.cpp | 6 - src/validation.cpp | 7 +- src/validation.h | 11 +- src/wallet/wallet.cpp | 26 - src/wallet/wallet.h | 12 - src/wallet/walletdb.cpp | 34 -- src/wallet/walletdb.h | 2 - 33 files changed, 730 insertions(+), 1119 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 75d36c7d..1dad2f0a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -139,10 +139,10 @@ class CMainParams : public CChainParams { consensus.nRewardsPayouts_1_2_BlockPayees = 1000; //! 1.3 Parameter - consensus.nRewardsBlocksPerRound_1_3 = 142500; - consensus.nRewardsFirst_1_3_Round = 31; - consensus.nRewardsPayouts_1_3_BlockStretch = 10990; // 1 week - consensus.nRewardsPayouts_1_3_BlockPayees = 10; + consensus.nRewardsBlocksPerRound_1_3 = 11000; // 1 week + consensus.nRewardsFirst_1_3_Round = 33; // Round 33 on 3/23 starts on block 1524100 + consensus.nRewardsPayouts_1_3_BlockStretch = 10000; + consensus.nRewardsPayouts_1_3_BlockPayees = 100; consensus.strRewardsGlobalVoteProofAddress = "TBD"; @@ -283,17 +283,17 @@ class CTestNetParams : public CChainParams { /* SmartReward params */ consensus.nRewardsConfirmationsRequired = 1; - consensus.nRewardsPayoutStartDelay = 20; + consensus.nRewardsPayoutStartDelay = 10; //! 1.2 Parameter - consensus.nRewardsBlocksPerRound_1_2 = 500; + consensus.nRewardsBlocksPerRound_1_2 = 100; consensus.nRewardsPayouts_1_2_BlockInterval = 2; consensus.nRewardsPayouts_1_2_BlockPayees = 1000; //! 1.3 Parameter - consensus.nRewardsBlocksPerRound_1_3 = 1500; - consensus.nRewardsFirst_1_3_Round = 13; - consensus.nRewardsPayouts_1_3_BlockStretch = 1000; + consensus.nRewardsBlocksPerRound_1_3 = 100; + consensus.nRewardsFirst_1_3_Round = 10; // block 201 start 1_2_8 401 start 1_3 + consensus.nRewardsPayouts_1_3_BlockStretch = 80; consensus.nRewardsPayouts_1_3_BlockPayees = 10; consensus.strRewardsGlobalVoteProofAddress = "TTUR2YweEsouT7nnqLGn3LgoykhPnFQkSY"; diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 5c59e39f..4d55ba47 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_HEIGHT = 1500001; +static const int HF_V1_3_HEIGHT = 1524100; // Round 33 starts 1524100 /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; @@ -40,8 +40,8 @@ static const int HF_V1_2_8_NODES_PER_BLOCK = 1; static const int HF_CHAIN_REWARD_END_HEIGHT = 717499999; /** Testnet payment start blocks*/ -static const int TESTNET_V1_2_8_PAYMENTS_HEIGHT = 101; -static const int TESTNET_V1_3_HEIGHT = 6526; +static const int TESTNET_V1_2_8_PAYMENTS_HEIGHT = 201; +static const int TESTNET_V1_3_HEIGHT = 1001; //round start is 10 x 100 block 1000-1100 payments start at 1110 /** Testnet payment intervals*/ static const int TESTNET_V1_2_8_NODES_PER_BLOCK = 1; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 9a2ec7cf..ff8d6a19 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -5,6 +5,7 @@ #include "primitives/transaction.h" +#include "pubkey.h" #include "hash.h" #include "tinyformat.h" #include "utilstrencodings.h" @@ -233,17 +234,33 @@ bool CTransaction::IsVoteKeyRegistration() const return false; } -bool CTransaction::IsVoteProof() const +bool CTransaction::IsActivationTx() const { - // Vote proof transactions must contain only 1 input - // which is from the address to register and maximum 2 outputs - // 1. OP_RETURN with the VoteProofData - // 2. change (optional) - if( vin.size() > 1 || vout.size() > 2 ) return false; - - for (std::vector::const_iterator it(vout.begin()); it != vout.end(); ++it) - { - if (it->IsVoteProofData() ) return true; + if (IsCoinBase()) return false; + + // Activation transaction is a Tx back to the issuing address, it should only have one input and one output + if ( (vin.size() == 1) && (vout.size() == 1) ) { + // Activation transaction should be P2PKH, get the hashed pubkey from output script + const CScript &outScript = vout.front().scriptPubKey; + if (!outScript.IsPayToPublicKeyHash()) return false; + uint160 hashBytes = uint160(std::vector(outScript.begin() + 3, outScript.begin() + 23)); + + // Get pubkey from input script signature by deconding ScriptSig + const CScript &scriptSig = vin.front().scriptSig; + CScript::const_iterator pc = scriptSig.begin(); + opcodetype opcode; + vector vch; + + // First Op should be the signature + scriptSig.GetOp(pc, opcode, vch); + if ((opcode < 0) || (opcode > OP_PUSHDATA4) || (vch.size() < 4)) return false; + + // Second Op should be the public key + scriptSig.GetOp(pc, opcode, vch); + uint160 hashedKey = Hash160(vch); + + // If hashed pubkey matches output hash, then the Tx destination matches the source + if (hashBytes == hashedKey) return true; } return false; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index ba43724e..896e2512 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -15,14 +15,8 @@ static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000; // Constants for vote proof transactions -static const CAmount REWARDS_VOTEPROOF_FEE = 0 * COIN; -static const CAmount REWARDS_VOTEPROOF_TX_FEE = 0.002 * COIN; - -static const int REWARDS_VOTEPROOF_O1_SCRIPT_SIZE = 0x28; -static const int REWARDS_VOTEPROOF_O1_DATA_SIZE = 0x26; - -static const int REWARDS_VOTEPROOF_O2_SCRIPT_SIZE = 0x3D; -static const int REWARDS_VOTEPROOF_O2_DATA_SIZE = 0x3B; +static const CAmount REWARDS_ACTIVATION_FEE = 0 * COIN; +static const CAmount REWARDS_ACTIVATION_TX_FEE = 0.002 * COIN; static const int WITNESS_SCALE_FACTOR = 4; @@ -231,11 +225,6 @@ class CTxOut return scriptPubKey.IsVoteKeyData() && nValue == VOTEKEY_REGISTER_FEE; } - bool IsVoteProofData() const - { - return scriptPubKey.IsVoteProofData() && nValue == REWARDS_VOTEPROOF_FEE; - } - uint32_t GetLockTime() const; friend bool operator==(const CTxOut& a, const CTxOut& b) @@ -475,7 +464,7 @@ class CTransaction bool IsZerocoinMint(const CTransaction& tx) const; bool IsVoteKeyRegistration() const; - bool IsVoteProof() const; + bool IsActivationTx() const; friend bool operator==(const CTransaction& a, const CTransaction& b) { diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 4b7eddfc..26eaa0ba 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -326,8 +326,8 @@ void BitcoinGUI::createActions() smartnodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6)); tabGroup->addAction(smartnodeAction); - smartrewardsAction = new QAction(platformStyle->SingleColorIcon(":/icons/smartrewards"), tr("&VoteRewards"), this); - smartrewardsAction->setStatusTip(tr("Show eligible addresses for VoteRewards")); + smartrewardsAction = new QAction(platformStyle->SingleColorIcon(":/icons/smartrewards"), tr("&SmartRewards"), this); + smartrewardsAction->setStatusTip(tr("Show eligible addresses for SmartRewards")); smartrewardsAction->setToolTip(smartrewardsAction->statusTip()); smartrewardsAction->setCheckable(true); smartrewardsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_7)); diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 7b958931..1cdd9e69 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -738,6 +738,7 @@ + Set Delay Qt::Horizontal diff --git a/src/qt/forms/smartrewardentry.ui b/src/qt/forms/smartrewardentry.ui index 82ad4979..50523262 100755 --- a/src/qt/forms/smartrewardentry.ui +++ b/src/qt/forms/smartrewardentry.ui @@ -19,20 +19,6 @@ Form - - #QSmartRewardEntry{ - - background-color: rgb(247, 245, 248); -} - -#eligiblePage{ - background-color: rgb(247, 245, 248); -} - -#infoPage{ - background-color: rgb(247, 245, 248); -} - @@ -204,8 +190,11 @@ true + + color: rgb(173, 47, 19); + - Voting required. Go to the SmartVoting Tab and vote for a proposal + ActivateRewards required. Click button below to activate this address for rewards true diff --git a/src/qt/forms/smartrewardslist.ui b/src/qt/forms/smartrewardslist.ui index 1da08d79..a6f07a66 100644 --- a/src/qt/forms/smartrewardslist.ui +++ b/src/qt/forms/smartrewardslist.ui @@ -59,7 +59,7 @@ - Initialize VoteRewards... + Initialize SmartRewards... Qt::AlignCenter @@ -189,7 +189,7 @@ - VoteRewards round + SmartRewards round @@ -336,7 +336,7 @@ - Estimated VoteRewards + Estimated SmartRewards @@ -473,7 +473,7 @@ - Send VoteProofs [0] + Activate Rewards [0] diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 496f72e1..454d602f 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -510,12 +510,12 @@ - &VoteRewards + &SmartRewards - Show eligible addresses for VoteRewards + Show eligible addresses for SmartRewards @@ -4427,7 +4427,7 @@ p, li { white-space: pre-wrap; } - Initialize VoteRewards... + Initialize SmartRewards... @@ -4437,7 +4437,7 @@ p, li { white-space: pre-wrap; } - VoteRewards round + SmartRewards round @@ -4492,7 +4492,7 @@ p, li { white-space: pre-wrap; } - Estimated VoteRewards + Estimated SmartRewards @@ -5851,7 +5851,7 @@ p, li { white-space: pre-wrap; } - Verifying VoteRewards... + Verifying SmartRewards... @@ -6128,7 +6128,7 @@ Recreating it now... - Creating VoteRewards database: + Creating SmartRewards database: @@ -6193,7 +6193,7 @@ Recreating it now... - Failed to verify VoteRewards database. + Failed to verify SmartRewards database. @@ -6383,12 +6383,12 @@ Recreating it now... - VoteRewards database exceeds current chain height. + SmartRewards database exceeds current chain height. - VoteRewards database is incomplete. + SmartRewards database is incomplete. diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 49b748b5..5c40752d 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -521,7 +521,23 @@ void SendCoinsDialog::updateInstantSend() CoinControlDialog::coinControl->fUseInstantSend = ui->checkUseInstantSend->isChecked(); coinControlUpdateLabels(); } - +/* +void SendCoinsDialog::updatetimelock() + timelockWidget = new QComboBox(this); + if (platformStyle->getUseExtraSpacing()) { + dateWidget->setFixedWidth(21); + } else { + dateWidget->setFixedWidth(20); + } + dateWidget->addItem(tr("Set Delay"), None); + dateWidget->addItem(tr("Delay 1 Week"), 1Week); + dateWidget->addItem(tr("Delay 1 Month"), 1Month); + dateWidget->addItem(tr("Delay 3 Months"), 3Months); + dateWidget->addItem(tr("Delay 6 Months"), 6Months); + dateWidget->addItem(tr("Delay 1 year"), 1Year); + dateWidget->addItem(tr("Custom..."), Custom); +// hlayout->addWidget(timelockWidget); +*/ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg) { QPair msgParams; diff --git a/src/qt/smartrewardentry.cpp b/src/qt/smartrewardentry.cpp index f856cebc..c7106478 100755 --- a/src/qt/smartrewardentry.cpp +++ b/src/qt/smartrewardentry.cpp @@ -87,9 +87,9 @@ void QSmartRewardEntry::setEligible(CAmount nEligible, CAmount nEstimated) ui->lblEstimated->setText(strEstimated + " SMART"); } -void QSmartRewardEntry::setVoted(bool fState) +void QSmartRewardEntry::setActivated(bool fState) { - fVoted = fState; + fActivated = fState; } void QSmartRewardEntry::setIsSmartNode(bool fState) @@ -97,11 +97,6 @@ void QSmartRewardEntry::setIsSmartNode(bool fState) fIsSmartNode = fState; } -void QSmartRewardEntry::setVoteProofConfirmations(int nConfirmations) -{ - nVoteProofConfirmations = nConfirmations; -} - QString QSmartRewardEntry::Address() const { return ui->lblAddress->text(); @@ -115,12 +110,6 @@ QSmartRewardEntry::State QSmartRewardEntry::CurrentState() if( !disqualifyingTx.IsNull() ) return OutgoingTransaction; - if( !fVoted ) return VotingRequired; - - if( nVoteProofConfirmations == -1 ) return VoteProofRequired; - - if( nVoteProofConfirmations < Params().GetConsensus().nRewardsConfirmationsRequired ) return VoteProofConfirmationsRequired; - if( nEligible ) return IsEligible; return Unknown; diff --git a/src/qt/smartrewardentry.h b/src/qt/smartrewardentry.h index 59f945b9..78b6e05b 100755 --- a/src/qt/smartrewardentry.h +++ b/src/qt/smartrewardentry.h @@ -25,9 +25,6 @@ class QSmartRewardEntry : public QFrame LowBalance, IsASmartNode, OutgoingTransaction, - VotingRequired, - VoteProofRequired, - VoteProofConfirmationsRequired, IsEligible }; @@ -37,16 +34,14 @@ class QSmartRewardEntry : public QFrame void setInfoText(const QString& strText, const QColor& color); void setEligible(CAmount nEligible, CAmount nEstimated); void setIsSmartNode(bool fState); - void setVoted(bool fState); - void setVoteProofConfirmations(int nConfirmations); + void setActivated(bool fState); QString Address() const; CAmount Balance() const { return nBalance; } CAmount BalanceAtStart() const { return nBalanceAtStart; } CAmount Eligible() const { return nEligible; } bool IsSmartNode() const { return fIsSmartNode; } - bool Voted() const { return fVoted; } - int VoteProofConfirmations() const { return nVoteProofConfirmations; } + bool Activated() const { return fActivated; } State CurrentState(); std::string ToString(); @@ -64,8 +59,7 @@ class QSmartRewardEntry : public QFrame CAmount nBalance; CAmount nEligible; bool fIsSmartNode; - bool fVoted; - int nVoteProofConfirmations; + bool fActivated; uint256 disqualifyingTx; private Q_SLOTS: diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index a2ad59d2..458e1aac 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -46,13 +46,12 @@ struct QSmartRewardField CAmount reward; uint256 disqualifyingTx; bool fIsSmartNode; - bool fVoted; - int nVoteProofConfirmations; + bool fActivated; QSmartRewardField() : label(QString()), address(QString()), balance(0), eligible(0),reward(0), disqualifyingTx(), - fIsSmartNode(false), fVoted(false), nVoteProofConfirmations(-1){} + fIsSmartNode(false), fActivated(false){} }; struct SortSmartRewardWidgets @@ -127,11 +126,8 @@ void SmartrewardsList::setClientModel(ClientModel *model) void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, const CBlockIndex *tip) { - LogPrintf("SmartrewardsList::updateOverviewUI %d\n", tip->nHeight); - int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - - if( currentRound.number < nFirst_1_3_Round ){ + if( !currentRound.Is_1_3() ){ ui->btnSendProofs->hide(); }else{ ui->btnSendProofs->show(); @@ -218,7 +214,6 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c ui->nextRoundLabel->setText(roundEndText); - CKeyID keyId; int nAvailableForProof = 0; std::map > mapCoins; model->listCoins(mapCoins); @@ -261,8 +256,9 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c change.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); change.balanceAtStart = reward->balanceAtStart; change.disqualifyingTx = reward->disqualifyingTx; + change.fActivated = reward->fActivated; - if( currentRound.number < nFirst_1_3_Round ){ + if( !currentRound.Is_1_3() ){ change.eligible = reward->balanceEligible && reward->disqualifyingTx.IsNull() ? reward->balanceEligible : 0; }else{ change.eligible = reward->IsEligible() ? reward->balanceEligible : 0; @@ -270,45 +266,8 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c change.reward = currentRound.percent * change.eligible; - if( reward->id.GetKeyID(keyId) ){ - - LOCK2(cs_main, pwalletMain->cs_wallet); - - change.fVoted = pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end(); - - if( pwalletMain->mapVoteProofs[keyId].find(currentRound.number) != pwalletMain->mapVoteProofs[keyId].end() ){ - - uint256 proofHash = pwalletMain->mapVoteProofs[keyId][currentRound.number]; - - CTransaction tx; - uint256 nBlockHash; - - if( !reward->voteProof.IsNull() ){ - change.nVoteProofConfirmations = Params().GetConsensus().nRewardsConfirmationsRequired; - }else if(!GetTransaction(proofHash, tx, Params().GetConsensus(), nBlockHash, true)){ - change.nVoteProofConfirmations = -1; - }else if(nBlockHash == uint256()) { - change.nVoteProofConfirmations = 0; - }else{ - - if (nBlockHash != uint256()) { - BlockMap::iterator mi = mapBlockIndex.find(nBlockHash); - if (mi != mapBlockIndex.end() && (*mi).second) { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) { - change.nVoteProofConfirmations = chainActive.Height() - pindex->nHeight + 1; - } - } - } - } - } - - if( pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end() && - pwalletMain->mapVoteProofs[keyId].find(currentRound.number) == pwalletMain->mapVoteProofs[keyId].end() && - reward->balanceEligible && reward->disqualifyingTx.IsNull() && reward->smartnodePaymentTx.IsNull() ){ - ++nAvailableForProof; - } - + if( currentRound.Is_1_3() && !change.fActivated ){ + ++nAvailableForProof; } } @@ -337,8 +296,9 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c rewardField.fIsSmartNode = !reward->smartnodePaymentTx.IsNull(); rewardField.balanceAtStart = reward->balanceAtStart; rewardField.disqualifyingTx = reward->disqualifyingTx; + rewardField.fActivated = reward->fActivated; - if( currentRound.number < nFirst_1_3_Round ){ + if( !currentRound.Is_1_3() ){ rewardField.eligible = reward->balanceEligible && reward->disqualifyingTx.IsNull() ? reward->balanceEligible : 0; }else{ rewardField.eligible = reward->IsEligible() ? reward->balanceEligible : 0; @@ -346,45 +306,8 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c rewardField.reward = currentRound.percent * rewardField.eligible; - if( reward->id.GetKeyID(keyId) ){ - - LOCK2(cs_main, pwalletMain->cs_wallet); - - rewardField.fVoted = pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end(); - - if( pwalletMain->mapVoteProofs[keyId].find(currentRound.number) != pwalletMain->mapVoteProofs[keyId].end() ){ - - uint256 proofHash = pwalletMain->mapVoteProofs[keyId][currentRound.number]; - - CTransaction tx; - uint256 nBlockHash; - - if( !reward->voteProof.IsNull() ){ - rewardField.nVoteProofConfirmations = Params().GetConsensus().nRewardsConfirmationsRequired; - }else if(!GetTransaction(proofHash, tx, Params().GetConsensus(), nBlockHash, true)){ - rewardField.nVoteProofConfirmations = -1; - }else if(nBlockHash == uint256()) { - rewardField.nVoteProofConfirmations = 0; - }else{ - - if (nBlockHash != uint256()) { - BlockMap::iterator mi = mapBlockIndex.find(nBlockHash); - if (mi != mapBlockIndex.end() && (*mi).second) { - CBlockIndex* pindex = (*mi).second; - if (chainActive.Contains(pindex)) { - rewardField.nVoteProofConfirmations = chainActive.Height() - pindex->nHeight + 1; - } - } - } - } - } - - if( pwalletMain->mapVoted[keyId].find(currentRound.number) != pwalletMain->mapVoted[keyId].end() && - pwalletMain->mapVoteProofs[keyId].find(currentRound.number) == pwalletMain->mapVoteProofs[keyId].end() && - reward->balanceEligible && reward->disqualifyingTx.IsNull() && reward->smartnodePaymentTx.IsNull() ){ - ++nAvailableForProof; - } - + if( currentRound.Is_1_3() && !rewardField.fActivated ){ + ++nAvailableForProof; } } @@ -432,36 +355,25 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c entry->setBalance(field.balance); entry->setIsSmartNode(field.fIsSmartNode); - entry->setVoted(field.fVoted); - entry->setVoteProofConfirmations(field.nVoteProofConfirmations); + entry->setActivated(field.fActivated); - if( currentRound.number >= nFirst_1_3_Round ){ + if( currentRound.Is_1_3() ){ entry->setMinBalance(SMART_REWARDS_MIN_BALANCE_1_3); - int nConfirmationsRequired = Params().GetConsensus().nRewardsConfirmationsRequired - field.nVoteProofConfirmations; - if( field.fIsSmartNode ){ entry->setInfoText("Address belongs to a SmartNode.", COLOR_NEGATIVE); }else if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE_1_3 ){ - entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_3/COIN), COLOR_NEGATIVE); + entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART. It can be activated now but it will not receive rewards until it has enough funds.").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_3/COIN), COLOR_NEGATIVE); }else if( !field.disqualifyingTx.IsNull() ){ entry->setDisqualifyingTx(field.disqualifyingTx); - entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); - }else if( !field.fVoted ){ - entry->setInfoText("Voting required. Go to the \"SmartVote\" tab and vote for a proposal with this address.", COLOR_NEGATIVE); - }else if( field.fVoted && field.nVoteProofConfirmations == -1){ - entry->setInfoText("VoteProof required. Click the button at the bottom to send the VoteProof for this address.", COLOR_WARNING); - }else if( field.fVoted && - nConfirmationsRequired > 0){ - entry->setInfoText(QString("%1 block confirmation required for the VoteProof transaction to become processed.").arg(nConfirmationsRequired), COLOR_WARNING); - }else if( field.fVoted && - nConfirmationsRequired <= 0 && - field.eligible ){ + entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1. It can be activated now but it will not receive any rewards until it becomes eligible").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); + }else if( field.fActivated && !field.eligible ){ + entry->setInfoText(QString("Address is activated but is not eligible until the next round."), COLOR_WARNING); + }else if( field.fActivated ){ entry->setEligible(field.eligible, field.reward); ++nEligibleAddresses; } - }else{ entry->setMinBalance(SMART_REWARDS_MIN_BALANCE_1_2); @@ -500,24 +412,17 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c std::sort(vecEntries.begin(), vecEntries.end(), SortSmartRewardWidgets()); - for( size_t i=0; ismartRewardsList->layout()->addWidget(vecEntries[i]); - - if( i < vecEntries.size() - 1 ){ + for (const auto &entry : vecEntries) { + ui->smartRewardsList->layout()->addWidget(entry); - // Add a horizontal line + // Add a horizontal line unless it's the last entry + if( entry != vecEntries.back() ){ QHBoxLayout* hBox = new QHBoxLayout(); - QSpacerItem* spacerLeft = new QSpacerItem(20, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); - QSpacerItem* spacerRight = new QSpacerItem(20, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); QWidget* lineContainer = new QWidget(); - lineContainer->setStyleSheet("background-color: rgb(247, 245, 248);"); QFrame* line = new QFrame(lineContainer); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Plain); - hBox->addSpacerItem(spacerLeft); hBox->addWidget(line); - hBox->addSpacerItem(spacerRight); hBox->setSpacing(0); hBox->setContentsMargins(0, 0, 0, 0); lineContainer->setLayout(hBox); @@ -527,10 +432,10 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c } if( nAvailableForProof ){ - ui->btnSendProofs->setText( QString(tr("Send VoteProofs [%1]")).arg(nAvailableForProof) ); + ui->btnSendProofs->setText( QString(tr("Send ActivateRewards [%1]")).arg(nAvailableForProof) ); ui->btnSendProofs->setEnabled(true); }else{ - ui->btnSendProofs->setText( tr("No address ready for a VoteProof") ); + ui->btnSendProofs->setText( tr("No addresses need to ActivateRewards") ); ui->btnSendProofs->setEnabled(false); } @@ -601,7 +506,7 @@ void SmartrewardsList::setState(SmartrewardsList::SmartRewardsListState state) void SmartrewardsList::on_btnSendProofs_clicked() { - SpecialTransactionDialog dlg(VOTE_PROOF_TRANSACTIONS, platformStyle); + SpecialTransactionDialog dlg(ACTIVATION_TRANSACTIONS, platformStyle); dlg.setModel(model); dlg.exec(); updateUI(); diff --git a/src/qt/smartvoting.cpp b/src/qt/smartvoting.cpp index 9f7f5b74..912dce49 100755 --- a/src/qt/smartvoting.cpp +++ b/src/qt/smartvoting.cpp @@ -51,8 +51,7 @@ SmartVotingPage::SmartVotingPage(const PlatformStyle *platformStyle, QWidget *pa QWidget(parent), ui(new Ui::SmartVotingPage), platformStyle(platformStyle), - walletModel(0), - nVoteProofRequired(0) + walletModel(0) { ui->setupUi(this); @@ -162,7 +161,7 @@ void SmartVotingPage::updateUI() void SmartVotingPage::proposalsUpdated(const string &strErr) { if( strErr != ""){ - QMessageBox::warning(this, "Error", QString("Could not update proposal list\n\n%1").arg(QString::fromStdString(strErr))); +// QMessageBox::warning(this, "Error", QString("Could not update proposal list\n\n%1").arg(QString::fromStdString(strErr))); return; } @@ -197,32 +196,12 @@ void SmartVotingPage::castVotes(){ CastVotesDialog dialog(platformStyle, votingManager, walletModel); - connect( &dialog, SIGNAL(votedForAddress(QString&, int, bool)), this, SLOT(voteDone(QString&, int, bool))); dialog.setVoting(mapVoteProposals); - nVoteProofRequired = 0; - dialog.exec(); - if( nVoteProofRequired ){ - - // Display message box - QMessageBox::StandardButton retval = QMessageBox::question(this, tr("VoteProof required"), - tr("Do you want to send a VoteProof for %1 address%2 to enable VoteRewards?\n\nThis can also be done later in the VoteRewards Tab.").arg(nVoteProofRequired).arg( nVoteProofRequired > 1 ? "es" : ""), - QMessageBox::Yes | QMessageBox::No, - QMessageBox::Yes); - - if(retval == QMessageBox::Yes){ - SpecialTransactionDialog dlg(VOTE_PROOF_TRANSACTIONS, platformStyle); - dlg.setModel(walletModel); - dlg.exec(); - } - - } - refreshProposals(true); uiInterface.NotifySmartRewardUpdate(); - } void SmartVotingPage::updateRefreshLock() @@ -269,40 +248,3 @@ void SmartVotingPage::balanceChanged(const CAmount &balance, const CAmount &unco updateUI(); } -void SmartVotingPage::voteDone(QString &address, int nProposalId, bool successful) -{ - if( successful ){ - - LOCK(pwalletMain->cs_wallet); - - CKeyID keyId; - std::string strProposal = strprintf("%d", nProposalId); - uint256 nProposalHash = Hash(strProposal.begin(), strProposal.end()); - CSmartAddress id(address.toStdString()); - - if(id.GetKeyID(keyId)){ - - LOCK(cs_rewardscache); - - int nCurrentRound = prewards->GetCurrentRound()->number; - - if( !pwalletMain->mapVoted[keyId].count(nCurrentRound) ){ - - pwalletMain->mapVoted[keyId].insert(std::make_pair(nCurrentRound, nProposalHash)); - pwalletMain->UpdateVotedMap(keyId); - } - - CSmartRewardEntry * entry; - - if( nCurrentRound >= Params().GetConsensus().nRewardsFirst_1_3_Round && - pwalletMain->mapVoteProofs[keyId].find(nCurrentRound) == pwalletMain->mapVoteProofs[keyId].end() && - prewards->GetRewardEntry(CSmartAddress(id.ToString(false)), entry, false) ){ - - if( entry->balanceEligible && !entry->fSmartnodePaymentTx ){ - ++nVoteProofRequired; - } - } - } - } - -} diff --git a/src/qt/smartvoting.h b/src/qt/smartvoting.h index abe55e16..09687ab9 100755 --- a/src/qt/smartvoting.h +++ b/src/qt/smartvoting.h @@ -60,8 +60,6 @@ class SmartVotingPage : public QWidget std::vector vecProposalWidgets; std::map mapVoteProposals; - int nVoteProofRequired; - public Q_SLOTS: void updateUI(); void updateProposalUI(); @@ -74,6 +72,5 @@ public Q_SLOTS: void scrollChanged(int value); void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); - void voteDone(QString &address, int nProposalId, bool successful); }; #endif // BITCOIN_QT_SMARTVOTING_H diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 0fc114db..ee87faee 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -40,6 +40,7 @@ #include #define SEND_CONFIRM_DELAY 5 +#define MAX_ACTIVATION_TRANSACTIONS 10 bool Error(std::string where, std::string message, QString &strError) { @@ -65,13 +66,13 @@ SpecialTransactionDialog::SpecialTransactionDialog(const SpecialTransactionType ui->labelFeeDesc->setText(strRegistrationFeeDescription); ui->descriptionLabel->setText(strRegistrationDescription); break; - case VOTE_PROOF_TRANSACTIONS: // TBD - nRequiredFee = REWARDS_VOTEPROOF_FEE; - nRequiredNetworkFee = REWARDS_VOTEPROOF_TX_FEE; - this->setWindowTitle(strVoteProofTitle); + case ACTIVATION_TRANSACTIONS: + nRequiredFee = REWARDS_ACTIVATION_FEE; + nRequiredNetworkFee = REWARDS_ACTIVATION_TX_FEE; + this->setWindowTitle(strActivationTxTitle); ui->labelFeeDesc->hide(); ui->labelFeeAmount->hide(); - ui->descriptionLabel->setText(strVoteProofDescription); + ui->descriptionLabel->setText(strActivationTxDescription); break; default: nRequiredFee = -1; @@ -135,23 +136,16 @@ void SpecialTransactionDialog::setModel(WalletModel *model) } } -QString SpecialTransactionDialog::GetTypeString() -{ - - switch(type){ - case REGISTRATION_TRANSACTIONS: - return "registration transactions"; - case VOTE_PROOF_TRANSACTIONS: - return "vote proof transactions"; - } - - return "Unknown"; -} - // ok button void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) { if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole){ + if ((type == ACTIVATION_TRANSACTIONS) && (mapOutputs.size() > MAX_ACTIVATION_TRANSACTIONS)) { + QMessageBox::warning(this, windowTitle(), + tr("No more than %1 activation transactions can be sent at once.").arg(MAX_ACTIVATION_TRANSACTIONS), + QMessageBox::Ok, QMessageBox::Ok); + return; + } int nCount = mapOutputs.size(); CAmount nTotalAmount = nCount * GetRequiredTotal(); @@ -161,7 +155,18 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) LogPrintf(" %s, out: %s\n", it.first.toStdString(), it.second.ToString()); } - QString strType = GetTypeString(); + QString strType; + switch(type){ + case REGISTRATION_TRANSACTIONS: + strType = nCount > 1 ? "registration transactions" : "registration transaction"; + break; + case ACTIVATION_TRANSACTIONS: + strType = nCount > 1 ? "activation transactions" : "activation transaction"; + break; + default: + strType = "Unknown"; + break; + } QString questionString = QString("Sending %1 %2, %3 each including fee") .arg(nCount) @@ -232,8 +237,8 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) "They are not derived from the wallet's seed so you are not able to recover them " "with any earlier backup of your wallet.")); break; - case VOTE_PROOF_TRANSACTIONS: - strResult.append(tr("It requires %1 block confirmation for the VoteProof transactions before the address will become eligible in the VoteRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); + case ACTIVATION_TRANSACTIONS: + strResult.append(tr("It requires %1 block confirmation for the activation transactions before the address will become eligible in the SmartRewards tab.").arg(Params().GetConsensus().nRewardsConfirmationsRequired)); break; } @@ -364,7 +369,6 @@ void SpecialTransactionDialog::selectSmallestOutput(QTreeWidgetItem* topLevel) COutPoint outpt(uint256S(smallestItem->text(COLUMN_TXHASH).toStdString()), smallestItem->text(COLUMN_VOUT_INDEX).toUInt()); mapOutputs.insert(std::make_pair(sAddress, outpt)); } - } void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) @@ -380,7 +384,7 @@ void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) case REGISTRATION_TRANSACTIONS: fSuccess = SendRegistration(it.first, it.second, strError); break; - case VOTE_PROOF_TRANSACTIONS:{ + case ACTIVATION_TRANSACTIONS:{ int nCurrentRound; @@ -389,7 +393,7 @@ void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) nCurrentRound = prewards->GetCurrentRound()->number; } - fSuccess = SendVoteProof(it.first, it.second, nCurrentRound, strError); + fSuccess = SendActivationTransaction(it.first, it.second, nCurrentRound, strError); }break; } @@ -398,7 +402,6 @@ void SpecialTransactionDialog::SendTransactions(std::vector &vecErrors) continue; } } - } bool SpecialTransactionDialog::SendRegistration(const QString &address, const COutPoint &out, QString &strError) @@ -584,7 +587,7 @@ bool SpecialTransactionDialog::SendRegistration(const QString &address, const CO return true; } -bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutPoint &out, int nCurrentRound, QString &strError) +bool SpecialTransactionDialog::SendActivationTransaction(const QString &address, const COutPoint &out, int nCurrentRound, QString &strError) { // ** // Check if the unspent output belongs to
or not @@ -594,12 +597,12 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP uint256 blockHash; if( !GetTransaction(out.hash, spendTx, Params().GetConsensus(), blockHash, true) ) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("TX-Hash %s doesn't belong to a transaction",out.hash.ToString()), strError); if( static_cast(spendTx.vout.size()) - 1 < out.n ) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("TX-Index %d out of range for TX %s",out.n, out.hash.ToString()), strError); @@ -612,21 +615,21 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP CSmartAddress voteAddress(address.toStdString()); if ( !voteAddress.IsValid() ) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Failed to validate address for TX %s, index %s", out.hash.ToString(), out.n), strError); CKeyID voteAddressKeyID; if (!voteAddress.GetKeyID(voteAddressKeyID)) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Address does't refer to a key for TX %s, index %s", out.hash.ToString(), out.n), strError); CTxDestination addressSolved; if (!ExtractDestination(utxo.scriptPubKey, addressSolved)) { - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Failed to extract address for output with TX %s, index %s", out.hash.ToString(), out.n), strError); @@ -636,37 +639,12 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP // Force option 1 - verify the vote address with the input of the register tx if( !CSmartAddress(addressSolved).GetKeyID(keyIdSolved) || keyIdSolved != voteAddressKeyID ){ - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Failed to force vote proof option one for address %s with TX %s, index %s", voteAddress.ToString(), out.hash.ToString(), out.n), strError); } - // ** - // ** Prepare the VoteProof data - // ** - - if( pwalletMain->mapVoted[voteAddressKeyID].find(nCurrentRound) == pwalletMain->mapVoted[voteAddressKeyID].end() ){ - return Error("GenerateVoteProof", - strprintf("Address %s did not yet vote during the VoteRewards round %d", - voteAddress.ToString(), nCurrentRound), - strError); - } - - std::vector vecData = { - OP_RETURN_VOTE_PROOF_FLAG, - 0x01 // Proof option 1 - }; - - CDataStream proofData(SER_NETWORK,0); - - proofData << nCurrentRound; - proofData << pwalletMain->mapVoted[voteAddressKeyID][nCurrentRound]; - - vecData.insert(vecData.end(), proofData.begin(), proofData.end()); - - CScript proofScript = CScript() << OP_RETURN << vecData; - // ** // Create the transaction // ** @@ -680,6 +658,20 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP coinControl.Select(output); coinControl.destChange = change; + // Write script to self address + CScript proofScript = GetScriptForDestination(addressSolved); + + + // Figure out how much the output contains + map::const_iterator it = pwalletMain->mapWallet.find(out.hash); + if (it == pwalletMain->mapWallet.end()) + return Error("GenerateActivation", + "Failed to find output transaction in wallet", + strError); + + const CWalletTx &tx = it->second; + CAmount nOutputAmount = tx.vout[out.n].nValue; + // Create and send the transaction CReserveKey reservekey(pwalletMain); CWalletTx proofTx; @@ -688,12 +680,12 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP vector vecSend; int nChangePosRet = -1; - CRecipient recipient = {proofScript, REWARDS_VOTEPROOF_FEE, false}; + CRecipient recipient = {proofScript, nOutputAmount, true}; vecSend.push_back(recipient); if (!pwalletMain->CreateTransaction(vecSend, proofTx, reservekey, nFeeRequired, nChangePosRet, err, &coinControl)) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Failed to generate transaction: %s for TX %s, index %d", err, out.hash.ToString(), out.n), strError); @@ -702,19 +694,13 @@ bool SpecialTransactionDialog::SendVoteProof(const QString &address, const COutP CValidationState state; if (!(CheckTransaction(proofTx, state, proofTx.GetHash(), false) || !state.IsValid())) - return Error("GenerateVoteProof", - strprintf("VoteProof transaction invalid for TX %s, index %d: %s", + return Error("GenerateActivation", + strprintf("Activation transaction invalid for TX %s, index %d: %s", out.hash.ToString(), out.n, state.GetRejectReason()), strError); - { - LOCK(pwalletMain->cs_wallet); - pwalletMain->mapVoteProofs[voteAddressKeyID].insert(std::make_pair(nCurrentRound, proofTx.GetHash())); - pwalletMain->UpdateVoteProofs(voteAddressKeyID); - } - if( !pwalletMain->CommitTransaction(proofTx, reservekey, g_connman.get()) ) - return Error("GenerateVoteProof", + return Error("GenerateActivation", strprintf("Failed to send the transaction TX %s", proofTx.ToString()), strError); @@ -854,7 +840,7 @@ void SpecialTransactionDialog::updateView() } - if( type == VOTE_PROOF_TRANSACTIONS ){ + if( type == ACTIVATION_TRANSACTIONS ){ CKeyID keyId; CSmartAddress voteAddress(sWalletAddress.toStdString()); int nCurrentRound = 0; @@ -864,20 +850,7 @@ void SpecialTransactionDialog::updateView() nCurrentRound = prewards->GetCurrentRound()->number; } - CSmartRewardEntry *reward = nullptr; - - if( voteAddress.GetKeyID(keyId) && prewards->GetRewardEntry(CSmartAddress::Legacy(voteAddress), reward, false) ){ - - LOCK(pwalletMain->cs_wallet); - - if( pwalletMain->mapVoted[keyId].find(nCurrentRound) == pwalletMain->mapVoted[keyId].end() || - pwalletMain->mapVoteProofs[keyId].find(nCurrentRound) != pwalletMain->mapVoteProofs[keyId].end() || - reward->balanceEligible == 0 || !reward->disqualifyingTx.IsNull() || !reward->smartnodePaymentTx.IsNull() ){ - // If not yet voted, no eligible balance or already vote proven skip it. - continue; - } - - }else{ + if( !voteAddress.GetKeyID(keyId) ){ continue; } } diff --git a/src/qt/specialtransactiondialog.h b/src/qt/specialtransactiondialog.h index 64f6059c..e8413905 100644 --- a/src/qt/specialtransactiondialog.h +++ b/src/qt/specialtransactiondialog.h @@ -31,7 +31,7 @@ namespace Ui { enum SpecialTransactionType { REGISTRATION_TRANSACTIONS, - VOTE_PROOF_TRANSACTIONS + ACTIVATION_TRANSACTIONS }; #define ASYMP_UTF8 "\xE2\x89\x88" @@ -71,7 +71,7 @@ class SpecialTransactionDialog : public QDialog void SendTransactions(std::vector &vecErrors); bool SendRegistration(const QString &address, const COutPoint &out, QString &strError); - bool SendVoteProof(const QString &address, const COutPoint &out, int nCurrentRound, QString &strError); + bool SendActivationTransaction(const QString &address, const COutPoint &out, int nCurrentRound, QString &strError); enum { @@ -84,7 +84,6 @@ class SpecialTransactionDialog : public QDialog }; friend class CCoinControlWidgetItem; - QString GetTypeString(); private Q_SLOTS: void showMenu(const QPoint &); void copyAddress(); @@ -103,10 +102,10 @@ static const QString strRegistrationDescription = ( ); static const QString strRegistrationFeeDescription = "Register fee"; -static const QString strVoteProofTitle = "Send VoteProofs"; -static const QString strVoteProofDescription = ( -"Use this form to send VoteProof transactions to make your addresses eligible for SmartRewards " -"after you cast a vote with them. A small fee of 0.001 SMART will be taken from outputs you choose.\n\n" +static const QString strActivationTxTitle = "Activate Rewards"; +static const QString strActivationTxDescription = ( +"Use this form to send an ActivateReward transaction to make your addresses eligible for SmartRewards. " +"A small fee of 0.002 SMART will be taken from outputs you choose.\n\n" "You can either manually select an input for each address or automatically select the smallest input for each address by clicking the checkbox below." ); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index a4f0da20..30196436 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -67,6 +67,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); + entry.push_back(Pair("activation", tx.IsActivationTx())); UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { UniValue in(UniValue::VOBJ); @@ -168,6 +169,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" + " \"activation\" : true|false, (boolean) true if the transaction is a SmartRewards activation transaction\n" " \"vin\" : [ (array of json objects)\n" " {\n" " \"txid\": \"id\", (string) The transaction id\n" diff --git a/src/rpc/smartrewards.cpp b/src/rpc/smartrewards.cpp index f276d6d7..2084bdaa 100644 --- a/src/rpc/smartrewards.cpp +++ b/src/rpc/smartrewards.cpp @@ -262,7 +262,7 @@ UniValue smartrewards(const UniValue& params, bool fHelp) obj.pushKV("balance", format(entry->balance)); obj.pushKV("balance_eligible", format(entry->balanceEligible)); obj.pushKV("is_smartnode", !entry->smartnodePaymentTx.IsNull()); - obj.pushKV("voted", !entry->voteProof.IsNull()); + obj.pushKV("activated", entry->fActivated); obj.pushKV("eligible", current->number < nFirst_1_3_Round ? entry->balanceEligible > 0 : entry->IsEligible()); return obj; diff --git a/src/sapi/sapi_smartrewards.cpp b/src/sapi/sapi_smartrewards.cpp index 950e78a5..8dfdf4bb 100644 --- a/src/sapi/sapi_smartrewards.cpp +++ b/src/sapi/sapi_smartrewards.cpp @@ -91,7 +91,7 @@ static bool CheckAddresses(HTTPRequest* req, std::vector vecAddr, s obj.pushKV("balance",UniValueFromAmount(entry->balance)); obj.pushKV("balance_eligible", UniValueFromAmount(entry->balanceEligible)); obj.pushKV("is_smartnode", !entry->smartnodePaymentTx.IsNull()); - obj.pushKV("voted", !entry->voteProof.IsNull()); + obj.pushKV("activated", entry->fActivated); obj.pushKV("eligible", current->number < nFirst_1_3_Round ? entry->balanceEligible > 0 : entry->IsEligible()); vecResults.push_back(obj); diff --git a/src/script/script.cpp b/src/script/script.cpp index 1ba53e44..53c75602 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -353,29 +353,6 @@ bool CScript::IsVoteKeyData() const { (*this)[4] == 0x02); } -bool CScript::IsVoteProofData() const { - - return (this->size() == REWARDS_VOTEPROOF_O1_SCRIPT_SIZE && - (*this)[0] == OP_RETURN && - (*this)[1] == REWARDS_VOTEPROOF_O1_DATA_SIZE && - (*this)[2] == OP_RETURN_VOTE_PROOF_FLAG && - (*this)[3] == 0x01); - - /* - return (this->size() == REWARDS_VOTEPROOF_O1_SCRIPT_SIZE && - (*this)[0] == OP_RETURN && - (*this)[1] == REWARDS_VOTEPROOF_O1_DATA_SIZE && - (*this)[2] == OP_RETURN_VOTE_PROOF_FLAG && - (*this)[3] == 0x01) || - - (this->size() == REWARDS_VOTEPROOF_O2_SCRIPT_SIZE && - (*this)[0] == OP_RETURN && - (*this)[1] == REWARDS_VOTEPROOF_O2_DATA_SIZE && - (*this)[2] == OP_RETURN_VOTE_PROOF_FLAG && - (*this)[3] == 0x02); - */ -} - bool CScript::HasCanonicalPushes() const { const_iterator pc = begin(); diff --git a/src/script/script.h b/src/script/script.h index 759c38dc..ccf62e1a 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -640,11 +640,10 @@ class CScript : public CScriptBase bool IsPayToScriptHashLocked() const; bool IsPayToWitnessScriptHash() const; bool IsWitnessProgram(int& version, std::vector& program) const; - + bool IsZerocoinMint() const; bool IsZerocoinSpend() const; bool IsVoteKeyData() const; - bool IsVoteProofData() const; // Called by IsStandardTx. bool HasCanonicalPushes() const; diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 8e27f89f..2222d8c7 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -2,25 +2,25 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "smartrewards/rewards.h" #include "consensus/consensus.h" #include "init.h" -#include "smartrewards/rewards.h" -#include "smartrewards/rewardspayments.h" +#include "rewards.h" +#include "script/standard.h" #include "smarthive/hive.h" -#include "smartnode/spork.h" #include "smartnode/smartnodepayments.h" -#include "script/standard.h" -#include "rewards.h" +#include "smartnode/spork.h" +#include "smartrewards/rewardspayments.h" #include "ui_interface.h" #include "validation.h" -#include -#include #include +#include +#include #define REWARDS_MAX_CACHE 400000000UL // 400MB -CSmartRewards *prewards = NULL; +CSmartRewards* prewards = NULL; CCriticalSection cs_rewardsdb; CCriticalSection cs_rewardscache; @@ -30,31 +30,31 @@ size_t nCacheRewardEntries; // Used for time conversions. boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); -struct CompareRewardScore -{ +struct CompareRewardScore { bool operator()(const std::pair& s1, - const std::pair& s2) const + const std::pair& s2) const { return (s1.first != s2.first) ? (s1.first < s2.first) : (s1.second->entry.balance < s2.second->entry.balance); } }; -struct ComparePaymentPrtList -{ +struct ComparePaymentPrtList { bool operator()(const CSmartRewardResultEntry* p1, - const CSmartRewardResultEntry* p2) const + const CSmartRewardResultEntry* p2) const { return *p1 < *p2; } }; // Estimate or return the current block height. -int GetBlockHeight(const CBlockIndex *index) +int GetBlockHeight(const CBlockIndex* index) { int64_t syncDiff = std::time(0) - index->GetBlockTime(); int64_t firstTxDiff; - if( MainNet() ) firstTxDiff = std::time(0) - nStartRewardTime; // Diff from the reward blocks start till now on mainnet. - else firstTxDiff = std::time(0) - nFirstTxTimestamp_Testnet; // Diff from the first transaction till now on testnet. + if (MainNet()) + firstTxDiff = std::time(0) - nStartRewardTime; // Diff from the reward blocks start till now on mainnet. + else + firstTxDiff = std::time(0) - nFirstTxTimestamp_Testnet; // Diff from the first transaction till now on testnet. return syncDiff > 1200 ? firstTxDiff / 55 : index->nHeight; // If we are 20 minutes near now use the current height. } @@ -65,32 +65,23 @@ bool ExtractDestination(const CScript& scriptPubKey, CSmartAddress& idRet) if (!Solver(scriptPubKey, whichType, vSolutions)) return false; - if (whichType == TX_PUBKEY) - { + if (whichType == TX_PUBKEY) { CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) return false; idRet = CSmartAddress(pubKey.GetID()); return true; - } - else if (whichType == TX_PUBKEYHASH) - { + } else if (whichType == TX_PUBKEYHASH) { idRet = CSmartAddress(CKeyID(uint160(vSolutions[0]))); return true; - } - else if (whichType == TX_SCRIPTHASH) - { + } else if (whichType == TX_SCRIPTHASH) { idRet = CSmartAddress(CScriptID(uint160(vSolutions[0]))); return true; - } - else if (whichType == TX_PUBKEYHASHLOCKED) - { + } else if (whichType == TX_PUBKEYHASHLOCKED) { idRet = CSmartAddress(CKeyID(uint160(vSolutions[0]))); return true; - } - else if (whichType == TX_SCRIPTHASHLOCKED) - { + } else if (whichType == TX_SCRIPTHASHLOCKED) { idRet = CSmartAddress(CScriptID(uint160(vSolutions[0]))); return true; } @@ -114,42 +105,40 @@ void CSmartRewards::UpdateRoundPayoutParameter() { AssertLockHeld(cs_rewardscache); - const CSmartRewardRound *round = cache.GetCurrentRound(); + const CSmartRewardRound* round = cache.GetCurrentRound(); int64_t nBlockPayees = round->nBlockPayees, nBlockInterval; int64_t nPayeeCount = round->eligibleEntries - round->disqualifiedEntries; int nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - if( round->number < nFirst_1_3_Round ){ - nBlockPayees = Params().GetConsensus().nRewardsPayouts_1_2_BlockPayees; + if ( round->number < nFirst_1_3_Round ) { + nBlockPayees = Params().GetConsensus().nRewardsPayouts_1_2_BlockPayees; nBlockInterval = Params().GetConsensus().nRewardsPayouts_1_2_BlockInterval; - }else if( nPayeeCount ){ - + } else if ( nPayeeCount ) { int64_t nBlockStretch = Params().GetConsensus().nRewardsPayouts_1_3_BlockStretch; int64_t nBlocksPerRound = Params().GetConsensus().nRewardsBlocksPerRound_1_3; int64_t nTempBlockPayees = Params().GetConsensus().nRewardsPayouts_1_3_BlockPayees; nBlockPayees = std::max(nTempBlockPayees, (nPayeeCount / nBlockStretch * nTempBlockPayees) + 1); - if( nPayeeCount > nBlockPayees ){ - + if (nPayeeCount > nBlockPayees) { int64_t nStartDelayBlocks = Params().GetConsensus().nRewardsPayoutStartDelay; int64_t nBlocksTarget = nStartDelayBlocks + nBlocksPerRound; nBlockInterval = ((nBlockStretch * nBlockPayees) / nPayeeCount) + 1; int64_t nStretchedLength = nPayeeCount / nBlockPayees * (nBlockInterval); - if( nStretchedLength > nBlocksTarget ){ + if (nStretchedLength > nBlocksTarget) { nBlockInterval--; - }else if( nStretchedLength < nBlockStretch ){ + } else if (nStretchedLength < nBlockStretch) { nBlockInterval++; } - }else{ + } else { // If its only one block to pay nBlockInterval = 1; } - }else{ + } else { // If there are no eligible smartreward entries nBlockPayees = 0; nBlockInterval = 0; @@ -165,8 +154,7 @@ void CSmartRewards::UpdatePercentage() const CSmartRewardRound *round = cache.GetCurrentRound(); double nPercent = 0.0; - - if( (round->eligibleSmart - round->disqualifiedSmart) > 0 ){ + if ( (round->eligibleSmart - round->disqualifiedSmart) > 0 ) { nPercent = double(round->rewards) / (round->eligibleSmart - round->disqualifiedSmart); }else{ nPercent = 0; @@ -175,6 +163,15 @@ void CSmartRewards::UpdatePercentage() cache.UpdateRoundPercent(nPercent); } +bool CSmartRewards::Is_1_3(uint16_t round) +{ + if (round >= Params().GetConsensus().nRewardsFirst_1_3_Round) { + return 1; + } else { + return 0; + } +} + void CSmartRewards::EvaluateRound(CSmartRewardRound &next) { LOCK(cs_rewardscache); @@ -206,58 +203,117 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) } } - auto entry = cache.GetEntries()->begin(); + if( cache.GetCurrentRound()->number >= nFirst_1_3_Round ) { + next.eligibleSmart = 0; + next.eligibleEntries = 0; + + int64_t nTime = GetTime(); + int64_t nStartHeight = next.startBlockHeight - (next.endBlockHeight - next.startBlockHeight); + double dBlockReward = 0.60; + next.rewards = 0; + + while( nStartHeight <= next.startBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; + std::list eligibleAddresses; + auto entry = cache.GetEntries()->begin(); + while(entry != cache.GetEntries()->end() ) { + if( entry->second->balanceAtStart >= nMinBalance && !SmartHive::IsHive(entry->second->id) && !entry->second->fDisqualifyingTx && entry->second->fActivated ) { + entry->second->balanceEligible = entry->second->balance; + next.eligibleSmart += entry->second->balanceEligible; + ++next.eligibleEntries; + eligibleAddresses.push_back(entry->first); + } else { + entry->second->balanceEligible = 0; + } + entry->second->balanceAtStart = entry->second->balance; + ++entry; + } - while(entry != cache.GetEntries()->end() ) { + // Check back all the previous rounds for adding weighted balance if applicable + if (cache.GetCurrentRound()->number - 8 >= nFirst_1_3_Round && !eligibleAddresses.empty()) { + int roundNumber = cache.GetCurrentRound()->number - 1; + while (roundNumber >= nFirst_1_3_Round) { + CSmartRewardResultEntryList results; + if (!GetRewardRoundResults(roundNumber, results)) { + break; + } - if( cache.GetCurrentRound()->number ){ + // Iterate over all still eligible addresses + auto address = eligibleAddresses.begin(); + while (address != eligibleAddresses.end()) { + // Look for address in the round results + auto addressResult = std::find_if(results.begin(), results.end(), + [&address](const CSmartRewardResultEntry& e) -> bool { + return *address == e.entry.id; + }); + + // If address was not in last round result => remove from list + if (addressResult == results.end()) { + address = eligibleAddresses.erase(address); + continue; + } - if( cache.GetCurrentRound()->number < nFirst_1_3_Round ){ - nReward = entry->second->balanceEligible > 0 && !entry->second->fDisqualifyingTx ? CAmount(entry->second->balanceEligible * round->percent) : 0; - }else{ - nReward = entry->second->IsEligible() ? CAmount(entry->second->balanceEligible * round->percent) : 0; + // If the address balance was not eligible => remove from list + if (!addressResult->entry.balanceEligible) { + address = eligibleAddresses.erase(address); + continue; + } + + // If we are at a "special round", add to the eligible balance with proper weight + CAmount toAdd = 0; + if (roundNumber == cache.GetCurrentRound()->number - 8) { + toAdd = addressResult->entry.balance; + } else if (roundNumber == cache.GetCurrentRound()->number - 16) { + toAdd = 2 * addressResult->entry.balance; + } else if (roundNumber == cache.GetCurrentRound()->number - 26) { + toAdd = 2 * addressResult->entry.balance; + } + + if (toAdd > 0) { + auto &cacheEntry = cache.GetEntries()->at(*address); + cacheEntry->balanceEligible += toAdd; + next.eligibleSmart += toAdd; + } + + address++; + } + + // If there are no more eligible addresses to check, exit the loop + if (eligibleAddresses.empty()) { + break; + } + + roundNumber--; } + } - pResult->results.push_back(new CSmartRewardResultEntry(entry->second, nReward)); + double rpercent = next.eligibleSmart > 10000 ? ( (double)next.rewards / (double)next.eligibleSmart ) : 0; + entry = cache.GetEntries()->begin(); + while(entry != cache.GetEntries()->end() ) { + nReward = entry->second->IsEligible() ? CAmount(entry->second->balanceEligible * rpercent) : 0; + pResult->results.push_back(new CSmartRewardResultEntry(entry->second, nReward)); if( nReward ){ pResult->payouts.push_back(pResult->results.back()); } - } - entry->second->balanceAtStart = entry->second->balance; + // Calculate rewards for next cycle + next.rewards = 0; + nStartHeight = next.startBlockHeight; + while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; - if( entry->second->balance >= nMinBalance && !SmartHive::IsHive(entry->second->id) ){ - entry->second->balanceEligible = entry->second->balance; - }else{ - entry->second->balanceEligible = 0; - } + // Reset outgoing transaction with every cycle. + entry->second->disqualifyingTx.SetNull(); + entry->second->fDisqualifyingTx = false; - // Reset outgoing transaction with every cycle. - entry->second->disqualifyingTx.SetNull(); - entry->second->fDisqualifyingTx = false; - // Reset SmartNode payment tx with every cycle in case a node was shut down during the cycle. - entry->second->smartnodePaymentTx.SetNull(); - entry->second->fSmartnodePaymentTx = false; - // Reset the vote proof tx with every cycle to force a new vote for eligibility - entry->second->voteProof.SetNull(); - entry->second->fVoteProven = false; - - if( next.number < nFirst_1_3_Round && entry->second->balanceEligible ){ - ++next.eligibleEntries; - next.eligibleSmart += entry->second->balanceEligible; - } - - ++entry; - } + // Reset SmartNode payment tx with every cycle in case a node was shut down during the cycle. + entry->second->smartnodePaymentTx.SetNull(); + entry->second->fSmartnodePaymentTx = false; - if( pResult->payouts.size() ){ - - if( round->number < nFirst_1_3_Round ){ - // Sort it to make sure the slices are the same network wide. - std::sort(pResult->payouts.begin(), pResult->payouts.end(), ComparePaymentPrtList() ); - }else{ + // Reset the vote proof tx 2 cycles before the first 1.3 round. + ++entry; + } + if( pResult->payouts.size() ){ uint256 blockHash; if(!GetBlockHash(blockHash, pResult->round.startBlockHeight)) { throw std::runtime_error(strprintf("CSmartRewards::EvaluateRound -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", round->startBlockHeight)); @@ -281,61 +337,123 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) for(auto s : vecScores) pResult->payouts.push_back(s.second); } - } + if( pResult->round.number ){ + cache.AddFinishedRound(pResult->round); + } - // Calculate the current rewards percentage - int64_t nTime = GetTime(); - int64_t nStartHeight = next.startBlockHeight; - double dBlockReward = next.number < nFirst_1_3_Round ? 0.15 : 0.30; - next.rewards = 0; + cache.SetResult(pResult); + cache.SetCurrentRound(next); - while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; + } else if( cache.GetCurrentRound()->number && ( cache.GetCurrentRound()->number < nFirst_1_3_Round )){ + auto entry = cache.GetEntries()->begin(); + while(entry != cache.GetEntries()->end() ) { - if( pResult->round.number ){ - cache.AddFinishedRound(pResult->round); - } + nReward = entry->second->balanceEligible > 0 && !entry->second->fDisqualifyingTx ? CAmount(entry->second->balanceEligible * round->percent) : 0; - cache.SetResult(pResult); - cache.SetCurrentRound(next); + pResult->results.push_back(new CSmartRewardResultEntry(entry->second, nReward)); + + if( nReward ){ + pResult->payouts.push_back(pResult->results.back()); + } + + entry->second->balanceAtStart = entry->second->balance; + + if( entry->second->balance >= nMinBalance && !SmartHive::IsHive(entry->second->id) ){ + entry->second->balanceEligible = entry->second->balance; + }else{ + entry->second->balanceEligible = 0; + } + + // Reset outgoing transaction with every cycle. + entry->second->disqualifyingTx.SetNull(); + entry->second->fDisqualifyingTx = false; + + // Reset SmartNode payment tx with every cycle in case a node was shut down during the cycle. + entry->second->smartnodePaymentTx.SetNull(); + entry->second->fSmartnodePaymentTx = false; + + if( entry->second->balanceEligible ){ + ++next.eligibleEntries; + next.eligibleSmart += entry->second->balanceEligible; + } + + // Reset activations and reset eligible before 1.3 round starts. + if( next.number == (nFirst_1_3_Round) ){ + entry->second->activationTx.SetNull(); + entry->second->fActivated = false; + next.eligibleEntries = 0; + next.eligibleSmart = 0; + } + ++entry; + } + + if( pResult->payouts.size() ){ + // Sort it to make sure the slices are the same network wide. + std::sort(pResult->payouts.begin(), pResult->payouts.end(), ComparePaymentPrtList() ); + } + + // Calculate the current rewards percentage + int64_t nTime = GetTime(); + int64_t nStartHeight = next.startBlockHeight; + double dBlockReward = next.number < nFirst_1_3_Round ? 0.15 : 0.60; + next.rewards = 0; + while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; + + if( pResult->round.number ){ + cache.AddFinishedRound(pResult->round); + } + cache.SetResult(pResult); + cache.SetCurrentRound(next); + } else { + // Calculate the current total smartrewards amount + int64_t nTime = GetTime(); + int64_t nStartHeight = next.startBlockHeight; + double dBlockReward = 0.15; + next.rewards = 0; + while( nStartHeight <= next.endBlockHeight) next.rewards += GetBlockValue(nStartHeight++, 0, nTime) * dBlockReward; + + cache.SetResult(pResult); + cache.SetCurrentRound(next); + } } -bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results) +bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList& results) { LOCK(cs_rewardsdb); return pdb->ReadRewardRoundResults(round, results); } -bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results) +bool CSmartRewards::GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList& results) { LOCK(cs_rewardsdb); return pdb->ReadRewardRoundResults(round, results); } -const CSmartRewardsRoundResult *CSmartRewards::GetLastRoundResult() +const CSmartRewardsRoundResult* CSmartRewards::GetLastRoundResult() { return cache.GetLastRoundResult(); } -bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts) +bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList& payouts) { LOCK(cs_rewardsdb); return pdb->ReadRewardPayouts(round, payouts); } -bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts) +bool CSmartRewards::GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList& payouts) { LOCK(cs_rewardsdb); return pdb->ReadRewardPayouts(round, payouts); } -bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry, bool fCreate) +bool CSmartRewards::GetRewardEntry(const CSmartAddress& id, CSmartRewardEntry*& entry, bool fCreate) { LOCK(cs_rewardscache); // Return the entry if its already in cache. auto it = cache.GetEntries()->find(id); - if( it != cache.GetEntries()->end() ){ + if (it != cache.GetEntries()->end()) { entry = it->second; return true; } @@ -343,12 +461,12 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *& entry = new CSmartRewardEntry(id); // Return the entry if its already in db. - if( pdb->ReadRewardEntry(id, *entry) ){ + if (pdb->ReadRewardEntry(id, *entry)) { cache.AddEntry(entry); return true; } - if( fCreate ){ + if (fCreate) { cache.AddEntry(entry); return true; } @@ -358,7 +476,7 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *& return false; } -bool CSmartRewards::GetRewardEntries(CSmartRewardEntryMap &entries) +bool CSmartRewards::GetRewardEntries(CSmartRewardEntryMap& entries) { LOCK(cs_rewardsdb); return pdb->ReadRewardEntries(entries); @@ -372,7 +490,7 @@ bool CSmartRewards::SyncCached() int nEntriesPre = cache.GetEntries()->size(); int nSizePre = cache.EstimatedSize(); - bool ret = pdb->SyncCached(cache); + bool ret = pdb->SyncCached(cache); cache.Clear(); @@ -390,9 +508,10 @@ bool CSmartRewards::IsSynced() { static bool fSynced = false; - if( fSynced ) return true; + if (fSynced) + return true; - fSynced = (GetTime() - cache.GetCurrentBlock()->nTime ) <= nRewardsSyncDistance; + fSynced = (GetTime() - cache.GetCurrentBlock()->nTime) <= nRewardsSyncDistance; return fSynced; } @@ -401,14 +520,14 @@ int CSmartRewards::GetBlocksPerRound(const int nRound) { const CChainParams& chainparams = Params(); - if( nRound < chainparams.GetConsensus().nRewardsFirst_1_3_Round ){ + if (nRound < chainparams.GetConsensus().nRewardsFirst_1_3_Round) { return chainparams.GetConsensus().nRewardsBlocksPerRound_1_2; - }else{ + } else { return chainparams.GetConsensus().nRewardsBlocksPerRound_1_3; } } -CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) +CSmartRewards::CSmartRewards(CSmartRewardsDB* prewardsdb) : pdb(prewardsdb) { LOCK2(cs_rewardscache, cs_rewardsdb); @@ -423,15 +542,15 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) cache.Load(block, round, rounds); - CSmartRewardsRoundResult *pResult = new CSmartRewardsRoundResult(); + CSmartRewardsRoundResult* pResult = new CSmartRewardsRoundResult(); - if( round.number > 1 ){ + if (round.number > 1) { pResult->fSynced = true; pResult->round = rounds[round.number - 1]; pdb->ReadRewardRoundResults(round.number - 1, pResult->results); - for( auto it : pResult->results ){ - if( it->reward ){ + for (auto it : pResult->results) { + if (it->reward) { pResult->payouts.push_back(it); } } @@ -442,20 +561,20 @@ CSmartRewards::CSmartRewards(CSmartRewardsDB *prewardsdb) : pdb(prewardsdb) LogPrintf("CSmartRewards::CSmartRewards\n Last block %s\n Current Round %s\n Rounds: %d", block.ToString(), round.ToString(), rounds.size()); } -bool CSmartRewards::GetLastBlock(CSmartRewardBlock &block) +bool CSmartRewards::GetLastBlock(CSmartRewardBlock& block) { LOCK(cs_rewardsdb); // Read the last block stored in the rewards database. return pdb->ReadLastBlock(block); } -bool CSmartRewards::GetTransaction(const uint256 nHash, CSmartRewardTransaction &transaction) +bool CSmartRewards::GetTransaction(const uint256 nHash, CSmartRewardTransaction& transaction) { LOCK2(cs_rewardscache, cs_rewardsdb); // If the transaction is already in the cache use this one. auto it = cache.GetAddedTransactions()->find(nHash); - if( it != cache.GetAddedTransactions()->end() ){ + if (it != cache.GetAddedTransactions()->end()) { transaction = it->second; return true; } @@ -473,48 +592,44 @@ const CSmartRewardRoundMap* CSmartRewards::GetRewardRounds() return cache.GetRounds(); } -void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) +void CSmartRewards::ProcessInput(const CTransaction& tx, const CTxOut& in, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result) { - uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry = nullptr; + uint16_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardEntry* rEntry = nullptr; CSmartAddress id; - if(!ExtractDestination(in.scriptPubKey ,id)){ + if (!ExtractDestination(in.scriptPubKey, id)) { LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Could't parse CSmartAddress: %s\n", in.ToString()); return; } - if(!GetRewardEntry(id, rEntry, false)){ + if (!GetRewardEntry(id, rEntry, false)) { LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Spend without previous receive - %s", tx.ToString()); return; } - // If its a voteproof transaction not instantly make the - // balance ineligible. First check if the change is sent back - // to the address or not to avoid exploiting fund sending - // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() && *voteProofCheck == nullptr ){ - *voteProofCheck = new CSmartAddress(rEntry->id); - nVoteProofIn += in.nValue; + if (nCurrentRound >= nFirst_1_3_Round && tx.IsActivationTx() && !rEntry->fActivated) { + rEntry->activationTx = tx.GetHash(); + rEntry->fActivated = true; } rEntry->balance -= in.nValue; - // If its a voteproof transaction not instantly make the - // balance ineligible. First check if the change is sent back - // to the address or not to avoid exploiting fund sending - // with voteproof transactions - if( nCurrentRound >= nFirst_1_3_Round && *voteProofCheck == nullptr && !rEntry->fDisqualifyingTx ){ - + if (nCurrentRound >= nFirst_1_3_Round && !tx.IsActivationTx() && !rEntry->fDisqualifyingTx) { if( rEntry->IsEligible() ){ result.disqualifiedEntries++; result.disqualifiedSmart += rEntry->balanceEligible; } - rEntry->disqualifyingTx = tx.GetHash(); rEntry->fDisqualifyingTx = true; + } + + if (nCurrentRound >= nFirst_1_3_Round && rEntry->fActivated && !tx.IsActivationTx()) { + rEntry->activationTx.SetNull(); + rEntry->fActivated = false; + } - }else if( nCurrentRound < nFirst_1_3_Round && !rEntry->fDisqualifyingTx ){ + if (nCurrentRound < nFirst_1_3_Round && !rEntry->fDisqualifyingTx) { rEntry->disqualifyingTx = tx.GetHash(); rEntry->fDisqualifyingTx = true; @@ -526,152 +641,55 @@ void CSmartRewards::ProcessInput(const CTransaction &tx, const CTxOut &in, CSmar } - if(rEntry->balance < 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::ProcessInput - Negative amount?! - %s", rEntry->ToString()); + if (rEntry->balance < 0) { rEntry->balance = 0; } - } -void CSmartRewards::ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result) +void CSmartRewards::ProcessOutput(const CTransaction& tx, const CTxOut& out, uint16_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult& result) { - uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry = nullptr; + CSmartRewardEntry* rEntry = nullptr; CSmartAddress id; - if( !ExtractDestination(out.scriptPubKey, id) ){ + if (!ExtractDestination(out.scriptPubKey, id)) { LogPrint("smartrewards-tx", "CSmartRewards::ProcessOutput - Could't parse CSmartAddress: %s\n", out.ToString()); return; - }else{ - - GetRewardEntry(id,rEntry, true); - - if( voteProofCheck ){ - - unsigned char cProofOption = 0; - - if( !out.IsVoteProofData() && - !(*voteProofCheck == rEntry->id) ){ - - CSmartRewardEntry *vkEntry = nullptr; - - GetRewardEntry(*voteProofCheck,vkEntry, true); - - if( vkEntry->IsEligible() ){ - result.disqualifiedEntries++; - result.disqualifiedSmart += vkEntry->balanceEligible; - } - - // Finally invalidate the balance since the change was not sent - // back to the sender! We don't want to allow - // a exploit to send around funds withouht breaking smartrewards. - vkEntry->disqualifyingTx = tx.GetHash(); - vkEntry->fDisqualifyingTx = true; - - }else if( !out.IsVoteProofData() && - (*voteProofCheck == rEntry->id) ){ - - CSmartRewardEntry *proofEntry = nullptr; - unsigned char cAddressType = 0; - uint32_t nProofRound; - uint160 addressHash; - uint256 nProposalHash; // Placeholder only for now - CSmartAddress proofAddress; - - BOOST_FOREACH(const CTxOut &outData, tx.vout) { - - if( outData.IsVoteProofData() ){ - - std::vector scriptData; - scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); - CDataStream ss(scriptData, SER_NETWORK, 0); - - ss >> cProofOption; - ss >> nProofRound; - ss >> nProposalHash; - - if( cProofOption == 0x01 && - voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ - proofAddress = *voteProofCheck; - proofEntry = rEntry; - }else if( cProofOption == 0x02 && - voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ - - ss >> cAddressType; - ss >> addressHash; - - if( cAddressType == 0x01 ){ - proofAddress = CSmartAddress(CKeyID(addressHash)); - }else if( cAddressType == 0x02){ - proofAddress = CSmartAddress(CScriptID(addressHash)); - }else{ - proofAddress = CSmartAddress(); // Invalid address type - } - - GetRewardEntry(proofAddress, proofEntry, true); - - }else{ - proofAddress = CSmartAddress(); // Invalid option - } - } - } - - if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - - if( cProofOption == 0x01 && proofEntry->balanceEligible ){ - proofEntry->balanceEligible -= nVoteProofIn - tx.GetValueOut(); - - if( proofEntry->balanceEligible < 0 ){ - proofEntry->balanceEligible = 0; - } - } - - if( !proofEntry->fVoteProven ){ - - if( nProofRound == nCurrentRound ){ - proofEntry->voteProof = tx.GetHash(); - proofEntry->fVoteProven = true; - } - - // If the entry is eligible now after the vote proof update the results - if( proofEntry->IsEligible() ){ - result.qualifiedEntries++; - result.qualifiedSmart += proofEntry->balanceEligible; - } - + } else { + if (GetRewardEntry(id, rEntry, true)) { + if (tx.IsActivationTx() && Is_1_3(nCurrentRound) && !SmartHive::IsHive(rEntry->id)) { + if (!rEntry->fActivated) { + rEntry->activationTx = tx.GetHash(); + rEntry->fActivated = true; + if ( rEntry->IsEligible() ) { + result.qualifiedEntries++; + result.qualifiedSmart += rEntry->balanceEligible; } } } - - delete voteProofCheck; } - rEntry->balance += out.nValue; - // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists - if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ + rEntry->balance += out.nValue; + if (Is_1_3(nCurrentRound) && tx.IsCoinBase()) { int nInterval = SmartNodePayments::PayoutInterval(nHeight); int nPayoutsPerBlock = SmartNodePayments::PayoutsPerBlock(nHeight); // Just to avoid potential zero divisions nPayoutsPerBlock = std::max(1, nPayoutsPerBlock); CAmount nNodeReward = SmartNodePayments::Payment(nHeight) / nPayoutsPerBlock; - // If we have an interval check if this is a node payout block - if( nInterval && !(nHeight % nInterval) ){ - - // If the amount matches and the entry is not yet marked as node do it - if( abs(out.nValue - nNodeReward ) < 2 ){ - - if( !rEntry->fSmartnodePaymentTx ){ - + if (nInterval && !(nHeight % nInterval)) { + // If the amount matches and the entry is not yet marked as node do it + if (abs(out.nValue - nNodeReward) < 2) { + if (!rEntry->fSmartnodePaymentTx) { // If it is currently eligible adjust the round's results - if( rEntry->IsEligible() ){ + if (rEntry->IsEligible() ) { ++result.disqualifiedEntries; result.disqualifiedSmart += rEntry->balanceEligible; + rEntry->activationTx.SetNull(); + rEntry->fActivated = false; } - rEntry->smartnodePaymentTx = tx.GetHash(); rEntry->fSmartnodePaymentTx = true; } @@ -687,20 +705,20 @@ bool CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& int nHeight = pIndex->nHeight; - if(nHeight == 0 || nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + if (nHeight == 0 || nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)) { return false; } CSmartRewardTransaction testTx; // For the first 4 rounds we have zerocoin exploits and we don't want to add them to the rewards db. - if( nCurrentRound <= 4 ){ + if (nCurrentRound <= 4) { // First check if the transaction hash did already come up in the past. - if( GetTransaction(tx.GetHash(), testTx) ){ + if (GetTransaction(tx.GetHash(), testTx)) { // If yes we want to ignore it! There are some double appearing transactions in the history due to zerocoin exploits. LogPrint("smartrewards-tx", "CSmartRewards::ProcessTransaction - [%s] Double appearance! First in %d - Now in %d\n", testTx.hash.ToString(), testTx.blockHeight, pIndex->nHeight); return false; - }else{ + } else { // If not save add it to the cache. cache.AddTransaction(CSmartRewardTransaction(pIndex->nHeight, tx.GetHash())); } @@ -709,183 +727,100 @@ bool CSmartRewards::ProcessTransaction(CBlockIndex* pIndex, const CTransaction& return true; } -void CSmartRewards::UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) +void CSmartRewards::UndoInput(const CTransaction& tx, const CTxOut& in, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result) { - uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry = nullptr; + uint16_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; + CSmartRewardEntry* rEntry = nullptr; CSmartAddress id; - if( !ExtractDestination(in.scriptPubKey, id) ){ + if (!ExtractDestination(in.scriptPubKey, id)) { LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Process Inputs: Could't parse CSmartAddress: %s\n", in.ToString()); return; } - if( !GetRewardEntry(id, rEntry, true) ){ + if (!GetRewardEntry(id, rEntry, true)) { LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Spend without previous receive - %s", tx.ToString()); return; } rEntry->balance += in.nValue; - if( nCurrentRound >= nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ - + if ( nCurrentRound >= nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash()) { rEntry->disqualifyingTx.SetNull(); rEntry->fDisqualifyingTx = false; - if( rEntry->IsEligible() ){ + if (rEntry->IsEligible()) { --result.disqualifiedEntries; result.disqualifiedSmart -= rEntry->balanceEligible; } - }else if( nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash() ){ - + } else if (nCurrentRound < nFirst_1_3_Round && rEntry->disqualifyingTx == tx.GetHash()) { rEntry->disqualifyingTx.SetNull(); rEntry->fDisqualifyingTx = false; - if( rEntry->balanceEligible ){ + if (rEntry->balanceEligible) { --result.disqualifiedEntries; result.disqualifiedSmart -= rEntry->balanceEligible; } - - } - - if(rEntry->balance < 0 ){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Negative amount?! - %s", rEntry->ToString()); - rEntry->balance = 0; + if(rEntry->balance < 0 ){ + LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Negative amount?! - %s", rEntry->ToString()); + rEntry->balance = 0; + } } - } -void CSmartRewards::UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result) +void CSmartRewards::UndoOutput(const CTransaction& tx, const CTxOut& out, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result) { - uint32_t nFirst_1_3_Round = Params().GetConsensus().nRewardsFirst_1_3_Round; - CSmartRewardEntry *rEntry = nullptr; + CSmartRewardEntry* rEntry = nullptr; CSmartAddress id; - if( !ExtractDestination(out.scriptPubKey, id) ){ + if (!ExtractDestination(out.scriptPubKey, id)) { LogPrint("smartrewards-tx", "CSmartRewards::UndoOutput - Process Outputs: Could't parse CSmartAddress: %s\n", out.ToString()); return; - }else{ - + } else { GetRewardEntry(id, rEntry, true); - - if( voteProofCheck ){ - - unsigned char cProofOption = 0; - - if( !out.IsVoteProofData() && - !(*voteProofCheck == rEntry->id) ){ - - CSmartRewardEntry *vkEntry = nullptr; - - GetRewardEntry(*voteProofCheck, vkEntry, true); - - if( vkEntry->disqualifyingTx == tx.GetHash() ){ - - vkEntry->disqualifyingTx.SetNull(); - vkEntry->fDisqualifyingTx = false; - - - if( vkEntry->IsEligible() ){ - --result.disqualifiedEntries; - result.disqualifiedSmart -= vkEntry->balanceEligible; - } - } - - }else if( !out.IsVoteProofData() && - (*voteProofCheck == rEntry->id) ){ - - CSmartRewardEntry *proofEntry = nullptr; - unsigned char cAddressType = 0; - uint32_t nProofRound; - uint160 addressHash; - uint256 nProposalHash; // Placeholder only for now - CSmartAddress proofAddress; - - BOOST_FOREACH(const CTxOut &outData, tx.vout) { - - if( outData.IsVoteProofData() ){ - - std::vector scriptData; - scriptData.insert(scriptData.end(), outData.scriptPubKey.begin() + 3, outData.scriptPubKey.end()); - CDataStream ss(scriptData, SER_NETWORK, 0); - - ss >> cProofOption; - ss >> nProofRound; - ss >> nProposalHash; - - if( cProofOption == 0x01 && - voteProofCheck->ToString(false) != Params().GetConsensus().strRewardsGlobalVoteProofAddress){ - proofAddress = *voteProofCheck; - proofEntry = rEntry; - }else if( cProofOption == 0x02 && - voteProofCheck->ToString(false) == Params().GetConsensus().strRewardsGlobalVoteProofAddress ){ - - ss >> cAddressType; - ss >> addressHash; - - if( cAddressType == 0x01 ){ - proofAddress = CSmartAddress(CKeyID(addressHash)); - }else if( cAddressType == 0x02){ - proofAddress = CSmartAddress(CScriptID(addressHash)); - }else{ - proofAddress = CSmartAddress(); // Invalid address type - } - - GetRewardEntry(proofAddress, proofEntry, true); - - }else{ - proofAddress = CSmartAddress(); // Invalid option - } - } - } - - if( proofAddress.IsValid() && proofEntry != nullptr && !SmartHive::IsHive(*voteProofCheck) ){ - - if( proofEntry->voteProof == tx.GetHash() ){ - - proofEntry->voteProof.SetNull(); - - --result.qualifiedEntries; - result.qualifiedSmart -= proofEntry->balanceEligible; - - if( cProofOption == 0x01 ){ - proofEntry->balanceEligible += nVoteProofIn - tx.GetValueOut(); - } - - } + if (!tx.IsActivationTx() && !rEntry->fActivated) { + rEntry->activationTx.SetNull(); + rEntry->fActivated = false; + if (rEntry->disqualifyingTx == tx.GetHash()) { + rEntry->disqualifyingTx.SetNull(); + rEntry->fDisqualifyingTx = false; + if (rEntry->IsEligible()) { + --result.disqualifiedEntries; + result.disqualifiedSmart -= rEntry->balanceEligible; } } - - delete voteProofCheck; + } else if (!tx.IsActivationTx() && rEntry->fActivated && !SmartHive::IsHive(rEntry->id)) { + if (rEntry->activationTx == tx.GetHash()) { + rEntry->activationTx.SetNull(); + rEntry->fActivated = false; + --result.qualifiedEntries; + result.qualifiedSmart -= rEntry->balanceEligible; + } } - rEntry->balance -= out.nValue; // If we are in the 1.3 cycles check for node rewards to remove node addresses from lists - if( nCurrentRound >= nFirst_1_3_Round && tx.IsCoinBase() ){ - - if( rEntry->smartnodePaymentTx == tx.GetHash() ){ - + if (Is_1_3(nCurrentRound) && tx.IsCoinBase()) { + if (rEntry->smartnodePaymentTx == tx.GetHash()) { rEntry->smartnodePaymentTx.SetNull(); rEntry->fSmartnodePaymentTx = false; - // If it is eligible now adjust the round's results - if( rEntry->IsEligible() ){ + if (rEntry->IsEligible()) { --result.disqualifiedEntries; result.disqualifiedSmart -= rEntry->balanceEligible; } } } } + if (rEntry->balance < 0) { + LogPrint("smartrewards-tx", "CSmartRewards::UndoInput - Negative amount?! - %s", rEntry->ToString()); + rEntry->balance = 0; + } } -void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result) +void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult& result) { - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - %s", tx.GetHash().ToString()); - - int nFirst_1_3_Round = chainparams.GetConsensus().nRewardsFirst_1_3_Round; - int nCurrentRound; { @@ -895,7 +830,7 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nHeight = pIndex->nHeight; - if(nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + if (nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)) { return; } @@ -904,49 +839,29 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CSmartRewardTransaction testTx; - if( GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight ){ + if (GetTransaction(tx.GetHash(), testTx) && testTx.blockHeight == pIndex->nHeight) { cache.RemoveTransaction(testTx); - }else if( nCurrentRound <= 4 ){ + } else if (nCurrentRound <= 4) { return; } - CSmartAddress *voteProofCheck = nullptr; - CAmount nVoteProofIn = 0; + BOOST_REVERSE_FOREACH (const CTxOut& out, tx.vout) { + if (out.scriptPubKey.IsZerocoinMint()) + continue; - if( nCurrentRound >= nFirst_1_3_Round && tx.IsVoteProof() ){ - - const Coin &coin = coins.AccessCoin(tx.vin[0].prevout); - const CTxOut &rOut = coin.out; - - CSmartAddress id; - - if( !ExtractDestination(rOut.scriptPubKey, id)){ - LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - Process VoteProof: Could't parse CSmartAddress: %s\n", rOut.ToString()); - return; - } - - nVoteProofIn = rOut.nValue; - voteProofCheck = new CSmartAddress(id); - } - - BOOST_REVERSE_FOREACH(const CTxOut &out, tx.vout) { - - if(out.scriptPubKey.IsZerocoinMint() ) continue; - - UndoOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRound, result); + UndoOutput(tx, out, nCurrentRound, result); } int nTime2 = GetTimeMicros(); // No reason to check the input here for new coins. - if( !tx.IsCoinBase() ){ - - BOOST_REVERSE_FOREACH(const CTxIn &in, tx.vin) { + if (!tx.IsCoinBase()) { + BOOST_REVERSE_FOREACH (const CTxIn& in, tx.vin) { + if (in.scriptSig.IsZerocoinSpend()) + continue; - if( in.scriptSig.IsZerocoinSpend() ) continue; - - const Coin &coin = coins.AccessCoin(in.prevout); - const CTxOut &rOut = coin.out; + const Coin& coin = coins.AccessCoin(in.prevout); + const CTxOut& rOut = coin.out; UndoInput(tx, rOut, nCurrentRound, result); } @@ -955,7 +870,7 @@ void CSmartRewards::UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nTime3 = GetTimeMicros(); double dProcessingTime = (nTime3 - nTime1) * 0.001; - if( dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-tx") ){ + if (dProcessingTime > 10.0 && LogAcceptCategory("smartrewards-tx")) { LogPrint("smartrewards-tx", "CSmartRewards::UndoTransaction - TX %s - %.2fms\n", tx.GetHash().ToString(), dProcessingTime); LogPrint("smartrewards-tx", " outputs - %.2fms\n", (nTime2 - nTime1) * 0.001); LogPrint("smartrewards-tx", " inputs - %.2fms\n", (nTime3 - nTime2) * 0.001); @@ -966,33 +881,31 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe { int nTime1 = GetTimeMicros(); - if(pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + if (pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)) { return true; } LOCK(cs_rewardscache); - const CSmartRewardRound *round = cache.GetCurrentRound(); + const CSmartRewardRound* round = cache.GetCurrentRound(); - if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight + 1 ){ + if (!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight + 1) { LogPrintf("CSmartRewards::CommitBlock - Invalid next block!"); return false; } - if( cache.GetLastRoundResult() && + if (cache.GetLastRoundResult() && cache.GetLastRoundResult()->fSynced && - pIndex->nHeight > cache.GetLastRoundResult()->round.GetLastRoundBlock() ){ - cache.ClearResult(); + pIndex->nHeight > cache.GetLastRoundResult()->round.GetLastRoundBlock()) { + cache.ClearResult(); } cache.ApplyRoundUpdateResult(result); // For the first round we have special parameter.. - if( !round->number ){ - - if( (MainNet() && pIndex->GetBlockTime() > nFirstRoundStartTime) || - (TestNet() && pIndex->nHeight >= nFirstRoundStartBlock_Testnet) ){ - + if (!round->number) { + if ((MainNet() && pIndex->GetBlockTime() > nFirstRoundStartTime) || + (TestNet() && pIndex->nHeight >= nFirstRoundStartBlock_Testnet)) { // Create the very first smartrewards round. CSmartRewardRound first; first.number = 1; @@ -1005,13 +918,11 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe // Evaluate the round and update the next rounds parameter. EvaluateRound(first); } - } // If just hit the next round threshold - if( ( MainNet() && round->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() > round->endBlockTime ) || - ( ( TestNet() || round->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == round->endBlockHeight ) ){ - + if ((MainNet() && round->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() > round->endBlockTime) || + ((TestNet() || round->number >= nRewardsFirstAutomatedRound - 1) && pIndex->nHeight == round->endBlockHeight)) { UpdatePercentage(); cache.UpdateRoundEnd(pIndex->nHeight, pIndex->GetBlockTime()); @@ -1025,26 +936,24 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe int nBlocksPerRound = GetBlocksPerRound(next.number); time_t startTime = (time_t)next.startBlockTime; - if( MainNet() ){ - - if( next.number == nRewardsFirstAutomatedRound - 1 ){ + if (MainNet()) { + if (next.number == nRewardsFirstAutomatedRound - 1) { // Let the round 12 end at height 574099 so that round 13 starts at 574100 next.endBlockHeight = HF_V1_2_SMARTREWARD_HEIGHT - 1; - next.endBlockTime = startTime + ( (next.endBlockHeight - next.startBlockHeight) * 55 ); - }else if(next.number < nRewardsFirstAutomatedRound){ - + next.endBlockTime = startTime + ((next.endBlockHeight - next.startBlockHeight) * 55); + } else if (next.number < nRewardsFirstAutomatedRound) { boost::gregorian::date endDate = boost::posix_time::from_time_t(startTime).date(); endDate += boost::gregorian::months(1); // End date at 00:00:00 + 25200 seconds (7 hours) to match the date at 07:00 UTC next.endBlockTime = time_t((boost::posix_time::ptime(endDate, boost::posix_time::seconds(25200)) - epoch).total_seconds()); - next.endBlockHeight = next.startBlockHeight + ( (next.endBlockTime - next.startBlockTime) / 55 ); - }else{ + next.endBlockHeight = next.startBlockHeight + ((next.endBlockTime - next.startBlockTime) / 55); + } else { next.endBlockHeight = next.startBlockHeight + nBlocksPerRound - 1; next.endBlockTime = startTime + nBlocksPerRound * 55; } - }else{ + } else { next.endBlockHeight = next.startBlockHeight + nBlocksPerRound - 1; next.endBlockTime = startTime + nBlocksPerRound * 55; } @@ -1057,7 +966,7 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe cache.UpdateHeights(GetBlockHeight(pIndex), cache.GetCurrentBlock()->nHeight); - if( LogAcceptCategory("smartrewards-bench") ){ + if (LogAcceptCategory("smartrewards-bench")) { int nTime2 = GetTimeMicros(); double dProcessingTime = (nTime2 - nTime1) * 0.001; LogPrint("smartrewards-bench", "Round %d - Block: %d\n", round->number, cache.GetCurrentBlock()->nHeight); @@ -1067,28 +976,28 @@ bool CSmartRewards::CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateRe // If we are synced notify the UI on each new block. // If not notify the UI every nRewardsUISyncUpdateRate blocks to let it update the // loading screen. - if( IsSynced() || !(cache.GetCurrentBlock()->nHeight % nRewardsUISyncUpdateRate) ) + if (IsSynced() || !(cache.GetCurrentBlock()->nHeight % nRewardsUISyncUpdateRate)) uiInterface.NotifySmartRewardUpdate(); return true; } -bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpdateResult &result) +bool CSmartRewards::CommitUndoBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result) { int nTime1 = GetTimeMicros(); - if(pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)){ + if (pIndex && pIndex->nHeight > sporkManager.GetSporkValue(SPORK_15_SMARTREWARDS_BLOCKS_ENABLED)) { return true; } LOCK2(cs_rewardscache, cs_rewardsdb); - if(!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight ){ + if (!pIndex || pIndex->nHeight != cache.GetCurrentBlock()->nHeight) { LogPrintf("CSmartRewards::CommitUndoBlock - Invalid next block!"); return false; } - const CSmartRewardRound *pRound = cache.GetCurrentRound(); + const CSmartRewardRound* pRound = cache.GetCurrentRound(); CSmartRewardsUpdateResult undoUpdate(pIndex->pprev->nHeight, pIndex->pprev->phashBlock, pIndex->pprev->GetBlockTime()); @@ -1100,20 +1009,19 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda cache.ApplyRoundUpdateResult(undoUpdate); // If just hit the last round's threshold - if( ( MainNet() && pRound->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < pRound->endBlockTime ) || - ( ( (TestNet() && pRound->number > 1) || pRound->number >= nRewardsFirstAutomatedRound - 1 ) && pIndex->nHeight == pRound->startBlockHeight ) ){ - + if ((MainNet() && pRound->number < nRewardsFirstAutomatedRound - 1 && pIndex->GetBlockTime() < pRound->endBlockTime) || + (((TestNet() && pRound->number > 1) || pRound->number >= nRewardsFirstAutomatedRound - 1) && pIndex->nHeight == pRound->startBlockHeight)) { // Recover the last round from the history as current round CSmartRewardRound prevRound = cache.GetRounds()->at(pRound->number - 1); cache.SetCurrentRound(prevRound); cache.RemoveFinishedRound(prevRound.number); - CSmartRewardsRoundResult *undoResult = new CSmartRewardsRoundResult(); + CSmartRewardsRoundResult* undoResult = new CSmartRewardsRoundResult(); undoResult->round = prevRound; - if( !GetRewardRoundResults(prevRound.number, undoResult->results) ){ + if (!GetRewardRoundResults(prevRound.number, undoResult->results)) { LogPrintf("CSmartRewards::CommitUndoBlock - Failed to read last round's results!"); return false; } @@ -1124,13 +1032,12 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda CSmartRewardEntryMap tmpEntries; pdb->ReadRewardEntries(tmpEntries); - for( auto itDb = tmpEntries.begin(); itDb != tmpEntries.end(); ++itDb){ - + for (auto itDb = tmpEntries.begin(); itDb != tmpEntries.end(); ++itDb) { auto itCache = cache.GetEntries()->find(itDb->first); - if( itCache == cache.GetEntries()->end() ){ + if (itCache == cache.GetEntries()->end()) { cache.AddEntry(itDb->second); - }else{ + } else { delete itDb->second; } } @@ -1142,8 +1049,8 @@ bool CSmartRewards::CommitUndoBlock(CBlockIndex *pIndex, const CSmartRewardsUpda int nTime2 = GetTimeMicros(); - if( LogAcceptCategory("smartrewards-block") ){ - LogPrint("smartrewards-block", "Round %d - Block: %d\n",pRound->number, cache.GetCurrentBlock()->nHeight); + if (LogAcceptCategory("smartrewards-block")) { + LogPrint("smartrewards-block", "Round %d - Block: %d\n", pRound->number, cache.GetCurrentBlock()->nHeight); LogPrint("smartrewards-block", " Commit undo block: %.2fms\n", (nTime2 - nTime1) * 0.001); } @@ -1154,11 +1061,11 @@ CSmartRewardsCache::~CSmartRewardsCache() { LOCK(cs_rewardscache); - for( std::pair it : entries ){ + for (std::pair it : entries) { delete it.second; } - if( result ){ + if (result) { result->Clear(); delete result; } @@ -1180,7 +1087,7 @@ unsigned long CSmartRewardsCache::EstimatedSize() return nEntriesSize + nRoundsSize + nTransactionsSize + nBlockSize; } -void CSmartRewardsCache::Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundMap &rounds) +void CSmartRewardsCache::Load(const CSmartRewardBlock& block, const CSmartRewardRound& round, const CSmartRewardRoundMap& rounds) { this->block = block; this->round = round; @@ -1199,15 +1106,15 @@ void CSmartRewardsCache::Clear() { LOCK(cs_rewardscache); - if( result ){ + if (result) { result->fSynced = true; } - if( undoResults ){ + if (undoResults) { undoResults->fSynced = true; } - for( auto it = entries.cbegin(); it != entries.cend();it++){ + for (auto it = entries.cbegin(); it != entries.cend(); it++) { delete it->second; } @@ -1218,12 +1125,10 @@ void CSmartRewardsCache::Clear() void CSmartRewardsCache::ClearResult() { - if( result ){ - + if (result) { auto it = result->results.begin(); - while( it != result->results.end() ){ - + while (it != result->results.end()) { delete *it; ++it; } @@ -1234,12 +1139,10 @@ void CSmartRewardsCache::ClearResult() result = nullptr; } - if( undoResults ){ - + if (undoResults) { auto it = undoResults->results.begin(); - while( it != undoResults->results.end() ){ - + while (it != undoResults->results.end()) { delete *it; ++it; } @@ -1251,23 +1154,23 @@ void CSmartRewardsCache::ClearResult() } } -void CSmartRewardsCache::SetCurrentBlock(const CSmartRewardBlock ¤tBlock) +void CSmartRewardsCache::SetCurrentBlock(const CSmartRewardBlock& currentBlock) { AssertLockHeld(cs_rewardscache); block = currentBlock; } -void CSmartRewardsCache::SetCurrentRound(const CSmartRewardRound ¤tRound) +void CSmartRewardsCache::SetCurrentRound(const CSmartRewardRound& currentRound) { AssertLockHeld(cs_rewardscache); round = currentRound; } -void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) +void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult* pResult) { AssertLockHeld(cs_rewardscache); - if( result ){ + if (result) { result->Clear(); delete result; } @@ -1275,11 +1178,11 @@ void CSmartRewardsCache::SetResult(CSmartRewardsRoundResult *pResult) result = pResult; } -void CSmartRewardsCache::SetUndoResult(CSmartRewardsRoundResult *pResult) +void CSmartRewardsCache::SetUndoResult(CSmartRewardsRoundResult* pResult) { AssertLockHeld(cs_rewardscache); - if( undoResults ){ + if (undoResults) { undoResults->Clear(); delete undoResults; } @@ -1287,11 +1190,11 @@ void CSmartRewardsCache::SetUndoResult(CSmartRewardsRoundResult *pResult) undoResults = pResult; } -void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result) +void CSmartRewardsCache::ApplyRoundUpdateResult(const CSmartRewardsUpdateResult& result) { AssertLockHeld(cs_rewardscache); - if( result.IsValid() ){ + if (result.IsValid()) { SetCurrentBlock(result.block); round.disqualifiedEntries += result.disqualifiedEntries; @@ -1333,49 +1236,49 @@ void CSmartRewardsCache::UpdateHeights(const int nHeight, const int nRewardHeigh rewardHeight = nRewardHeight; } -void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound &round) +void CSmartRewardsCache::AddFinishedRound(const CSmartRewardRound& round) { AssertLockHeld(cs_rewardscache); rounds[round.number] = round; } -void CSmartRewardsCache::RemoveFinishedRound(const int &nNumber) +void CSmartRewardsCache::RemoveFinishedRound(const int& nNumber) { AssertLockHeld(cs_rewardscache); auto it = rounds.find(nNumber); - if( it != rounds.end() ){ + if (it != rounds.end()) { rounds.erase(it); } } -void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction &transaction) +void CSmartRewardsCache::AddTransaction(const CSmartRewardTransaction& transaction) { LOCK(cs_rewardscache); auto it = removeTransactions.find(transaction.hash); - if( it != removeTransactions.end() ){ + if (it != removeTransactions.end()) { removeTransactions.erase(it); - }else{ + } else { addTransactions.insert(std::make_pair(transaction.hash, transaction)); } } -void CSmartRewardsCache::RemoveTransaction(const CSmartRewardTransaction &transaction) +void CSmartRewardsCache::RemoveTransaction(const CSmartRewardTransaction& transaction) { LOCK(cs_rewardscache); auto it = addTransactions.find(transaction.hash); - if( it != addTransactions.end() ){ + if (it != addTransactions.end()) { addTransactions.erase(it); - }else{ + } else { removeTransactions.insert(std::make_pair(transaction.hash, transaction)); } } -void CSmartRewardsCache::AddEntry(CSmartRewardEntry *entry) +void CSmartRewardsCache::AddEntry(CSmartRewardEntry* entry) { LOCK(cs_rewardscache); entries[entry->id] = entry; @@ -1383,7 +1286,7 @@ void CSmartRewardsCache::AddEntry(CSmartRewardEntry *entry) void CSmartRewardsRoundResult::Clear() { - for( CSmartRewardResultEntry *resultEntry : results ){ + for (CSmartRewardResultEntry* resultEntry : results) { delete resultEntry; } diff --git a/src/smartrewards/rewards.h b/src/smartrewards/rewards.h index 71495aae..5928ee9c 100644 --- a/src/smartrewards/rewards.h +++ b/src/smartrewards/rewards.h @@ -7,8 +7,8 @@ #include "sync.h" -#include #include "consensus/consensus.h" +#include using namespace std; @@ -32,11 +32,11 @@ const int64_t nFirstRoundStartBlock = 1; const int64_t nFirstRoundEndBlock = 60001; // Timestamps of the first round's start and end on testnet -const int64_t nFirstTxTimestamp_Testnet = 1527192589; +const int64_t nFirstTxTimestamp_Testnet = 1579594059; const int64_t nFirstRoundStartTime_Testnet = nFirstTxTimestamp_Testnet; -const int64_t nFirstRoundEndTime_Testnet = nFirstRoundStartTime_Testnet + (2*60*60); +const int64_t nFirstRoundEndTime_Testnet = nFirstRoundStartTime_Testnet + (1 * 60 * 60); const int64_t nFirstRoundStartBlock_Testnet = TESTNET_V1_2_8_PAYMENTS_HEIGHT - 1; -const int64_t nFirstRoundEndBlock_Testnet = nFirstRoundStartBlock_Testnet + 500; +const int64_t nFirstRoundEndBlock_Testnet = nFirstRoundStartBlock_Testnet + 100; void ThreadSmartRewards(bool fRecreate = false); CAmount CalculateRewardsForBlockRange(int64_t start, int64_t end); @@ -46,17 +46,17 @@ extern CCriticalSection cs_rewardsdb; extern size_t nCacheRewardEntries; -struct CSmartRewardsUpdateResult -{ +struct CSmartRewardsUpdateResult { int64_t disqualifiedEntries; int64_t disqualifiedSmart; int64_t qualifiedEntries; int64_t qualifiedSmart; CSmartRewardBlock block; CSmartRewardsUpdateResult() : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() {} - CSmartRewardsUpdateResult(const int nHeight, const uint256* pBlockHash, const int64_t nBlockTime) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block(nHeight, pBlockHash, nBlockTime) { } - CSmartRewardsUpdateResult(const CBlockIndex* pIndex) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() { - if( pIndex && pIndex->phashBlock ){ + CSmartRewardsUpdateResult(const int nHeight, const uint256* pBlockHash, const int64_t nBlockTime) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block(nHeight, pBlockHash, nBlockTime) {} + CSmartRewardsUpdateResult(const CBlockIndex* pIndex) : disqualifiedEntries(0), disqualifiedSmart(0), qualifiedEntries(0), qualifiedSmart(0), block() + { + if (pIndex && pIndex->phashBlock) { block = CSmartRewardBlock(pIndex->nHeight, pIndex->phashBlock, pIndex->nTime); } } @@ -64,13 +64,12 @@ struct CSmartRewardsUpdateResult bool IsValid() const { return block.IsValid(); } }; -struct CSmartRewardsRoundResult -{ +struct CSmartRewardsRoundResult { CSmartRewardRound round; CSmartRewardResultEntryPtrList results; CSmartRewardResultEntryPtrList payouts; bool fSynced; - CSmartRewardsRoundResult(){fSynced = false;} + CSmartRewardsRoundResult() { fSynced = false; } void Clear(); }; @@ -86,28 +85,27 @@ class CSmartRewardsCache CSmartRewardTransactionMap addTransactions; CSmartRewardTransactionMap removeTransactions; CSmartRewardEntryMap entries; - CSmartRewardsRoundResult *result; - CSmartRewardsRoundResult *undoResults; + CSmartRewardsRoundResult* result; + CSmartRewardsRoundResult* undoResults; public: - - CSmartRewardsCache() : block(), round(), rounds(), addTransactions(), removeTransactions(), entries(), result(nullptr), undoResults(nullptr) { } + CSmartRewardsCache() : block(), round(), rounds(), addTransactions(), removeTransactions(), entries(), result(nullptr), undoResults(nullptr) {} ~CSmartRewardsCache(); unsigned long EstimatedSize(); - void Load(const CSmartRewardBlock &block, const CSmartRewardRound &round, const CSmartRewardRoundMap &rounds); + void Load(const CSmartRewardBlock& block, const CSmartRewardRound& round, const CSmartRewardRoundMap& rounds); bool NeedsSync(); void Clear(); void ClearResult(); - void SetCurrentBlock(const CSmartRewardBlock ¤tBlock); - void SetCurrentRound(const CSmartRewardRound ¤tRound); - void SetResult(CSmartRewardsRoundResult *pResult); - void SetUndoResult(CSmartRewardsRoundResult *pResult); + void SetCurrentBlock(const CSmartRewardBlock& currentBlock); + void SetCurrentRound(const CSmartRewardRound& currentRound); + void SetResult(CSmartRewardsRoundResult* pResult); + void SetUndoResult(CSmartRewardsRoundResult* pResult); - void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult &result); + void ApplyRoundUpdateResult(const CSmartRewardsUpdateResult& result); void UpdateRoundPayoutParameter(int64_t nBlockPayees, int64_t nBlockInterval); void UpdateRoundEnd(int nBlockHeight, int64_t nBlockTime); void UpdateRoundPercent(double dPercent); @@ -122,16 +120,16 @@ class CSmartRewardsCache const CSmartRewardsRoundResult* GetLastRoundResult() const { return result; } const CSmartRewardsRoundResult* GetUndoResult() const { return undoResults; } - void AddFinishedRound(const CSmartRewardRound &round); - void RemoveFinishedRound(const int &nNumber); - void AddTransaction(const CSmartRewardTransaction &transaction); - void RemoveTransaction(const CSmartRewardTransaction &transaction); - void AddEntry(CSmartRewardEntry *entry); + void AddFinishedRound(const CSmartRewardRound& round); + void RemoveFinishedRound(const int& nNumber); + void AddTransaction(const CSmartRewardTransaction& transaction); + void RemoveTransaction(const CSmartRewardTransaction& transaction); + void AddEntry(CSmartRewardEntry* entry); }; class CSmartRewards { - CSmartRewardsDB * pdb; + CSmartRewardsDB* pdb; CSmartRewardsCache cache; mutable CCriticalSection csRounds; @@ -139,17 +137,17 @@ class CSmartRewards void UpdateRoundPayoutParameter(); void UpdatePercentage(); - bool ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry); - bool GetRewardEntries(CSmartRewardEntryMap &entries); -public: + bool ReadRewardEntry(const CSmartAddress& id, CSmartRewardEntry& entry); + bool GetRewardEntries(CSmartRewardEntryMap& entries); - CSmartRewards(CSmartRewardsDB *prewardsdb); +public: + CSmartRewards(CSmartRewardsDB* prewardsdb); ~CSmartRewards() { delete pdb; } void Lock(); bool IsLocked(); - bool GetLastBlock(CSmartRewardBlock &block); - bool GetTransaction(const uint256 hash, CSmartRewardTransaction &transaction); + bool GetLastBlock(CSmartRewardBlock& block); + bool GetTransaction(const uint256 hash, CSmartRewardTransaction& transaction); const CSmartRewardRound* GetCurrentRound(); const CSmartRewardRoundMap* GetRewardRounds(); @@ -161,38 +159,39 @@ class CSmartRewards int GetBlocksPerRound(const int nRound); - bool Update(CBlockIndex *pindexNew, const CChainParams& chainparams, const int nCurrentRound, CSmartRewardsUpdateResult &result); - bool UpdateRound(const CSmartRewardRound &round); + bool Update(CBlockIndex* pindexNew, const CChainParams& chainparams, const int nCurrentRound, CSmartRewardsUpdateResult& result); + bool UpdateRound(const CSmartRewardRound& round); - void ProcessInput(const CTransaction &tx, const CTxOut &in, CSmartAddress **voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); - void ProcessOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount nVoteProofIn, uint32_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult &result); + void ProcessInput(const CTransaction& tx, const CTxOut& in, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result); + void ProcessOutput(const CTransaction& tx, const CTxOut& out, uint16_t nCurrentRound, int nHeight, CSmartRewardsUpdateResult& result); - void UndoInput(const CTransaction &tx, const CTxOut &in, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); - void UndoOutput(const CTransaction &tx, const CTxOut &out, CSmartAddress *voteProofCheck, CAmount &nVoteProofIn, uint32_t nCurrentRound, CSmartRewardsUpdateResult &result); + void UndoInput(const CTransaction& tx, const CTxOut& in, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result); + void UndoOutput(const CTransaction& tx, const CTxOut& out, uint16_t nCurrentRound, CSmartRewardsUpdateResult& result); bool ProcessTransaction(CBlockIndex* pIndex, const CTransaction& tx, int nCurrentRound); - void UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult &result); + void UndoTransaction(CBlockIndex* pIndex, const CTransaction& tx, CCoinsViewCache& coins, const CChainParams& chainparams, CSmartRewardsUpdateResult& result); bool CommitBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); bool CommitUndoBlock(CBlockIndex* pIndex, const CSmartRewardsUpdateResult& result); - bool GetRewardEntry(const CSmartAddress &id, CSmartRewardEntry *&entry, bool fCreate); + bool GetRewardEntry(const CSmartAddress& id, CSmartRewardEntry*& entry, bool fCreate); - void EvaluateRound(CSmartRewardRound &next); - bool StartFirstRound(const CSmartRewardRound &next, const CSmartRewardEntryList &entries); - bool FinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardRound &next, const CSmartRewardEntryList &entries, const CSmartRewardResultEntryList &results); - bool UndoFinalizeRound(const CSmartRewardRound ¤t, const CSmartRewardResultEntryList &results); + void EvaluateRound(CSmartRewardRound& next); + bool StartFirstRound(const CSmartRewardRound& next, const CSmartRewardEntryList& entries); + bool FinalizeRound(const CSmartRewardRound& current, const CSmartRewardRound& next, const CSmartRewardEntryList& entries, const CSmartRewardResultEntryList& results); + bool UndoFinalizeRound(const CSmartRewardRound& current, const CSmartRewardResultEntryList& results); - bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results); - bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results); + bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryList& results); + bool GetRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList& results); const CSmartRewardsRoundResult* GetLastRoundResult(); - bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts); - bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts); + bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryList& payouts); + bool GetRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList& payouts); + bool Is_1_3(uint16_t round); }; /** Global variable that points to the active rewards object (protected by cs_main) */ -extern CSmartRewards *prewards; +extern CSmartRewards* prewards; extern bool fSmartRewardsRunning; #endif // REWARDS_H diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index 55e398f0..c9ef67c4 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -6,17 +6,17 @@ #include "chainparams.h" #include "hash.h" -#include "pow.h" -#include "uint256.h" -#include "ui_interface.h" #include "init.h" +#include "pow.h" #include "rewards.h" #include "rewardsdb.h" +#include "ui_interface.h" +#include "uint256.h" #include -#include #include "leveldb/include/leveldb/db.h" +#include using namespace std; @@ -31,12 +31,11 @@ static const char DB_TX_HASH = 't'; static const char DB_VERSION = 'V'; -CSmartRewardsDB::CSmartRewardsDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "rewards", nCacheSize, fMemory, fWipe) { - - if( !Exists(DB_VERSION) ){ +CSmartRewardsDB::CSmartRewardsDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "rewards", nCacheSize, fMemory, fWipe) +{ + if (!Exists(DB_VERSION)) { Write(DB_VERSION, REWARDS_DB_VERSION); } - } bool CSmartRewardsDB::Verify(int& lastBlockHeight) @@ -47,17 +46,17 @@ bool CSmartRewardsDB::Verify(int& lastBlockHeight) lastBlockHeight = 0; - if( !Read(DB_VERSION, dbVersion) ){ + if (!Read(DB_VERSION, dbVersion)) { LogPrintf("CSmartRewards::Verify() Could't read DB_VERSION\n"); return false; } - if( dbVersion < REWARDS_DB_VERSION ){ + if (dbVersion < REWARDS_DB_VERSION) { LogPrintf("CSmartRewards::Verify() DB_VERSION too old.\n"); return false; } - if(!ReadLastBlock(last)){ + if (!ReadLastBlock(last)) { LogPrintf("CSmartRewards::Verify() No block here yet\n"); return true; } @@ -67,27 +66,27 @@ bool CSmartRewardsDB::Verify(int& lastBlockHeight) return true; } -bool CSmartRewardsDB::ReadBlock(const int nHeight, CSmartRewardBlock &block) +bool CSmartRewardsDB::ReadBlock(const int nHeight, CSmartRewardBlock& block) { - return Read(make_pair(DB_BLOCK,nHeight), block); + return Read(make_pair(DB_BLOCK, nHeight), block); } -bool CSmartRewardsDB::ReadLastBlock(CSmartRewardBlock &block) +bool CSmartRewardsDB::ReadLastBlock(CSmartRewardBlock& block) { return Read(DB_BLOCK_LAST, block); } -bool CSmartRewardsDB::ReadTransaction(const uint256 hash, CSmartRewardTransaction &transaction) +bool CSmartRewardsDB::ReadTransaction(const uint256 hash, CSmartRewardTransaction& transaction) { - return Read(make_pair(DB_TX_HASH,hash), transaction); + return Read(make_pair(DB_TX_HASH, hash), transaction); } -bool CSmartRewardsDB::ReadRound(const int16_t number, CSmartRewardRound &round) +bool CSmartRewardsDB::ReadRound(const int16_t number, CSmartRewardRound& round) { - return Read(make_pair(DB_ROUND,number), round); + return Read(make_pair(DB_ROUND, number), round); } -bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundMap &rounds) +bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundMap& rounds) { boost::scoped_ptr pcursor(NewIterator()); @@ -95,7 +94,7 @@ bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundMap &rounds) while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair key; + std::pair key; if (pcursor->GetKey(key) && key.first == DB_ROUND) { CSmartRewardRound nValue; if (pcursor->GetValue(nValue)) { @@ -112,40 +111,41 @@ bool CSmartRewardsDB::ReadRounds(CSmartRewardRoundMap &rounds) return true; } -bool CSmartRewardsDB::ReadCurrentRound(CSmartRewardRound &round) +bool CSmartRewardsDB::ReadCurrentRound(CSmartRewardRound& round) { return Read(DB_ROUND_CURRENT, round); } -bool CSmartRewardsDB::ReadRewardEntry(const CSmartAddress &id, CSmartRewardEntry &entry) +bool CSmartRewardsDB::ReadRewardEntry(const CSmartAddress& id, CSmartRewardEntry& entry) { - return Read(make_pair(DB_REWARD_ENTRY,id), entry); + return Read(make_pair(DB_REWARD_ENTRY, id), entry); } -bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) +bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache& cache) { CDBBatch batch(*this); - if( cache.GetUndoResult() != nullptr && !cache.GetUndoResult()->fSynced ){ - + if (cache.GetUndoResult() != nullptr && !cache.GetUndoResult()->fSynced) { CSmartRewardResultEntryPtrList tmpResults = cache.GetUndoResult()->results; auto entry = cache.GetEntries()->begin(); - while( entry != cache.GetEntries()->end() ){ - + while (entry != cache.GetEntries()->end()) { CSmartAddress searchAddress = entry->second->id; auto it = std::find_if(tmpResults.begin(), - tmpResults.end(), - [searchAddress](const CSmartRewardResultEntry* rEntry) -> bool { - return rEntry->entry.id == searchAddress; - }); + tmpResults.end(), + [searchAddress](const CSmartRewardResultEntry* rEntry) -> bool { + return rEntry->entry.id == searchAddress; + }); - if( it == tmpResults.end() ){ + if (it == tmpResults.end()) { batch.Erase(make_pair(DB_REWARD_ENTRY, entry->first)); - }else{ + } else { CSmartRewardEntry rewardEntry = (*it)->entry; + + std::cout << rewardEntry.ToString() << std::endl; + batch.Write(make_pair(DB_REWARD_ENTRY, rewardEntry.id), rewardEntry); batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetUndoResult()->round.number, rewardEntry.id))); tmpResults.erase(it); @@ -156,23 +156,21 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) auto it = tmpResults.begin(); - while( it != tmpResults.end() ){ - batch.Write(make_pair(DB_REWARD_ENTRY,(*it)->entry.id), (*it)->entry); + while (it != tmpResults.end()) { + batch.Write(make_pair(DB_REWARD_ENTRY, (*it)->entry.id), (*it)->entry); batch.Erase(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetUndoResult()->round.number, (*it)->entry.id))); ++it; } - }else{ - + } else { auto entry = cache.GetEntries()->begin(); - while( entry != cache.GetEntries()->end() ){ - - if( entry->second->balance <= 0 ){ - batch.Erase(make_pair(DB_REWARD_ENTRY,entry->first)); - }else{ - batch.Write(make_pair(DB_REWARD_ENTRY,entry->first), *entry->second); + while (entry != cache.GetEntries()->end()) { + if (entry->second->balance <= 0) { + batch.Erase(make_pair(DB_REWARD_ENTRY, entry->first)); + } else { + batch.Write(make_pair(DB_REWARD_ENTRY, entry->first), *entry->second); } ++entry; @@ -181,34 +179,33 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) auto addTx = cache.GetAddedTransactions()->begin(); - while( addTx != cache.GetAddedTransactions()->end() ){ + while (addTx != cache.GetAddedTransactions()->end()) { batch.Write(make_pair(DB_TX_HASH, addTx->first), addTx->second); ++addTx; } auto removeTx = cache.GetRemovedTransactions()->begin(); - while( removeTx != cache.GetRemovedTransactions()->end() ){ + while (removeTx != cache.GetRemovedTransactions()->end()) { batch.Erase(make_pair(DB_TX_HASH, removeTx->first)); ++removeTx; } auto round = cache.GetRounds()->begin(); - while( round != cache.GetRounds()->end() ){ + while (round != cache.GetRounds()->end()) { batch.Write(make_pair(DB_ROUND, round->first), round->second); ++round; } batch.Write(DB_BLOCK_LAST, *cache.GetCurrentBlock()); - if( cache.GetCurrentRound()->number ){ + if (cache.GetCurrentRound()->number) { batch.Write(DB_ROUND_CURRENT, *cache.GetCurrentRound()); } - if( cache.GetLastRoundResult() != nullptr && !cache.GetLastRoundResult()->fSynced ){ - - BOOST_FOREACH(const CSmartRewardResultEntry *s, cache.GetLastRoundResult()->results) { + if (cache.GetLastRoundResult() != nullptr && !cache.GetLastRoundResult()->fSynced) { + BOOST_FOREACH (const CSmartRewardResultEntry* s, cache.GetLastRoundResult()->results) { batch.Write(make_pair(DB_ROUND_SNAPSHOT, make_pair(cache.GetLastRoundResult()->round.number, s->entry.id)), *s); } } @@ -216,19 +213,19 @@ bool CSmartRewardsDB::SyncCached(const CSmartRewardsCache &cache) return WriteBatch(batch, true); } -bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryMap &entries) { - +bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryMap& entries) +{ boost::scoped_ptr pcursor(NewIterator()); pcursor->Seek(DB_REWARD_ENTRY); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair key; + std::pair key; if (pcursor->GetKey(key) && key.first == DB_REWARD_ENTRY) { CSmartRewardEntry entry; if (pcursor->GetValue(entry)) { - entries.insert(std::make_pair(entry.id, new CSmartRewardEntry(entry) )); + entries.insert(std::make_pair(entry.id, new CSmartRewardEntry(entry))); pcursor->Next(); } else { return error("failed to get reward entry"); @@ -241,18 +238,18 @@ bool CSmartRewardsDB::ReadRewardEntries(CSmartRewardEntryMap &entries) { return true; } -bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryList &results) { - +bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryList& results) +{ boost::scoped_ptr pcursor(NewIterator()); - pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT,round)); + pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT, round)); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair> key; + std::pair > key; if (pcursor->GetKey(key) && key.first == DB_ROUND_SNAPSHOT) { - - if( key.second.first != round ) break; + if (key.second.first != round) + break; CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { @@ -269,18 +266,18 @@ bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRe return true; } -bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList &results) { - +bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardResultEntryPtrList& results) +{ boost::scoped_ptr pcursor(NewIterator()); - pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT,round)); + pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT, round)); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair> key; + std::pair > key; if (pcursor->GetKey(key) && key.first == DB_ROUND_SNAPSHOT) { - - if( key.second.first != round ) break; + if (key.second.first != round) + break; CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { @@ -297,22 +294,23 @@ bool CSmartRewardsDB::ReadRewardRoundResults(const int16_t round, CSmartRewardRe return true; } -bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList &payouts) { - +bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryList& payouts) +{ boost::scoped_ptr pcursor(NewIterator()); - pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT,round)); + pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT, round)); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair> key; + std::pair > key; if (pcursor->GetKey(key) && key.first == DB_ROUND_SNAPSHOT) { - - if( key.second.first != round ) break; + if (key.second.first != round) + break; CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { - if( nValue.reward ) payouts.push_back(nValue); + if (nValue.reward) + payouts.push_back(nValue); pcursor->Next(); } else { return error("failed to get reward entry"); @@ -325,26 +323,28 @@ bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultE return true; } -bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList &payouts) { - +bool CSmartRewardsDB::ReadRewardPayouts(const int16_t round, CSmartRewardResultEntryPtrList& payouts) +{ boost::scoped_ptr pcursor(NewIterator()); - pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT,round)); + pcursor->Seek(make_pair(DB_ROUND_SNAPSHOT, round)); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair> key; + std::pair > key; if (pcursor->GetKey(key) && key.first == DB_ROUND_SNAPSHOT) { - - if( key.second.first != round ) break; + if (key.second.first != round) + break; CSmartRewardResultEntry nValue; if (pcursor->GetValue(nValue)) { - if( nValue.reward ) payouts.push_back(new CSmartRewardResultEntry(nValue)); + if (nValue.reward) + payouts.push_back(new CSmartRewardResultEntry(nValue)); pcursor->Next(); } else { // Delete everything if something fails - for( auto it : payouts ) delete it; + for (auto it : payouts) + delete it; payouts.clear(); return error("failed to get reward entry"); } @@ -371,25 +371,25 @@ void CSmartRewardEntry::SetNull() fDisqualifyingTx = false; smartnodePaymentTx.SetNull(); fSmartnodePaymentTx = false; - voteProof.SetNull(); - fVoteProven = false; + activationTx.SetNull(); + fActivated = false; } string CSmartRewardEntry::ToString() const { std::stringstream s; - s << strprintf("CSmartRewardEntry(id=%s, balance=%d, balanceEligible=%d, isSmartNode=%b, voteProven=%b)\n", + s << strprintf("CSmartRewardEntry(id=%s, balance=%d, balanceEligible=%d, isSmartNode=%b, activated=%b)\n", GetAddress(), balance, balanceEligible, fSmartnodePaymentTx, - fVoteProven); + fActivated); return s.str(); } bool CSmartRewardEntry::IsEligible() { - return fVoteProven && !fSmartnodePaymentTx && balanceEligible > 0 && !fDisqualifyingTx; + return fActivated && !fSmartnodePaymentTx && balanceEligible > 0 && !fDisqualifyingTx; } string CSmartRewardBlock::ToString() const @@ -406,13 +406,14 @@ void CSmartRewardRound::UpdatePayoutParameter() { nPayeeCount = eligibleEntries - disqualifiedEntries; - if( nPayeeCount > 0 && nBlockPayees > 0){ + if (nPayeeCount > 0 && nBlockPayees > 0) { int64_t nPayoutDelay = Params().GetConsensus().nRewardsPayoutStartDelay; nRewardBlocks = nPayeeCount / nBlockPayees; - if( nPayeeCount % nBlockPayees ) nRewardBlocks += 1; + if (nPayeeCount % nBlockPayees) + nRewardBlocks += 1; - nLastRoundBlock = endBlockHeight + nPayoutDelay + ( (nRewardBlocks - 1) * nBlockInterval ); + nLastRoundBlock = endBlockHeight + nPayoutDelay + ((nRewardBlocks - 1) * nBlockInterval); } } diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index 6a48e401..f68c5ee6 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -183,6 +183,7 @@ class CSmartRewardRound int GetPayeeCount() const { return nPayeeCount; } int GetRewardBlocks() const { return nRewardBlocks; } int GetLastRoundBlock() const { return nLastRoundBlock; } + bool Is_1_3() const { return number >= Params().GetConsensus().nRewardsFirst_1_3_Round; } std::string ToString() const; }; @@ -202,8 +203,8 @@ class CSmartRewardEntry READWRITE(balanceEligible); READWRITE(disqualifyingTx); READWRITE(fDisqualifyingTx); - READWRITE(voteProof); - READWRITE(fVoteProven); + READWRITE(activationTx); + READWRITE(fActivated); READWRITE(smartnodePaymentTx); READWRITE(fSmartnodePaymentTx); } @@ -214,20 +215,20 @@ class CSmartRewardEntry CAmount balanceEligible; uint256 disqualifyingTx; bool fDisqualifyingTx; - uint256 voteProof; - bool fVoteProven; + uint256 activationTx; + bool fActivated; uint256 smartnodePaymentTx; bool fSmartnodePaymentTx; CSmartRewardEntry() : id(CSmartAddress()), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), - voteProof(uint256()), fVoteProven(false), + activationTx(uint256()), fActivated(false), smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} CSmartRewardEntry(const CSmartAddress &address) : id(address), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), - voteProof(uint256()), fVoteProven(false), + activationTx(uint256()), fActivated(false), smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} friend bool operator==(const CSmartRewardEntry& a, const CSmartRewardEntry& b) diff --git a/src/smartvoting/proposal.cpp b/src/smartvoting/proposal.cpp index 546d411b..2cf0762a 100644 --- a/src/smartvoting/proposal.cpp +++ b/src/smartvoting/proposal.cpp @@ -525,8 +525,6 @@ bool CProposal::IsCollateralValid(std::string& strError, int& fMissingConfirmati CScript findDataScript; findDataScript << OP_RETURN << ToByteVector(nExpectedHash); - CScript findHiveScript = SmartHive::Script(SmartHive::ProjectTreasury); - bool fFoundOpReturn = false; bool fFoundFee = false; for (const auto& output : txCollateral.vout) { @@ -539,10 +537,6 @@ bool CProposal::IsCollateralValid(std::string& strError, int& fMissingConfirmati LogPrintf ("CProposal::IsCollateralValid -- %s\n", strError); return false; } - if(output.scriptPubKey == findHiveScript && output.nValue >= nMinFee) { - DBG( std::cout << "IsCollateralValid fFoundFee = true" << std::endl; ); - fFoundFee = true; - } if(output.scriptPubKey == findDataScript && output.nValue == 0) { DBG( std::cout << "IsCollateralValid fFoundOpReturn = true" << std::endl; ); fFoundOpReturn = true; diff --git a/src/validation.cpp b/src/validation.cpp index f7474f8b..40737ed6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2398,9 +2398,6 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd std::map, CAmount> vecInputs; std::map, CAmount> vecOutputs; - CSmartAddress *voteProofCheck = nullptr; - CAmount nVoteProofIn = 0; - int nCurrentRewardsRound = prewards->GetCurrentRound()->number; bool fProcessRewards = !fIsVerifyDB && prewards->ProcessTransaction(pindex, tx, nCurrentRewardsRound); @@ -2439,7 +2436,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd const CTxOut &prevout = coin.out; if( fProcessRewards && !input.scriptSig.IsZerocoinSpend() ){ - prewards->ProcessInput(tx, prevout, &voteProofCheck, nVoteProofIn, nCurrentRewardsRound, smartRewardsResult); + prewards->ProcessInput(tx, prevout, nCurrentRewardsRound, smartRewardsResult); } if (fAddressIndex || fSpentIndex || fDepositIndex) @@ -2530,7 +2527,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd const CTxOut &out = tx.vout[k]; if( fProcessRewards && !out.scriptPubKey.IsZerocoinMint() ){ - prewards->ProcessOutput(tx, out, voteProofCheck, nVoteProofIn, nCurrentRewardsRound, pindex->nHeight, smartRewardsResult); + prewards->ProcessOutput(tx, out, nCurrentRewardsRound, pindex->nHeight, smartRewardsResult); } if (fAddressIndex || fDepositIndex) { diff --git a/src/validation.h b/src/validation.h index a5f1f063..0761328a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -89,16 +89,16 @@ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB /** Dust Hard Limit, ignored as wallet inputs (mininput default) */ static const int64_t DUST_HARD_LIMIT = 1000; // 0.00001 SMART mininput /** Maximum number of script-checking threads allowed */ -static const int MAX_SCRIPTCHECK_THREADS = 16; +static const int MAX_SCRIPTCHECK_THREADS = 15; // was 16 /** -par default (number of script-checking threads, 0 = auto) */ static const int DEFAULT_SCRIPTCHECK_THREADS = 0; /** Number of blocks that can be requested at any given time from a single peer. */ -static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; +static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 64; //was 16 /** Timeout in seconds during which a peer must stall block download progress before being disconnected. */ -static const unsigned int BLOCK_STALLING_TIMEOUT = 2; +static const unsigned int BLOCK_STALLING_TIMEOUT = 1; //was 2 /** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ -static const unsigned int MAX_HEADERS_RESULTS = 2000; +static const unsigned int MAX_HEADERS_RESULTS = 2000; //was 2000 /** Maximum depth of blocks we're willing to serve as compact blocks to peers * when requested. For older blocks, a regular BLOCK response will be sent. */ static const int MAX_CMPCTBLOCK_DEPTH = 5; @@ -239,7 +239,8 @@ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; // full block file chunks, we need the high water mark which triggers the prune to be // one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB // Setting the target to > than 1414MB will make it likely we can respect the target. -static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 1414 * 1024 * 1024; +// x2 for 8MB blocks = 2818 +static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 2818 * 1024 * 1024; /** * Process an incoming block. This only returns after the best known valid diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 321e54e5..5ed5a66c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -461,28 +461,6 @@ bool CWallet::UpdateVotingKeyRegistration(const CKeyID &keyId) { return CWalletDB(strWalletFile).UpdateVotingKeyRegistration(keyId, mapVotingKeyRegistrations[keyId]); } -bool CWallet::LoadVotedMap(const CKeyID &keyId, const std::map &mapVoted) { - AssertLockHeld(cs_wallet); - this->mapVoted[keyId] = mapVoted; - return true; -} - -bool CWallet::UpdateVotedMap(const CKeyID &keyId) { - AssertLockHeld(cs_wallet); - return CWalletDB(strWalletFile).UpdateVotedMap(keyId, mapVoted[keyId]); -} - -bool CWallet::LoadVoteProofs(const CKeyID &keyId, const std::map &mapVoteProofs) { - AssertLockHeld(cs_wallet); - this->mapVoteProofs[keyId] = mapVoteProofs; - return true; -} - -bool CWallet::UpdateVoteProofs(const CKeyID &keyId) { - AssertLockHeld(cs_wallet); - return CWalletDB(strWalletFile).UpdateVoteProofs(keyId, mapVoteProofs[keyId]); -} - bool CWallet::LoadCryptedVotingKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedVotingKey(vchPubKey, vchCryptedSecret); } @@ -2991,10 +2969,6 @@ bool CWallet::GetProposalFeeTX(CWalletTx& tx, const CSmartAddress& fromAddress, vector< CRecipient > vecSend; vecSend.push_back(dataRecipient); - CScript hiveScript = SmartHive::Script(SmartHive::ProjectTreasury); - CRecipient hiveRecipient = {hiveScript, nAmount, false}; - vecSend.push_back(hiveRecipient); - CCoinControl coinControl; coinControl.destChange = fromAddress.Get(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index ee231d96..c9746227 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -675,10 +675,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map mapVotingKeyMetadata; std::map mapVotingKeyRegistrations; - /* SmartRewards Vote proof */ - std::map> mapVoted; - std::map> mapVoteProofs; - typedef std::map MasterKeyMap; MasterKeyMap mapMasterKeys; unsigned int nMasterKeyMaxID; @@ -840,14 +836,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool LoadVotingKeyRegistration(const CKeyID &keyId, const uint256 &txhash); //! Update votekeys registrations bool UpdateVotingKeyRegistration(const CKeyID &keyId); - //! Load voted rounds per address (used by LoadWallet) - bool LoadVotedMap(const CKeyID &keyId, const std::map &mapVoted); - //! Update voted round per address - bool UpdateVotedMap(const CKeyID &keyId); - //! Load vote proofs per address (used by LoadWallet) - bool LoadVoteProofs(const CKeyID &keyId, const std::map &mapVoteProofs); - //! Update vote proofs per address - bool UpdateVoteProofs(const CKeyID &keyId); //! Adds an encrypted key to the store, and saves it to disk. bool AddCryptedVotingKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 10b63cdd..fa2d659a 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -135,20 +135,6 @@ bool CWalletDB::UpdateVotingKeyRegistration(const CKeyID& keyId, const uint256& txHash, true); } -bool CWalletDB::UpdateVotedMap(const CKeyID& keyId, const std::map& mapVoted) -{ - nWalletDBUpdated++; - return Write(std::make_pair(std::string("vmap"), keyId), - mapVoted, true); -} - -bool CWalletDB::UpdateVoteProofs(const CKeyID& keyId, const std::map& mapVoteProofs) -{ - nWalletDBUpdated++; - return Write(std::make_pair(std::string("vproofs"), keyId), - mapVoteProofs, true); -} - bool CWalletDB::WriteVotingKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CVotingKeyMetadata& keyMeta) { nWalletDBUpdated++; @@ -748,26 +734,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, pwallet->LoadVotingKeyRegistration(keyId, txHash); } - else if (strType == "vmap") - { - CKeyID keyId; - ssKey >> keyId; - std::map mapVoted; - ssValue >> mapVoted; - wss.nMapVoted++; - - pwallet->LoadVotedMap(keyId, mapVoted); - } - else if (strType == "vproofs") - { - CKeyID keyId; - ssKey >> keyId; - std::map mapVoteProofs; - ssValue >> mapVoteProofs; - wss.nMapVoteProofs++; - - pwallet->LoadVoteProofs(keyId, mapVoteProofs); - } else if (strType == "defaultkey") { ssValue >> pwallet->vchDefaultKey; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 2e5348c6..91f2aa38 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -166,8 +166,6 @@ class CWalletDB : public CDB bool WriteVotingMasterKey(unsigned int nID, const CMasterKey& kMasterKey); bool UpdateVotingKeyMeta(const CKeyID& keyId, const CVotingKeyMetadata& keyMeta); bool UpdateVotingKeyRegistration(const CKeyID& keyId, const uint256& txHash); - bool UpdateVotedMap(const CKeyID& keyId, const std::map& mapVoted); - bool UpdateVoteProofs(const CKeyID& keyId, const std::map& mapVoteProofs); bool WriteCScript(const uint160& hash, const CScript& redeemScript); From 4e29eb2f8c7c2a6237bf9c7df9723ec42bdb98a8 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Tue, 16 Jun 2020 23:33:08 +0200 Subject: [PATCH 096/126] Update SmartHive payments --- src/smarthive/hive.cpp | 20 ++++---------------- src/smarthive/hive.h | 5 +---- src/smarthive/hivepayments.cpp | 13 +++++-------- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/smarthive/hive.cpp b/src/smarthive/hive.cpp index 8e6a5968..5264ee0a 100644 --- a/src/smarthive/hive.cpp +++ b/src/smarthive/hive.cpp @@ -25,13 +25,10 @@ void SmartHive::Init() { SmartHive::Web_Legacy, new CSmartAddress("Sgq5c4Rznibagv1aopAfPA81jac392scvm") }, { SmartHive::Quality_Legacy, new CSmartAddress("Sc61Gc2wivtuGd6recqVDqv4R38TcHqFS8") }, - { SmartHive::ProjectTreasury, new CSmartAddress("TBD") }, { SmartHive::Support, new CSmartAddress("TBD") }, { SmartHive::Development, new CSmartAddress("TBD") }, { SmartHive::Outreach, new CSmartAddress("TBD") }, - { SmartHive::WebMobileSmartCard, new CSmartAddress("TBD") }, - { SmartHive::Exchanges, new CSmartAddress("TBD") }, - { SmartHive::Merchants, new CSmartAddress("TBD") } + { SmartHive::SmartHub, new CSmartAddress("TBD") }, }; addressesTestnet = { @@ -44,13 +41,10 @@ void SmartHive::Init() { SmartHive::Web_Legacy, new CSmartAddress("TBWBQ1rCXm16huegLWvSz5TCs5KzfoYaNB") }, { SmartHive::Quality_Legacy, new CSmartAddress("TVuTV7d5vBKyfg5j45RnnYgdo9G3ET2t2f") }, - { SmartHive::ProjectTreasury, new CSmartAddress("6HaFiyiFN3SvcXQkE9TrkVvRX2bC4fxhi4") }, { SmartHive::Support, new CSmartAddress("6Tr3PdsFSm3DfN2b8vQ4Eqo7LzvZ238yXt") }, { SmartHive::Development, new CSmartAddress("6VE4Qzox3pEXtPLYhroepY9oiMS8YAgmJ9") }, { SmartHive::Outreach, new CSmartAddress("6WNuCbGoM9ZeMYdW7uXwxNV7u4mgmBKmVY") }, - { SmartHive::WebMobileSmartCard, new CSmartAddress("6bF1bs7A9eth2zuZqNQmCGB2jeap7fZnUE") }, - { SmartHive::Exchanges, new CSmartAddress("6dBFiy4HLZF81Df2FwwcjYjXWWoP3Vqm2b") }, - { SmartHive::Merchants, new CSmartAddress("6HKbGxK7RSoyrpoJj7CCLJ1s56E9B7QNJn") } + { SmartHive::SmartHub, new CSmartAddress("6bF1bs7A9eth2zuZqNQmCGB2jeap7fZnUE") }, }; scriptsMainnet = { @@ -63,13 +57,10 @@ void SmartHive::Init() { SmartHive::Web_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Web_Legacy)->GetScript())) }, // New hive 2 { SmartHive::Quality_Legacy, new CScript(std::move(addressesMainnet.at(SmartHive::Quality_Legacy)->GetScript())) }, // New hive 3 - { SmartHive::ProjectTreasury, new CScript(std::move(addressesMainnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasury multisig { SmartHive::Support, new CScript(std::move(addressesMainnet.at(SmartHive::Support)->GetScript())) }, // Support hive multisig { SmartHive::Development, new CScript(std::move(addressesMainnet.at(SmartHive::Development)->GetScript())) }, // Development hive multisig { SmartHive::Outreach, new CScript(std::move(addressesMainnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive multisig - { SmartHive::WebMobileSmartCard, new CScript(std::move(addressesMainnet.at(SmartHive::WebMobileSmartCard)->GetScript())) }, // Outreach hive multisig - { SmartHive::Exchanges, new CScript(std::move(addressesMainnet.at(SmartHive::Exchanges)->GetScript())) }, // Exchange funds multisig - { SmartHive::Merchants, new CScript(std::move(addressesMainnet.at(SmartHive::Merchants)->GetScript())) }, // Merchant funds multisig + { SmartHive::SmartHub, new CScript(std::move(addressesMainnet.at(SmartHive::SmartHub)->GetScript())) }, // Outreach hive multisig }; scriptsTestnet = { @@ -82,13 +73,10 @@ void SmartHive::Init() { SmartHive::Web_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Web_Legacy)->GetScript())) }, // New hive 2 { SmartHive::Quality_Legacy, new CScript(std::move(addressesTestnet.at(SmartHive::Quality_Legacy)->GetScript())) }, // New hive 3 - { SmartHive::ProjectTreasury, new CScript(std::move(addressesTestnet.at(SmartHive::ProjectTreasury)->GetScript())) }, // SmartHive treasury multisig { SmartHive::Support, new CScript(std::move(addressesTestnet.at(SmartHive::Support)->GetScript())) }, // Support hive multisig { SmartHive::Development, new CScript(std::move(addressesTestnet.at(SmartHive::Development)->GetScript())) }, // Development hive multisig { SmartHive::Outreach, new CScript(std::move(addressesTestnet.at(SmartHive::Outreach)->GetScript())) }, // Outreach hive multisig - { SmartHive::WebMobileSmartCard, new CScript(std::move(addressesTestnet.at(SmartHive::WebMobileSmartCard)->GetScript())) }, // Outreach hive multisig - { SmartHive::Exchanges, new CScript(std::move(addressesTestnet.at(SmartHive::Exchanges)->GetScript())) }, // Exchange funds multisig - { SmartHive::Merchants, new CScript(std::move(addressesTestnet.at(SmartHive::Merchants)->GetScript())) }, // Merchant funds multisig + { SmartHive::SmartHub, new CScript(std::move(addressesTestnet.at(SmartHive::SmartHub)->GetScript())) }, // Outreach hive multisig }; init = true; diff --git a/src/smarthive/hive.h b/src/smarthive/hive.h index 73807b7d..904410b4 100644 --- a/src/smarthive/hive.h +++ b/src/smarthive/hive.h @@ -56,10 +56,7 @@ namespace SmartHive{ Development, Outreach, Support, - ProjectTreasury, - WebMobileSmartCard, - Exchanges, - Merchants + SmartHub, }; const CScript* ScriptPtr(SmartHive::Payee payee); diff --git a/src/smarthive/hivepayments.cpp b/src/smarthive/hivepayments.cpp index e8fc25e9..6332e8d1 100644 --- a/src/smarthive/hivepayments.cpp +++ b/src/smarthive/hivepayments.cpp @@ -79,16 +79,13 @@ void SmartHivePayments::Init() ); hiveSplit_1_3 = new CSmartHiveBatchSplit( - 55, // Split 55% of the block reward as followed. + 29, // Split 29% of the block reward as followed. nPayoutInterval_1_3, // Trigger the payouts every n blocks { - new CSmartHiveClassic(SmartHive::Exchanges, 0.05), - new CSmartHiveClassic(SmartHive::Merchants, 0.05), - new CSmartHiveClassic(SmartHive::Outreach, 0.0625), - new CSmartHiveClassic(SmartHive::Support, 0.0625), - new CSmartHiveClassic(SmartHive::Development, 0.0625), - new CSmartHiveClassic(SmartHive::WebMobileSmartCard, 0.0625), - new CSmartHiveClassic(SmartHive::ProjectTreasury, 0.2), + new CSmartHiveClassic(SmartHive::Outreach, 0.0075), + new CSmartHiveClassic(SmartHive::Support, 0.0725), + new CSmartHiveClassic(SmartHive::Development, 0.0725), + new CSmartHiveClassic(SmartHive::SmartHub, 0.0725), } ); From 13794d4cff78b32f043698895eb5039cefd0307d Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Tue, 16 Jun 2020 23:31:16 +0200 Subject: [PATCH 097/126] Update mining rewards --- src/smartmining/miningpayments.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smartmining/miningpayments.cpp b/src/smartmining/miningpayments.cpp index dce135c4..2940d628 100644 --- a/src/smartmining/miningpayments.cpp +++ b/src/smartmining/miningpayments.cpp @@ -220,7 +220,7 @@ static bool CheckSignature(const CBlock &block, const CBlockIndex *pindex) CAmount GetMiningReward(CBlockIndex * pindex, CAmount blockReward) { - return blockReward / 20; // 5% + return blockReward / 100; // 1% } void SmartMining::FillPayment(CMutableTransaction& coinbaseTx, int nHeight, CBlockIndex * pindexPrev, CAmount blockReward, CTxOut &outSignature, const CSmartAddress &signingAddress) From 9ae107d7455d4662a0b59e614e2b73954641a03d Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Tue, 16 Jun 2020 23:24:26 +0200 Subject: [PATCH 098/126] Fix typo in command-line parameters help --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 6fe72a82..17adb28e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -613,7 +613,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sapithreads=",_("Set the number of threads for SAPI requests (default: 4)")); strUsage += HelpMessageOpt("-sapiworkqueue=",_("Set the queue for SAPI requests (default: 16)")); strUsage += HelpMessageOpt("-sapiservertimeout=",_("Set the seconds before SAPI timeout (default: 30)")); - strUsage += HelpMessageOpt("-sapiwhitelist:",_("Whitelist ip for SAPI")); + strUsage += HelpMessageOpt("-sapiwhitelist=",_("Whitelist ip for SAPI")); return strUsage; } From 57956af2e091652506b3943712d8ef18b40a4a2e Mon Sep 17 00:00:00 2001 From: Solarminer Date: Mon, 30 Dec 2019 01:57:59 -0600 Subject: [PATCH 099/126] Update Block Disk Space --- src/validation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation.h b/src/validation.h index 0761328a..73956823 100644 --- a/src/validation.h +++ b/src/validation.h @@ -239,8 +239,8 @@ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; // full block file chunks, we need the high water mark which triggers the prune to be // one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB // Setting the target to > than 1414MB will make it likely we can respect the target. -// x2 for 8MB blocks = 2818 -static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 2818 * 1024 * 1024; +// x2 for 8MB blocks = 2818 - Assume blocks will be half full over 288 blocks. +static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 1414 * 1024 * 1024; /** * Process an incoming block. This only returns after the best known valid From f6bbed10f43f631b708ecbf24c2a1d32f141fc00 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Mon, 30 Dec 2019 16:07:37 -0600 Subject: [PATCH 100/126] Fix payment allocation --- src/qt/locale/bitcoin_en.ts | 2 +- src/smarthive/hivepayments.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 454d602f..f24e4c4f 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -4427,7 +4427,7 @@ p, li { white-space: pre-wrap; } - Initialize SmartRewards... + Initializing SmartRewards... diff --git a/src/smarthive/hivepayments.cpp b/src/smarthive/hivepayments.cpp index 6332e8d1..f2dd0372 100644 --- a/src/smarthive/hivepayments.cpp +++ b/src/smarthive/hivepayments.cpp @@ -82,7 +82,7 @@ void SmartHivePayments::Init() 29, // Split 29% of the block reward as followed. nPayoutInterval_1_3, // Trigger the payouts every n blocks { - new CSmartHiveClassic(SmartHive::Outreach, 0.0075), + new CSmartHiveClassic(SmartHive::Outreach, 0.0725), new CSmartHiveClassic(SmartHive::Support, 0.0725), new CSmartHiveClassic(SmartHive::Development, 0.0725), new CSmartHiveClassic(SmartHive::SmartHub, 0.0725), From bcd554e7c3ea20be6abbe71ab7b9dfa3e82eee3b Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Mon, 30 Dec 2019 16:36:02 -0600 Subject: [PATCH 101/126] Text Update --- src/qt/forms/smartrewardslist.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/forms/smartrewardslist.ui b/src/qt/forms/smartrewardslist.ui index a6f07a66..4cfab0d1 100644 --- a/src/qt/forms/smartrewardslist.ui +++ b/src/qt/forms/smartrewardslist.ui @@ -59,7 +59,7 @@ - Initialize SmartRewards... + Initializing SmartRewards... Qt::AlignCenter From fb3a31595fcf56de1af2cdbc5e68d68cb5dbd1ec Mon Sep 17 00:00:00 2001 From: Solarminer Date: Mon, 30 Dec 2019 23:29:38 -0600 Subject: [PATCH 102/126] Timelock --- src/qt/forms/sendcoinsdialog.ui | 32 ++++++++++++++------------------ src/qt/sendcoinsdialog.cpp | 6 +++--- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 1cdd9e69..53c855ac 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -684,24 +684,18 @@ true - + - - - - 0 - 0 - - + - Clear all fields of the form. + Send to multiple recipients at once - Clear &All + Add &Recipient - :/icons/remove:/icons/remove + :/icons/add:/icons/add false @@ -709,16 +703,18 @@ - + + + + 0 + 0 + + - Send to multiple recipients at once + Lock a transaction to be spent at future time. - Add &Recipient - - - - :/icons/add:/icons/add + &TimeLock false diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 5c40752d..c329d545 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -434,9 +434,9 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) } } QWidget::setTabOrder(prev, ui->sendButton); - QWidget::setTabOrder(ui->sendButton, ui->clearButton); - QWidget::setTabOrder(ui->clearButton, ui->addButton); - return ui->addButton; + QWidget::setTabOrder(ui->sendButton, ui->addButton); + QWidget::setTabOrder(ui->addButton, ui->clearButton); + return ui->clearButton; } void SendCoinsDialog::setAddress(const QString &address) From b8a842349102bd43dd63925646e80ab1c743e9f9 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Tue, 31 Dec 2019 00:37:07 -0600 Subject: [PATCH 103/126] Miningreward change block --- src/smartmining/miningpayments.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/smartmining/miningpayments.cpp b/src/smartmining/miningpayments.cpp index 2940d628..8a91bb64 100644 --- a/src/smartmining/miningpayments.cpp +++ b/src/smartmining/miningpayments.cpp @@ -220,7 +220,12 @@ static bool CheckSignature(const CBlock &block, const CBlockIndex *pindex) CAmount GetMiningReward(CBlockIndex * pindex, CAmount blockReward) { + if( pindex->nHeight < HF_V1_3_HEIGHT ){ + return blockReward / 20; // 5% + } + else { return blockReward / 100; // 1% + } } void SmartMining::FillPayment(CMutableTransaction& coinbaseTx, int nHeight, CBlockIndex * pindexPrev, CAmount blockReward, CTxOut &outSignature, const CSmartAddress &signingAddress) From 0f492ffdcb380393f8dc5606104e5fa31eac9a04 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Thu, 23 Jan 2020 23:25:51 +0100 Subject: [PATCH 104/126] Upgrade ZeroMQ dependency to version 4.3.1 --- depends/packages/zeromq.mk | 24 +++++++++---- .../0001-fix-build-with-older-mingw64.patch | 30 ++++++++++++++++ .../0002-disable-pthread_set_name_np.patch | 35 +++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch create mode 100644 depends/patches/zeromq/0002-disable-pthread_set_name_np.patch diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index f8901f72..6f35ede2 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,21 +1,32 @@ package=zeromq -$(package)_version=4.1.4 -$(package)_download_path=http://download.zeromq.org +$(package)_version=4.3.1 +$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=e99f44fde25c2e4cb84ce440f87ca7d3fe3271c2b8cfbc67d55e4de25e6fe378 +$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb +$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars - $(package)_config_opts=--without-documentation --disable-shared --without-libsodium + $(package)_config_opts=--without-docs --disable-shared --disable-curve --disable-curve-keygen --disable-perf + $(package)_config_opts += --without-libsodium --without-libgssapi_krb5 --without-pgm --without-norm --without-vmci + $(package)_config_opts += --disable-libunwind --disable-radix-tree --without-gcov --disable-dependency-tracking + $(package)_config_opts += --disable-Werror --disable-drafts --enable-option-checking $(package)_config_opts_linux=--with-pic + $(package)_config_opts_android=--with-pic $(package)_cxxflags=-std=c++11 endef +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/0001-fix-build-with-older-mingw64.patch && \ + patch -p1 < $($(package)_patch_dir)/0002-disable-pthread_set_name_np.patch && \ + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub config +endef + define $(package)_config_cmds $($(package)_autoconf) endef define $(package)_build_cmds - $(MAKE) libzmq.la + $(MAKE) src/libzmq.la endef define $(package)_stage_cmds @@ -23,5 +34,6 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds - rm -rf bin share + sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \ + rm -rf bin share lib/*.la endef diff --git a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch new file mode 100644 index 00000000..b911ac56 --- /dev/null +++ b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch @@ -0,0 +1,30 @@ +From f6866b0f166ad168618aae64c7fbee8775d3eb23 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:44:58 -0400 +Subject: [PATCH] fix build with older mingw64 + +--- + src/windows.hpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/windows.hpp b/src/windows.hpp +index 6c3839fd..2c32ec79 100644 +--- a/src/windows.hpp ++++ b/src/windows.hpp +@@ -58,6 +58,13 @@ + #include + #include + #include ++ ++#if defined __MINGW64_VERSION_MAJOR && __MINGW64_VERSION_MAJOR < 4 ++// Workaround for mingw-w64 < v4.0 which did not include ws2ipdef.h in iphlpapi.h. ++// Fixed in mingw-w64 by 9bd8fe9148924840d315b4c915dd099955ea89d1. ++#include ++#include ++#endif + #include + + #if !defined __MINGW32__ +-- +2.17.1 + diff --git a/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch new file mode 100644 index 00000000..b1c6f78a --- /dev/null +++ b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch @@ -0,0 +1,35 @@ +From c9bbdd6581d07acfe8971e4bcebe278a3676cf03 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:57:18 -0400 +Subject: [PATCH] disable pthread_set_name_np + +pthread_set_name_np adds a Glibc requirement on >= 2.12. +--- + src/thread.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/thread.cpp b/src/thread.cpp +index a1086b0c..9943f354 100644 +--- a/src/thread.cpp ++++ b/src/thread.cpp +@@ -308,7 +308,7 @@ void zmq::thread_t::setThreadName (const char *name_) + */ + if (!name_) + return; +- ++#if 0 + #if defined(ZMQ_HAVE_PTHREAD_SETNAME_1) + int rc = pthread_setname_np (name_); + if (rc) +@@ -324,6 +324,8 @@ void zmq::thread_t::setThreadName (const char *name_) + #elif defined(ZMQ_HAVE_PTHREAD_SET_NAME) + pthread_set_name_np (_descriptor, name_); + #endif ++#endif ++ return; + } + + #endif +-- +2.17.1 + From b9b5440fa73685c8ca7ef6f4cffb7b8524adb3b4 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Tue, 11 Feb 2020 12:26:59 +0100 Subject: [PATCH 105/126] Add SAPI endpoint to create raw transaction --- src/sapi/sapi.h | 36 ++++++++++++++++ src/sapi/sapi_transaction.cpp | 79 +++++++++++++++++++++++++++++++++++ src/sapi/sapi_validation.cpp | 77 +++++++++++++++++++++++++++++++++- 3 files changed, 190 insertions(+), 2 deletions(-) diff --git a/src/sapi/sapi.h b/src/sapi/sapi.h index 58bbbf78..e1cc3d6c 100644 --- a/src/sapi/sapi.h +++ b/src/sapi/sapi.h @@ -73,6 +73,9 @@ enum Codes{ TxAlreadyInBlockchain, TxCantRelay, TxNotFound, + TxMissingTxId, + TxMissingVout, + TxInvalidParameter, /* smartreward errors */ RewardsDatabaseBusy = 6000, NoActiveRewardRound, @@ -96,6 +99,9 @@ namespace Keys{ const std::string maxInputs = "maxInputs"; const std::string height = "height"; const std::string hash = "hash"; + const std::string inputs = "inputs"; + const std::string outputs = "outputs"; + const std::string locktime = "locktime"; } namespace Validation{ @@ -189,6 +195,36 @@ namespace Validation{ SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const final; }; + class Array : public Base{ + public: + Array() : Base(UniValue::VARR) {} + SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const override; + }; + + class Object : public Base{ + public: + Object() : Base(UniValue::VOBJ) {} + SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const override; + }; + + class Outputs : public Object{ + public: + Outputs() : Object() {} + SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const final; + }; + + class Transaction : public Object{ + public: + Transaction() : Object() {} + SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const final; + }; + + class Transactions : public Array{ + public: + Transactions() : Array() {} + SAPI::Result Validate(const std::string ¶meter, const UniValue &value) const final; + }; + std::string ResultMessage(SAPI::Codes value); } diff --git a/src/sapi/sapi_transaction.cpp b/src/sapi/sapi_transaction.cpp index 2dc017b5..f757e73d 100644 --- a/src/sapi/sapi_transaction.cpp +++ b/src/sapi/sapi_transaction.cpp @@ -14,6 +14,7 @@ extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool static bool transaction_send(HTTPRequest* req, const std::map &mapPathParams, const UniValue &bodyParameter); static bool transaction_check(HTTPRequest* req, const std::map &mapPathParams, const UniValue &bodyParameter); +static bool transaction_create(HTTPRequest* req, const std::map &mapPathParams, const UniValue &bodyParameter); SAPI::EndpointGroup transactionEndpoints = { "transaction", @@ -31,6 +32,14 @@ SAPI::EndpointGroup transactionEndpoints = { SAPI::BodyParameter(SAPI::Keys::instantpay, new SAPI::Validation::Bool(), true), SAPI::BodyParameter(SAPI::Keys::overridefees, new SAPI::Validation::Bool(), true) } + }, + { + "create", HTTPRequest::POST, UniValue::VOBJ, transaction_create, + { + SAPI::BodyParameter(SAPI::Keys::inputs, new SAPI::Validation::Transactions()), + SAPI::BodyParameter(SAPI::Keys::outputs, new SAPI::Validation::Outputs()), + SAPI::BodyParameter(SAPI::Keys::locktime, new SAPI::Validation::UInt(), true), + } } } }; @@ -196,3 +205,73 @@ static bool transaction_send(HTTPRequest* req, const std::map &mapPathParams, const UniValue &bodyParameter) +{ + UniValue inputs = bodyParameter[SAPI::Keys::inputs].get_array(); + UniValue sendTo = bodyParameter[SAPI::Keys::outputs].get_obj(); + CMutableTransaction rawTx; + + if (bodyParameter.exists(SAPI::Keys::locktime)) { + rawTx.nLockTime = bodyParameter[SAPI::Keys::locktime].get_int64(); + } + + for (unsigned int idx = 0; idx < inputs.size(); idx++) { + const UniValue& input = inputs[idx]; + const UniValue& o = input.get_obj(); + + uint256 txid = ParseHashO(o, "txid"); + + const UniValue& vout_v = find_value(o, "vout"); + if (!vout_v.isNum()) + return SAPI::Error(req, SAPI::TxMissingVout, "Invalid parameter, missing vout key"); + int nOutput = vout_v.get_int(); + if (nOutput < 0) + return SAPI::Error(req, SAPI::TxInvalidParameter, "Invalid parameter, vout must be positive"); + + uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits::max() - 1 : std::numeric_limits::max()); + + // set the sequence number if passed in the parameters object + const UniValue& sequenceObj = find_value(o, "sequence"); + if (sequenceObj.isNum()) { + int64_t seqNr64 = sequenceObj.get_int64(); + if (seqNr64 < 0 || seqNr64 > std::numeric_limits::max()) + return SAPI::Error(req, SAPI::TxInvalidParameter, "Invalid parameter, sequence number is out of range"); + else + nSequence = (uint32_t)seqNr64; + } + + CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); + rawTx.vin.push_back(in); + } + + set setAddress; + vector addrList = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, addrList) { + if (name_ == "data") { + std::vector data = ParseHexV(sendTo[name_].getValStr(),"Data"); + + CTxOut out(0, CScript() << OP_RETURN << data); + rawTx.vout.push_back(out); + } else { + CBitcoinAddress address(name_); + if (!address.IsValid()) + return SAPI::Error(req, SAPI::TxInvalidParameter, string("Invalid SmartCash address: ") + name_); + + if (setAddress.count(address)) + return SAPI::Error(req, SAPI::TxInvalidParameter, string("Invalid parameter, duplicated address: ") + name_); + setAddress.insert(address); + + CScript scriptPubKey = GetScriptForDestination(address.Get()); + CAmount nAmount = AmountFromValue(sendTo[name_]); + + CTxOut out(nAmount, scriptPubKey); + rawTx.vout.push_back(out); + } + } + + UniValue result(UniValue::VOBJ); + result.pushKV("hex", EncodeHexTx(rawTx)); + SAPI::WriteReply(req, result); + + return true; +} diff --git a/src/sapi/sapi_validation.cpp b/src/sapi/sapi_validation.cpp index 5fac6b24..76593f54 100644 --- a/src/sapi/sapi_validation.cpp +++ b/src/sapi/sapi_validation.cpp @@ -230,6 +230,75 @@ SAPI::Result SAPI::Validation::AmountRange::Validate(const string ¶meter, co return SAPI::Result(code, message); } +SAPI::Result SAPI::Validation::Array::Validate(const std::string ¶meter, const UniValue &value) const +{ + SAPI::Codes code = SAPI::Valid; + return SAPI::Result(code, ResultMessage(code)); +} + +SAPI::Result SAPI::Validation::Object::Validate(const std::string ¶meter, const UniValue &value) const +{ + SAPI::Codes code = SAPI::Valid; + return SAPI::Result(code, ResultMessage(code)); +} + +SAPI::Result SAPI::Validation::Outputs::Validate(const std::string ¶meter, const UniValue &value) const +{ + SAPI::Codes code = SAPI::Valid; + SAPI::Result result = Object::Validate(parameter, value); + if( result != SAPI::Valid ) return result; + + const UniValue &object = value.get_obj(); + vector outputList = object.getKeys(); + BOOST_FOREACH(const string& name_, outputList) { + if( name_ == "data" ) { + result = HexString().Validate(parameter, object[name_]); + if( result != SAPI::Valid ) return result; + } else { + result = SmartCashAddress().Validate(parameter, UniValue(name_)); + if( result != SAPI::Valid ) return result; + result = Amount().Validate(parameter, object[name_]); + if( result != SAPI::Valid ) return result; + } + } + + return SAPI::Result(code, ResultMessage(code)); +} + +SAPI::Result SAPI::Validation::Transaction::Validate(const std::string ¶meter, const UniValue &value) const +{ + SAPI::Codes code = SAPI::Valid; + SAPI::Result result = Object::Validate(parameter, value); + if( result != SAPI::Valid ) return result; + + const UniValue &object = value.get_obj(); + if( !object.exists("txid") ){ + code = SAPI::TxMissingTxId; + return SAPI::Result(code, ResultMessage(code)); + } + if( !object.exists("vout") ){ + code = SAPI::TxMissingVout; + return SAPI::Result(code, ResultMessage(code)); + } + + return SAPI::Result(code, ResultMessage(code)); +} + +SAPI::Result SAPI::Validation::Transactions::Validate(const std::string ¶meter, const UniValue &value) const +{ + SAPI::Codes code = SAPI::Valid; + SAPI::Result result = Array::Validate(parameter, value); + if( result != SAPI::Valid ) return result; + + const UniValue &array = value.get_array(); + for (unsigned int i = 0; i < array.size(); i++) { + result = Transaction().Validate(parameter, array[i]); + if( result != SAPI::Valid ) return result; + } + + return SAPI::Result(code, ResultMessage(code)); +} + std::string SAPI::Validation::ResultMessage(SAPI::Codes value) { switch(value){ @@ -255,7 +324,7 @@ std::string SAPI::Validation::ResultMessage(SAPI::Codes value) case DoubleOutOfRange: return "Double value out of the valid range: %8.8f - %8.8f"; case InvalidSmartCashAddress: - return "Invalid SmartCash"; + return "Invalid SmartCash address"; case EmptyString: return "String is empty"; case InvalidHexString: @@ -293,7 +362,7 @@ std::string SAPI::Validation::ResultMessage(SAPI::Codes value) return "No deposits available"; case NoUtxosAvailble: return "No unspent outpouts available"; - /* transaction errors */ + /* transaction errors */ case TxDecodeFailed: return "Transaction decode failed"; case TxNotSpecified: @@ -310,6 +379,10 @@ std::string SAPI::Validation::ResultMessage(SAPI::Codes value) return "Failed to relay transaction"; case TxNotFound: return "Transaction not found"; + case TxMissingTxId: + return "Missing 'txid' field in transaction"; + case TxMissingVout: + return "Missing 'vout' field in transaction"; /* smartreward errors */ case RewardsDatabaseBusy: return "SmartRewards database busy"; From a5d9cbe839f4fb19cf72a93fbf7a1732d7511efd Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Wed, 26 Feb 2020 10:26:21 +0100 Subject: [PATCH 106/126] Add LockTime feature to the send coins dialog --- src/qt/forms/sendcoinsdialog.ui | 25 +++++-- src/qt/sendcoinsdialog.cpp | 110 +++++++++++++++++++++++++--- src/qt/sendcoinsdialog.h | 8 +- src/qt/smartproposaltab.cpp | 2 +- src/qt/specialtransactiondialog.cpp | 2 +- src/qt/walletmodel.cpp | 11 ++- src/qt/walletmodel.h | 3 +- 7 files changed, 138 insertions(+), 23 deletions(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 53c855ac..f46c92e1 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -324,7 +324,7 @@ Qt::ActionsContextMenu - 0.00 BTC + 0.00 SMART Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse @@ -684,7 +684,7 @@ true - + @@ -703,7 +703,7 @@ - + 0 @@ -713,11 +713,22 @@ Lock a transaction to be spent at future time. - - &TimeLock + + + + + + blocks - - false + + + + + + true + + + MMMM d yy hh:mm:ss diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index c329d545..0e8c3e1c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -15,6 +15,7 @@ #include "sendcoinsentry.h" #include "walletmodel.h" +#include "validation.h" #include "base58.h" #include "coincontrol.h" #include "validation.h" // mempool and minRelayTxFee @@ -22,6 +23,7 @@ #include "util.h" #include "txmempool.h" #include "wallet/wallet.h" +#include "chainparams.h" #include #include @@ -29,7 +31,10 @@ #include #include -#define SEND_CONFIRM_DELAY 3 +#define SEND_CONFIRM_DELAY 3 +#define SEND_CONFIRM_DELAY_LOCKTIME 10 +#define ONE_MONTH (30.5 * 24 * 60 * 60) +#define ONE_YEAR (365 * 24 * 60 * 60) SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), @@ -38,17 +43,16 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa model(0), fNewRecipientAllowed(true), fFeeMinimized(true), - platformStyle(platformStyle) + platformStyle(platformStyle), + nLockTime(0) { ui->setupUi(this); if (!platformStyle->getImagesOnButtons()) { ui->addButton->setIcon(QIcon()); - ui->clearButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon()); } else { ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add")); - ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send")); } @@ -57,7 +61,30 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa addEntry(); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + + // Timelock + const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; + ui->timelockCombo->setVisible(true); + timeLockItems.emplace_back("Set LockTime", 0); + timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); + timeLockItems.emplace_back("Custom (until block)", -1); + timeLockItems.emplace_back("Custom (until date)", -1); + for (const auto &i : timeLockItems) { + ui->timelockCombo->addItem(i.first); + } + + ui->timeLockCustomBlocks->setVisible(false); + ui->timeLockCustomBlocks->setRange(1, 1000000); + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); + connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); + connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, + SLOT(timeLockCustomDateChanged(const QDateTime&))); + connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); // Coin Control connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); @@ -222,6 +249,7 @@ void SendCoinsDialog::on_sendButton_clicked() if(entry->validate()) { recipients.append(entry->getValue()); + recipients.last().nLockTime = nLockTime; } else { @@ -306,7 +334,30 @@ void SendCoinsDialog::on_sendButton_clicked() formatted.append(recipientElement); } - QString questionString = tr("Are you sure you want to send?"); + QString questionString; + + if (nLockTime > 0) { + // Figure out unlocking date and time + QDateTime unlockDateTime; + if (nLockTime < LOCKTIME_THRESHOLD) + { + const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; + unlockDateTime = QDateTime::currentDateTime().addSecs(nLockTime * nAvgBlockTime); + } + else + { + unlockDateTime.setMSecsSinceEpoch(nLockTime * 1000); + } + + questionString.append(""); + questionString.append(tr("This is not a normal transaction. ")); + questionString.append(tr("Do not use this to deposit funds to an exchange.")); + questionString.append(tr("Funds sent will not be spendable until approximatively ")); + questionString.append(unlockDateTime.toString("MMMM d yy hh:mm:ss")); + questionString.append("

"); + } + + questionString.append(tr("Are you sure you want to send?")); questionString.append("

%1"); if(txFee > 0) @@ -336,7 +387,10 @@ void SendCoinsDialog::on_sendButton_clicked() .arg(alternativeUnits.join(" " + tr("or") + "
"))); SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), - questionString.arg(formatted.join("
")), SEND_CONFIRM_DELAY, this); + questionString.arg(formatted.join("
")), + nLockTime > 0 ? SEND_CONFIRM_DELAY_LOCKTIME : SEND_CONFIRM_DELAY, + nLockTime > 0 ? QMessageBox::Warning : QMessageBox::Question, + this); confirmationDialog.exec(); QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result(); @@ -356,6 +410,9 @@ void SendCoinsDialog::on_sendButton_clicked() accept(); CoinControlDialog::coinControl->UnSelectAll(); coinControlUpdateLabels(); + ui->timelockCombo->setCurrentIndex(0); + ui->timeLockCustomBlocks->setVisible(false); + ui->timeLockCustomDate->setVisible(false); } fNewRecipientAllowed = true; } @@ -435,8 +492,8 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) } QWidget::setTabOrder(prev, ui->sendButton); QWidget::setTabOrder(ui->sendButton, ui->addButton); - QWidget::setTabOrder(ui->addButton, ui->clearButton); - return ui->clearButton; + QWidget::setTabOrder(ui->addButton, ui->timelockCombo); + return ui->timelockCombo; } void SendCoinsDialog::setAddress(const QString &address) @@ -880,9 +937,40 @@ void SendCoinsDialog::coinControlUpdateLabels() } } +void SendCoinsDialog::timelockComboChanged(int index) +{ + if (timeLockItems[index].first == "Custom (until block)") { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(true); + nLockTime = ui->timeLockCustomBlocks->value(); + } + else if (timeLockItems[index].first == "Custom (until date)") + { + ui->timeLockCustomDate->setVisible(true); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; + } + else + { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; + } +} + +void SendCoinsDialog::timeLockCustomBlocksChanged(int i) +{ + nLockTime = i; +} + +void SendCoinsDialog::timeLockCustomDateChanged(const QDateTime &dt) +{ + nLockTime = dt.toMSecsSinceEpoch() / 1000; +} + SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay, - QWidget *parent) : - QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay) + QMessageBox::Icon icon, QWidget *parent) : + QMessageBox(icon, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay) { setDefaultButton(QMessageBox::Cancel); yesButton = button(QMessageBox::Yes); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index e577d9cc..7fe6639d 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -64,6 +64,8 @@ public Q_SLOTS: bool fNewRecipientAllowed; bool fFeeMinimized; const PlatformStyle *platformStyle; + std::vector> timeLockItems; + int64_t nLockTime; // Process WalletModel::SendCoinsReturn and generate a pair consisting // of a message and message flags for use in Q_EMIT message(). @@ -92,6 +94,9 @@ private Q_SLOTS: void coinControlClipboardPriority(); void coinControlClipboardLowOutput(); void coinControlClipboardChange(); + void timelockComboChanged(int); + void timeLockCustomBlocksChanged(int); + void timeLockCustomDateChanged(const QDateTime&); void setMinimumFee(); void updateFeeSectionControls(); void updateMinFeeLabel(); @@ -110,7 +115,8 @@ class SendConfirmationDialog : public QMessageBox Q_OBJECT public: - SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0); + SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, + QMessageBox::Icon icon = QMessageBox::Question, QWidget *parent = 0); int exec(); private Q_SLOTS: diff --git a/src/qt/smartproposaltab.cpp b/src/qt/smartproposaltab.cpp index b4583229..c6b47421 100644 --- a/src/qt/smartproposaltab.cpp +++ b/src/qt/smartproposaltab.cpp @@ -350,7 +350,7 @@ void SmartProposalTabWidget::publish() questionString.append("

Proposal fee: %1 SMART"); SendConfirmationDialog confirmationDialog(tr("Confirm send proposal fee"), - questionString.arg(CAmountToDouble(SMARTVOTING_PROPOSAL_FEE)), 3, this); + questionString.arg(CAmountToDouble(SMARTVOTING_PROPOSAL_FEE)), 3, QMessageBox::Question, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result(); diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index ee87faee..9001cee7 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -178,7 +178,7 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), nTotalAmount))); SendConfirmationDialog confirmationDialog(tr("Confirm send %1").arg(strType), - questionString, SEND_CONFIRM_DELAY, this); + questionString, SEND_CONFIRM_DELAY, QMessageBox::Question, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ebe07677..ea84e9d2 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -253,7 +253,16 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact setAddress.insert(rcp.address); ++nAddresses; - CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + CScript scriptPubKey; + if (rcp.nLockTime > 0) + { + scriptPubKey = GetLockedScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get(), + rcp.nLockTime); + } + else + { + scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + } CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 6d4d80a3..6f9af55d 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -42,7 +42,7 @@ class SendCoinsRecipient public: explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): - address(addr), label(label), amount(amount), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} + address(addr), label(label), amount(amount), nLockTime(0), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A
address-B
address-C. @@ -57,6 +57,7 @@ class SendCoinsRecipient bool fUseInstantSend; bool fUseNewAddressFormat; CAmount amount; + int64_t nLockTime; // If from a payment request, this is used for storing the memo QString message; From 9a3b59a400460586246d5c754bc3372df5f3b196 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Mon, 27 Apr 2020 21:45:11 +0200 Subject: [PATCH 107/126] Add possibility to create a time-locked address using the 'getnewaddress' RPC command --- src/rpc/client.cpp | 1 + src/wallet/rpcwallet.cpp | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 3874a546..6ef3419c 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -145,6 +145,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddressmempool", 0}, { "getaddresses", 0}, { "getaddresses", 1}, + { "getnewaddress", 1}, { "getrandomkeypair", 0}, { "dumpprivkey", 1}, { "dumpwallet", 1} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bccc80e6..03ce7354 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -110,16 +110,20 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() > 1) + if (fHelp || params.size() > 2) throw runtime_error( - "getnewaddress ( \"account\" )\n" + "getnewaddress ( \"account\" locktime)\n" "\nReturns a new SmartCash address for receiving payments.\n" "If 'account' is specified (DEPRECATED), it is added to the address book \n" "so payments received with the address will be credited to 'account'.\n" "\nArguments:\n" "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" + "2. locktime (numeric, optional, default=0) Locktime. Non-0 value locks the address to be spendable until after a locking period. If locktime is less than 500000000, then it is processed as the block height at which the address becomes spendable. If locktime is greater than 500000000 then it is processed as a UNIX timestamp after which the coins attached to the address can be spent." "\nResult:\n" - "\"smartcashaddress\" (string) The new SmartCash address\n" + "{\n" + " \"address\":\"address\", (string) The new SmartCash address\n" + " \"redeemScript\":\"hex\", (string) The hex encoded redeem script if locktime was set\n" + "}\n" "\nExamples:\n" + HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", "") @@ -132,6 +136,10 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) if (params.size() > 0) strAccount = AccountFromValue(params[0]); + int nLockTime = 0; + if (params.size() > 1) + nLockTime = params[1].get_int(); + if (!pwalletMain->IsLocked(true)) pwalletMain->TopUpKeyPool(); @@ -140,10 +148,21 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) if (!pwalletMain->GetKeyFromPool(newKey, false)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); CKeyID keyID = newKey.GetID(); + UniValue obj(UniValue::VOBJ); - pwalletMain->SetAddressBook(keyID, strAccount, "receive"); + if (nLockTime > 0) { + CScript redeemScript = GetLockedScriptForDestination(keyID, nLockTime); + CScriptID scriptHash(redeemScript); + pwalletMain->AddCScript(redeemScript); + pwalletMain->SetAddressBook(scriptHash, strAccount, "receive"); + obj.push_back(Pair("address", CBitcoinAddress(scriptHash).ToString())); + obj.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } else { + pwalletMain->SetAddressBook(keyID, strAccount, "receive"); + obj.push_back(Pair("address", CBitcoinAddress(keyID).ToString())); + } - return CBitcoinAddress(keyID).ToString(); + return obj; } UniValue getaddress(const UniValue& params, bool fHelp) From 18c24b856ab12996be8b421b049b9910bec8c311 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Mon, 27 Apr 2020 21:48:05 +0200 Subject: [PATCH 108/126] Add creation of time-locked receive addresses from UI --- src/qt/addresstablemodel.cpp | 18 ++++++++- src/qt/addresstablemodel.h | 2 +- src/qt/coincontroldialog.cpp | 46 ++++++++++++++++----- src/qt/editaddressdialog.cpp | 67 ++++++++++++++++++++++++++++++- src/qt/editaddressdialog.h | 5 +++ src/qt/forms/editaddressdialog.ui | 34 ++++++++++++++++ src/qt/forms/sendcoinsdialog.ui | 2 +- 7 files changed, 157 insertions(+), 17 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 9b0033af..a8395e9f 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -351,7 +351,7 @@ void AddressTableModel::updateEntry(const QString &address, priv->updateEntry(address, label, isMine, purpose, status); } -QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address) +QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address, int64_t lockTime) { std::string strLabel = label.toStdString(); std::string strAddress = address.toStdString(); @@ -394,7 +394,21 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con return QString(); } } - strAddress = CBitcoinAddress(newKey.GetID()).ToString(type == ReceiveNew); + + CKeyID keyID = newKey.GetID(); + if(lockTime > 0 ) + { + CScript redeemScript = GetLockedScriptForDestination(keyID, lockTime); + strAddress = CBitcoinAddress(CScriptID(redeemScript)).ToString(type == ReceiveNew); + { + LOCK(wallet->cs_wallet); + wallet->AddCScript(redeemScript); + } + } + else + { + strAddress = CBitcoinAddress(keyID).ToString(type == ReceiveNew); + } } else { diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 34bd4b55..4f35c3cc 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -63,7 +63,7 @@ class AddressTableModel : public QAbstractTableModel /* Add an address to the model. Returns the added address on success, and an empty string otherwise. */ - QString addRow(const QString &type, const QString &label, const QString &address); + QString addRow(const QString &type, const QString &label, const QString &address, int64_t lockTime = 0); /* Look up label for address in address book, if not found return empty string. */ diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index db28f1a1..9435ab49 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -745,6 +745,7 @@ void CoinControlDialog::updateView() int nInputSum = 0; BOOST_FOREACH(const COutput& out, coins.second) { int nInputSize = 0; + int64_t nLockTime = -1; nSum += out.tx->vout[out.i].nValue; nChildren++; @@ -765,10 +766,29 @@ void CoinControlDialog::updateView() if (!treeMode || (!(sAddress == sWalletAddress))) itemOutput->setText(COLUMN_ADDRESS, sAddress); - CPubKey pubkey; - CKeyID *keyid = boost::get(&outputAddress); - if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed()) - nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes) + // Check if output is locked P2PKH, if so then get lock time + if(out.tx->vout[out.i].scriptPubKey.IsPayToScriptHash()) + { + const CScriptID& hash = boost::get(outputAddress); + CScript redeemScript; + if(pwalletMain->GetCScript(hash, redeemScript)) + { + if (redeemScript.IsPayToPublicKeyHashLocked()) + { + int nLockTimeLength = redeemScript[0]; + std::vector lockTimeVch(redeemScript.begin() + 1, + redeemScript.begin() + 1 + nLockTimeLength); + nLockTime = CScriptNum(lockTimeVch, false).getint(); + } + } + } + else + { + CPubKey pubkey; + CKeyID *keyid = boost::get(&outputAddress); + if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed()) + nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes) + } } // label @@ -812,9 +832,13 @@ void CoinControlDialog::updateView() // vout index itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); - bool fOutputLocked = out.nLockTime && ( - ( out.nLockTime < LOCKTIME_THRESHOLD && nCurrentHeight < (int)out.nLockTime ) || - ( out.nLockTime >= LOCKTIME_THRESHOLD && nCurrentTime < out.nLockTime ) ); + if( nLockTime <= 0 ){ + nLockTime = out.nLockTime; + } + + bool fOutputLocked = nLockTime && ( + ( nLockTime < LOCKTIME_THRESHOLD && nCurrentHeight < nLockTime ) || + ( nLockTime >= LOCKTIME_THRESHOLD && nCurrentTime < nLockTime ) ); itemOutput->setData(COLUMN_LOCKED, Qt::UserRole, QVariant(fOutputLocked)); @@ -824,14 +848,14 @@ void CoinControlDialog::updateView() model->lockCoin(outpt); - if( out.nLockTime < LOCKTIME_THRESHOLD ){ - itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until block %1").arg(out.nLockTime)); + if( nLockTime < LOCKTIME_THRESHOLD ){ + itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until block %1").arg(nLockTime)); }else{ QDateTime timestamp; - timestamp.setTime_t(out.nLockTime); + timestamp.setTime_t(nLockTime); itemOutput->setText(COLUMN_ADDRESS, QString("Output locked until %1").arg(timestamp.toString(Qt::SystemLocaleShortDate))); } - }else if( out.nLockTime ){ + }else if( nLockTime ){ model->unlockCoin(outpt); } diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 118fcbdf..cafe14ac 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -7,16 +7,22 @@ #include "addresstablemodel.h" #include "guiutil.h" +#include "validation.h" +#include "chainparams.h" #include #include +#define ONE_MONTH (30.5 * 24 * 60 * 60) +#define ONE_YEAR (365 * 24 * 60 * 60) + EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), mapper(0), mode(mode), - model(0) + model(0), + nLockTime(0) { ui->setupUi(this); @@ -42,6 +48,30 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); + + // Timelock + const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; + ui->timelockCombo->setVisible(true); + timeLockItems.emplace_back("Set LockTime", 0); + timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); + timeLockItems.emplace_back("Custom (until block)", -1); + timeLockItems.emplace_back("Custom (until date)", -1); + for (const auto &i : timeLockItems) { + ui->timelockCombo->addItem(i.first); + } + + ui->timeLockCustomBlocks->setVisible(false); + ui->timeLockCustomBlocks->setRange(1, 1000000); + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); + connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); + connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, + SLOT(timeLockCustomDateChanged(const QDateTime&))); + connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); } EditAddressDialog::~EditAddressDialog() @@ -77,7 +107,8 @@ bool EditAddressDialog::saveCurrentRow() address = model->addRow( mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive, ui->labelEdit->text(), - ui->addressEdit->text()); + ui->addressEdit->text(), + nLockTime); break; case EditReceivingAddress: case EditSendingAddress: @@ -142,3 +173,35 @@ void EditAddressDialog::setAddress(const QString &address) this->address = address; ui->addressEdit->setText(address); } + +void EditAddressDialog::timelockComboChanged(int index) +{ + if (timeLockItems[index].first == "Custom (until block)") { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(true); + nLockTime = ui->timeLockCustomBlocks->value(); + } + else if (timeLockItems[index].first == "Custom (until date)") + { + ui->timeLockCustomDate->setVisible(true); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; + } + else + { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; + } +} + +void EditAddressDialog::timeLockCustomBlocksChanged(int i) +{ + nLockTime = i; +} + +void EditAddressDialog::timeLockCustomDateChanged(const QDateTime &dt) +{ + nLockTime = dt.toMSecsSinceEpoch() / 1000; +} + diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index ddb67ece..a1d1e69e 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -42,6 +42,9 @@ class EditAddressDialog : public QDialog public Q_SLOTS: void accept(); + void timelockComboChanged(int); + void timeLockCustomBlocksChanged(int); + void timeLockCustomDateChanged(const QDateTime&); private: bool saveCurrentRow(); @@ -52,6 +55,8 @@ public Q_SLOTS: AddressTableModel *model; QString address; + std::vector> timeLockItems; + int64_t nLockTime; }; #endif // BITCOIN_QT_EDITADDRESSDIALOG_H diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index c1aea363..215a96c6 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -54,6 +54,40 @@ + + + + + + + + 0 + 0 + + + + Create an address whose coins cannot be spent before a predefined locking period. + + + + + + + block height + + + + + + + true + + + MMMM d yy hh:mm:ss + + + + diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index f46c92e1..8020f0e2 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -718,7 +718,7 @@ - blocks + block height From 07b4cb995f6c1f7a28122c072544db93da7a5f87 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Wed, 29 Apr 2020 23:03:09 +0200 Subject: [PATCH 109/126] Enable TimeLock features only when BIP65 supermajority is enforced --- src/qt/editaddressdialog.cpp | 8 ++++++- src/qt/sendcoinsdialog.cpp | 8 ++++++- src/validation.cpp | 7 +----- src/validation.h | 7 ++++++ src/wallet/rpcwallet.cpp | 43 +++++++++++++++++++++++++++--------- 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index cafe14ac..7992ea46 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -51,7 +51,6 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : // Timelock const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; - ui->timelockCombo->setVisible(true); timeLockItems.emplace_back("Set LockTime", 0); timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); @@ -72,6 +71,13 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, SLOT(timeLockCustomDateChanged(const QDateTime&))); connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); + + // Make Timelock feature visible only if supermajority enforced BIP65 + if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, + Params().GetConsensus())) + { + ui->timelockCombo->setVisible(false); + } } EditAddressDialog::~EditAddressDialog() diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0e8c3e1c..1afb68c0 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -64,7 +64,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa // Timelock const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; - ui->timelockCombo->setVisible(true); timeLockItems.emplace_back("Set LockTime", 0); timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); @@ -77,6 +76,13 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa ui->timelockCombo->addItem(i.first); } + // Make Timelock feature visible only if supermajority enforced BIP65 + if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, + Params().GetConsensus())) + { + ui->timelockCombo->setVisible(false); + } + ui->timeLockCustomBlocks->setVisible(false); ui->timeLockCustomBlocks->setRange(1, 1000000); ui->timeLockCustomDate->setVisible(false); diff --git a/src/validation.cpp b/src/validation.cpp index 40737ed6..0cbbaec1 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -121,11 +121,6 @@ struct COrphanTx { }; void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); -/** - * Returns true if there are nRequired or more blocks of minVersion or above - * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. - */ -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); static void CheckBlockIndex(const Consensus::Params& consensusParams); /** Constant stuff for coinbase transactions we create: */ @@ -4036,7 +4031,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha return true; } -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) +bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) { unsigned int nFound = 0; for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) diff --git a/src/validation.h b/src/validation.h index 73956823..bb4dd7c9 100644 --- a/src/validation.h +++ b/src/validation.h @@ -261,6 +261,13 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 1414 * 1024 * 1024; * @return True if state.IsValid() */ bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool* fNewBlock); + +/** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. + */ +bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); + /** * Process incoming block headers. * diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 03ce7354..fc7b0b6e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -110,24 +110,45 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; + bool fBIP65Enabled = IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, + Params().GetConsensus()); + if (fHelp || params.size() > 2) - throw runtime_error( + { + std::string errorMsg = "getnewaddress ( \"account\" locktime)\n" "\nReturns a new SmartCash address for receiving payments.\n" "If 'account' is specified (DEPRECATED), it is added to the address book \n" "so payments received with the address will be credited to 'account'.\n" "\nArguments:\n" - "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" - "2. locktime (numeric, optional, default=0) Locktime. Non-0 value locks the address to be spendable until after a locking period. If locktime is less than 500000000, then it is processed as the block height at which the address becomes spendable. If locktime is greater than 500000000 then it is processed as a UNIX timestamp after which the coins attached to the address can be spent." - "\nResult:\n" - "{\n" - " \"address\":\"address\", (string) The new SmartCash address\n" - " \"redeemScript\":\"hex\", (string) The hex encoded redeem script if locktime was set\n" - "}\n" + "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"; + + if (fBIP65Enabled) + { + errorMsg += + "2. locktime (numeric, optional, default=0) Locktime. Non-0 value locks the address to be spendable until after a locking period. If locktime is less than 500000000, then it is processed as the block height at which the address becomes spendable. If locktime is greater than 500000000 then it is processed as a UNIX timestamp after which the coins attached to the address can be spent." + "\nResult:\n" + "{\n" + " \"address\":\"address\", (string) The new SmartCash address\n" + " \"redeemScript\":\"hex\", (string) The hex encoded redeem script if locktime was set\n" + "}\n"; + } + else + { + errorMsg += + "\nResult:\n" + "{\n" + " \"address\":\"address\", (string) The new SmartCash address\n" + "}\n"; + } + + errorMsg += "\nExamples:\n" + HelpExampleCli("getnewaddress", "") - + HelpExampleRpc("getnewaddress", "") - ); + + HelpExampleRpc("getnewaddress", ""); + + throw runtime_error(errorMsg); + } LOCK2(cs_main, pwalletMain->cs_wallet); @@ -137,7 +158,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp) strAccount = AccountFromValue(params[0]); int nLockTime = 0; - if (params.size() > 1) + if (fBIP65Enabled && (params.size() > 1)) nLockTime = params[1].get_int(); if (!pwalletMain->IsLocked(true)) From f6416e3979b4a5dffc48d9bebad5c9269f8998b7 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 3 May 2020 00:32:12 +0200 Subject: [PATCH 110/126] Add UI elements to generate time-locked payment requests --- src/qt/forms/receivecoinsdialog.ui | 30 +++++++++++++ src/qt/receivecoinsdialog.cpp | 70 +++++++++++++++++++++++++++++- src/qt/receivecoinsdialog.h | 5 +++ 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index fd289408..9b9d8410 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -169,6 +169,36 @@ + + + + + 0 + 0 + + + + Lock a transaction to be spent at future time. + + + + + + + block height + + + + + + + true + + + MMMM d yy hh:mm:ss + + + diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 72615f44..8409e529 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -14,6 +14,7 @@ #include "receiverequestdialog.h" #include "recentrequeststablemodel.h" #include "walletmodel.h" +#include "validation.h" #include #include @@ -22,12 +23,16 @@ #include #include +#define ONE_MONTH (30.5 * 24 * 60 * 60) +#define ONE_YEAR (365 * 24 * 60 * 60) + ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), columnResizingFixer(0), model(0), - platformStyle(platformStyle) + platformStyle(platformStyle), + nLockTime(0) { ui->setupUi(this); @@ -61,6 +66,36 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + + // Timelock + const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; + timeLockItems.emplace_back("Set LockTime", 0); + timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); + timeLockItems.emplace_back("Custom (until block)", -1); + timeLockItems.emplace_back("Custom (until date)", -1); + for (const auto &i : timeLockItems) { + ui->timelockCombo->addItem(i.first); + } + + // Make Timelock feature visible only if supermajority enforced BIP65 + if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, + Params().GetConsensus())) + { + ui->timelockCombo->setVisible(false); + } + + ui->timeLockCustomBlocks->setVisible(false); + ui->timeLockCustomBlocks->setRange(1, 1000000); + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); + connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); + connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, + SLOT(timeLockCustomDateChanged(const QDateTime&))); + connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); } void ReceiveCoinsDialog::setModel(WalletModel *model) @@ -155,7 +190,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() }else{ receive = AddressTableModel::Receive; } - address = model->getAddressTableModel()->addRow(receive, label, ""); + address = model->getAddressTableModel()->addRow(receive, label, "", nLockTime); } SendCoinsRecipient info(address, label, ui->reqAmount->value(), ui->reqMessage->text()); @@ -278,3 +313,34 @@ void ReceiveCoinsDialog::copyAmount() { copyColumnToClipboard(RecentRequestsTableModel::Amount); } + +void ReceiveCoinsDialog::timelockComboChanged(int index) +{ + if (timeLockItems[index].first == "Custom (until block)") { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(true); + nLockTime = ui->timeLockCustomBlocks->value(); + } + else if (timeLockItems[index].first == "Custom (until date)") + { + ui->timeLockCustomDate->setVisible(true); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; + } + else + { + ui->timeLockCustomDate->setVisible(false); + ui->timeLockCustomBlocks->setVisible(false); + nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; + } +} + +void ReceiveCoinsDialog::timeLockCustomBlocksChanged(int i) +{ + nLockTime = i; +} + +void ReceiveCoinsDialog::timeLockCustomDateChanged(const QDateTime &dt) +{ + nLockTime = dt.toMSecsSinceEpoch() / 1000; +} diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 226fd65c..fba5c4d0 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -59,6 +59,8 @@ public Q_SLOTS: WalletModel *model; QMenu *contextMenu; const PlatformStyle *platformStyle; + std::vector> timeLockItems; + int64_t nLockTime; void copyColumnToClipboard(int column); virtual void resizeEvent(QResizeEvent *event); @@ -74,6 +76,9 @@ private Q_SLOTS: void copyLabel(); void copyMessage(); void copyAmount(); + void timelockComboChanged(int); + void timeLockCustomBlocksChanged(int); + void timeLockCustomDateChanged(const QDateTime&); }; #endif // BITCOIN_QT_RECEIVECOINSDIALOG_H From b0a78355c11583ac4b4ed2df4720ebce7a0a3d40 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 3 May 2020 02:17:09 +0200 Subject: [PATCH 111/126] Create TimeLockSettings custom widget to centralize time-locked TX UI stuff --- src/Makefile.qt.include | 3 + src/qt/editaddressdialog.cpp | 69 +------------------ src/qt/editaddressdialog.h | 5 -- src/qt/forms/editaddressdialog.ui | 35 +--------- src/qt/forms/receivecoinsdialog.ui | 29 +------- src/qt/forms/sendcoinsdialog.ui | 29 +------- src/qt/receivecoinsdialog.cpp | 68 +----------------- src/qt/receivecoinsdialog.h | 5 -- src/qt/sendcoinsdialog.cpp | 75 ++------------------ src/qt/sendcoinsdialog.h | 5 -- src/qt/timelocksettingswidget.cpp | 106 +++++++++++++++++++++++++++++ src/qt/timelocksettingswidget.h | 39 +++++++++++ 12 files changed, 161 insertions(+), 307 deletions(-) create mode 100644 src/qt/timelocksettingswidget.cpp create mode 100644 src/qt/timelocksettingswidget.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 5f5a193e..15771d76 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -180,6 +180,7 @@ QT_MOC_CPP = \ qt/moc_smartproposaltab.cpp \ qt/moc_splashscreen.cpp \ qt/moc_specialtransactiondialog.cpp \ + qt/moc_timelocksettingswidget.cpp \ qt/moc_trafficgraphwidget.cpp \ qt/moc_transactiondesc.cpp \ qt/moc_transactiondescdialog.cpp \ @@ -269,6 +270,7 @@ BITCOIN_QT_H = \ qt/smartproposaltab.h \ qt/splashscreen.h \ qt/specialtransactiondialog.h \ + qt/timelocksettingswidget.h \ qt/trafficgraphdata.h \ qt/trafficgraphwidget.h \ qt/transactiondesc.h \ @@ -405,6 +407,7 @@ BITCOIN_QT_WALLET_CPP = \ qt/smartvotingmanager.cpp \ qt/smartproposaltab.cpp \ qt/specialtransactiondialog.cpp \ + qt/timelocksettingswidget.cpp \ qt/transactiondesc.cpp \ qt/transactiondescdialog.cpp \ qt/transactionfilterproxy.cpp \ diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 7992ea46..3eca8569 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -13,16 +13,12 @@ #include #include -#define ONE_MONTH (30.5 * 24 * 60 * 60) -#define ONE_YEAR (365 * 24 * 60 * 60) - EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), mapper(0), mode(mode), - model(0), - nLockTime(0) + model(0) { ui->setupUi(this); @@ -48,36 +44,6 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : mapper = new QDataWidgetMapper(this); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); - - // Timelock - const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; - timeLockItems.emplace_back("Set LockTime", 0); - timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); - timeLockItems.emplace_back("Custom (until block)", -1); - timeLockItems.emplace_back("Custom (until date)", -1); - for (const auto &i : timeLockItems) { - ui->timelockCombo->addItem(i.first); - } - - ui->timeLockCustomBlocks->setVisible(false); - ui->timeLockCustomBlocks->setRange(1, 1000000); - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); - connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); - connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, - SLOT(timeLockCustomDateChanged(const QDateTime&))); - connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); - - // Make Timelock feature visible only if supermajority enforced BIP65 - if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, - Params().GetConsensus())) - { - ui->timelockCombo->setVisible(false); - } } EditAddressDialog::~EditAddressDialog() @@ -114,7 +80,7 @@ bool EditAddressDialog::saveCurrentRow() mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive, ui->labelEdit->text(), ui->addressEdit->text(), - nLockTime); + ui->timeLockSettings->getLockTime()); break; case EditReceivingAddress: case EditSendingAddress: @@ -180,34 +146,3 @@ void EditAddressDialog::setAddress(const QString &address) ui->addressEdit->setText(address); } -void EditAddressDialog::timelockComboChanged(int index) -{ - if (timeLockItems[index].first == "Custom (until block)") { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(true); - nLockTime = ui->timeLockCustomBlocks->value(); - } - else if (timeLockItems[index].first == "Custom (until date)") - { - ui->timeLockCustomDate->setVisible(true); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; - } - else - { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; - } -} - -void EditAddressDialog::timeLockCustomBlocksChanged(int i) -{ - nLockTime = i; -} - -void EditAddressDialog::timeLockCustomDateChanged(const QDateTime &dt) -{ - nLockTime = dt.toMSecsSinceEpoch() / 1000; -} - diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index a1d1e69e..ddb67ece 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -42,9 +42,6 @@ class EditAddressDialog : public QDialog public Q_SLOTS: void accept(); - void timelockComboChanged(int); - void timeLockCustomBlocksChanged(int); - void timeLockCustomDateChanged(const QDateTime&); private: bool saveCurrentRow(); @@ -55,8 +52,6 @@ public Q_SLOTS: AddressTableModel *model; QString address; - std::vector> timeLockItems; - int64_t nLockTime; }; #endif // BITCOIN_QT_EDITADDRESSDIALOG_H diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index 215a96c6..a85c1067 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -54,40 +54,9 @@ - + - - - - - - 0 - 0 - - - - Create an address whose coins cannot be spent before a predefined locking period. - - - - - - - block height - - - - - - - true - - - MMMM d yy hh:mm:ss - - - - + diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 9b9d8410..f305d6e7 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -170,34 +170,7 @@ - - - - 0 - 0 - - - - Lock a transaction to be spent at future time. - - - - - - - block height - - - - - - - true - - - MMMM d yy hh:mm:ss - - + diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 8020f0e2..289a2e31 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -703,34 +703,7 @@ - - - - 0 - 0 - - - - Lock a transaction to be spent at future time. - - - - - - - block height - - - - - - - true - - - MMMM d yy hh:mm:ss - - + diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 8409e529..4c9fa697 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -23,16 +23,12 @@ #include #include -#define ONE_MONTH (30.5 * 24 * 60 * 60) -#define ONE_YEAR (365 * 24 * 60 * 60) - ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), columnResizingFixer(0), model(0), - platformStyle(platformStyle), - nLockTime(0) + platformStyle(platformStyle) { ui->setupUi(this); @@ -66,36 +62,6 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); - - // Timelock - const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; - timeLockItems.emplace_back("Set LockTime", 0); - timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); - timeLockItems.emplace_back("Custom (until block)", -1); - timeLockItems.emplace_back("Custom (until date)", -1); - for (const auto &i : timeLockItems) { - ui->timelockCombo->addItem(i.first); - } - - // Make Timelock feature visible only if supermajority enforced BIP65 - if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, - Params().GetConsensus())) - { - ui->timelockCombo->setVisible(false); - } - - ui->timeLockCustomBlocks->setVisible(false); - ui->timeLockCustomBlocks->setRange(1, 1000000); - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); - connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); - connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, - SLOT(timeLockCustomDateChanged(const QDateTime&))); - connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); } void ReceiveCoinsDialog::setModel(WalletModel *model) @@ -190,7 +156,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() }else{ receive = AddressTableModel::Receive; } - address = model->getAddressTableModel()->addRow(receive, label, "", nLockTime); + address = model->getAddressTableModel()->addRow(receive, label, "", ui->timeLockSettings->getLockTime()); } SendCoinsRecipient info(address, label, ui->reqAmount->value(), ui->reqMessage->text()); @@ -314,33 +280,3 @@ void ReceiveCoinsDialog::copyAmount() copyColumnToClipboard(RecentRequestsTableModel::Amount); } -void ReceiveCoinsDialog::timelockComboChanged(int index) -{ - if (timeLockItems[index].first == "Custom (until block)") { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(true); - nLockTime = ui->timeLockCustomBlocks->value(); - } - else if (timeLockItems[index].first == "Custom (until date)") - { - ui->timeLockCustomDate->setVisible(true); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; - } - else - { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; - } -} - -void ReceiveCoinsDialog::timeLockCustomBlocksChanged(int i) -{ - nLockTime = i; -} - -void ReceiveCoinsDialog::timeLockCustomDateChanged(const QDateTime &dt) -{ - nLockTime = dt.toMSecsSinceEpoch() / 1000; -} diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index fba5c4d0..226fd65c 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -59,8 +59,6 @@ public Q_SLOTS: WalletModel *model; QMenu *contextMenu; const PlatformStyle *platformStyle; - std::vector> timeLockItems; - int64_t nLockTime; void copyColumnToClipboard(int column); virtual void resizeEvent(QResizeEvent *event); @@ -76,9 +74,6 @@ private Q_SLOTS: void copyLabel(); void copyMessage(); void copyAmount(); - void timelockComboChanged(int); - void timeLockCustomBlocksChanged(int); - void timeLockCustomDateChanged(const QDateTime&); }; #endif // BITCOIN_QT_RECEIVECOINSDIALOG_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 1afb68c0..24dd070c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -33,8 +33,6 @@ #define SEND_CONFIRM_DELAY 3 #define SEND_CONFIRM_DELAY_LOCKTIME 10 -#define ONE_MONTH (30.5 * 24 * 60 * 60) -#define ONE_YEAR (365 * 24 * 60 * 60) SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), @@ -43,8 +41,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa model(0), fNewRecipientAllowed(true), fFeeMinimized(true), - platformStyle(platformStyle), - nLockTime(0) + platformStyle(platformStyle) { ui->setupUi(this); @@ -62,36 +59,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); - // Timelock - const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; - timeLockItems.emplace_back("Set LockTime", 0); - timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); - timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); - timeLockItems.emplace_back("Custom (until block)", -1); - timeLockItems.emplace_back("Custom (until date)", -1); - for (const auto &i : timeLockItems) { - ui->timelockCombo->addItem(i.first); - } - - // Make Timelock feature visible only if supermajority enforced BIP65 - if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, - Params().GetConsensus())) - { - ui->timelockCombo->setVisible(false); - } - - ui->timeLockCustomBlocks->setVisible(false); - ui->timeLockCustomBlocks->setRange(1, 1000000); - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); - connect(ui->timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); - connect(ui->timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, - SLOT(timeLockCustomDateChanged(const QDateTime&))); - connect(ui->timelockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timelockComboChanged(int))); - // Coin Control connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); @@ -246,6 +213,7 @@ void SendCoinsDialog::on_sendButton_clicked() QList recipients; bool valid = true; + int64_t nLockTime = ui->timeLockSettings->getLockTime(); for(int i = 0; i < ui->entries->count(); ++i) { @@ -416,9 +384,7 @@ void SendCoinsDialog::on_sendButton_clicked() accept(); CoinControlDialog::coinControl->UnSelectAll(); coinControlUpdateLabels(); - ui->timelockCombo->setCurrentIndex(0); - ui->timeLockCustomBlocks->setVisible(false); - ui->timeLockCustomDate->setVisible(false); + ui->timeLockSettings->reset(); } fNewRecipientAllowed = true; } @@ -498,8 +464,8 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) } QWidget::setTabOrder(prev, ui->sendButton); QWidget::setTabOrder(ui->sendButton, ui->addButton); - QWidget::setTabOrder(ui->addButton, ui->timelockCombo); - return ui->timelockCombo; + QWidget::setTabOrder(ui->addButton, ui->timeLockSettings); + return ui->timeLockSettings; } void SendCoinsDialog::setAddress(const QString &address) @@ -943,37 +909,6 @@ void SendCoinsDialog::coinControlUpdateLabels() } } -void SendCoinsDialog::timelockComboChanged(int index) -{ - if (timeLockItems[index].first == "Custom (until block)") { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(true); - nLockTime = ui->timeLockCustomBlocks->value(); - } - else if (timeLockItems[index].first == "Custom (until date)") - { - ui->timeLockCustomDate->setVisible(true); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = ui->timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; - } - else - { - ui->timeLockCustomDate->setVisible(false); - ui->timeLockCustomBlocks->setVisible(false); - nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; - } -} - -void SendCoinsDialog::timeLockCustomBlocksChanged(int i) -{ - nLockTime = i; -} - -void SendCoinsDialog::timeLockCustomDateChanged(const QDateTime &dt) -{ - nLockTime = dt.toMSecsSinceEpoch() / 1000; -} - SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay, QMessageBox::Icon icon, QWidget *parent) : QMessageBox(icon, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay) diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 7fe6639d..4f1cb2cd 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -64,8 +64,6 @@ public Q_SLOTS: bool fNewRecipientAllowed; bool fFeeMinimized; const PlatformStyle *platformStyle; - std::vector> timeLockItems; - int64_t nLockTime; // Process WalletModel::SendCoinsReturn and generate a pair consisting // of a message and message flags for use in Q_EMIT message(). @@ -94,9 +92,6 @@ private Q_SLOTS: void coinControlClipboardPriority(); void coinControlClipboardLowOutput(); void coinControlClipboardChange(); - void timelockComboChanged(int); - void timeLockCustomBlocksChanged(int); - void timeLockCustomDateChanged(const QDateTime&); void setMinimumFee(); void updateFeeSectionControls(); void updateMinFeeLabel(); diff --git a/src/qt/timelocksettingswidget.cpp b/src/qt/timelocksettingswidget.cpp new file mode 100644 index 00000000..c2be526e --- /dev/null +++ b/src/qt/timelocksettingswidget.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2020 The SmartCash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "validation.h" +#include "chainparams.h" + +#include "timelocksettingswidget.h" + +#define ONE_MONTH (30.5 * 24 * 60 * 60) +#define ONE_YEAR (365 * 24 * 60 * 60) + +TimeLockSettingsWidget::TimeLockSettingsWidget(QWidget *parent) : + QWidget(parent), + nLockTime(0) +{ + const int nAvgBlockTime = Params().GetConsensus().nPowTargetSpacing; + timeLockItems.emplace_back("Set LockTime", 0); + timeLockItems.emplace_back("1 month", (int)(ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("2 months", (int)(2 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("3 months", (int)(3 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("6 months", (int)(6 * ONE_MONTH / nAvgBlockTime)); + timeLockItems.emplace_back("1 year", (int)(ONE_YEAR / nAvgBlockTime)); + timeLockItems.emplace_back("Custom (until block)", -1); + timeLockItems.emplace_back("Custom (until date)", -1); + + timeLockCombo = new QComboBox(); + for (const auto &i : timeLockItems) { + timeLockCombo->addItem(i.first); + } + + QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + + timeLockCombo->setSizePolicy(sizePolicy); + timeLockCombo->setToolTip("Lock a transaction to be spent at future time."); + + // Make Timelock feature visible only if supermajority enforced BIP65 + if(!IsSuperMajority(4, chainActive.Tip(), Params().GetConsensus().nMajorityEnforceBlockUpgrade, + Params().GetConsensus())) + { + timeLockCombo->setVisible(false); + } + + timeLockCustomBlocks = new QSpinBox(); + timeLockCustomBlocks->setVisible(false); + timeLockCustomBlocks->setRange(1, 1000000); + timeLockCustomBlocks->setValue(chainActive.Height()); + + timeLockCustomDate = new QDateTimeEdit(); + timeLockCustomDate->setVisible(false); + timeLockCustomDate->setMinimumDateTime(QDateTime::currentDateTime()); + timeLockCustomDate->setCalendarPopup(true); + timeLockCustomDate->setDisplayFormat("MMMM d yy hh:mm:ss"); + + connect(timeLockCustomBlocks, SIGNAL(valueChanged(int)), this, SLOT(timeLockCustomBlocksChanged(int))); + connect(timeLockCustomDate, SIGNAL(dateTimeChanged(const QDateTime&)), this, + SLOT(timeLockCustomDateChanged(const QDateTime&))); + connect(timeLockCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(timeLockComboChanged(int))); + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(timeLockCombo); + layout->addWidget(timeLockCustomBlocks); + layout->addWidget(timeLockCustomDate); +} + +void TimeLockSettingsWidget::timeLockComboChanged(int index) +{ + if (timeLockItems[index].first == "Custom (until block)") { + timeLockCustomDate->setVisible(false); + timeLockCustomBlocks->setVisible(true); + nLockTime = timeLockCustomBlocks->value(); + } + else if (timeLockItems[index].first == "Custom (until date)") + { + timeLockCustomDate->setVisible(true); + timeLockCustomBlocks->setVisible(false); + nLockTime = timeLockCustomDate->dateTime().toMSecsSinceEpoch() / 1000; + } + else + { + timeLockCustomDate->setVisible(false); + timeLockCustomBlocks->setVisible(false); + nLockTime = timeLockItems[index].second > 0 ? chainActive.Height() + timeLockItems[index].second : 0; + } +} + +void TimeLockSettingsWidget::timeLockCustomBlocksChanged(int i) +{ + nLockTime = i; +} + +void TimeLockSettingsWidget::timeLockCustomDateChanged(const QDateTime& dt) +{ + nLockTime = dt.toMSecsSinceEpoch() / 1000; +} + +void TimeLockSettingsWidget::reset() +{ + timeLockCombo->setCurrentIndex(0); + timeLockCustomBlocks->setVisible(false); + timeLockCustomDate->setVisible(false); +} diff --git a/src/qt/timelocksettingswidget.h b/src/qt/timelocksettingswidget.h new file mode 100644 index 00000000..ebd7dd05 --- /dev/null +++ b/src/qt/timelocksettingswidget.h @@ -0,0 +1,39 @@ +// Copyright (c) 2020 The SmartCash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_TIMELOCKSETTINGSWIDGET_H +#define BITCOIN_QT_TIMELOCKSETTINGSWIDGET_H + +#include +#include + +#include +#include +#include +#include + +class TimeLockSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit TimeLockSettingsWidget(QWidget *parent = 0); + + int64_t getLockTime() { return nLockTime; } + void reset(); + +private: + QComboBox *timeLockCombo; + QSpinBox *timeLockCustomBlocks; + QDateTimeEdit *timeLockCustomDate; + std::vector> timeLockItems; + int64_t nLockTime; + +private Q_SLOTS: + void timeLockComboChanged(int); + void timeLockCustomBlocksChanged(int); + void timeLockCustomDateChanged(const QDateTime&); +}; + +#endif // BITCOIN_QT_TIMELOCKSETTINGSWIDGET_H From 114c4e3003a7cc110a33aed9897dac3f8638f953 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 3 May 2020 22:48:02 +0200 Subject: [PATCH 112/126] Add function to keystore to get all the stored scripts at once --- src/keystore.cpp | 10 ++++++++++ src/keystore.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/keystore.cpp b/src/keystore.cpp index b04b769f..85efd001 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -88,6 +88,16 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) return false; } +std::set CBasicKeyStore::GetCScripts() const +{ + LOCK(cs_KeyStore); + std::set setScripts; + for (const auto& mi : mapScripts) { + setScripts.insert(mi.first); + } + return setScripts; +} + static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) { //TODO: Use Solver to extract this? diff --git a/src/keystore.h b/src/keystore.h index b423f6a5..7745a00f 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -154,6 +154,7 @@ class CBasicKeyStore : public CKeyStore virtual bool AddCScript(const CScript& redeemScript); virtual bool HaveCScript(const CScriptID &hash) const; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const; + virtual std::set GetCScripts() const; virtual bool AddWatchOnly(const CScript &dest); virtual bool RemoveWatchOnly(const CScript &dest); From 5082072d9e92d3a7c6439b4a87d06677835103ca Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 3 May 2020 22:48:57 +0200 Subject: [PATCH 113/126] Modify dumpwallet/imporwallet RPC calls to also export/import scripts stored in wallet --- src/wallet/rpcdump.cpp | 81 +++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index f2679bc5..3b9fd9fa 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -457,40 +457,46 @@ UniValue importwallet(const UniValue& params, bool fHelp) if (vstr.size() < 2) continue; CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) - continue; - CKey key = vchSecret.GetKey(); - CPubKey pubkey = key.GetPubKey(); - assert(key.VerifyPubKey(pubkey)); - CKeyID keyid = pubkey.GetID(); - if (pwalletMain->HaveKey(keyid)) { - LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); - continue; - } - int64_t nTime = DecodeDumpTime(vstr[1]); - std::string strLabel; - bool fLabel = true; - for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { - if (boost::algorithm::starts_with(vstr[nStr], "#")) - break; - if (vstr[nStr] == "change=1") - fLabel = false; - if (vstr[nStr] == "reserve=1") - fLabel = false; - if (boost::algorithm::starts_with(vstr[nStr], "label=")) { - strLabel = DecodeDumpString(vstr[nStr].substr(6)); - fLabel = true; + if (vchSecret.SetString(vstr[0])) { + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + CKeyID keyid = pubkey.GetID(); + if (pwalletMain->HaveKey(keyid)) { + LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); + continue; + } + int64_t nTime = DecodeDumpTime(vstr[1]); + std::string strLabel; + bool fLabel = true; + for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { + if (boost::algorithm::starts_with(vstr[nStr], "#")) + break; + if (vstr[nStr] == "change=1") + fLabel = false; + if (vstr[nStr] == "reserve=1") + fLabel = false; + if (boost::algorithm::starts_with(vstr[nStr], "label=")) { + strLabel = DecodeDumpString(vstr[nStr].substr(6)); + fLabel = true; + } + } + LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); + if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; + if (fLabel) + pwalletMain->SetAddressBook(keyid, strLabel, "receive"); + nTimeBegin = std::min(nTimeBegin, nTime); + } else if (IsHex(vstr[0])) { + std::vector vData(ParseHex(vstr[0])); + CScript script = CScript(vData.begin(), vData.end()); + if (!pwalletMain->HaveCScript(CScriptID(script))) { + pwalletMain->AddCScript(script); } } - LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { - fGood = false; - continue; - } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwalletMain->SetAddressBook(keyid, strLabel, "receive"); - nTimeBegin = std::min(nTimeBegin, nTime); } file.close(); pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI @@ -770,6 +776,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) std::set setKeyPool; pwalletMain->GetKeyBirthTimes(mapKeyBirth); pwalletMain->GetAllReserveKeys(setKeyPool); + std::set setScripts = pwalletMain->GetCScripts(); // sort time/key pairs std::vector > vKeyBirth; @@ -848,6 +855,16 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) } } file << "\n"; + for (const CScriptID &scriptid : setScripts) { + CScript script; + std::string create_time = "0"; + std::string address = CBitcoinAddress(scriptid).ToString(); + if(pwalletMain->GetCScript(scriptid, script)) { + file << strprintf("%s script=1", HexStr(script.begin(), script.end())); + file << strprintf(" # addr=%s\n", address); + } + } + file << "\n"; file << "# End of dump\n"; file.close(); return NullUniValue; From ec6d8ee0b491e7e88153a007bb1cb8eb77b45681 Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Sat, 9 May 2020 01:56:38 -0500 Subject: [PATCH 114/126] Update Mainnet 1.3 Block --- src/chainparams.cpp | 2 +- src/consensus/consensus.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1dad2f0a..e76ebc5d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -140,7 +140,7 @@ class CMainParams : public CChainParams { //! 1.3 Parameter consensus.nRewardsBlocksPerRound_1_3 = 11000; // 1 week - consensus.nRewardsFirst_1_3_Round = 33; // Round 33 on 3/23 starts on block 1524100 + consensus.nRewardsFirst_1_3_Round = 36; // Round 36 on 6/25 starts on block 1666600 consensus.nRewardsPayouts_1_3_BlockStretch = 10000; consensus.nRewardsPayouts_1_3_BlockPayees = 100; diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 4d55ba47..12728d9d 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -29,7 +29,7 @@ static const int HF_V1_2_MULTINODE_VOTING_HEIGHT = 535000; static const int HF_V1_2_MULTINODE_PAYOUT_HEIGHT = 545005; static const int HF_V1_2_SMARTREWARD_HEIGHT = 574100; static const int HF_V1_2_8_SMARNODE_NEW_COLLATERAL_HEIGHT = 910000; -static const int HF_V1_3_HEIGHT = 1524100; // Round 33 starts 1524100 +static const int HF_V1_3_HEIGHT = 1666600; // Round 36 starts 1666600 /* Mainnet payment intervals*/ static const int HF_V1_2_NODES_PER_BLOCK = 10; From a220989e1ca40ca99d635835d56d4016e193e409 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 10 May 2020 00:34:09 +0200 Subject: [PATCH 115/126] Modify SmartRewards db structure to store the bonus level of a specific entry --- src/smartrewards/rewards.cpp | 5 +++++ src/smartrewards/rewardsdb.cpp | 6 ++++-- src/smartrewards/rewardsdb.h | 15 +++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 2222d8c7..74cd1037 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -260,17 +260,22 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) // If we are at a "special round", add to the eligible balance with proper weight CAmount toAdd = 0; + CSmartRewardEntry::BonusLevel bonus = CSmartRewardEntry::NoBonus; if (roundNumber == cache.GetCurrentRound()->number - 8) { toAdd = addressResult->entry.balance; + bonus = CSmartRewardEntry::TwoMonthsBonus; } else if (roundNumber == cache.GetCurrentRound()->number - 16) { toAdd = 2 * addressResult->entry.balance; + bonus = CSmartRewardEntry::FourMonthsBonus; } else if (roundNumber == cache.GetCurrentRound()->number - 26) { toAdd = 2 * addressResult->entry.balance; + bonus = CSmartRewardEntry::SixMonthsBonus; } if (toAdd > 0) { auto &cacheEntry = cache.GetEntries()->at(*address); cacheEntry->balanceEligible += toAdd; + cacheEntry->bonusLevel = bonus; next.eligibleSmart += toAdd; } diff --git a/src/smartrewards/rewardsdb.cpp b/src/smartrewards/rewardsdb.cpp index c9ef67c4..a6b3fc20 100644 --- a/src/smartrewards/rewardsdb.cpp +++ b/src/smartrewards/rewardsdb.cpp @@ -373,17 +373,19 @@ void CSmartRewardEntry::SetNull() fSmartnodePaymentTx = false; activationTx.SetNull(); fActivated = false; + bonusLevel = NoBonus; } string CSmartRewardEntry::ToString() const { std::stringstream s; - s << strprintf("CSmartRewardEntry(id=%s, balance=%d, balanceEligible=%d, isSmartNode=%b, activated=%b)\n", + s << strprintf("CSmartRewardEntry(id=%s, balance=%d, balanceEligible=%d, isSmartNode=%b, activated=%b, bonus=%d)\n", GetAddress(), balance, balanceEligible, fSmartnodePaymentTx, - fActivated); + fActivated, + bonusLevel); return s.str(); } diff --git a/src/smartrewards/rewardsdb.h b/src/smartrewards/rewardsdb.h index f68c5ee6..9e54bfe1 100644 --- a/src/smartrewards/rewardsdb.h +++ b/src/smartrewards/rewardsdb.h @@ -207,8 +207,16 @@ class CSmartRewardEntry READWRITE(fActivated); READWRITE(smartnodePaymentTx); READWRITE(fSmartnodePaymentTx); + READWRITE(bonusLevel); } + enum BonusLevel { + NoBonus = 0, + TwoMonthsBonus, + FourMonthsBonus, + SixMonthsBonus + }; + CSmartAddress id; CAmount balance; CAmount balanceAtStart; @@ -219,17 +227,20 @@ class CSmartRewardEntry bool fActivated; uint256 smartnodePaymentTx; bool fSmartnodePaymentTx; + uint8_t bonusLevel; CSmartRewardEntry() : id(CSmartAddress()), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), activationTx(uint256()), fActivated(false), - smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} + smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false), + bonusLevel(NoBonus) {} CSmartRewardEntry(const CSmartAddress &address) : id(address), balance(0), balanceAtStart(0), balanceEligible(0), disqualifyingTx(uint256()), fDisqualifyingTx(false), activationTx(uint256()), fActivated(false), - smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false) {} + smartnodePaymentTx(uint256()), fSmartnodePaymentTx(false), + bonusLevel(NoBonus) {} friend bool operator==(const CSmartRewardEntry& a, const CSmartRewardEntry& b) { From 773306cfddbd776c6279e011b7b5bc6e88c7e7db Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sun, 10 May 2020 00:36:36 +0200 Subject: [PATCH 116/126] Show 1.3 bonus level on eligible addresses in SmartRewards tab --- src/qt/forms/smartrewardentry.ui | 13 +++++++++++++ src/qt/smartrewardentry.cpp | 23 +++++++++++++++++++++++ src/qt/smartrewardentry.h | 1 + src/qt/smartrewardslist.cpp | 6 +++++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/qt/forms/smartrewardentry.ui b/src/qt/forms/smartrewardentry.ui index 50523262..57d2a9f1 100755 --- a/src/qt/forms/smartrewardentry.ui +++ b/src/qt/forms/smartrewardentry.ui @@ -113,6 +113,19 @@ + + + + + 75 + true + + + + color: rgb(60, 179, 113); + + + diff --git a/src/qt/smartrewardentry.cpp b/src/qt/smartrewardentry.cpp index c7106478..1cd3faed 100755 --- a/src/qt/smartrewardentry.cpp +++ b/src/qt/smartrewardentry.cpp @@ -20,6 +20,7 @@ QSmartRewardEntry::QSmartRewardEntry(const QString& strLabel, const QString& str ui->lblLabel->setText(strLabel); ui->lblAddress->setText(strAddress); + ui->lblBonus->setVisible(false); QAction *copyAddressAction = new QAction(tr("Copy address"), this); QAction *copyLabelAction = new QAction(tr("Copy label"), this); @@ -97,6 +98,28 @@ void QSmartRewardEntry::setIsSmartNode(bool fState) fIsSmartNode = fState; } +void QSmartRewardEntry::setBonusText(uint8_t bonusLevel) +{ + switch (bonusLevel) { + case CSmartRewardEntry::TwoMonthsBonus: + ui->lblBonus->setText("2 months bonus"); + ui->lblBonus->setVisible(true); + break; + case CSmartRewardEntry::FourMonthsBonus: + ui->lblBonus->setText("4 months bonus"); + ui->lblBonus->setVisible(true); + break; + case CSmartRewardEntry::SixMonthsBonus: + ui->lblBonus->setText("6 months bonus"); + ui->lblBonus->setVisible(true); + break; + default: + ui->lblBonus->setText(""); + ui->lblBonus->setVisible(false); + break; + } +} + QString QSmartRewardEntry::Address() const { return ui->lblAddress->text(); diff --git a/src/qt/smartrewardentry.h b/src/qt/smartrewardentry.h index 78b6e05b..23454a22 100755 --- a/src/qt/smartrewardentry.h +++ b/src/qt/smartrewardentry.h @@ -35,6 +35,7 @@ class QSmartRewardEntry : public QFrame void setEligible(CAmount nEligible, CAmount nEstimated); void setIsSmartNode(bool fState); void setActivated(bool fState); + void setBonusText(uint8_t bonusLevel); QString Address() const; CAmount Balance() const { return nBalance; } diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 458e1aac..5247df91 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -47,11 +47,13 @@ struct QSmartRewardField uint256 disqualifyingTx; bool fIsSmartNode; bool fActivated; + uint8_t bonusLevel; QSmartRewardField() : label(QString()), address(QString()), balance(0), eligible(0),reward(0), disqualifyingTx(), - fIsSmartNode(false), fActivated(false){} + fIsSmartNode(false), fActivated(false), + bonusLevel(CSmartRewardEntry::NoBonus) {} }; struct SortSmartRewardWidgets @@ -297,6 +299,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c rewardField.balanceAtStart = reward->balanceAtStart; rewardField.disqualifyingTx = reward->disqualifyingTx; rewardField.fActivated = reward->fActivated; + rewardField.bonusLevel = reward->bonusLevel; if( !currentRound.Is_1_3() ){ rewardField.eligible = reward->balanceEligible && reward->disqualifyingTx.IsNull() ? reward->balanceEligible : 0; @@ -360,6 +363,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( currentRound.Is_1_3() ){ entry->setMinBalance(SMART_REWARDS_MIN_BALANCE_1_3); + entry->setBonusText(field.bonusLevel); if( field.fIsSmartNode ){ entry->setInfoText("Address belongs to a SmartNode.", COLOR_NEGATIVE); From a530ffb428885bbe83d6a89dcc85c4c4de227fa4 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Sun, 10 May 2020 18:55:24 -0500 Subject: [PATCH 117/126] Add checkpoints and adjust sync status --- src/chainparams.cpp | 12 ++++++++---- src/checkpoints.cpp | 2 +- src/smartrewards/rewards.cpp | 1 - 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e76ebc5d..cce2d51d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -215,12 +215,16 @@ class CMainParams : public CChainParams { ( 75000, uint256S("0x000000000002ee203026137ebc460e1886e09b9fdb0e83697e5a74976088e75c")) ( 170000, uint256S("0x000000000000670ff41fbb4ad819b48bfe1c35623f13297d3fbf9bf02abcd87c")) ( 500000, uint256S("0x00000000000016a1fa8e650e5a82babefeb9225ffe78614bc4b23cf160d16eeb")) + ( 750000, uint256S("0x000000000000456bd57843a6650155f9c09b42c47e5a8d24418881a88ce8aa2e")) ( 1000000, uint256S("0x00000000000008e14776878dba228ac957a97205df4716ce1913ae4339e7aeb9")) - ( 1030000, uint256S("0x00000000000000d7e76cc6c30a2bece10f552123ad3c9a63beceb0d553a46f04")), - 1557812640, // * UNIX timestamp of last checkpoint block - 4095887, // * total number of transactions between genesis and last checkpoint + ( 1030000, uint256S("0x00000000000000d7e76cc6c30a2bece10f552123ad3c9a63beceb0d553a46f04")) + ( 1250000, uint256S("0x00000000000036b03ca216e92c83c9d0d152c1fdfac74c1bfc0cfc1cfa00f451")) + ( 1500000, uint256S("0x0000000000001e396ce1ea9dfde2956fef0f606a5d6cbbcb1a5ba6e1081eadf5")) + ( 1599000, uint256S("0x00000000000024edb61519ed6ebdf085f5dd25a0963103dc108b68e5f88604f3")), + 1589123846, // * UNIX timestamp of last checkpoint block + 11577739, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) - 12000.0 // * estimated number of transactions per day after checkpoint + 33000.0 // * estimated number of transactions per day after checkpoint }; } }; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 5d83dc15..2816c939 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -23,7 +23,7 @@ namespace Checkpoints { * can be up to 20, while when downloading from a slow network with a * fast multicore CPU, it won't be much higher than 1. */ - static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; + static const double SIGCHECK_VERIFICATION_FACTOR = 1.0; //! Guess how far we are in the verification process at the given block index double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) { diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 74cd1037..4c2b2d7f 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -291,7 +291,6 @@ void CSmartRewards::EvaluateRound(CSmartRewardRound &next) } } - double rpercent = next.eligibleSmart > 10000 ? ( (double)next.rewards / (double)next.eligibleSmart ) : 0; entry = cache.GetEntries()->begin(); while(entry != cache.GetEntries()->end() ) { From ffb081871e64f41bf05deef3d7f7b1538f130988 Mon Sep 17 00:00:00 2001 From: thesolarminer Date: Mon, 18 May 2020 16:23:49 -0500 Subject: [PATCH 118/126] Disable Mainnet --- src/init.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 17adb28e..0dd1c652 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2295,10 +2295,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman))); -/* if( MainNet() ){ + if( MainNet() ){ InitError("Mainnet is not available in this beta. You can start the client on Testnet with testnet=1 in the smartcash.conf or -testnet=1 as command line argument."); StartShutdown(); - }*/ + } return !fRequestShutdown; } From a67af5ec94d343a3159255739bf053c872e0ffb0 Mon Sep 17 00:00:00 2001 From: Solarminer Date: Wed, 20 May 2020 01:28:16 -0500 Subject: [PATCH 119/126] Update seeds --- contrib/seeds/nodes_main.txt | 4 +++- src/chainparams.cpp | 12 ++++-------- src/chainparamsseeds.h | 6 ++++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index 57fb951a..890fa475 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -7,4 +7,6 @@ 64.110.130.146:9678 103.42.212.200:9678 45.76.38.200:9678 -198.245.51.138:19678 \ No newline at end of file +[2620:1e8:2:1::300:9678] +[2604:880:a:6::776:9678] +172.110.9.185:19678 diff --git a/src/chainparams.cpp b/src/chainparams.cpp index cce2d51d..8f7a1be9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -171,14 +171,11 @@ class CMainParams : public CChainParams { // Note that of those with the service bits flag, most only support a subset of possible options vSeeds.push_back(CDNSSeedData("seed.smrt.cash", "seed.smrt.cash", false)); - vSeeds.push_back(CDNSSeedData("seed1.smrt.cash", "seed1.smrt.cash", false)); - vSeeds.push_back(CDNSSeedData("seed2.smrt.cash", "seed2.smrt.cash", false)); + vSeeds.push_back(CDNSSeedData("seed.smrt.run", "seed.smrt.run", false)); + vSeeds.push_back(CDNSSeedData("seed.smrt.best", "seed.smrt.best", false)); + vSeeds.push_back(CDNSSeedData("seed.smarts.cash", "seed.smarts.cash", false)); vSeeds.push_back(CDNSSeedData("seed1.smartcash.org", "seed1.smartcash.org", false)); vSeeds.push_back(CDNSSeedData("seed2.smartcash.org", "seed2.smartcash.org", false)); - vSeeds.push_back(CDNSSeedData("seed.smartcash.cc", "seed.smartcash.cc", false)); - vSeeds.push_back(CDNSSeedData("seed2.smartcash.cc", "seed2.smartcash.cc", false)); - vSeeds.push_back(CDNSSeedData("seed3.smartcash.cc", "seed3.smartcash.cc", false)); - vSeeds.push_back(CDNSSeedData("seed4.smartcash.cc", "seed4.smartcash.cc", false)); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,63); //S @@ -324,8 +321,7 @@ class CTestNetParams : public CChainParams { vFixedSeeds.clear(); vSeeds.clear(); // nodes with support for servicebits filtering should be at the top - vSeeds.push_back(CDNSSeedData("testnet.smartcash.cc", "testnet.smartcash.cc", true)); - vSeeds.push_back(CDNSSeedData("testnet.smrt.cash", "testnet.smrt.cash", true)); + vSeeds.push_back(CDNSSeedData("testnet.smrt.run", "testnet.smrt.run", true)); base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,65); //T base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,21); diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 289a4279..4a2b272d 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -16,10 +16,12 @@ static SeedSpec6 pnSeed6_main[] = { {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x6e,0x12,0x45}, 9678}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x6e,0x82,0x92}, 9678}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x2a,0xd4,0xc8}, 9678}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4c,0x26,0xc8}, 9678} + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4c,0x26,0xc8}, 9678}, + {{0x26,0x20,0x01,0xe8,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0x00,0x96,0x78}, 9678}, + {{0x26,0x04,0x08,0x80,0x00,0x0a,0x00,0x06,0x00,0x00,0x00,0x00,0x07,0x76,0x96,0x78}, 9678} }; static SeedSpec6 pnSeed6_test[] = { - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xf5,0x33,0x8a}, 19678} + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x6e,0x09,0xb9}, 19678} }; #endif // BITCOIN_CHAINPARAMSSEEDS_H From 799c4cc0791266db5649aa041a859f33db9069eb Mon Sep 17 00:00:00 2001 From: Solarminer Date: Thu, 21 May 2020 19:16:49 -0500 Subject: [PATCH 120/126] Update popup fee --- src/primitives/transaction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 896e2512..916d99cf 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -16,7 +16,7 @@ static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000; // Constants for vote proof transactions static const CAmount REWARDS_ACTIVATION_FEE = 0 * COIN; -static const CAmount REWARDS_ACTIVATION_TX_FEE = 0.002 * COIN; +static const CAmount REWARDS_ACTIVATION_TX_FEE = 0.001 * COIN; static const int WITNESS_SCALE_FACTOR = 4; From c55e3fe0456015bdfc318f77945aa1ccdf9375e9 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Sat, 23 May 2020 21:41:58 +0200 Subject: [PATCH 121/126] Add button to send all available coins to the send tab --- src/qt/forms/sendcoinsentry.ui | 9 ++++++++- src/qt/sendcoinsentry.cpp | 15 +++++++++++++++ src/qt/sendcoinsentry.h | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index 703bcace..c0f37c57 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -163,7 +163,7 @@ - + @@ -177,6 +177,13 @@ + + + + U&se Available Balance + + + diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index d063f2c8..56a08c35 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -42,12 +42,15 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *pare // just a label for displaying bitcoin address(es) ui->payTo_is->setFont(GUIUtil::fixedPitchFont()); + ui->horizontalLayoutAmount->insertStretch(-1, 3); + // Connect signals connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged())); connect(ui->checkboxSubtractFeeFromAmount, SIGNAL(toggled(bool)), this, SIGNAL(subtractFeeFromAmountChanged())); connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked())); connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked())); connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked())); + connect(ui->useAvailableBalanceButton, SIGNAL(clicked()), this, SLOT(useAvailableBalanceButtonClicked())); } SendCoinsEntry::~SendCoinsEntry() @@ -264,3 +267,15 @@ bool SendCoinsEntry::updateLabel(const QString &address) return false; } + +void SendCoinsEntry::useAvailableBalanceButtonClicked() +{ + CAmount amount = model->getBalance(); + if (amount > 0) { + ui->payAmount->setValue(amount); + ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Checked); + } else { + ui->payAmount->setValue(0); + } +} + diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index a8be670c..5642b959 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -60,6 +60,7 @@ private Q_SLOTS: void on_addressBookButton_clicked(); void on_pasteButton_clicked(); void updateDisplayUnit(); + void useAvailableBalanceButtonClicked(); private: SendCoinsRecipient recipient; From c1d896614d6f9538aedf3686b163a323cc2ee8ec Mon Sep 17 00:00:00 2001 From: Solarminer Date: Sat, 30 May 2020 01:35:47 -0500 Subject: [PATCH 122/126] Text cleanup --- src/init.cpp | 2 +- src/qt/forms/smartrewardslist.ui | 4 ++-- src/qt/sendcoinsdialog.cpp | 2 +- src/qt/smartrewardentry.cpp | 6 +++--- src/qt/smartrewardslist.cpp | 12 ++++++------ src/qt/specialtransactiondialog.cpp | 2 +- src/qt/specialtransactiondialog.h | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 0dd1c652..8b9da3b5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -830,7 +830,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); } - if (GetBoolArg("-smartnode", false)) { + if (GetBoolArg("-smartnode", true)) { // smartnodes must accept connections from outside if (SoftSetBoolArg("-listen", true) && SoftSetBoolArg("-sapi", true)) LogPrintf("%s: parameter interaction: -smartnode=1 -> setting -listen=1 and -sapi=1\n", __func__); diff --git a/src/qt/forms/smartrewardslist.ui b/src/qt/forms/smartrewardslist.ui index 4cfab0d1..d6e63183 100644 --- a/src/qt/forms/smartrewardslist.ui +++ b/src/qt/forms/smartrewardslist.ui @@ -189,7 +189,7 @@ - SmartRewards round + SmartRewards Round @@ -269,7 +269,7 @@ - Current reward + Current Reward Annualized diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 24dd070c..65b2f25c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -325,7 +325,7 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append(""); questionString.append(tr("This is not a normal transaction. ")); - questionString.append(tr("Do not use this to deposit funds to an exchange.")); + questionString.append(tr("Do not use this to deposit funds to an exchange. ")); questionString.append(tr("Funds sent will not be spendable until approximatively ")); questionString.append(unlockDateTime.toString("MMMM d yy hh:mm:ss")); questionString.append("

"); diff --git a/src/qt/smartrewardentry.cpp b/src/qt/smartrewardentry.cpp index 1cd3faed..8c277a27 100755 --- a/src/qt/smartrewardentry.cpp +++ b/src/qt/smartrewardentry.cpp @@ -102,15 +102,15 @@ void QSmartRewardEntry::setBonusText(uint8_t bonusLevel) { switch (bonusLevel) { case CSmartRewardEntry::TwoMonthsBonus: - ui->lblBonus->setText("2 months bonus"); + ui->lblBonus->setText("2 months 2x bonus"); ui->lblBonus->setVisible(true); break; case CSmartRewardEntry::FourMonthsBonus: - ui->lblBonus->setText("4 months bonus"); + ui->lblBonus->setText("4 months 4x bonus"); ui->lblBonus->setVisible(true); break; case CSmartRewardEntry::SixMonthsBonus: - ui->lblBonus->setText("6 months bonus"); + ui->lblBonus->setText("6 months 6x bonus"); ui->lblBonus->setVisible(true); break; default: diff --git a/src/qt/smartrewardslist.cpp b/src/qt/smartrewardslist.cpp index 5247df91..35ad5a83 100644 --- a/src/qt/smartrewardslist.cpp +++ b/src/qt/smartrewardslist.cpp @@ -136,7 +136,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c } QString percentText; - percentText.sprintf("%.2f%%", currentRound.percent * 100); + percentText.sprintf("%.2f%%", currentRound.percent * 100 * 52); ui->percentLabel->setText(percentText); ui->roundLabel->setText(QString::number(currentRound.number)); @@ -165,17 +165,17 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c uint64_t minutes = (minutesLeft % 1440) % 60; if( days ){ - roundEndText += QString("%1day%2").arg(days).arg(days > 1 ? "s":""); + roundEndText += QString("%1 day%2").arg(days).arg(days > 1 ? "s":""); } if( hours ){ if( days ) roundEndText += ", "; - roundEndText += QString("%1hour%2").arg(hours).arg(hours > 1 ? "s":""); + roundEndText += QString("%1 hour%2").arg(hours).arg(hours > 1 ? "s":""); } if( !days && minutes ){ if( hours ) roundEndText += ", "; - roundEndText += QString("%1minute%2").arg(minutes).arg(minutes > 1 ? "s":""); + roundEndText += QString("%1 minute%2").arg(minutes).arg(minutes > 1 ? "s":""); } roundEndText += " )"; @@ -368,7 +368,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c if( field.fIsSmartNode ){ entry->setInfoText("Address belongs to a SmartNode.", COLOR_NEGATIVE); }else if( field.balanceAtStart < SMART_REWARDS_MIN_BALANCE_1_3 ){ - entry->setInfoText(QString("Address only held %1 SMART at the round's startblock. Minimum required: %2 SMART. It can be activated now but it will not receive rewards until it has enough funds.").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_3/COIN), COLOR_NEGATIVE); + entry->setInfoText(QString("Qualified balance is only %1 SMART at the round's startblock. Minimum required: %2 SMART. It can be activated now but it will not receive rewards until it has enough funds.").arg(BitcoinUnits::format(BitcoinUnit::SMART, field.balanceAtStart)).arg(SMART_REWARDS_MIN_BALANCE_1_3/COIN), COLOR_NEGATIVE); }else if( !field.disqualifyingTx.IsNull() ){ entry->setDisqualifyingTx(field.disqualifyingTx); entry->setInfoText(QString("Address disqualified due to an outgoing transaction with the hash %1. It can be activated now but it will not receive any rewards until it becomes eligible").arg(QString::fromStdString(field.disqualifyingTx.ToString())), COLOR_NEGATIVE); @@ -445,7 +445,7 @@ void SmartrewardsList::updateOverviewUI(const CSmartRewardRound ¤tRound, c ui->lblActiveAddresses->setText(QString::number(vecEntries.size())); ui->lblEligibleAddresses->setText(QString::number(nEligibleAddresses)); - QString strEstimated = QString::fromStdString(strprintf("%d", rewardSum/COIN)); + QString strEstimated = QString::fromStdString(strprintf("%d", (rewardSum + 50000000)/COIN)); AddThousandsSpaces(strEstimated); ui->lblTotalRewards->setText(strEstimated + " SMART"); } diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 9001cee7..104f124f 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -142,7 +142,7 @@ void SpecialTransactionDialog::buttonBoxClicked(QAbstractButton* button) if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole){ if ((type == ACTIVATION_TRANSACTIONS) && (mapOutputs.size() > MAX_ACTIVATION_TRANSACTIONS)) { QMessageBox::warning(this, windowTitle(), - tr("No more than %1 activation transactions can be sent at once.").arg(MAX_ACTIVATION_TRANSACTIONS), + tr("Only %1 activation transactions can be sent at once.").arg(MAX_ACTIVATION_TRANSACTIONS), QMessageBox::Ok, QMessageBox::Ok); return; } diff --git a/src/qt/specialtransactiondialog.h b/src/qt/specialtransactiondialog.h index e8413905..e19cdb4e 100644 --- a/src/qt/specialtransactiondialog.h +++ b/src/qt/specialtransactiondialog.h @@ -105,7 +105,7 @@ static const QString strRegistrationFeeDescription = "Register fee"; static const QString strActivationTxTitle = "Activate Rewards"; static const QString strActivationTxDescription = ( "Use this form to send an ActivateReward transaction to make your addresses eligible for SmartRewards. " -"A small fee of 0.002 SMART will be taken from outputs you choose.\n\n" +"A small fee of 0.001 SMART will be taken from outputs you choose.\n\n" "You can either manually select an input for each address or automatically select the smallest input for each address by clicking the checkbox below." ); From a96992dc0356d2dbfea2234477c0360bd7b16890 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Mon, 1 Jun 2020 01:45:59 +0200 Subject: [PATCH 123/126] Add colors to activated and smartnode addresses in the activation list --- src/qt/forms/specialtransactiondialog.ui | 3 +++ src/qt/guiconstants.h | 4 ++++ src/qt/specialtransactiondialog.cpp | 29 +++++++++++++++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/qt/forms/specialtransactiondialog.ui b/src/qt/forms/specialtransactiondialog.ui index ab47896b..566ce924 100644 --- a/src/qt/forms/specialtransactiondialog.ui +++ b/src/qt/forms/specialtransactiondialog.ui @@ -363,6 +363,9 @@ + + + diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 8c8d1ab7..d2c83329 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -37,6 +37,10 @@ static const bool DEFAULT_SPLASHSCREEN = true; #define COLOR_TX_STATUS_DANGER QColor(200, 100, 100) /* Transaction list -- TX status decoration - default color */ #define COLOR_BLACK QColor(0, 0, 0) +/* SmartRewards Tab -- Bonus text and activated addresses */ +#define COLOR_GREEN QColor(60, 179, 113) +/* SmartRewards Tab -- SmartNode address */ +#define COLOR_YELLOW QColor(255, 199, 15) /* Tooltips longer than this (in characters) are converted into rich text, so that they can be word-wrapped. diff --git a/src/qt/specialtransactiondialog.cpp b/src/qt/specialtransactiondialog.cpp index 104f124f..7ee5ba39 100644 --- a/src/qt/specialtransactiondialog.cpp +++ b/src/qt/specialtransactiondialog.cpp @@ -14,6 +14,7 @@ #include "txmempool.h" #include "walletmodel.h" #include "sendcoinsdialog.h" +#include "guiconstants.h" #include "coincontrol.h" #include "consensus/validation.h" @@ -115,6 +116,10 @@ SpecialTransactionDialog::SpecialTransactionDialog(const SpecialTransactionType ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it + ui->legendLabel->setText(QString("Green addresses are already activated. " + "Yellow addresses are SmartNode inputs and do not qualify for SmartRewards.") + .arg(COLOR_GREEN.name()).arg(COLOR_YELLOW.name())); + UpdateElements(); // default view is sorted by amount desc @@ -820,7 +825,7 @@ void SpecialTransactionDialog::updateView() model->listCoins(mapCoins, false); BOOST_FOREACH(const PAIRTYPE(QString, std::vector)& coins, mapCoins) { - + QBrush lineBrush; QString sWalletAddress = coins.first; QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); @@ -842,17 +847,29 @@ void SpecialTransactionDialog::updateView() if( type == ACTIVATION_TRANSACTIONS ){ CKeyID keyId; - CSmartAddress voteAddress(sWalletAddress.toStdString()); + CSmartAddress address(CSmartAddress::Legacy(sWalletAddress.toStdString())); int nCurrentRound = 0; + CSmartRewardEntry *reward = nullptr; { LOCK(cs_rewardscache); nCurrentRound = prewards->GetCurrentRound()->number; + prewards->GetRewardEntry(address, reward, false); } - if( !voteAddress.GetKeyID(keyId) ){ + if( !address.GetKeyID(keyId) ){ continue; } + + if (reward) { + if (reward->fActivated) { + // Address is already activated + lineBrush.setColor(COLOR_GREEN); + } else if (!reward->smartnodePaymentTx.IsNull()) { + // Address is linked to a SmartNode + lineBrush.setColor(COLOR_YELLOW); + } + } } CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem(); @@ -876,9 +893,11 @@ void SpecialTransactionDialog::updateView() itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); // label + itemWalletAddress->setForeground(COLUMN_LABEL, lineBrush); itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); // address + itemWalletAddress->setForeground(COLUMN_ADDRESS, lineBrush); itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); CAmount nSum = 0; @@ -916,13 +935,12 @@ void SpecialTransactionDialog::updateView() { itemOutput->setDisabled(true); } - } itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); + itemWalletAddress->setForeground(COLUMN_AMOUNT, lineBrush); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum)); - } for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) @@ -936,5 +954,4 @@ void SpecialTransactionDialog::updateView() UpdateElements(); connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int))); - } From e4e8dbe72a7825f9b5c39a4281b91d3d5ae6a14a Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Fri, 5 Jun 2020 18:22:58 +0200 Subject: [PATCH 124/126] Only make SmartNode payments if a minimum number of SmartNodes is active on the network --- src/consensus/consensus.h | 3 +++ src/smartnode/smartnodepayments.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 12728d9d..2c90438f 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -49,6 +49,9 @@ static const int TESTNET_V1_2_8_NODES_BLOCK_INTERVAL = 2; static const int TESTNET_V1_3_NODES_PER_BLOCK = 1; static const int TESTNET_V1_3_NODES_BLOCK_INTERVAL = 2; +/** Minimum number of active SmartNodes required to make SmartNode payments */ +static const int MIN_ACTIVE_SMARTNODES = 3; + inline unsigned int MaxBlockSigOps() { return MAX_BLOCK_SERIALIZED_SIZE / 50; diff --git a/src/smartnode/smartnodepayments.cpp b/src/smartnode/smartnodepayments.cpp index 2c61fa02..8a1e0e2d 100644 --- a/src/smartnode/smartnodepayments.cpp +++ b/src/smartnode/smartnodepayments.cpp @@ -231,6 +231,8 @@ void CSmartnodePayments::FillBlockPayee(CMutableTransaction& txNew, int nHeight, { vxoutSmartNodes.clear(); + if( mnodeman.size() < MIN_ACTIVE_SMARTNODES ) return; + if( MainNet() ){ if( nHeight < HF_V1_1_SMARTNODE_HEIGHT ){ From 7d9c7dd041364a282412bac065b307be54be6556 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Wed, 10 Jun 2020 23:20:03 +0200 Subject: [PATCH 125/126] fix small bug in variable naming --- src/base58.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base58.cpp b/src/base58.cpp index 75a7041e..c757d5cc 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -220,7 +220,7 @@ bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) vchData.resize(vchTempNew.size() - nVersionBytes); if (!vchData.empty()) memcpy(&vchData[0], &vchTempNew[nVersionBytes], vchData.size()); - memory_cleanse(&vchTemp[0], vchTempNew.size()); + memory_cleanse(&vchTempNew[0], vchTempNew.size()); } From 263d41962c5d40aaf8665775147429bf26d405f8 Mon Sep 17 00:00:00 2001 From: Gregory Lemercier Date: Wed, 10 Jun 2020 23:21:06 +0200 Subject: [PATCH 126/126] Nullify pointer after deleting it to avoid potential issues --- src/smartrewards/rewards.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smartrewards/rewards.cpp b/src/smartrewards/rewards.cpp index 4c2b2d7f..4919e3ea 100644 --- a/src/smartrewards/rewards.cpp +++ b/src/smartrewards/rewards.cpp @@ -476,6 +476,7 @@ bool CSmartRewards::GetRewardEntry(const CSmartAddress& id, CSmartRewardEntry*& } delete entry; + entry = nullptr; return false; }